Skip to content

Spark 3.1: fill ORC initial defaults on the row reader - #264

Closed
cbb330 wants to merge 1 commit into
chbush/oh120-orc-default-fillfrom
chbush/oh120-spark31-default-fill
Closed

Spark 3.1: fill ORC initial defaults on the row reader#264
cbb330 wants to merge 1 commit into
chbush/oh120-orc-default-fillfrom
chbush/oh120-spark31-default-fill

Conversation

@cbb330

@cbb330 cbb330 commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Opts the Spark 3.1 iterative ORC reader into #263's initial-default projection and supplies Spark's constant conversion to the ID-binding StructReader.

  • RowDataReader explicitly calls supportsInitialDefaults().
  • SparkOrcValueReaders converts missing-field defaults into Spark's in-memory representation.
  • Constant conversion lives in SparkValueConverters, shared with the existing partition-constant path.
  • ORC scans projecting an initial default are routed away from vectorization until the vectorized reader is implemented.

Scope

Spark 3.1 iterative ORC reads only. The vectorized ORC reader is intentionally deferred; schemas without projected initial defaults continue to vectorize normally.

Other Spark and Flink versions do not opt into #263 and retain their previous projection behavior.

Stack

  1. ORC: bind struct fields by Iceberg field id in generic and Spark 3.1 readers #265 — ID-based StructReader backport
  2. ORC: fill initial defaults for missing id-bound fields #263 — Generic ORC initial-default fill and reader capability gate
  3. This PR — Spark 3.1 iterative ORC initial-default fill

Review this PR's delta against chbush/oh120-orc-default-fill.

Testing Done

  • Spark 3.1 row tests cover declared, undeclared, and nested defaults
  • Spark scan tests cover mixed old/new ORC files and physical value/null precedence
  • Spark filter tests cover top-level and nested defaults, null parents, equality, set, range, and string-prefix predicates
  • Reader-factory tests verify default projections use iterative reads while ordinary projections remain vectorized
  • Spotless passes
  • Spark 3.1 CI passes

}
}

protected static Object convertConstant(Type type, Object value) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

why is this moved out of base data reater?

Comment on lines +117 to +118
// Follow-up: wire initial-default constants into VectorizedSparkOrcReaders. Tables whose
// in-memory schema declares defaults must remain on the row reader until this path is wired.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is there a PR for the vectorized spark orc readers?

@mkuchenbecker mkuchenbecker left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

the delineation of spark 3.1 and 3.5 is unclear to me why this is implemented in 3.1?

@cbb330
cbb330 force-pushed the chbush/oh120-spark31-default-fill branch 2 times, most recently from 459d91f to b6b7d89 Compare August 3, 2026 01:38
@cbb330
cbb330 force-pushed the chbush/oh120-orc-default-fill branch from 3fd044f to 5175788 Compare August 3, 2026 01:58
@cbb330
cbb330 force-pushed the chbush/oh120-spark31-default-fill branch from b6b7d89 to 77082fc Compare August 3, 2026 01:58
@cbb330
cbb330 force-pushed the chbush/oh120-orc-default-fill branch from 5175788 to 540604c Compare August 3, 2026 02:03
@cbb330
cbb330 force-pushed the chbush/oh120-spark31-default-fill branch 2 times, most recently from af3ada9 to 2880ffb Compare August 3, 2026 05:47
@cbb330
cbb330 force-pushed the chbush/oh120-orc-default-fill branch from 540604c to 60115f6 Compare August 3, 2026 06:42
@cbb330
cbb330 force-pushed the chbush/oh120-spark31-default-fill branch from 2880ffb to b5e1ffa Compare August 3, 2026 06:42
@cbb330
cbb330 force-pushed the chbush/oh120-orc-default-fill branch from 60115f6 to d5893e8 Compare August 3, 2026 07:10
@cbb330
cbb330 force-pushed the chbush/oh120-spark31-default-fill branch from b5e1ffa to fd15d74 Compare August 3, 2026 07:10
@cbb330
cbb330 force-pushed the chbush/oh120-orc-default-fill branch from d5893e8 to ca18b89 Compare August 3, 2026 07:13
@cbb330
cbb330 force-pushed the chbush/oh120-spark31-default-fill branch 2 times, most recently from 73b8758 to c7082d1 Compare August 3, 2026 07:25
Opt the Spark 3.1 row ORC reader into default filling by supplying Spark's
constant converter to the id-binding StructReader, so an absent field that
declares an initial-default is materialized in Spark's in-memory
representation.

Move convertConstant out of BaseDataReader into SparkValueConverters in the
data package, mirroring Flink's RowDataUtil. The converter is a value
conversion utility rather than reader behavior, and the readers that need it
live in the data package. This keeps BaseDataReader package-private instead
of widening an internal class to public, and leaves the dependency running
source -> data.

Mirrors the Generic reader; the visitor call site is unchanged. Vectorized
reads are not wired yet, so a table whose schema declares defaults must stay
on the row reader.

Co-authored-by: Cursor <cursoragent@cursor.com>

@mkuchenbecker mkuchenbecker left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Mostly LGTM, some additional testing and I want to undrestand the default behavior. I know it was moved but it seems like a silent failure (correct me if im wrong on that).

}

return new GenericInternalRow(values);
default:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is the default here correct? Should i.e. i assume this is an error condition.

Comment on lines +50 to +58
private static final Schema WRITE_SCHEMA =
new Schema(
required(1, "id", Types.LongType.get()), optional(2, "data", Types.StringType.get()));

private static final Schema READ_SCHEMA =
new Schema(
required(1, "id", Types.LongType.get()),
optional(2, "data", Types.StringType.get()),
Types.NestedField.optional("country")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can we exercise all data types?

@cbb330

cbb330 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #267. This was the Spark half of Option A; defaulted scans now stay on the row reader in the #267#269 stack. Closing.

@cbb330 cbb330 closed this Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants