Skip to content

fix(editor): make statement splitting dollar-quote aware for PostgreSQL (#1559)#1560

Open
datlechin wants to merge 3 commits into
mainfrom
worktree-fix-1559-dollar-quote
Open

fix(editor): make statement splitting dollar-quote aware for PostgreSQL (#1559)#1560
datlechin wants to merge 3 commits into
mainfrom
worktree-fix-1559-dollar-quote

Conversation

@datlechin
Copy link
Copy Markdown
Member

Summary

Fixes #1559. Running a PostgreSQL script with a DO $$ ... $$; block or a dollar-quoted function body failed with ERROR: unterminated dollar-quoted string at or near "$$".

Root cause

The editor's statement splitter, SQLStatementScanner, splits a buffer on semicolons while skipping over strings and comments, but it had no concept of PostgreSQL dollar-quoting. A semicolon inside DO $$ BEGIN ...; ... END $$; was treated as a statement terminator, so a broken fragment reached the server.

A second splitter, SQLFileParser (used only for SQL file import), already handled dollar-quoting correctly and was gated by dialect. The editor path never got that logic. QueryClassifier.isMultiStatement delegates to the editor splitter, so the MCP, AI, and safe-mode gates miscounted these scripts too.

What changed

  • New SqlDollarQuote holds the dollar-quote lexing (opener detection, close matching, identifier rules) as one shared, pure NSString helper.
  • SQLFileParser now delegates to it. Behavior is unchanged; its existing tests still pass.
  • SQLStatementScanner takes a dialect and treats a dollar-quoted region as opaque when the dialect is PostgreSQL family. A token-start guard keeps $1 positional parameters and a$$ identifiers from being read as openers. Other dialects are unaffected.
  • The dialect is threaded from every execution call site (Execute All, Execute Current Statement, EXPLAIN, ClickHouse) and into QueryClassifier.isMultiStatement, so the AI/MCP/safe-mode gates stop miscounting a DO block as multi-statement.

Tests

  • New SQLStatementScanner cases: DO $$ ... $$;, tagged $func$, nested different tags, $1 not an opener, a$$ identifier not an opener, dialect gating, and cursor inside a dollar body.
  • All existing SQLFileParser, QueryClassifier, and scanner tests pass.
  • swiftlint --strict clean.

Not in scope

The two splitters still differ on nested block comments and E'...' escapes, and autocomplete is not dialect-aware. These are separate from this issue and left for a follow-up.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a1b2445a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +134 to +137
SQLStatementScanner.allStatements(
in: sql,
dialect: SqlDialect.from(databaseTypeId: databaseType.rawValue)
).count > 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Classify PostgreSQL DO blocks before unblocking them

For PostgreSQL, this now makes DO $$ BEGIN DROP TABLE t; END $$; count as a single statement, but classifyTier still only checks top-level prefixes and returns .safe for DO. The AI/MCP execute_query paths rely on this multi-statement guard plus the tier check before running with pre-cleared capabilities, so a destructive operation hidden inside a dollar-quoted DO block can bypass the dedicated confirmation tool and safe-mode write/destructive classification. Please either classify DO blocks conservatively for PostgreSQL or keep a separate non-UI guard for these executable blocks.

Useful? React with 👍 / 👎.

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.

Cannot run scipts with DO $$ ... END $$;

1 participant