Skip to content

feat(grammar): PERFORM, EXECUTE, RETURN QUERY, INTO targets, DO and CALL - #374

Draft
sebsnyk wants to merge 4 commits into
DerekStride:mainfrom
sebsnyk:feat/dynamic-sql
Draft

sebsnyk wants to merge 4 commits into
DerekStride:mainfrom
sebsnyk:feat/dynamic-sql

Conversation

@sebsnyk

@sebsnyk sebsnyk commented Sep 10, 2026

Copy link
Copy Markdown

Stacked PR, converted to draft. This sits fourth in the order #371 -> #372 -> #373 -> #374 and depends on #373. GitHub cannot base a fork PR on another fork branch, so the diff below includes the predecessors; only the last commit (90e976f) is this change. It is not ready for review until #371 to #373 land and it is rebased; closing it until then is a reasonable call.

Problem

The last group of statements that real PL/pgSQL bodies use every few lines: perform, execute ... into ... using, return next / return query, select ... into strict, insert ... returning ... into, and the do $$ ... $$ block that migrations wrap them in. The sample in #236 has RETURNING * INTO session_record as its one remaining unparsed construct after #371 to #373; with this PR it parses without an ERROR node. Against real sources:

source ERROR nodes with #373 with this PR
PostgreSQL src/test/regress/sql/plpgsql.sql 363 252
pg_partman sql/functions/check_default.sql 9 6
utPLSQL source/core/ut_utils.pkb 233 232

pg_partman's remaining six are @extschema@ templating placeholders and SET search_path = ... in the function header (#364, separate PR). utPLSQL still needs Oracle's header shape and package bodies.

Solution

A new grammar/statements/dynamic-sql.js:

  • perform_statement: PERFORM [DISTINCT] select_expression [from ...], reusing the select tail so joins, where, order by and limit come for free.
  • execute_statement: EXECUTE [IMMEDIATE] expr [INTO [STRICT] target, ...] [USING [IN | OUT | IN OUT] arg, ...]. IMMEDIATE and the argument modes are PL/SQL's spelling of the same statement.
  • _function_return extended with RETURN NEXT expr and RETURN QUERY (query | EXECUTE ...).
  • SELECT ... INTO [STRICT] ... in _select_statement, and RETURNING ... INTO [STRICT] target, ... on returning, so insert, update and delete all take it. Both are optional keywords in an existing position; existing trees are unchanged.
  • OPEN cursor [SCROLL] FOR EXECUTE ... on the open_statement from feat(grammar): declaration attributes and cursors in procedural bodies #373.
  • do_statement: DO [LANGUAGE x] $$ [<<label>>] [DECLARE ...] BEGIN ... [EXCEPTION ...] END $$ or a string body, in statement so it works at the top level.
  • call_statement: CALL procedure(args), also in statement.

Notes

sebsnyk and others added 4 commits September 10, 2026 17:08
Function and procedure bodies could hold SQL statements and RETURN but
none of the control flow that PL/pgSQL and PL/SQL bodies are made of.
Adds assignment with `:=` or `=`, `NULL`, `IF ... ELSIF ... ELSE ...
END IF`, `CASE ... END CASE`, `LOOP`, `WHILE ... LOOP`, `FOR ... IN`
over an integer range, a query or a cursor, `FOREACH ... IN ARRAY`,
`EXIT` and `CONTINUE` with an optional label and `WHEN`, `<<label>>`
on blocks and loops, nested `DECLARE ... BEGIN ... END` blocks and a
bare `RETURN`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the error-handling statements of PL/pgSQL and PL/SQL bodies:
`RAISE` with a level, a format string and arguments, a condition name,
`SQLSTATE` or `USING` options; `ASSERT`; `EXCEPTION WHEN ... THEN`
handlers at the end of a function body, procedure body or block, with
`OR`-joined conditions, `SQLSTATE` and `OTHERS`; and
`GET [CURRENT | STACKED] DIAGNOSTICS`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Declarations gain `%TYPE` and `%ROWTYPE` (also in parameters),
`CONSTANT`, `NOT NULL`, `=` and `DEFAULT` initialisers, `ALIAS FOR`,
and cursor declarations in both the PL/pgSQL (`c [NO SCROLL] CURSOR
(args) FOR query`) and PL/SQL (`CURSOR c RETURN type IS query`) forms.
Bodies gain `OPEN`, `FETCH`, `MOVE` and `CLOSE`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the statements a PL/pgSQL or PL/SQL body uses to run SQL:
`PERFORM`, `EXECUTE [IMMEDIATE] expr [INTO [STRICT] targets] [USING
args]`, `RETURN NEXT expr`, `RETURN QUERY query | EXECUTE ...`,
`SELECT ... INTO STRICT`, `RETURNING ... INTO [STRICT] targets`, and
`OPEN cursor FOR EXECUTE ...`. Adds the top-level `DO [LANGUAGE x]
$$ ... $$` block and `CALL procedure(args)`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant