Skip to content

chore: move dead and defensive serde guards out of convert - #5595

Open
andygrove wants to merge 2 commits into
mainfrom
andygrove/serde-invariant-dead-guards
Open

chore: move dead and defensive serde guards out of convert#5595
andygrove wants to merge 2 commits into
mainfrom
andygrove/serde-invariant-dead-guards

Conversation

@andygrove

Copy link
Copy Markdown
Member

Which issue does this PR close?

Part of #5574. First of a few small PRs moving convert-side declines into getSupportLevel; this one is deliberately the zero-risk slice.

Rationale for this change

A serde that reports Compatible from getSupportLevel and then returns None from convert breaks the serde invariant, and it is also the one shape the codegen dispatcher cannot see — dispatchIfFallback is reached only from the Unsupported and Incompatible arms of exprToProtoInternal (QueryPlanSerde.scala:941 and :968), so a decline from inside convert always costs a whole-operator Spark fallback.

Auditing all 35 convert-side declines, five are node-local and had no user-visible effect, because each guard was already dead or unreachable. Those are worth moving first: the change is provably behavior-preserving, and it shrinks the surface the harder follow-ups have to reason about.

What changes are included in this PR?

  • CometFromUnixTime (unixtime.scala) and CometUnixTimestamp (datetime.scala) re-checked in convert exactly what getSupportLevel had already reported as Unsupported. CometFromUnixTime additionally mixes in CodegenDispatchFallback, so the Unsupported result is either dispatched or fails before convert; either way the declining input never reached the duplicated check. Removed.
  • CometShuffle (collectionOperations.scala) and CometUuid (nondetermenistic.scala) guarded a randomSeed that their own comments note is always defined in a resolved plan. Moved to getSupportLevel; convert now reads the seed directly, matching the existing pattern in CometKnownFloatingPointNormalized and CometRandStr.
  • CometScalarSubquery screened the data type in convert. Moved to getSupportLevel. The serializeDataType backstop stays — that is a genuinely different predicate from supportedDataType, as the scaladoc on serializeDataType spells out.

Also drops four withFallbackReason imports that became unused.

Deliberately not included: CometLiteral. Its convert guards look like the same pattern but are reachable, not dead — supportedDataType admits CalendarIntervalType while the literal value match has no arm for it, so a non-null calendar-interval literal really does fall through to case dt =>. Left as-is.

How are these changes tested?

No new tests, because there is no new behavior — the point of this slice is that the removed guards were unreachable. Covered by existing suites:

  • CometTemporalExpressionSuite, CometUuidExpressionSuite, CometArrayExpressionSuite — 92 tests
  • CometSqlFileTestSuite (includes from_unix_time_enabled.sql, to_unix_timestamp_time_parser_policy.sql, to_unix_timestamp_time_parser_policy_corrected.sql) and CometExpressionSuite — 607 tests

All green on Spark 4.1.

Five serdes report Compatible from getSupportLevel and then decline inside
convert. That combination breaks the serde invariant, and it is also the
one shape the codegen dispatcher cannot see: dispatchIfFallback is reached
only from the Unsupported and Incompatible arms of exprToProtoInternal, so
a decline from convert always costs a whole-operator Spark fallback.

None of these five had a user-visible effect, because each guard was
either dead or unreachable:

- CometFromUnixTime and CometUnixTimestamp re-checked in convert exactly
  what getSupportLevel had already reported as Unsupported, so convert was
  never reached for the declining input.
- CometShuffle and CometUuid guarded a randomSeed their own comments note
  is always defined in a resolved plan. Moved to getSupportLevel.
- CometScalarSubquery screened the data type in convert. Moved to
  getSupportLevel; the serializeDataType backstop stays, since that is a
  different predicate from supportedDataType.

CometLiteral is deliberately left alone: supportedDataType admits
CalendarIntervalType but the literal value match has no arm for it, so
that guard is reachable rather than dead.

Related to #5574.
return None
}

// getSupportLevel reports an unsupported input type before reaching here, so no re-check.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Keep string-input rejection ahead of the collation opt-in

On Spark 4.0, unix_timestamp(s, collate('yyyy-MM-dd', 'UTF8_LCASE')) with a non-foldable plain STRING column s makes getSupportLevel return Incompatible before it checks isSupportedInputType. With spark.comet.expression.UnixTimestamp.allowIncompatible=true, exprToProto therefore calls this method. The deleted guard returned None for that input. This now serializes the string child into the native UnixTimestamp expression. The format is not serialized, so no collated scan or Collate serializer is required. Native SparkUnixTimestamp only accepts date/timestamp inputs, and its unsupported-string error propagates instead of falling back to Spark. Could we retain the input-type rejection even when collation selects Incompatible, and cover this live-string/collated-format case in a regression test? This path is source-traced. The SQL witness was not executed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, and it reproduces. getSupportLevel checked collation first, so unix_timestamp(s, 'yyyy-MM-dd HH:mm:ss' COLLATE UTF8_LCASE) over a plain STRING column returned Incompatible before it ever looked at the input type, and with allowIncompatible=true that goes straight to convert — which no longer has the guard. Running it on this branch gives CometNativeException: unix_timestamp does not support input type: Utf8 instead of a fallback.

Fixed in 559c0f9 by screening the input type ahead of the collation check: a non-date/timestamp input has no native path at all, so it should report Unsupported regardless of collation, and allowIncompatible should never be able to reach it. Collation still reports Incompatible for the input types that do have a native path, so the opt-in behavior there is unchanged. Added the live-string/collated-format case to CometTemporalExpressionSuite — it fails on the parent commit with the native error above and passes with the fix.

CometUnixTimestamp.getSupportLevel checked for a non-default collation
first, so unix_timestamp(s, 'fmt' COLLATE UTF8_LCASE) over a plain STRING
column reported Incompatible before it ever looked at the input type. With
spark.comet.expression.UnixTimestamp.allowIncompatible=true, exprToProto
waves Incompatible straight through to convert, and the input-type guard
that used to live there is gone as of the previous commit. The string child
was therefore serialized into the native UnixTimestamp expression, whose
kernel accepts only date/timestamp:

  CometNativeException: unix_timestamp does not support input type: Utf8

Reorder getSupportLevel so an unsupported input type reports Unsupported
regardless of collation. A non-date/timestamp input has no native path at
all, so allowIncompatible must not be able to reach it. Collation remains
Incompatible for the input types that do have a native path, so the
existing opt-in behavior is unchanged.

@sunchao sunchao left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 559c0f9a9746595567dc5afccb47dfbc93e358c1. The previously reported string-input/collation guard issue is fixed, with no new P1/P2 findings. Current CI shows 62 successful checks and 9 skipped. No local tests were run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants