Skip to content

fix(sql): resolve 'Invalid column' error in WINDOW JOIN with aliased columns#6701

Merged
bluestreak01 merged 2 commits intomasterfrom
vi_fix_win_bug
Jan 24, 2026
Merged

fix(sql): resolve 'Invalid column' error in WINDOW JOIN with aliased columns#6701
bluestreak01 merged 2 commits intomasterfrom
vi_fix_win_bug

Conversation

@bluestreak01
Copy link
Copy Markdown
Member

Summary

  • Fixed a bug where WINDOW JOIN queries using aliased columns in expressions with aggregates would fail with Invalid column: <column> error at position 0
  • The issue occurred when the same column was both aliased (e.g., t.price AS fill_price) and used in an expression with aggregates (e.g., (t.price - sum(...)))

Problem

When processing expressions containing aggregates in WINDOW JOIN context, the SqlOptimiser.replaceIfAggregateOrLiteral() method failed to correctly resolve column references because:

  1. It looked up the column in translatingModel to get its alias
  2. Then tried to verify this alias exists in groupByModel using groupByModel.getColumnNameToAliasMap().get(translatingAlias)
  3. For window joins, both models are the same (windowJoinModel), and the lookup failed because the map stores token -> alias, not alias -> something

This caused the column to be re-added with a bare name instead of using the existing alias, leading to the "Invalid column" error at code generation time.

Fix

  1. Pass windowJoinModel as the translating model to emitAggregatesAndLiterals when isWindowJoin is true
  2. Add a special case in replaceIfAggregateOrLiteral for when translatingModel == groupByModel (window join case) to directly return the found alias

Test plan

  • Added reproducer test in SqlParserTest.testWindowJoin() - verifies correct query model is generated
  • Added end-to-end test in WindowJoinTest.testWindowJoinSelfJoinWithAggregatesInSelectAndWhere() - verifies query executes correctly
  • All existing WindowJoinTest tests pass (184 tests)

Example query that was failing

SELECT 
    t.timestamp,
    t.price AS fill_price,
    sum(w.price * w.quantity) / sum(w.quantity) AS vwap_5m,
    (t.price - sum(w.price * w.quantity) / sum(w.quantity)) 
        / (sum(w.price * w.quantity) / sum(w.quantity)) * 10000 AS slippage_bps
FROM fx_trades t
WINDOW JOIN fx_trades w 
    ON (t.symbol = w.symbol)
    RANGE BETWEEN 5 minutes PRECEDING AND 1 microseconds PRECEDING
    EXCLUDE PREVAILING
WHERE t.symbol = 'EURUSD'
ORDER BY t.timestamp
LIMIT 100

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 24, 2026

Walkthrough

Changes to SqlOptimiser modify alias resolution and aggregate/literal emission logic for window join scenarios. When a literal references a column, the code now short-circuits for certain window join cases or preserves group-by key tracking. Additionally, the translatingModel parameter for emitAggregatesAndLiterals is conditionally set based on whether a window join is present. Test cases are added for self-join window join scenarios with aggregates.

Changes

Cohort / File(s) Summary
Core Query Optimizer Logic
core/src/main/java/io/questdb/griffin/SqlOptimiser.java
Modified replaceIfAggregateOrLiteral to short-circuit literal handling when translatingAlias equals groupByModel, otherwise compute and track alias from groupByModel. Updated rewriteSelect0HandleOperation to pass isWindowJoin ? windowJoinModel : translatingModel to emitAggregatesAndLiterals.
SQL Parser Tests
core/src/test/java/io/questdb/test/griffin/SqlParserTest.java
Added test case for self-join window join scenario with aliased columns used in multiple expressions, covering alias handling and expression propagation in window-join contexts.
Window Join Tests
core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java
Added testWindowJoinSelfJoinWithAggregatesInSelectAndWhere test method covering self-join window join with aggregates in select clause and where clause, including table setup, data insertion, and query validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

Bug, SQL

Suggested reviewers

  • puzpuzpuz
  • mtopolnik
  • jerrinot
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main fix: resolving an 'Invalid column' error in WINDOW JOIN queries with aliased columns, which is the core change in the PR.
Description check ✅ Passed The description is directly related to the changeset, providing clear explanation of the bug, root cause, fix implementation, and test coverage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.40.5)
core/src/main/java/io/questdb/griffin/SqlOptimiser.java
core/src/test/java/io/questdb/test/griffin/SqlParserTest.java

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit pls review, find bugs

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 24, 2026

Oops, something went wrong! Please try again later. 🐰 💔

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit whenever you can, review my bugs

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 24, 2026

@bluestreak01: I'll review the pull request and look for potential bugs. Starting the review now.


🧠 Learnings used
Learnt from: bluestreak01
Repo: questdb/questdb PR: 6673
File: core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java:2616-2618
Timestamp: 2026-01-19T21:43:19.228Z
Learning: In test `testWindowJoinFailsWhenSlaveDoesNotSupportTimeFrames` in `core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java`, the use of `AND` between timestamp equality conditions (e.g., `ts = 'X' AND ts = 'Y'`) is intentional to prevent intrinsic interval creation. This ensures the window join fails as expected when the slave doesn't support time frames, which is necessary after PR `#6673` added OR timestamp intrinsics recognition.

Learnt from: bluestreak01
Repo: questdb/questdb PR: 6643
File: core/src/main/java/io/questdb/griffin/SqlOptimiser.java:8671-8687
Timestamp: 2026-01-20T00:59:19.630Z
Learning: QuestDB’s parser rejects pure window functions (e.g., row_number(), rank()) used without an OVER clause; such invocations are invalid and fail early, so validators don’t need to catch pure-name window functions in window specs.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@questdb-butler
Copy link
Copy Markdown

⚠️ Enterprise CI Failed

The enterprise test suite failed for this PR.

Build: View Details
Tested Commit: f08359e49443d3e1f9916917d0a9e6b6181539a5

Please investigate the failure before merging.

@glasstiger
Copy link
Copy Markdown
Contributor

[PR Coverage check]

😍 pass : 13 / 13 (100.00%)

file detail

path covered line new line coverage
🔵 io/questdb/griffin/SqlOptimiser.java 13 13 100.00%

@bluestreak01
Copy link
Copy Markdown
Member Author

@CodeRabbit what is the story?

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jan 24, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@bluestreak01: Let me examine the changes in detail to provide you with a thorough review and identify any potential bugs.


🏁 Script executed:

#!/bin/bash
# Get the diff for the PR to examine the actual changes
gh pr diff 6701 --repo questdb/questdb

Length of output: 10965


🏁 Script executed:

#!/bin/bash
# Check the enterprise CI failure details if available
gh pr checks 6701 --repo questdb/questdb

Length of output: 8502


🏁 Script executed:

#!/bin/bash
# Look at the specific changes in SqlOptimiser.java around the replaceIfAggregateOrLiteral method
gh pr diff 6701 --repo questdb/questdb -- core/src/main/java/io/questdb/griffin/SqlOptimiser.java

Length of output: 36


@bluestreak01: Here's my comprehensive review of the changes:

Implementation Analysis

The fix correctly addresses the root cause you described. The logic is sound:

  1. Window join special case: When translatingModel == groupByModel (identity check), it directly returns nextLiteral(translatingAlias), which is correct since for window joins both models are the same windowJoinModel instance.

  2. Restructured logic: The new nested structure properly handles the flow:

    • If translatingAlias is null → falls through to add as key (same as before)
    • If translatingAlias exists and it's a window join → early return with the alias
    • If translatingAlias exists but not a window join → looks up existingAlias and proceeds with original logic

⚠️ Potential Issues Found

1. Enterprise CI Failure

The enterprise test suite failed. This is concerning and should be investigated before merging:

Recommendation: Check the enterprise CI logs to see if the failure is related to this change or a flaky test.

2. Logic flow edge case

When translatingAlias != null but translatingModel != groupByModel and existingAlias == null, the code now falls through to add the column as a key. This is the same behavior as before, but I want to confirm this is intentional for the window join fix.

3. Test coverage observation

The test testWindowJoinSelfJoinWithAggregatesInSelectAndWhere has hardcoded UUIDs in the expected output:

2025-01-01T00:00:00.000000Z\t0010cde8-12ce-40ee-8010-a928bb8b9650\tEURUSD...

Since UUIDs are generated with rnd_uuid4(), these are non-deterministic. This test might be flaky unless there's seed initialization I'm not seeing in the diff.

📋 Code Quality Notes

Positive:

  • ✅ 100% code coverage (13/13 lines)
  • ✅ Comprehensive test cases covering both query model validation and end-to-end execution
  • ✅ Clear comments explaining the window join special case
  • ✅ The reference equality check (==) is appropriate here for object identity

Suggestions:

  • The comment mentions "groupByNodes/groupByAliases lists are not used for window joins since GROUP BY is disallowed with WINDOW JOIN" - consider adding an assertion to verify this invariant if not already present elsewhere

🔍 Next Steps

  1. Investigate the Enterprise CI failure - this is blocking
  2. Verify the UUID test won't be flaky
  3. Consider adding a test case where translatingAlias != null but existingAlias == null for non-window joins to ensure backward compatibility

Would you like me to investigate the Enterprise CI failure logs or check the test for potential flakiness?


🧠 Learnings used
Learnt from: bluestreak01
Repo: questdb/questdb PR: 6673
File: core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java:2616-2618
Timestamp: 2026-01-19T21:43:19.228Z
Learning: In test `testWindowJoinFailsWhenSlaveDoesNotSupportTimeFrames` in `core/src/test/java/io/questdb/test/griffin/WindowJoinTest.java`, the use of `AND` between timestamp equality conditions (e.g., `ts = 'X' AND ts = 'Y'`) is intentional to prevent intrinsic interval creation. This ensures the window join fails as expected when the slave doesn't support time frames, which is necessary after PR `#6673` added OR timestamp intrinsics recognition.

Learnt from: bluestreak01
Repo: questdb/questdb PR: 6643
File: core/src/main/java/io/questdb/griffin/SqlOptimiser.java:8671-8687
Timestamp: 2026-01-20T00:59:19.630Z
Learning: QuestDB’s parser rejects pure window functions (e.g., row_number(), rank()) used without an OVER clause; such invocations are invalid and fail early, so validators don’t need to catch pure-name window functions in window specs.

@bluestreak01 bluestreak01 merged commit e5cd8dc into master Jan 24, 2026
42 of 43 checks passed
@bluestreak01 bluestreak01 deleted the vi_fix_win_bug branch January 24, 2026 16:22
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.

3 participants