Skip to content

feat(java): add fragment-level addColumns from an Arrow stream - #9231

Open
zhangyue19921010 wants to merge 1 commit into
lance-format:mainfrom
zhangyue19921010:java-fragment-add-columns-by-reader
Open

zhangyue19921010 wants to merge 1 commit into
lance-format:mainfrom
zhangyue19921010:java-fragment-add-columns-by-reader

Conversation

@zhangyue19921010

Copy link
Copy Markdown
Collaborator

Expose FileFragment::add_columns(NewColumnTransform::Reader) through the Java bindings as Fragment.addColumns(ArrowArrayStream, Optional batchSize), the fragment-level equivalent of Dataset.addColumns(reader).

Unlike Fragment.mergeColumns, the stream is zipped positionally against the fragment's live rows and is never buffered in full, so callers that can supply one row per live row in row address order (e.g. distributed backfill engines) can add columns far larger than memory. Streams with too few or too many rows fail instead of misaligning.

Expose FileFragment::add_columns(NewColumnTransform::Reader) through the Java
bindings as Fragment.addColumns(ArrowArrayStream, Optional<Long> batchSize),
the fragment-level equivalent of Dataset.addColumns(reader).

Unlike Fragment.mergeColumns, the stream is zipped positionally against the
fragment's live rows and is never buffered in full, so callers that can supply
one row per live row in row address order (e.g. distributed backfill engines)
can add columns far larger than memory. Streams with too few or too many rows
fail instead of misaligning.
@github-actions github-actions Bot added A-java Java bindings + JNI enhancement New feature or request labels Sep 15, 2026

@lance-gatekeeper lance-gatekeeper Bot 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.

Gate recommendation: request changes.

The fragment-scoped streaming path is the right mechanism and the normal row-alignment behavior works, but the new batch-size boundary must reject zero before entering Rust's updater. A positive-value check keeps invalid caller configuration from terminating the JVM while preserving the streaming design.

let batch_size = match env.get_long_opt(&batch_size)? {
Some(value) => Some(
value
.try_into()

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.

A zero value passes this conversion and reaches FragmentReader::read_all(0), whose system-column path constructs step_by(0). The panic crosses the extern "system" entrypoint, cannot unwind, and aborts the JVM instead of returning an input error. Reject non-positive values here (or at the shared updater boundary) and cover Optional.of(0L) with a Java regression test.

Reproducer

After exporting a valid 21-row stream in testAddColumnsByReader, I ran:

assertThrows(
    IllegalArgumentException.class,
    () -> fragment.addColumns(stream, Optional.of(0L)));

Expected: IllegalArgumentException. Observed:

panicked ... step_by.rs: assertion failed: step != 0
panic in a function that cannot unwind
thread caused non-unwinding panic. aborting.

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 15, 2026
@zhangyue19921010

Copy link
Copy Markdown
Collaborator Author

blocked on #9233

@lance-gatekeeper lance-gatekeeper Bot removed the K-changes Latest Gatekeeper recommendation requests changes. label Sep 15, 2026

@lance-gatekeeper lance-gatekeeper Bot 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.

Gate recommendation: request changes.

The author's dependency note changes the acceptance path: #9233 contains the shared Updater::try_new guard for the verified zero-batch-size JVM abort. The fragment-scoped streaming design remains sound, but land #9233 before this PR (and refresh this branch if needed); until that guard is in this PR's merge base, the current head remains unsafe for Optional.of(0L).

@lance-gatekeeper lance-gatekeeper Bot added the K-changes Latest Gatekeeper recommendation requests changes. label Sep 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-java Java bindings + JNI enhancement New feature or request K-changes Latest Gatekeeper recommendation requests changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant