8000 fix(postgres): tell a self-join's alias.* apart by its alias by colinhacks · Pull Request #92 · colinhacks/reylo · GitHub
[go: up one dir, main page]

Skip to content

fix(postgres): tell a self-join's alias.* apart by its alias - #92

Merged
colinhacks merged 2 commits into
mainfrom
fix/pg-self-join-star
Oct 23, 2026
Merged

colinhacks merged 2 commits into
mainfrom
fix/pg-self-join-star

Conversation

@colinhacks
Copy link
Copy Markdown
Owner

In a table joined to itself, alias.* lost track of which reading each column came from. So every column of the table came out nullable, including on the preserved side. The engine tells a self-join's readings apart by alias for alias.column targets, but it gave up as soon as a * appeared in the select list. A to_jsonb(a) is read through an a.* probe, so it was affected too:

select a.id, to_jsonb(a) as earlier, to_jsonb(b) as later from users a left join users b on b.id > a.id
  • Before: earlier: { id: int4?, name: text?, email: text? }?
  • After: earlier: { id: int4, name: text, email: text? }, with later unchanged as { id: int4, name: text, email: text? }?

The rule

alias.* over a table's reading stands for that table's columns, in order, by that reading. Each column is nullable where an outer join nulls that reading, and otherwise it is as the catalog says. A bare *, a star of an item that isn't a table, and a column count that doesn't add up still say nothing, as before.

Oracle (inference_precision)

  • whole_row_json_self_join: earlier goes from { id: int4?, name: text?, email: text? }? to { id: int4, name: text, email: text? }.
  • New whole_row_json_self_full_join: both objects stay nullable, and their fields keep their own nullability.
  • New whole_row_star_self_join (a.*, b.name): { id: int4, name: text, email: text?, later: text? }.
  • New whole_row_star_self_join_nulled (a.name, b.*): { earlier: text, id: int4?, name: text?, email: text? }. The nulled side stays nullable.

8000
Copilot AI balanced review requested due to automatic review settings October 23, 2026 21:45
@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 10:36pm 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.

< 8000 input type="hidden" name="_method" value="put" autocomplete="off" />

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 critical issues. One edge case is inline: the check that each target is one column is gone.

Reviewed changes

I reviewed the whole diff. It teaches aliased_columns to expand a top-level alias.* over a table reading, so that each half of a self-join keeps its own nullability.

  • alias.* expansion: a star over an alias whose FROM item is a table now adds width(table) entries of (table, nulled). A bare *, a star over a subselect, function or WITH item, and a table whose width is unknown or ambiguous still give nothing.
  • width: this is the column count of the one self.relations entry with that name. RELATION_COLUMNS_QUERY fills it with attnum > 0, non-dropped, pg_table_is_visible columns, which matches what a.* expands to for a visible table.
  • Count guard moved: the early target_list.len() != count check is replaced by out.len() != count after expansion.
  • Oracle and artifact: whole_row_json_self_join's preserved side is no longer nullable. Three new inference_precision cases cover a full self-join, a.* on the preserved side and b.* on the nulled side. engine.wasm is rebuilt. postgres.mdx:444 already states the rule ("told apart by its alias"), so the docs need no change.

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

Comment thread engine/postgres/src/postgres.rs Resolved
@colinhacks
colinhacks force-pushed the fix/pg-self-join-star branch from 53aabcd to 19e830d Compare October 23, 2026 22:35
@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 new issues found. The edge case from the last review is closed.

Reviewed changes

Since the last review, one commit adds two guards to aliased_columns, so a misjudged alias.* width can no longer line up with the wrong columns.

  • (x).* gives up: a target that is an A_Indirection containing A_Star now returns no readings at all. Every target other than alias.* is therefore exactly one column, and the final out.len() != count check catches a wrong width on its own.
  • Schema-named stars give up: items now collects into qualified the alias of each RangeVar written with a schema, and a star over one of those aliases returns no readings. width only ever answers for the visible table, so this keeps it from reporting the visible table's width for a different table of the same name.
  • Unit tests: the counter-example from the last review, a variant without the composite and a lone (b.addr).* are now asserts in a_star_of_a_reading_is_its_tables_columns_by_that_reading.

Pullfrog  | View workflow run | Using claude-opus-5-5 | 𝕏

@colinhacks
colinhacks merged commit 5280fa9 into main Oct 23, 2026
6 checks passed
@colinhacks
colinhacks deleted the fix/pg-self-join-star branch October 23, 2026 22:45
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