Skip to content

fix(semantics): accept short LAG and LEAD calls, lateral scopes and lambda parameters - #167

Merged
kvlonge merged 4 commits into
mainfrom
fix/window-arity-comma-lateral
Nov 11, 2026
Merged

kvlonge merged 4 commits into
mainfrom
fix/window-arity-comma-lateral

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Why

Semantic checks refused DuckDB SQL the engine runs, and missed some errors it refuses:

  • LAG(x), LAG(x, n), LEAD(x) and LEAD(x, n) raised E203, because the catalogue listed LAG and LEAD only with three arguments.
  • A LATERAL item was checked against every FROM item of its level. A derived table nested in it raised a false E222 for an item to its left, and the LATERAL body could read items to its right, or itself, without an error.
  • DuckDB runs a derived table without LATERAL as lateral when it reads an item to its left, but it raised E222.
  • A lambda parameter in a grouped SELECT, such as list_filter(ARRAY_AGG(x), lambda e: e <> 'null'), raised E230 as an ungrouped column.

Changes

  • The DuckDB catalogue extractor records each argument count DuckDB binds for a window function, which adds LAG and LEAD with one and two arguments.
  • Each FROM item records where its sources start. A LATERAL item, and anything nested in it, reads only the items before it, then the enclosing queries, in every dialect.
  • Under DuckDB only, a derived table without LATERAL reads the items before it, in name resolution and in lineage.
  • The grouping check exempts a lambda's parameters inside its body and still checks outer columns there.

Verification

  • New regression tests fail on main and pass here. They go through DuckDB's and PostgreSQL's own parsers, and every verdict was checked on DuckDB 2.0.0 and PostgreSQL 18.6.
  • cargo test -p sqlquack-semantics --all-features
  • make check-ci
  • make verify-recorded: 0 failed, and no other changes.
  • Not checked on Snowflake: no engine access was available for this change. Snowflake goes through the same paths and gets the same verdicts.

duckdb_functions() lists each window function once with every parameter,
so the catalogue recorded only three-argument LAG and LEAD, and arity
checks refused LAG(x), LAG(x, n), LEAD(x) and LEAD(x, n), which DuckDB
runs. The extractor now asks the engine which shorter counts each
fixed-arity window function binds and records one row per count. Every
other window function already matched DuckDB 2.0.0.
…closing items

Name resolution gave a derived table that is not LATERAL no enclosing
scope, so a derived table nested in a LATERAL subquery could not read the
FROM items before that subquery and reported them as unknown aliases. It
now reads the enclosing queries, as lineage tracing already does, while
only a LATERAL item also reads its left siblings.
A LATERAL item was checked against every FROM item of its level, so its
body, and any derived table nested in it, could read items to its right
and itself without an error, though engines refuse both. It now reads
only the items before it, then the enclosing queries.

DuckDB also runs a derived table without LATERAL as lateral when it
reads an item before it. Name resolution and lineage now let it do so
under DuckDB only; PostgreSQL and the other dialects still refuse it.
The grouping check walked into lambda bodies and reported a lambda's own
parameter, such as e in list_filter(ARRAY_AGG(x), lambda e: e <> 'null'),
as a column that must be grouped. A parameter is bound only inside its
lambda's body, so it is now exempt there, while outer columns in the body
and a column of the same name outside the lambda are still checked.
@kvlonge kvlonge changed the title fix(semantics): accept short LAG and LEAD calls and nested lateral reads fix(semantics): accept short LAG and LEAD calls, lateral scopes and lambda parameters Nov 11, 2026
@kvlonge
kvlonge merged commit 226a3a8 into main Nov 11, 2026
9 checks passed
@kvlonge
kvlonge deleted the fix/window-arity-comma-lateral branch November 11, 2026 01:32
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.

1 participant