chore(sql): move join const-filter merge to optimizer#6856
chore(sql): move join const-filter merge to optimizer#6856bluestreak01 merged 5 commits intomasterfrom
Conversation
The fix for #6762 (commit 2263b2a) addressed double-wrapping of FilteredRecordCursorFactory in SqlCodeGenerator by combining filters at runtime. This follow-up moves the fix earlier into the pipeline: SqlOptimiser.optimiseJoins() now merges non-compile-time-constant constWhereClause expressions (e.g. NOW() = NOW()) into the last join model's postJoinWhereClause, so the code generator never sees both clauses separately. Truly constant expressions (e.g. 1 > 10, false) remain as constWhereClause so the code generator can still optimize them away to EmptyTableRecordCursorFactory. The generator-level wrapWithFilter() workaround and its AND_FUNCTION_FACTORY static field are removed. The assertion at FilteredRecordCursorFactory:44 stays as a development-time canary. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThe pull request removes the filter composition pattern using Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
core/src/test/java/io/questdb/test/griffin/engine/join/JoinTest.java (1)
3668-3669: Keep SQL keywords uppercase in the updated test query.Line 3669 reintroduces lowercase SQL keywords inside test SQL (
select). Please keep them uppercase to match the repo’s test SQL convention.As per coding guidelines "In SQL statements within test code, use UPPERCASE for SQL keywords (CREATE TABLE, INSERT, SELECT ... AS ... FROM, etc.)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/src/test/java/io/questdb/test/griffin/engine/join/JoinTest.java` around lines 3668 - 3669, The SQL in JoinTest.java contains lowercase keywords in the inline query; update the inner query from "select 1" to "SELECT 1" so all SQL keywords are uppercase (e.g., the fragment SELECT * FROM (SELECT x as "foo.bar" FROM long_sequence(5)) LEFT JOIN (SELECT 1) ON true;), ensuring the test follows the repo convention for uppercase SQL keywords.core/src/main/java/io/questdb/griffin/SqlOptimiser.java (1)
4542-4551: Move new static helper to the static-method section (alphabetical slot).
isCompileTimeConstantisprivate staticbut currently sits in the instance-method area. Please place it with other static helpers in alphabetical order.As per coding guidelines: "
**/*.java: Group Java class members by kind (static vs. instance) and visibility, sorted alphabetically. When adding new methods or fields, insert them in the correct alphabetical position among existing members of the same kind."🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core/src/main/java/io/questdb/griffin/SqlOptimiser.java` around lines 4542 - 4551, The private static helper method isCompileTimeConstant(ExpressionNode) is currently placed among instance methods; move it into the class's private static helpers section and insert it alphabetically with other static methods so it appears in the correct static-method area (keep the method signature and logic unchanged; reference ExpressionNode.CONSTANT and ExpressionNode.OPERATION remain the same). Ensure it resides with other private static members and follows alphabetical ordering for consistency with the project's Java member grouping rules.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@core/src/main/java/io/questdb/griffin/SqlCodeGenerator.java`:
- Line 3289: The code currently wraps an already-filtered factory in a new
FilteredRecordCursorFactory, which violates FilteredRecordCursorFactory's
assertion that its base is not filtered; update the wrap sites (the return that
constructs new FilteredRecordCursorFactory in SqlCodeGenerator around
generateSelectChoose(), and the analogous sites near the other repeats) to
detect when factory instanceof FilteredRecordCursorFactory, then merge the two
filters and return a single FilteredRecordCursorFactory whose base is the inner
factory's base and whose filter is the combined predicate (or otherwise unwrap
the inner factory and attach a combined filter), rather than nesting; apply the
same change at the other two occurrences referenced (the wrap around lines
5040-5043 and the one at 5103) and add a regression test that executes a nested
filtered subquery (e.g., select * from (select * from x where a>0) where b>0)
with parallel filters disabled to ensure no AssertionError is thrown.
In `@core/src/main/java/io/questdb/griffin/SqlOptimiser.java`:
- Around line 4528-4539: The code currently moves the entire constWhere
(constWhere) to the last join's post-join filter whenever
isCompileTimeConstant(constWhere) is false; instead, break constWhere into
conjunctive terms, keep the terms that are compile-time-constant
(isCompileTimeConstant(term)) in model.setConstWhereClause(...) and only move
the non-compile-time terms into
lastModel.setPostJoinWhereClause(concatFilters(...,
lastModel.getPostJoinWhereClause(), nonConstCombined)); update the logic around
model.getOrderedJoinModels()/lastIndex to only be triggered when there are
non-compile-time terms to move, and ensure that if a compile-time constant term
evaluates to false the constWhere remains (so EmptyTable optimization still
applies); add regression tests for mixed filters like WHERE false AND now() =
now() and WHERE true AND now() = now() to validate behavior.
---
Nitpick comments:
In `@core/src/main/java/io/questdb/griffin/SqlOptimiser.java`:
- Around line 4542-4551: The private static helper method
isCompileTimeConstant(ExpressionNode) is currently placed among instance
methods; move it into the class's private static helpers section and insert it
alphabetically with other static methods so it appears in the correct
static-method area (keep the method signature and logic unchanged; reference
ExpressionNode.CONSTANT and ExpressionNode.OPERATION remain the same). Ensure it
resides with other private static members and follows alphabetical ordering for
consistency with the project's Java member grouping rules.
In `@core/src/test/java/io/questdb/test/griffin/engine/join/JoinTest.java`:
- Around line 3668-3669: The SQL in JoinTest.java contains lowercase keywords in
the inline query; update the inner query from "select 1" to "SELECT 1" so all
SQL keywords are uppercase (e.g., the fragment SELECT * FROM (SELECT x as
"foo.bar" FROM long_sequence(5)) LEFT JOIN (SELECT 1) ON true;), ensuring the
test follows the repo convention for uppercase SQL keywords.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5046d39a-3a05-47ef-b1a2-9b3c1b964c9b
📒 Files selected for processing (3)
core/src/main/java/io/questdb/griffin/SqlCodeGenerator.javacore/src/main/java/io/questdb/griffin/SqlOptimiser.javacore/src/test/java/io/questdb/test/griffin/engine/join/JoinTest.java
|
@bluestreak01, comments from Claude: The core approach is sound. Merging at the AST level during optimization is architecturally cleaner than the runtime wrapWithFilter approach that combined compiled Function objects. One concern with With the old code, the compiled AndFunction could detect that one operand is constant false and report This is a minor performance regression for an extremely unlikely query pattern. In practice, nobody writes
Observations:
Test Coverage: Adequate but Could Be Stronger Missing:
|
mergeConstIntoPostJoinWhereClause now flattens the AND-tree and classifies each conjunct independently. Compile-time constant terms (e.g. 1 > 10) stay in constWhereClause for EmptyTableRecordCursorFactory folding; runtime terms (e.g. NOW() = NOW()) move to postJoinWhereClause. Previously, a mixed expression like (1 > 10 AND NOW() = NOW()) was treated as a single non-compile-time block, losing the Empty table optimization. Adds extractAndTerms() and isCompileTimeConstant() static helpers. Adds tests for mixed false+runtime, true+runtime, and plan assertions. Co-Authored-By: Claude Opus 4.6 <[email protected]>
|
@glasstiger thanks for the thorough review. Addressing each point: Mixed expressions (
Test coverage — both gaps are now covered:
|
[PR Coverage check]😍 pass : 36 / 37 (97.30%) file detail
|
Follow-up to #6824 (fixes #6762).
Summary
SqlOptimiser.optimiseJoins()now merges non-compile-time-constantconstWhereClauseexpressions (e.g.NOW() = NOW()) into the last join model'spostJoinWhereClause, so the code generator never sees both clauses separately and cannot double-wrapFilteredRecordCursorFactory1 > 10,false) stay asconstWhereClauseso the code generator can still optimize them away toEmptyTableRecordCursorFactorywrapWithFilter()workaround andAND_FUNCTION_FACTORYstatic field from fix(sql): fix AssertionError that could be triggered by JOIN SQL #6824 are removed; the assertion atFilteredRecordCursorFactory:44remains as a development-time canarytestJoinInnerPostJoinMultipleJoinsFilter— it tests multi-way joins with post-join filters, not the double-wrap bugTest plan
JoinTestfull suite (173 tests) passesExplainPlanTestfull suite (521 tests) passesConstantReassociationTest(9 tests) passestestJoinInnerPostJoinAndConstFilterstill covers the AssertionError at FilteredRecordCursorFactory.java #6762 regression