Skip to content

fix(deparser): keep qualified relation in LIKE and REFRESH MATERIALIZED VIEW - #361

Open
R3gardless wants to merge 1 commit into
constructive-io:mainfrom
R3gardless:fix/deparser-table-like-qualified-relation
Open

R3gardless wants to merge 1 commit into
constructive-io:mainfrom
R3gardless:fix/deparser-table-like-qualified-relation

Conversation

@R3gardless

@R3gardless R3gardless commented Oct 13, 2026 •

Copy link
Copy Markdown

Problem

A schema- or catalog-qualified relation is dropped when deparsing CREATE TABLE ... (LIKE ...) and REFRESH MATERIALIZED VIEW, which produces SQL that no longer parses. Both pretty: true and pretty: false are affected (reproduced on 18.3.12). Unqualified names work.

Input Output before this PR
CREATE TABLE t (LIKE s.p INCLUDING ALL) CREATE TABLE t (LIKE INCLUDING ALL)
CREATE TABLE t (LIKE s.p) CREATE TABLE t (LIKE ) → syntax error at or near ")"
REFRESH MATERIALIZED VIEW s.mv REFRESH MATERIALIZED VIEW

Root cause

TableLikeClause.relation and RefreshMatViewStmt.relation are typed as a bare RangeVar, not a Node-wrapped { RangeVar: ... }. Both visitors passed the field to this.visit(node.relation as any, ...), and visit() dispatches on the object's first key:

  • unqualified: first key is relname, so it hit the relname() helper, which happens to return the quoted name (this is why LIKE p worked);
  • qualified: first key is schemaname (or catalogname), so it hit the schemaname() helper, which finds no String/sval on the object and returns ''.

Fix

Call this.RangeVar(node.relation, context) directly, the same way the other bare-RangeVar fields are handled (CreateStmt.relation, IndexStmt.relation, etc.). I checked every visitor that passes a RangeVar-typed field to visit(), and these two were the only ones. RangeTableSample.relation is a wrapped Node, so visit() is correct there.

This is the same root cause as #348 (PartitionCmd.name), which was fixed in #352. That fix did not cover TableLikeClause and RefreshMatViewStmt.

Tests

  • New kitchen-sink fixture __fixtures__/kitchen-sink/misc/qualified-like-and-refresh.sql (unqualified, schema-qualified, catalog-qualified, quoted identifiers, INCLUDING/EXCLUDING options, CONCURRENTLY ... WITH NO DATA). I regenerated it with npm run kitchen-sink. It fails on main with INVALID_DEPARSED_SQL and passes with this fix.
  • packages/deparser: npx jest: 313 suites, 749 tests, 424 snapshots, all passing.
  • Ran a separate check that parse(deparse(ast)) equals ast (ignoring locations) in both plain and pretty mode for the cases above, including LIKE db.s.p INCLUDING DEFAULTS EXCLUDING INDEXES.

…ED VIEW

TableLikeClause.relation and RefreshMatViewStmt.relation are bare RangeVar
objects, not Node-wrapped. Passing them to visit() dispatched on the first
object key instead of the node type: an unqualified relation starts with
"relname" and happened to hit the relname() helper, but a qualified one
starts with "schemaname"/"catalogname" and rendered as an empty string,
e.g. CREATE TABLE t (LIKE s.p) -> CREATE TABLE t (LIKE ).

Call RangeVar() directly, like the other bare-RangeVar fields.
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