Skip to content

chore: combined merge of #364, #367, #365, #366, #368, #369, #370 - #371

Open
pyramation wants to merge 17 commits into
mainfrom
devin/1792902167-combined-deparser-fixes
Open

pyramation wants to merge 17 commits into
mainfrom
devin/1792902167-combined-deparser-fixes

Conversation

@pyramation

Copy link
Copy Markdown
Collaborator

Summary

One merge PR that folds seven open PRs in, in merge order, using merge commits (no rebase). If this merges, the individual PRs can be closed.

Folded PR Broken → fixed
#364 FETCH ALL / MOVE ALL from the WASM AST (howMany = 2147483647) deparsed as a numeric count → deparses as ALL
#367 normalizeTree skipped nodes under a constructor key (JSON_ARRAYAGG / JSON_OBJECTAGG), which caused false round-trip diffs → those nodes are normalized
#365 the PL/pgSQL deparser re-indented newlines inside string literals (changing their value), turned "char" into char and dropped an empty CASE ... ELSE → all three kept intact
#366 no regression coverage over the PostgreSQL regression SQL → corpus round-trip tests with a known-failures ratchet
#368 AND CHAIN, trigger names in ALTER TRIGGER ... RENAME, XMLSERIALIZE ... INDENT, SHOW quoting, COPY option values, tablespaces/index options and FETCH ... WITH TIES were silently dropped or changed → preserved
#369 JSON_QUERY / JSON_VALUE / JSON_EXISTS / JSON_TABLE threw "does not handle node type" → deparsed
#370 ALTER STATISTICS ... RENAME threw, and operator names were emitted unquoted or unvalidated, so the SQL could reparse as a different operator → supported, quoted and validated

Conflicts were resolved by regenerating, not by hand-editing. The only conflict was __fixtures__/generated/generated.json (from #370), fixed with npm run fixtures. npm run kitchen-sink (deparser) and npm run fixtures (plpgsql-deparser) were then re-run on the merged tree with no diff. The build re-inferred packages/pgsql-types/src/field-metadata.json from the new fixtures: stxstattarget is now nullable and ParamRef was added as a tag.

Ratchet (#366 known failures), regenerated with UPDATE_KNOWN_FAILURES=1

Before (at #366) After (all folded)
deparser 594 statements in 47 files 149 statements in 37 files
plpgsql-deparser 72 65

The update only removed entries; no new failures were added.

Checks

  • pnpm run build: OK.
  • pnpm run lint: 0 errors.
  • pnpm -r --no-bail run test: deparser 1180, transform 255, plpgsql-deparser 116, transform-ast 1443, plpgsql-parser 345 and all other packages pass. Three things fail locally, all outside the CI matrix: @pgsql/cli and pgsql-types have no tests, and the plpgsql-parse roundtrip snapshot fails on main as well.

Link to Devin session: https://app.devin.ai/sessions/cb07c6509db64478af655f52611468f4
Open in Devin Desktop: https://app.devin.ai/desktop/session/cb07c6509db64478af655f52611468f4?variant=devin
Requested by: @pyramation

… SHOW quoting, COPY values, tablespaces and WITH TIES
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@tenki-reviewer

tenki-reviewer Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review complete. 🟡 1 medium

💬 Inline comments (1)

🧹 Nitpicks (3) — 🟢 3 low
  • 🟢 skipQuoted ends nested block comments early (plpgsql-deparser.ts:2443) — PostgreSQL block comments nest, but the new skipQuoted closes a /* comment at the first */ (packages/plpgsql-deparser/src/plpgsql-deparser.ts:2443), so for /* outer /* inner */ rest */ scanning resumes inside the outer comment.
  • 🟢 END CASE inside BEGIN ATOMIC disables splitting (make-regress-fixtures.ts:46) — In splitWithScanner, the CASE that follows an END (i.e. END CASE) is re-counted as opening a new CASE (packages/deparser/scripts/make-regress-fixtures.ts:47).
  • 🟢 Emit raw defname in tablespace options (deparser.ts:6235) — The tablespace DefElem branch interpolates node.defname without identifier quoting (packages/deparser/src/deparser.ts:6235), a line this PR rewrote.

The change introduces a PostgreSQL regression-statement corpus generator and round-trip ratchet tests for both deparser packages, then fixes a series of deparse-fidelity bugs surfaced by that corpus. All new fixtures pair 1:1 with generated data and test files, and the codegen metadata changes align with the deparser updates.

Files Change
packages/deparser/scripts/make-regress-fixtures.ts, packages/deparser/__tests__/regress/regress-corpus.test.ts, packages/plpgsql-deparser/__tests__/regress-corpus.test.ts New corpus fixture generator and ratchet round-trip tests with known-failure tracking
packages/deparser/src/deparser.ts Fidelity fixes: FETCH/MOVE ALL with WITH TIES, qualified operator-name validation, SHOW quoting, ALTER STATISTICS, rename/tablespace/constraint options, JSON_TABLE and JSON query functions
packages/plpgsql-deparser/src/plpgsql-deparser.ts PL/pgSQL fixes: bare ELSE for empty else_stmts, quoted "char" type, string-literal-aware indent scanning
packages/deparser/scripts/clean-utils.ts, packages/pgsql-types/src/field-metadata.json, packages/transform/src/round-trip-core.ts Metadata widening (stxstattarget, limitCount tags), hasOwnProperty fix, corpus statement cleaning
__fixtures__/**, packages/deparser/__tests__/** New kitchen-sink fixtures, tests, pretty snapshots, and known-failure ratchets
.agents/skills/testing-fixtures/SKILL.md, packages/deparser/package.json Skill docs and fixtures:regress script wiring

Reviewed commit: 85078d9

@tenki-reviewer tenki-reviewer Bot 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.

This PR adds a regression-corpus ratchet for the SQL and PL/pgSQL deparsers plus a batch of deparser fidelity fixes (FETCH FIRST WITH TIES, operator-name validation, SHOW/ALTER STATISTICS/tablespace/JSON_TABLE handling, PL/pgSQL ELSE and indent scanning).

Key findings

}
if (ch === '$') {
const prev = start > 0 ? text[start - 1] : '';
const tag = /^\$([A-Za-z_\u0080-\uffff][A-Za-z0-9_\u0080-\uffff]*)?\$/.exec(text.slice(start));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 performance · medium

Dollar-tag scan copies whole remaining text per $

The new indent loop calls skipQuoted for every $ character, and the $ branch does /^\$...\$/.exec(text.slice(start)) (packages/plpgsql-deparser/src/plpgsql-deparser.ts:2449) — a full copy of the remaining string per $. PL/pgSQL bodies contain many $ tokens ($1/$2 parameters, dollar-quoted strings), so deparsing a large body does O(n²) memory traffic where the previous single-pass regex replace was linear. The loop itself is fine; the slice is the quadratic part.

📋 Prompt for AI Agents

In packages/plpgsql-deparser/src/plpgsql-deparser.ts at line 2449, replace the text.slice(start) argument with a sticky-anchored match: create a module-level regex /^\$([A-Za-z_\u0080-\uffff][A-Za-z0-9_\u0080-\uffff]*)?\$/y, set regex.lastIndex = start before each exec against text, and read the match — this avoids copying the entire remainder of the string for every $ in the body.

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