Skip to content

[SPARK-58814][SQL] Cover CHAR/VARCHAR round-trips and stop ORC truncating scans - #58317

Open
srielau wants to merge 2 commits into
apache:masterfrom
srielau:SPARK-58814-format-roundtrips
Open

[SPARK-58814][SQL] Cover CHAR/VARCHAR round-trips and stop ORC truncating scans#58317
srielau wants to merge 2 commits into
apache:masterfrom
srielau:SPARK-58814-format-roundtrips

Conversation

@srielau

@srielau srielau commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Parent: SPARK-58794 (first-class CHAR/VARCHAR under spark.sql.charVarchar.standardSemantics.enabled).

  • Under standardSemantics, keep Spark responsible for CHAR/VARCHAR assignment and scan checks on ORC by requesting physical ORC STRING. The row decoder accepts all StringType subtypes recursively. Preserve-only mode retains native ORC CHAR/VARCHAR enforcement.
  • Add SPARK-58814 coverage for major formats under standardSemantics:
    • Parquet/ORC nested CHAR/VARCHAR (struct/array/map keys) on file-only inference, V1 and V2
    • Avro nested inference plus explicit-schema pad/overflow (V1 and V2)
    • CSV/JSON user-schema scans, length checks, and catalog INSERT assignment/overflow
    • Cross-flag: standardSemantics=false collapses to STRING; preserveCharVarcharTypeInfo keeps types

Parquet already embeds Spark schema JSON in footer metadata, so nested CHAR/VARCHAR inference needed tests rather than a writer change.

Why are the changes needed?

Without this, Spark-written files and user-specified schemas do not keep first-class CHAR/VARCHAR through round-trips in the remaining format gaps. For ORC specifically, an explicit schema("c CHAR(4)") read sent native ORC char(n) via MAPRED_INPUT_SCHEMA, so ORC truncated "abcdef" to "abcd" before charTypeReadSideCheck and EXCEED_LIMIT_LENGTH never fired.

Does this PR introduce any user-facing change?

Yes, when spark.sql.charVarchar.standardSemantics.enabled is true (unreleased / master):

  • ORC no longer silently truncates oversized CHAR/VARCHAR values on schema-specified reads; Spark rejects them with EXCEED_LIMIT_LENGTH.
  • Parquet/ORC/Avro file-only inference and CSV/JSON user schemas preserve CHAR/VARCHAR types and apply pad/length and INSERT assignment as covered by the new tests.

How was this patch tested?

New tests in BasicCharVarcharTestSuite (SPARK-58814: major formats preserve CHAR/VARCHAR schemas and values) and AvroSuite (V1 and V2). Also ran existing ORC query suites and scalastyle:

build/sbt "sql/testOnly org.apache.spark.sql.BasicCharVarcharTestSuite -- -z SPARK-58814"
build/sbt "avro/testOnly org.apache.spark.sql.avro.AvroV1Suite -- -z SPARK-58814"
build/sbt "avro/testOnly org.apache.spark.sql.avro.AvroV2Suite -- -z SPARK-58814"
build/sbt "sql/testOnly org.apache.spark.sql.execution.datasources.orc.OrcV1QuerySuite"
build/sbt "sql/testOnly org.apache.spark.sql.execution.datasources.orc.OrcV2QuerySuite"
build/sbt "sql/scalastyle" "sql/Test/scalastyle" "avro/scalastyle" "avro/Test/scalastyle"

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Cursor Grok 4.6

…ting scans

Keep Spark responsible for CHAR/VARCHAR assignment and scan checks: ORC
was mapping an explicit CHAR/VARCHAR read schema to native ORC types,
which truncated oversize values before Spark could reject them. Add
Parquet/ORC/CSV/Avro coverage for nested inference, user schemas, and
INSERT assignment under standardSemantics.

@cloud-fan cloud-fan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please address the non-vectorized ORC decoder incompatibility and preserve-only VARCHAR enforcement, then make the nested ORC regression test materialize the collection fields it introduces.

This mapping is unconditional, so it also runs when preserveCharVarcharTypeInfo=true is the only reason the constrained type is retained and standard semantics is disabled. That branch of addPaddingForScan installs no VARCHAR read-side check. Requesting ORC string therefore removes native varchar(n) enforcement and can expose abcdef under a VARCHAR(4) schema. Please preserve the native constrained schema in preserve-only mode or add equivalent validation, with a value-level regression test for this flag combination.

Comment thread sql/core/src/test/scala/org/apache/spark/sql/CharVarcharTestSuite.scala Outdated
…cement

Decode all string-family types in the row reader, while retaining native ORC
constraints in preserve-only mode. Materialize nested collections and verify
nested overflow checks across V1/V2 and vectorized/row readers.

@cloud-fan cloud-fan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review summary

Two changes are needed before this is safe to merge: bind ORC reader schema selection to the persisted/analyzed CHAR/VARCHAR semantics so view results cannot silently change with the caller configuration, and make the Avro regression test observe its array and map values.

Findings

2 total: 0 P0, 1 P1, 1 P2, 0 P3.

Blocking (P1)

  • Keep the view-bound CHAR/VARCHAR mode for ORC scanssql/core/src/main/scala/org/apache/spark/sql/execution/datasources/orc/OrcUtils.scala:443 — see inline.

Non-blocking (P2)

  • Assert the Avro array and map values that the test createsconnector/avro/src/test/scala/org/apache/spark/sql/avro/AvroSuite.scala:3742 — see inline.

// Under standard semantics, keep Spark responsible for CHAR/VARCHAR assignment and scan
// checks. Native ORC would truncate or pad before Spark can validate the original value.
// Preserve-only mode retains the native constrained schema and its legacy enforcement.
case _: CharType | _: VarcharType if SQLConf.get.charVarcharStandardSemantics =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking (P1): This reads the task-side caller configuration, but spark.sql.charVarchar.standardSemantics.enabled is persisted with views. If a view is resolved with standard semantics and its caller later disables the setting, this branch requests native ORC VARCHAR; ORC can then truncate abcdef to abcd before the view's already-resolved Spark length check sees the value. That makes the persisted view caller-dependent and silently bypasses EXCEED_LIMIT_LENGTH. Please carry the analyzed/view-bound semantics into ORC reader construction instead, and add a permanent-view regression that flips the caller setting.

val readBack = spark.read.format("avro").load(path)
assert(DataType.equalsIgnoreNullability(readBack.schema, input.schema))
checkAnswer(
readBack.selectExpr("concat('<', c, '>')", "v", "concat('<', s.c, '>')"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Non-blocking (P2): This case creates the array and map, but the projection only materializes c, v, and s.c. Column pruning can skip decoding both collection fields, so a regression in array/map conversion or CHAR-key padding would still pass. Please select a and m as well and assert Seq("q") and Map("k " -> "v").

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