Skip to content

Conversation

@pyramation
Copy link
Collaborator

fix(plpgsql-deparser): support nested DECLARE blocks inside FOR loops

Summary

Implements lineno-based scope tracking to correctly assign variables to their enclosing blocks. Previously, variables declared inside a FOR loop body were hoisted to the top-level DECLARE section, which changed semantics (variables should be reinitialized on each loop iteration).

The fix uses line numbers from the AST to determine which variables belong to which blocks:

  • Variables with lineno <= topLevelBlockLineno stay in the top-level DECLARE
  • Variables with lineno > topLevelBlockLineno are assigned to the nearest nested block whose lineno is greater than the variable's lineno

This fixes the last remaining failing fixture (plpgsql_varprops-13.sql). All 190 fixtures now pass round-trip testing.

Review & Testing Checklist for Human

  • Verify the lineno-based algorithm handles edge cases correctly (e.g., multiple nested blocks at same nesting level, deeply nested blocks)
  • Test with a real PL/pgSQL function that has nested DECLARE inside a FOR loop to confirm the output is valid syntax
  • Check that functions WITHOUT nested DECLARE blocks still work correctly (regression test)

Recommended test plan: Run the round-trip tests locally (npm test in packages/plpgsql-deparser) and manually inspect the output for plpgsql_varprops-13.sql to verify the nested DECLARE appears in the correct position.

Notes

Implements lineno-based scope tracking to correctly assign variables to their
enclosing blocks. Variables declared inside a FOR loop body are now emitted
in a nested DECLARE section before the inner BEGIN, preserving the correct
semantics where variables are reinitialized on each loop iteration.

Key changes:
- Add buildBlockDatumMap() to assign datums to blocks based on lineno ranges
- Add collectNestedBlockLinenos() to find all nested block linenos in the AST
- Modify deparseDeclareSection() to accept included/excluded datum indices
- Modify deparseBlock() to emit DECLARE sections for its assigned datums
- Modify deparseFunction() to exclude nested block datums from top-level DECLARE

This fixes the last remaining failing fixture (plpgsql_varprops-13.sql).
All 190 fixtures now pass round-trip testing.
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@pyramation pyramation merged commit a5944ab into main Jan 7, 2026
18 checks passed
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