Skip to content

fix: validate substrait filters that need no field pruning - #8484

Merged
Xuanwo merged 3 commits into
lance-format:mainfrom
1fanwang:fix/7805-substrait-validate-unpruned
Aug 23, 2026
Merged

Xuanwo merged 3 commits into
lance-format:mainfrom
1fanwang:fix/7805-substrait-validate-unpruned

Conversation

@1fanwang

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Rationale for this change

remap_expr_references doubles as the validation pass that rejects operators we cannot push down (window functions, subqueries, lambdas), but parse_substrait only calls it when remove_extension_types actually drops a field. A filter whose base schema has no extension types skips the checks entirely, and the unsupported expression reaches the DataFusion consumer instead.

The user sees a consumer-level error rather than ours. A subquery over an unpruned schema reports:

Substrait error: Subquery expression without SubqueryType is not allowed

instead of Window functions or subqueries not allowed in filter expression.

What changes are included in this PR?

remap_expr_references now runs unconditionally.

The guard it replaces is not load-bearing for the remapping itself: remove_extension_types builds the index mapping by walking every field and only advancing the destination counter for fields it keeps, so when nothing is dropped the mapping is the identity and the remap is a no-op. Dropping the guard adds the validation without changing any index.

This keeps validation and remapping as one traversal rather than two that have to be kept in step.

Are these changes tested?

Yes. test_unsupported_operator_rejected_without_pruning parses a subquery and a lambda against a single-Int32 base schema, which needs no pruning, and asserts each is rejected with its own message.

On the current code the subquery case reaches the consumer instead:

cargo test -p lance-datafusion --features substrait --lib substrait::tests::test_unsupported_operator
Before
running 1 test
test substrait::tests::test_unsupported_operator_rejected_without_pruning ... FAILED

---- substrait::tests::test_unsupported_operator_rejected_without_pruning stdout ----
thread '...' panicked at rust/lance-datafusion/src/substrait.rs:712:9:
unexpected error: LanceError(IO): Substrait error: Subquery expression without SubqueryType is not allowed, rust/lance-datafusion/src/substrait.rs:333:9

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 84 filtered out
After
running 14 tests
test substrait::tests::test_parse_substrait_aggregate_multiple_aggregates ... ok
test substrait::tests::test_parse_substrait_aggregate_sum ... ok
test substrait::tests::test_parse_substrait_aggregate_count_star ... ok
test substrait::tests::test_parse_substrait_aggregate_sum_with_group_by ... ok
test substrait::tests::test_substrait_conversion ... ok
test substrait::tests::test_expr_substrait_roundtrip ... ok
test substrait::tests::test_substrait_roundtrip_with_list_struct_struct ... ok
test substrait::tests::test_substrait_roundtrip_with_fixed_size_list_column ... ok
test substrait::tests::test_substrait_roundtrip_like ... ok
test substrait::tests::test_substrait_roundtrip_with_list_of_struct ... ok
test substrait::tests::test_substrait_roundtrip_with_many_nested_columns ... ok
test substrait::tests::test_substrait_roundtrip_starts_with ... ok
test substrait::tests::test_unsupported_operator_rejected_without_pruning ... ok
test substrait::tests::test_substrait_roundtrip_with_null_and_float16_columns ... ok

test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 71 filtered out

The roundtrip tests above cover the pruning and nested-schema paths, including List<Struct> and extension-type removal, so they would catch a remap regression. The whole lance-datafusion suite passes (85 tests).

Are there any user-facing changes?

Unsupported filter operators are now rejected with the descriptive error in the case that previously slipped through. No API change.

@github-actions github-actions Bot added the bug Something isn't working label Aug 11, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-changes Latest Gatekeeper recommendation requests changes. and removed K-changes Latest Gatekeeper recommendation requests changes. labels Aug 11, 2026
lance-gatekeeper[bot]

This comment was marked as outdated.

@lance-gatekeeper lance-gatekeeper Bot added K-changes Latest Gatekeeper recommendation requests changes. and removed K-changes Latest Gatekeeper recommendation requests changes. labels Aug 11, 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: approve.

The conditional-validation defect and its panic regressions are now covered: unsupported operators are checked for unpruned schemas, omitted roots remain compatible, and malformed non-leading IfThen clauses return an input error.

@lance-gatekeeper lance-gatekeeper Bot added the K-approved Latest Gatekeeper recommendation permits acceptance. label Aug 11, 2026
remap_expr_references also rejects operators that cannot be pushed down,
but it only ran when remove_extension_types actually dropped a field. A
filter over a schema with no extension types therefore skipped the
checks and reached the DataFusion consumer.

Run it unconditionally. When nothing is dropped the index mapping is the
identity, so the remap is a no-op and only the validation is added.

Signed-off-by: 1fanwang <1fannnw@gmail.com>
Running the walker on every filter exposed its unwraps on optional
proto fields. An omitted root_type means a root reference, and a leading
if-clause without then supplies the case expression, so both are valid
input that panicked. Handle those, and report the remaining absent
fields as invalid input rather than panicking on user-supplied bytes.

Signed-off-by: 1fanwang <1fannnw@gmail.com>
DataFusion only reads a clause's condition as the case expression for
ifs[0]; it unwraps then for every later clause. Skipping an absent then
on all of them let that panic through instead of reporting invalid input.

Signed-off-by: 1fanwang <1fannnw@gmail.com>
@1fanwang
1fanwang force-pushed the fix/7805-substrait-validate-unpruned branch from 9278c30 to 58d3461 Compare August 11, 2026 19:36
@Xuanwo
Xuanwo merged commit efaca3b into lance-format:main Aug 23, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working K-approved Latest Gatekeeper recommendation permits acceptance.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Substrait filter validation (lambda/window/subquery rejection) is skipped when no schema fields are pruned

3 participants