8000 fix(postgres): read an outer column's bare name over every from by colinhacks · Pull Request #78 · colinhacks/reylo · GitHub
[go: up one dir, main page]

Skip to content

fix(postgres): read an outer column's bare name over every from - #78

Merged
colinhacks merged 3 commits into
mainfrom
fix/pg-leaf-outer-name
Oct 23, 2026
Merged

colinhacks merged 3 commits into
mainfrom
fix/pg-leaf-outer-name

Conversation

@colinhacks
Copy link
Copy Markdown
Owner

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:

-- users (…, p text), posts (id bigint primary key, user_id bigint not null, title text not null)
select (select jsonb_agg(p) from posts p where p.id = 1) as j from users

In this statement, p is users.p, because Postgres reads a bare name as a column of any FROM in scope before it reads it as an item's row.

  • Before: j: [posts{ id: int8, user_id: int8, title: text }]?, while the column holds ["a"]
  • After: 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:

  • the name is no column of the subquery's own FROM for certain;
  • a FROM around it may have a column of that name.

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 under coalesce(…, '[]')
  • jsonb_build_object('p', p) and 'p', upper(p)
  • a count(p) inside a nested subquery of the value

No other case changes.

Copilot AI balanced review requested due to automatic review settings October 23, 2026 18:28
@vercel
vercel Bot commented Oct 23, 2026 •
Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
reylo Ready Ready Preview Oct 23, 2026 7:58pm UTC

Request Review

Copilot AI left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@pullfrog pullfrog Bot left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ 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::leaf now 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-field ColumnRef names, 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 complements lacks.
  • Oracle: there are five new json_subqueries statements, 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.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using claude-opus-5-5 | 𝕏

Comment thread engine/postgres/src/jsonshape.rs Resolved
@colinhacks
colinhacks force-pushed the fix/pg-leaf-outer-name branch from 9682cec to 99cacb5 Compare October 23, 2026 19:57
@colinhacks
colinhacks merged commit 85b362f into main Oct 23, 2026
6 checks passed
@colinhacks
colinhacks deleted the fix/pg-leaf-outer-name branch October 23, 2026 20:04
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.

2 participants

0