chore: fallback to Spark if legacy sql configurations are set - #4799
chore: fallback to Spark if legacy sql configurations are set#4799comphead wants to merge 34 commits into
Conversation
| `spark.sql.legacy.timeParserPolicy`). Comet implements current Spark semantics and does **not** | ||
| reproduce these legacy behaviors. | ||
|
|
||
| By default, when Comet detects that any `spark.sql.legacy.*` config is set to `true`, it disables |
There was a problem hiding this comment.
can't we just update the serde for specific expressions to return Unsupported rather than fall back for all queries, even queries that would not be affected by a legacy config?
There was a problem hiding this comment.
we should just fall back to the codegen dispatch approach in most cases
There was a problem hiding this comment.
Let me investigate this, sometimes the conf param is vaguely explained like
val LEGACY_JAVA_CHARSETS = buildConf("spark.sql.legacy.javaCharsets")
.internal()
.doc("When set to true, the functions like `encode()` can use charsets from JDK while " +
"encoding or decoding string values. If it is false, such functions support only one of " +
"the charsets: 'US-ASCII', 'ISO-8859-1', 'UTF-8', 'UTF-16BE', 'UTF-16LE', 'UTF-16', " +
"'UTF-32'.")
.version("4.0.0")
.booleanConf
.createWithDefault(false)
it refers to encode() explicitly but also to something else. Maybe I can fish out exact functions from Spark code depending on legacy params and in this case we can fallback to codegen dispatch
There was a problem hiding this comment.
Also, Spark has legacy configs that default to true, so this will make all jobs fall back by default.
val VIEW_SCHEMA_BINDING_ENABLED = buildConf("spark.sql.legacy.viewSchemaBindingMode")
.internal()
.doc("Set to false to disable the WITH SCHEMA clause for view DDL and suppress the line in " +
"DESCRIBE EXTENDED and SHOW CREATE TABLE.")
.version("4.0.0")
.booleanConf
.createWithDefault(true)f5d2abc to
7125db0
Compare
| - test("cast to variant/to_variant_object with scan input") { | ||
| + test("cast to variant/to_variant_object with scan input", | ||
| + IgnoreComet("\"VariantType\" not supported")) { |
There was a problem hiding this comment.
This seems like a regression. This test was previously passing because we fell back to Spark and now we fail the query?
| // without duplicating the legacy branch natively. | ||
| private val legacyNegativeIndexConfig = "spark.sql.legacy.negativeIndexInArrayInsert" | ||
|
|
||
| private val legacyNegativeIndexReason = | ||
| s"`$legacyNegativeIndexConfig=true` legacy negative-index semantics are not implemented" + | ||
| " natively" | ||
|
|
||
| override def getIncompatibleReasons(): Seq[String] = Seq(legacyNegativeIndexReason) | ||
|
|
||
| override def getSupportLevel(expr: ArrayInsert): SupportLevel = { | ||
| if (SQLConf.get.getConfString(legacyNegativeIndexConfig, "false").toBoolean) { | ||
| Incompatible(Some(legacyNegativeIndexReason)) | ||
| } else { | ||
| Compatible() | ||
| } | ||
| } |
There was a problem hiding this comment.
This change looks good and could really be a standalone PR. This also looks like a bug fix for an issue where we were lacking tests?
| } | ||
|
|
||
| object CometCount extends CometAggregateExpressionSerde[Count] { | ||
|
|
There was a problem hiding this comment.
could you revert this whitespace change
| "spark.sql.legacy.parquet.datetimeRebaseModeInRead" -> "CORRECTED", | ||
| "spark.sql.legacy.parquet.datetimeRebaseModeInWrite" -> "CORRECTED", | ||
| "spark.sql.legacy.parquet.int96RebaseModeInRead" -> "CORRECTED", | ||
| "spark.sql.legacy.parquet.int96RebaseModeInWrite" -> "CORRECTED", | ||
| "spark.sql.legacy.parquet.nanosAsLong" -> "false", |
There was a problem hiding this comment.
Can we not handle the parquet ones in scan planning?
The CodegenDispatchFallback mixin on CometStrToMap and the matching str_to_map_collation.sql fixture edit belong with the collation PR, not this legacy-conf branch. Revert both back to upstream/main here; they land on the `collation` branch instead.
The updated assertions in this fixture rely on CometStrToMap having CodegenDispatchFallback mixed in, which now lives on the collation branch. Revert to upstream/main here so the file matches the on-disk serde behaviour of the chore branch.
|
Nice to see the redesign land. A couple of correctness questions before this ships. (Review drafted with LLM assistance.) 1. The new test in Either the flag needs to go into 2. Setting the primary parquet key instead of the legacy alias silently bypasses the fallback. The fallback keys off 3. Description bullet mentions The description's session-wide bullet reads |
|
Comparing the curated lists here against the inventory in #4180, these
Should any of these be added to Some may already be safe to ignore. A few are analyzer-side and get resolved before Comet ever sees the plan ( |
| if (triggered.nonEmpty) { | ||
| val keys = triggered.mkString(", ") | ||
| logWarning( | ||
| "Comet extension is disabled because the following execution-affecting " + | ||
| s"spark.sql.legacy.* configs are set to non-default values: $keys. Comet does not " + | ||
| "implement these legacy execution semantics. To keep Comet enabled anyway, set " + | ||
| s"${COMET_LEGACY_CONF_FALLBACK_ENABLED.key}=false (Spark compatibility is not " + | ||
| "guaranteed in that case).") | ||
| return false |
There was a problem hiding this comment.
Do we still need this? I thought we were moving the checks to the affected expressions/scans now? Disabling the plugin seems like overkill, IMO
| extends CometExpressionSerde[Cast] | ||
| with CometExprShim | ||
| with CometTypeShim | ||
| with CodegenDispatchFallback { |
There was a problem hiding this comment.
Adding codegen-dispatch for cast is a large change. Seems like this should be a separate PR?
|
Zooming out from the individual file comments, I think this PR is doing several independent things and would be much easier to review and to revert if it were split. Right now it is 24 files touching 25 distinct legacy configs plus a A split I would find easy to review, roughly in dependency order: 1. Per-scan Parquet fallback. 2. Session-wide fallback. 3. 4. 5. Per-expression legacy gates. These could go together or separately. I already noted on the individual files that Note that 3 has to land before the Happy to review each piece quickly as it comes. Splitting would also mean the low-risk parts (1 and 2) are not blocked on working out the (Comment drafted with LLM assistance.) |
|
I'll detach cast as codegen as a separate PR |
|
Also will remove the global Comet fallback for params and we need to address them separately |
Which issue does this PR close?
Closes #4786.
Closes #5013
Rationale for this change
spark.sql.legacy.*configs opt into pre-modern Spark semantics that Comet's native operatorsdon't implement. Leaving Comet enabled when they're set can silently diverge from Spark. This
PR makes Comet safe-by-default across the whole family.
What changes are included in this PR?
Session-wide fallback — new
spark.comet.legacyConfFallback.enabled(defaulttrue).When any curated
spark.sql.legacy.*key is set to a non-default value,isCometLoadedreturns
falseand warns. Curated set (via newLegacyConfFallback+ version-shimmedShimLegacyConfFallback) covers decimal/analyzer rules, char/varchar, upcast/type-coercion,optimizer plan-shaping, view-schema compensation, and file-source cache options.
Per-scan Parquet fallback —
CometScanRule.parquetFallbackReasonchecks both the primarykey and its
spark.sql.legacy.*alias fordatetimeRebaseModeInRead,int96RebaseModeInRead,and
nanosAsLong, falling back only the affected scan. Write-side configs excluded.Per-expression handling for configs tied to specific expressions:
Cast: honortimeParserPolicy; routecastComplexTypesToString.enabledvia codegendispatch; add
VariantTypeguard.ArrayInsert: gatenegativeIndexInArrayInsertviaCodegenDispatchFallback.In/InSet: gatenullInEmptyListBehavior(resolved asexplicit || !ansiEnabled).StructsToCsv: gatenullValueWrittenAsQuotedEmptyStringCsv.StringLPad/StringRPad: rejectBinaryTypestr(lpadRpadAlwaysReturnString).Size/ArrayExists(already honored via Spark-constructed fields).Shim — new
isVariantTypeonCometTypeShim(false on 3.x, real check on 4.x).Tests + docs — unit tests for session-wide and per-scan fallbacks, SQL file tests for
legacy dispatch (
array_insert,exists, complex-type cast), refreshed 4.0.2/4.1.2 diffs,new "Spark legacy configs" section in
compatibility/index.md.How are these changes tested?
New tests in
CometSparkSessionExtensionsSuite,CometScanRuleSuite, updatedCometCastSuite/CometExpressionSuite, new SQL file tests, refreshed Spark diffs.