Fix PL/pgSQL IF hang and bump tree-sitter-postgres to 1.2.2#8
Conversation
format_stmt_if never advanced its child index for the closing `kw_if` of `END IF`, so any `format_plpgsql` body containing an IF statement looped forever. Add the missing increment and cover it with regression tests (IF/THEN and IF/ELSIF/ELSE). Bump tree-sitter-postgres to 1.2.2, which fixes a float_literal lexer bug that split decimals like `0.00` into `0` + `.00`. That previously corrupted output (`(0.00)::real` -> `(0 .00)::real`, `0.0` -> `.0`); the affected production views now parse cleanly. Add example binaries for exercising the PL/pgSQL path (format_plpgsql_test, dump_plpgsql), mirroring the existing SQL examples. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
PR monitoring complete — this PR is green and ready to merge. CI status:
Merge state: MERGEABLE / CLEAN. No automated review feedback to address: this repository has no automated reviewer (CodeRabbit, Claude Code Review, etc.) installed, and there are no open review threads or comments on the PR. No code changes were required during monitoring. Ready for human review/merge. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughFixes an infinite loop in ChangesPL/pgSQL formatter fix and tooling
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/dump_plpgsql.rs`:
- Line 7: The short variable assignment on line 7 uses byte slicing with [..60]
which can panic if it cuts through a multibyte UTF-8 character. Replace this
byte-level truncation with character-safe truncation by iterating through the
string's characters and truncating after the 60th character, or by finding the
byte boundary that corresponds to the 60th character to ensure the slice always
ends at a valid UTF-8 boundary.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: e636f3b5-bbdf-4fb7-beca-cdb53bff219c
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
Cargo.tomlexamples/dump_plpgsql.rsexamples/format_plpgsql_test.rssrc/formatter/plpgsql.rstests/plpgsql_test.rs
| fn print_tree(node: tree_sitter::Node, source: &str, indent: usize) { | ||
| let kind = node.kind(); | ||
| let text = &source[node.byte_range()]; | ||
| let short = if text.len() > 60 { &text[..60] } else { text }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd /tmp && find . -name "dump_plpgsql.rs" -type f 2>/dev/null | head -5Repository: gmr/libpgfmt
Length of output: 38
🏁 Script executed:
git ls-files examples/dump_plpgsql.rsRepository: gmr/libpgfmt
Length of output: 81
🏁 Script executed:
cat -n examples/dump_plpgsql.rs | head -20Repository: gmr/libpgfmt
Length of output: 822
Use UTF-8-safe truncation for preview text.
Line 7 can panic on valid SQL containing multibyte characters because byte slicing ([..60]) may cut through a UTF-8 code point.
Proposed fix
- let short = if text.len() > 60 { &text[..60] } else { text };
+ let short = if text.len() > 60 { text.chars().take(60).collect::<String>() } else { text.to_string() };
let short = short.replace('\n', "\\n");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let short = if text.len() > 60 { &text[..60] } else { text }; | |
| let short = if text.len() > 60 { text.chars().take(60).collect::<String>() } else { text.to_string() }; | |
| let short = short.replace('\n', "\\n"); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/dump_plpgsql.rs` at line 7, The short variable assignment on line 7
uses byte slicing with [..60] which can panic if it cuts through a multibyte
UTF-8 character. Replace this byte-level truncation with character-safe
truncation by iterating through the string's characters and truncating after the
60th character, or by finding the byte boundary that corresponds to the 60th
character to ensure the slice always ends at a valid UTF-8 boundary.
Summary
Fixes two issues surfaced by production DDL that libpgfmt couldn't handle.
1. PL/pgSQL
IFinfinite-loop hangformat_stmt_ifwalked the statement's named children in awhileloop but only advanced the index for the openingkw_if. The closingkw_ifofEND IFhit the same match arm, fell through without incrementing, and the loop spun forever. Anyformat_plpgsqlbody containing anIFstatement hung.Fix: advance the index for the closing
kw_if. Addedtests/plpgsql_test.rscoveringIF/THEN/END IFandIF/ELSIF/ELSE(these would hang before the fix; the existingcreate_functionfixture didn't catch it because the SQL path treats the function body as opaque text).2. Decimal literals corrupted (
0.00->0 .00)tree-sitter-postgres 1.2.1 had a
float_literallexer bug (stray trailing space in the regex) that split decimals like0.00into0(anERRORnode) +.00. libpgfmt then emitted invalid SQL —(0.00)::real->(0 .00)::realandTHEN 0.0->THEN .0.Fix: bump
tree-sitter-postgresto 1.2.2 (gmr/tree-sitter-postgres#41), which corrects the lexer. The affected production views now parse with zeroERRORnodes and format to valid SQL.Also adds
format_plpgsql_testanddump_plpgsqlexample binaries for exercising the PL/pgSQL path, mirroring the existing SQL examples.Verification
just check(fmt + clippy + test) passes; all test suites green.0.00::real,0.0,12.5e3,.5all format correctly with no ERROR nodes.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
New Features
Tests