fix: add 21 plpgsql deparser edge case fixtures and fix 7 schema_rename failures#291
Merged
pyramation merged 3 commits intomainfrom Apr 7, 2026
Merged
Conversation
Add comprehensive test coverage for nested block compositions, blocks inside control structures, deep nesting patterns, untested statement types, and real-world patterns that exercise the END; bug class. Group 1 - Nested Block Compositions (CRITICAL): - Nested block followed by RETURN, IF, RAISE, PERFORM, assignment - Labeled nested block Group 2 - Blocks Inside Control Structures (HIGH): - Block inside IF THEN branch with exception handler - Block inside LOOP body with exception handler - Block inside CASE WHEN Group 3 - Deep Nesting & Sequential Blocks: - Two sequential nested blocks - Triple-nested blocks - Block inside exception handler action Group 4 - Untested Statement Types: - FOR integer loop, FOR query loop, labeled FOR loop - RETURN NEXT with OUT parameters, RETURN QUERY - ASSERT statement, CALL statement Group 5 - Real-World Patterns: - Permission bitnum trigger pattern (the original bug-exposing function) - Multi-step sign-in pattern with nested IF chains Also adds pre-existing plpgsql_schema_rename failures to KNOWN_FAILING_FIXTURES allowlist (7 fixtures with whitespace mismatch in query expressions).
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Two root causes fixed: 1. cleanPlpgsqlTree query normalization bug: The transform function applied normalizeQueryWhitespace to ALL keys named 'query', but PLpgSQL_stmt_return_query.query is an object (wrapping PLpgSQL_expr), not a string. normalizeQueryWhitespace returned non-strings unchanged WITHOUT recursing, so the inner PLpgSQL_expr.query string was never normalized. Fixed by making the query handler recurse into objects. 2. GET DIAGNOSTICS kind mapping: The parser returns diag_item.kind as a string (e.g. 'ROW_COUNT') but getDiagItemKindName() only handled numeric enum values. Added string-based mapping so both forms work. Also removed KNOWN_FAILING_FIXTURES allowlist — all 225 fixtures now pass round-trip testing.
4 snapshots updated: all show the corrected output where GET DIAGNOSTICS now includes ROW_COUNT instead of an empty string.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds 21 new PL/pgSQL deparser test fixtures to prevent regression of the
END;bug fix and improve coverage of previously untested statement types. Also fixes two deparser bugs that caused 7 pre-existingplpgsql_schema_rename-*fixture failures — all 225 fixtures now pass round-trip testing with no allowlist.5 groups of fixtures (Tests 17–37):
END;followed by RETURN, IF, RAISE, PERFORM, assignment; labeled blocksBug fixes
Two deparser bugs were causing 7
plpgsql_schema_rename-*fixtures to fail onmain. Instead of allowlisting them, both root causes were fixed:cleanPlpgsqlTreequery normalization (test-utils/index.ts): Thetransformfunction appliednormalizeQueryWhitespaceto all keys namedquery, butPLpgSQL_stmt_return_query.queryis an object (wrappingPLpgSQL_expr), not a string.normalizeQueryWhitespacereturned non-strings unchanged without recursing, so the innerPLpgSQL_expr.querystring was never normalized — causing false AST mismatches on multi-line SQL. Fixed by making thequeryhandler recurse into objects viatransform(val, cleanProps).getDiagItemKindNamestring/number mismatch (plpgsql-deparser.ts): The parser returnsdiag_item.kindas a string (e.g."ROW_COUNT"), but the deparser only handled numericDiagItemKindenum values — soGET DIAGNOSTICS deleted_count = ROW_COUNTwas deparsed asGET DIAGNOSTICS deleted_count = ;(empty kind). Added a string-name lookup path alongside the existing numeric switch. Four pre-existing snapshots were updated to reflect the corrected output.Review & Testing Checklist for Human
cleanPlpgsqlTreerecursion fix is safe: The newqueryhandler incleanPropsrecurses into objects whenqueryis not a string. Confirm this doesn't accidentally normalize non-query objects or cause infinite recursion (it delegates back totransformwith the same props, which only recurses on object/array types). Note: this fix is in the test comparison utility, not the deparser itself — multi-line SQL may still be formatted differently after deparsing, but the round-trip AST comparison now correctly normalizes both sides.getDiagItemKindNamestring values match parser output: The string map keys ('ROW_COUNT','PG_CONTEXT', etc.) must exactly match what@libpg-query/parserreturns inPLpgSQL_diag_item.kind. Cross-check against the parser's protobuf definitions if possible.hydrate-demo.test.ts.snap,schema-rename-mapped.test.ts.snap, andplpgsql-pretty.test.ts.snap— all diffs should only show= ;→= ROW_COUNT;.RETURN NEXT(with OUT params) instead ofRETURN NEXT recbecause the deparser drops the expression fromRETURN NEXT <variable>. Decide if you'd prefer a deliberately-failing fixture to document this gap instead.generated.json: The diff includes 12plpgsql_schema_rename-*entries — these are NOT new fixtures from this PR; they were already in__fixtures__/plpgsql/plpgsql_schema_rename.sqland are now picked up by the regenerated JSON. Verify no fixtures were accidentally removed.Recommended test plan:
cd packages/plpgsql-deparser && pnpm fixtures && npx jestNotes
deparser-fixes.test.ts, 6 inplpgsql-deparser.test.ts, plus hydrate, schema-rename, pretty tests, etc.)deparser-fixes.test.tsduplicates its SQL inline rather than loading fromgenerated.json— this matches the existing patternLink to Devin session: https://app.devin.ai/sessions/7ac7bb4b376e4458b088c01e61913be0
Requested by: @pyramation