Skip to content

Support implicit lateral joins for set-returning functions in FROM - #3152

Open
zachmu wants to merge 3 commits into
mainfrom
zachmu/issue3112
Open

Support implicit lateral joins for set-returning functions in FROM#3152
zachmu wants to merge 3 commits into
mainfrom
zachmu/issue3112

Conversation

@zachmu

@zachmu zachmu commented Aug 20, 2026

Copy link
Copy Markdown
Member

Set-returning functions in the FROM list can now reference columns of preceding tables (implicit and explicit LATERAL joins).

Fixes #3112.

In Postgres, a function called in the FROM list may reference columns of
tables that precede it in the same FROM clause: it is an implicit LATERAL
join, and the LATERAL keyword is a noise word for function-call FROM items.

Queries like the following now work:

  SELECT k.u FROM pg_index i, unnest(i.indkey) AS k(u)
  WHERE i.indexrelid = 'bug15_ab'::regclass;

Function-call FROM items that follow another FROM item are now marked as
lateral during AST conversion, and lateral function items are converted to a
TableFuncExpr wrapped in a lateral subquery, which GMS knows how to scope
and execute. This also fixes the explicit LATERAL keyword before a function
call in FROM, which previously failed with an unsupported-syntax error, and
WITH ORDINALITY over such functions.

Fixes #3112
@itoqa

itoqa Bot commented Aug 20, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: b45b757: 14 test cases ran, 1 failed ❌, 12 passed ✅, 1 additional finding ⚠️.

Summary

Coverage spans correlated array expansion across common join forms, aliasing, row numbering, independent functions, and scope boundaries, including edge cases such as empty arrays and nested joins. The core query behavior is broadly healthy, but outer-join preservation has a correctness gap that can silently omit source data.

Merge with caution — this PR causes a medium-severity data-correctness failure in left joins when correlated expansion produces no rows, so affected results can be incomplete. A separate medium-severity parenthesized-join failure is unrelated to the PR and is a flag for later.

Tests run by Ito

View full run

Result Severity Type Description
Medium severity Rev The query returned only (2, 10) and (2, 20). It omitted the required (1, NULL) row even though the join was a LEFT JOIN.
Alias The query used the function name as its output name and returned rows (1,10), (1,20), and (2,30).
General Implicit and explicit lateral queries returned the right values for every outer row, even when the arrays had different lengths. The same associations stayed correct when a second table was added.
General Correlated array results keep the right values and numbering. Empty arrays return no rows, and numbering starts at 1 for each non-empty row in both query forms.
General Unqualified and schema-qualified unnest queries returned the same values. The explicit u(value) alias kept its renamed column and returned the correct rows for each table row.
General The correlated function returned the expected rows, while the neighboring subquery was rejected without an explicit LATERAL keyword. Adding LATERAL only to the subquery, or to both items, returned the expected rows.
Function The independent function returned 7 for both table rows, producing (1, 7) and (2, 7) as expected.
Lateral The query succeeded without the LATERAL keyword and returned the expected values for each row: (1,10), (1,20), and (2,30).
Lateral The query returned each array value beside the correct table row: (1,10), (1,20), and (2,30).
Lateral The query returned the expected rows for each input record, and the version with the optional keyword returned the same results.
Ordinality The query returned both array values for the first row and one value for the second row. Numbering started at 1 again for the second row, as expected.
Ordinality The implicit query and the query with CROSS JOIN LATERAL returned the same values and row numbers for both input arrays.
Subquery A subquery in the FROM list could not read a table placed before it unless the query used the explicit LATERAL keyword. The explicit form succeeded, so function handling did not widen subquery scope.
⚠️ Medium severity General The query stops with an internal unsupported-expression error when the joined tables are wrapped in parentheses. The expected unnested values are never returned.
Additional Findings Details

These findings are unrelated to the current changes but were observed during testing.

🟡 Parenthesized joins fail before scope checking
  • Severity: Medium Medium severity
  • Description: The query stops with an internal unsupported-expression error when the joined tables are wrapped in parentheses. The expected unnested values are never returned.
  • Impact: Queries that use a parenthesized joined table with array unnesting fail instead of returning results. Users can usually rewrite the query without the parentheses, but the affected query form does not work.
  • Steps to Reproduce:
    1. Create local tables t1(id integer, arr integer[]) and t2(id integer, name text), with t1 rows (1, ARRAY[10,20]) and (2, ARRAY[30]) and matching t2 rows.
    2. Run SELECT j.id, u.value FROM (t1 JOIN t2 ON t1.id=t2.id) AS j CROSS JOIN unnest(j.arr) AS u(value) ORDER BY j.id, u.value.
    3. Observe the error unhandled table expression: *tree.ParenTableExpr instead of rows for ids 1 and 2.
  • Stub / mock content: The query used local test tables and array rows created for this verification; no stubs, mocks, route interception, or bypasses were applied.
  • Code Analysis: In server/ast/select_clause.go:112-117, the PR calls markImplicitLateralFunctions before nodeFrom. Its recursive branch at lines 184-190 correctly walks a JoinTableExpr and a ParenTableExpr, but that only annotates the parsed tree. Conversion then reaches nodeAliasedTableExpr in server/ast/aliased_table_expr.go. That function handles TableName, Subquery, and RowsFromExpr at lines 40-161; its default at lines 162-164 returns errors.Errorf("unhandled table expression: %T", expr). For the query's AS j wrapper, node.Expr is *tree.ParenTableExpr, so conversion exits at that default before the later lateral rewrite can run. server/ast/table_expr.go:93-100 supports ParenTableExpr only when it is converted as a top-level table expression, not when it is nested inside AliasedTableExpr.Expr. The smallest practical fix is to add a ParenTableExpr case to nodeAliasedTableExpr that converts the inner join and preserves the alias, or otherwise unwraps this specific wrapper before the existing table-expression conversion. The PR diff does not change this function, so this is a pre-existing conversion gap exposed by the test shape rather than a regression caused by the PR.
Evidence Package

Tip

Reply with @itoqa to send us feedback on this test run.

Comment thread server/ast/select_clause.go
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor
Main PR
Total 42090 42090
Successful 19252 19234
Failures 22838 22856
Partial Successes1 5465 5472
Main PR
Successful 45.7401% 45.6973%
Failures 54.2599% 54.3027%

${\color{red}Regressions (31)}$

alter_table

QUERY:          SELECT conrelid = '161342'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('161342')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

cluster

QUERY:          SELECT conrelid = '157705'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('157705')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

create_table

QUERY:          SELECT conrelid = '144387'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144387')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144390'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144390')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144426'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144426')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144757'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144757')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144731'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144731')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144552'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144552')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144856'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144856')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144867'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144867')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '144912'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('144912')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

indexing

QUERY:          SELECT conrelid = '163832'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('163832')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '163832'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('163832')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '163832'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('163832')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164055'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164055')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164059'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164059')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164067'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164067')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164108'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164108')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164120'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164120')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164416'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164416')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164419'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164419')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '164422'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('164422')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

insert

QUERY:          SELECT conrelid = '143503'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('143503')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '143897'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('143897')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

replica_identity

QUERY:          SELECT conrelid = '151508'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('151508')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '151508'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('151508')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

rowsecurity

QUERY:          SELECT conrelid = '151576'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('151576')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

tablespace

QUERY:          SELECT conrelid = '142332'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('142332')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '142332'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('142332')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

triggers

QUERY:          SELECT conrelid = '146693'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('146693')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope
QUERY:          SELECT conrelid = '146684'::pg_catalog.regclass AS sametable,
       conname,
       pg_catalog.pg_get_constraintdef(oid, true) AS condef,
       conrelid::pg_catalog.regclass AS ontable
  FROM pg_catalog.pg_constraint,
       pg_catalog.pg_partition_ancestors('146684')
 WHERE conrelid = relid AND contype = 'f' AND conparentid = 0
ORDER BY sametable DESC, conname;
RECEIVED ERROR: column "relid" could not be found in any table in scope

${\color{lightgreen}Progressions (13)}$

join

QUERY: select * from
(values (1, array[10,20]), (2, array[20,30])) as v1(v1x,v1ys)
left join (values (1, 10), (2, 20)) as v2(v2x,v2y) on v2x = v1x
left join unnest(v1ys) as u1(u1y) on u1y = v2y;
QUERY: select count(*) from tenk1 a, lateral generate_series(1,two) g;
QUERY: select * from (values(1)) x(lb),
  lateral generate_series(lb,4) x4;
QUERY: select * from (select f1/1000000000 from int4_tbl) x(lb),
  lateral generate_series(lb,4) x4;

numeric

QUERY: select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,i) j;
QUERY: select * from generate_series(1::numeric, 3::numeric) i, generate_series(1,5,i) j;

rangefuncs

QUERY: SELECT * FROM (VALUES (1),(2),(3)) v(r), generate_series(10+r,20-r) f(i);
QUERY: SELECT * FROM (VALUES (1),(2),(3)) v(r), generate_series(10+r,20-r) WITH ORDINALITY AS f(i,o);
QUERY: SELECT * FROM (VALUES (1),(2),(3)) v(r), unnest(array[r*10,r*20,r*30]) f(i);
QUERY: SELECT * FROM (VALUES (1),(2),(3)) v(r), unnest(array[r*10,r*20,r*30]) WITH ORDINALITY AS f(i,o);
QUERY: SELECT * FROM (VALUES (1),(2),(3)) v1(r1),
              LATERAL (SELECT r1, * FROM (VALUES (10),(20),(30)) v2(r2)
                                         LEFT JOIN generate_series(r2,r2+3) f(i) ON ((r2+i)<100) OFFSET 0) s1;
QUERY: SELECT * FROM (VALUES (1),(2),(3)) v1(r1),
              LATERAL (SELECT r1, * FROM (VALUES (10),(20),(30)) v2(r2)
                                         LEFT JOIN generate_series(r1,2+r2/5) f(i) ON ((r2+i)<100) OFFSET 0) s1;
QUERY: SELECT *
FROM (VALUES (1),(2)) v1(r1)
    LEFT JOIN LATERAL (
        SELECT *
        FROM generate_series(1, v1.r1) AS gs1
        LEFT JOIN LATERAL (
            SELECT *
            FROM generate_series(1, gs1) AS gs2
            LEFT JOIN generate_series(1, gs2) AS gs3 ON TRUE
        ) AS ss1 ON TRUE
        FULL JOIN generate_series(1, v1.r1) AS gs4 ON FALSE
    ) AS ss0 ON TRUE;

Footnotes

  1. These are tests that we're marking as Successful, however they do not match the expected output in some way. This is due to small differences, such as different wording on the error messages, or the column names being incorrect while the data itself is correct.

@coffeegoddd

coffeegoddd commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

@zachmu DOLT

read_tests from_latency to_latency percent_change
covering_index_scan_postgres 2.48 2.48 0.0
groupby_scan_postgres 77.19 77.19 0.0
index_join_postgres 2.22 2.26 1.8
index_join_scan_postgres 1.58 1.58 0.0
index_scan_postgres 484.44 493.24 1.82
oltp_point_select 0.37 0.36 -2.7
oltp_read_only 6.32 6.43 1.74
select_random_points 0.7 0.7 0.0
select_random_ranges 1.03 1.03 0.0
table_scan_postgres 484.44 493.24 1.82
types_table_scan_postgres 1213.57 1213.57 0.0
write_tests from_latency to_latency percent_change
oltp_delete_insert_postgres 6.67 6.67 0.0
oltp_insert 3.36 3.36 0.0
oltp_read_write 13.46 13.46 0.0
oltp_update_index 3.55 3.62 1.97
oltp_update_non_index 3.25 3.25 0.0
oltp_write_only 7.04 7.04 0.0
types_delete_insert_postgres 7.17 7.17 0.0

zachmu added 2 commits August 28, 2026 19:10
A left lateral join over a set-returning function that produces no rows must
still return the left row, null-extended. Requires the go-mysql-server fix on
branch zachmu/lateral-left-join-on-true (memo exec builder rebuilt filterless
lateral joins as lateral cross joins) plus a GMS dependency bump.
@itoqa

itoqa Bot commented Aug 28, 2026

Copy link
Copy Markdown

Ito QA test results
Ito Diff Reportb45b7577934861: 8 test cases ran, 1 fixed ✅, 7 passing ✅.

Diff Summary

Coverage exercises correlated table-function queries across implicit and explicit join forms, including aliasing, row numbering, subquery scope, and matching results across related rows. It also checks edge cases such as empty or null inputs, filtered results, preserved rows in outer joins, and repeated constant values.

Safe to merge — the exercised query behavior is healthy across normal flows and important boundary cases, with no PR-attributable regressions or failing checks. No merge blocker was identified.

Tests run by Ito

View full run

Result State Severity Type Description
❌->✅ Fixed General Non-lateral subqueries reject references to the earlier table, even when a table function appears between them. An explicit LATERAL subquery returns one matching row for each source row.
Passing General The implicit and explicit queries returned the same three named columns and the same three rows. Each source row received the correct generated values and its own ordinality starting at 1.
Passing General The query kept every source row when the array was empty, NULL, or filtered by the join condition. Populated arrays still returned their matching values.
Passing General Comma, CROSS JOIN, and INNER JOIN queries returned the same values. Row numbering started at 1 for each source row.
Passing Contract The query returned 7 once for each source row. Both source rows, ids 1 and 2, appeared exactly once.
Passing Functions Comma, CROSS JOIN, and INNER JOIN queries all returned the expected values from each source row. The local target has no browser page, so the SQL results are the relevant evidence.
Passing Join A left join kept all three source rows. Empty and NULL arrays produced a blank related value, while the populated array produced both values.
Passing Lateral Both the implicit and explicit LATERAL queries returned the expected index keys 1 and 2 in the same order.
⏸️ Skipped Alias The query used the function name as its output name and returned rows (1,10), (1,20), and (2,30).
⏸️ Skipped General Implicit and explicit lateral queries returned the right values for every outer row, even when the arrays had different lengths. The same associations stayed correct when a second table was added.
⏸️ Skipped General Correlated array results keep the right values and numbering. Empty arrays return no rows, and numbering starts at 1 for each non-empty row in both query forms.
⏸️ Skipped General Unqualified and schema-qualified unnest queries returned the same values. The explicit u(value) alias kept its renamed column and returned the correct rows for each table row.
⏸️ Skipped General The correlated function returned the expected rows, while the neighboring subquery was rejected without an explicit LATERAL keyword. Adding LATERAL only to the subquery, or to both items, returned the expected rows.
⏸️ Skipped Function The independent function returned 7 for both table rows, producing (1, 7) and (2, 7) as expected.
⏸️ Skipped Lateral The query returned each array value beside the correct table row: (1,10), (1,20), and (2,30).
⏸️ Skipped Lateral The query returned the expected rows for each input record, and the version with the optional keyword returned the same results.
⏸️ Skipped Ordinality The query returned both array values for the first row and one value for the second row. Numbering started at 1 again for the second row, as expected.
⏸️ Skipped Ordinality The implicit query and the query with CROSS JOIN LATERAL returned the same values and row numbers for both input arrays.
⏸️ Skipped Subquery A subquery in the FROM list could not read a table placed before it unless the query used the explicit LATERAL keyword. The explicit form succeeded, so function handling did not widen subquery scope.
Tests that are no longer relevant

Below are tests that previously ran and are no longer relevant:

Type Test Description
Rev Empty lateral results drop source rows Dropped because The prior review scenario is superseded by the current AC-3 primary and the current REV-2 candidate tests a different multi-relation scope scenario.

Tip

Reply with @itoqa to send us feedback on this test run.

@zachmu
zachmu requested a review from Hydrocharged August 28, 2026 21:58
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.

implicit lateral join for set-returning functions

2 participants