`run_sql` with `no_transaction: true` mis-splits dollar-quoted ($$) PL/pgSQL blocks

Author: gabegorelickCreated Jun 26, 2026Updated Jul 8, 2026
Labelsk/bug

Version Information

Server Version: v2.48.5 CLI Version (for CLI related issue): n/a

Environment

OSS

What is the current behaviour?

When run_sql is called with no_transaction: true, the server splits the SQL into individual statements via splitSQLStatements. That splitter mis-handles bare $$ dollar-quoting: it represents the empty tag internally as the single character "$", and its closing-delimiter check is a prefix match against that tag. As a result, any lone $ inside the body (e.g. a $ regex end-anchor in a string literal like '^foo$') is mistaken for the closing $$. The parser then falls out of dollar-quote mode and treats the next ; as a statement separator, slicing a single DO $$ … $$; / CREATE FUNCTION … $$; block into invalid fragments. Postgres then rejects the fragment with a syntax error.

This only happens with no_transaction: true; the default path sends the whole body in one call and is unaffected. Named dollar-quote tags ($tag$ … $tag$) are also unaffected.

The relevant code is at https://github.com/hasura/graphql-engine/blob/v2.48.5/server/src-lib/Hasura/Backends/Postgres/DDL/RunSQL.hs#L302-L335

What is the expected behaviour?

No syntax error when running SQL that contains $$ in no_transaction mode.

How to reproduce the issue?

  1. Call run_sql with DO $$ BEGIN IF 'x' ~ '^x$' THEN NULL; END IF; END $$; and no_transaction: true
  2. Notice that it fails with Postgres syntax error
  3. Run the same SQL, but without no_transaction: true.
  4. Notice that it succeeds

Screenshots or Screencast

Please provide any traces or logs that could help here.

Any possible solutions/workarounds you're aware of?

Use named dollar-quote tags ($foo$) instead of $$. Or don't use no_transaction.

Keywords