Skip to content

feat(grammar): declaration attributes and cursors in procedural bodies - #373

Draft
sebsnyk wants to merge 3 commits into
DerekStride:mainfrom
sebsnyk:feat/declarations-and-cursors
Draft

feat(grammar): declaration attributes and cursors in procedural bodies#373
sebsnyk wants to merge 3 commits into
DerekStride:mainfrom
sebsnyk:feat/declarations-and-cursors

Conversation

@sebsnyk

@sebsnyk sebsnyk commented Sep 10, 2026

Copy link
Copy Markdown

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

Problem

Declarations and cursors are where PL/SQL sources fail first, and they are common in PL/pgSQL too: v employees.salary%type, l_row employees%rowtype, c constant int := 3, n int not null default 0, arg alias for $1, cursor c is select ..., open / fetch ... into / close. Oracle's HR sample schema declares every procedure parameter with %type, so none of its procedures parse past the signature. Against real sources:

source ERROR nodes with #372 with this PR
PostgreSQL src/test/regress/sql/plpgsql.sql 414 363
pg_partman sql/functions/check_default.sql 11 9
utPLSQL source/core/ut_utils.pkb 233 233

utPLSQL does not move because it needs Oracle's IS ... END name; header shape and package bodies, which are the next PR.

Solution

  • type_attribute: object_reference % (TYPE | ROWTYPE), accepted wherever a declaration or a function argument takes a type. It is a separate alternative next to _type rather than an addition to _type itself, so column definitions and casts are untouched.
  • function_declaration accepts CONSTANT, NOT NULL, and = / DEFAULT as well as :=; a second form covers name ALIAS FOR $n | name. The initialiser itself is unchanged (a parenthesised statement or a literal); allowing any expression there changes the tree of an existing test and is left for a separate PR.
  • cursor_declaration: name [NO SCROLL | SCROLL] CURSOR [(args)] [RETURN type] (FOR | IS) query, and the PL/SQL word order CURSOR name .... Cursor parameters reuse function_arguments.
  • open_statement, fetch_statement, move_statement, close_statement in grammar/statements/cursors.js, with the PL/pgSQL directions (NEXT, PRIOR, FIRST, LAST, ABSOLUTE n, RELATIVE n, FORWARD, BACKWARD) and OPEN c FOR query for cursor variables. OPEN c FOR EXECUTE ... comes with dynamic SQL in the next PR.
  • The DECLARE section is one hidden rule (_declare_section) shared by function_body, procedure_body and block; the tree is unchanged.

One resolution worth a look: in FETCH ABSOLUTE n IN cur, the count is followed by IN, which is also the start of expr IN (...). The direction rule is prec.left so the count reduces first.

Notes

sebsnyk and others added 3 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>
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