Repository navigation
fix(postgres): read an outer column's bare name over every from - #78
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
ℹ️ No issues with the fix itself. One misplaced doc comment inline.
Reviewed changes
I reviewed the whole PR: the leaf-probe widening in jsonshape.rs, the new Level::shows, the oracle statements, and the rebuilt artifact.
- Widened leaf probe:
Builder::leafnow reads an expression over its FROM joined with every enclosing FROM when a bare name in it isn't certainly a column here but may be a column further out. Widened drafts are keyed separately and get no narrow fallback. renamed_in_probe/bare_names: these collect one-fieldColumnRefnames, including names inside nested subqueries, and gate on!here.shows(n) && around.any(!lacks(n)). They skip an enclosing level whose FROM equals the current one (the FILTER re-push).Level::shows: a certain-column check that complementslacks.- Oracle: there are five new
json_subqueriesstatements, and none of the existing lines change.
I checked that the widening is sound. Joining the FROMs into one can only turn a name into an ambiguity or duplicate-alias error, which resolves to unknown. It can't turn it into a different column, because the case where a column of the innermost FROM wins (here.shows) is excluded first. infer::plan_here only probes the top level, so it doesn't need the same guard.
claude-opus-5-5 | 𝕏
9682cec to
99cacb5
Compare

A JSON value inside a scalar subquery is typed by a probe: the value selected over the subquery's own FROM. A bare name in that value can be a column of a FROM around the subquery. When the subquery's FROM also has an item by that name, the probe read the name as that item's whole row. So the value came back typed as the wrong thing, which is unsound:
In this statement,
pisusers.p, because Postgres reads a bare name as a column of any FROM in scope before it reads it as an item's row.j: [posts{ id: int8, user_id: int8, title: text }]?, while the column holds["a"]j: [text?]?The rule
A bare name in a value is read over the subquery's FROM and every FROM around it, joined into one FROM (the probe the planner already falls back to for a correlated value), when both of these hold:
This includes a name inside a subquery of the value. Over the joined FROM, a column is a column before an item's row, just as in the statement.
Oracle
New statements in
json_subqueries, all unsound or unchecked before:jsonb_agg(p), bare and undercoalesce(…, '[]')jsonb_build_object('p', p)and'p', upper(p)count(p)inside a nested subquery of the valueNo other case changes.