Skip to content

Fix string-bodied CREATE FUNCTION swallowing the next statement#97

Merged
MasterOdin merged 1 commit into
coresql:mainfrom
murrayju:murrayju/fix-string-bodied-create-function-termination
Jun 10, 2026
Merged

Fix string-bodied CREATE FUNCTION swallowing the next statement#97
MasterOdin merged 1 commit into
coresql:mainfrom
murrayju:murrayju/fix-string-bodied-create-function-termination

Conversation

@murrayju

@murrayju murrayju commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Problem

The library fails to split the following into two statements:

create function foo() returns void as 'select 1' language sql;
SELECT 1;

It is parsed as a single CREATE_FUNCTION that greedily consumes the trailing SELECT 1;.

The bug is broader than the single reported case — it affects any CREATE FUNCTION/PROCEDURE whose body is a quoted or dollar-quoted string (PostgreSQL/Snowflake/standard SQL), and PostgreSQL CREATE TRIGGER (which only references a function). These only worked before when they happened to be the last statement, since end-of-input terminated them.

Root cause

CREATE_FUNCTION/CREATE_PROCEDURE/CREATE_TRIGGER are in statementsWithEnds, so a semicolon only terminates them once statement.canEnd is set — and canEnd is only set when a BEGIN...END block closes. When the body is a single string/dollar-quoted token (no block) or the trigger has no body, canEnd was never set, so the statement swallowed everything after it.

Fix

  • Set canEnd once a string/dollar-quoted body has been consumed at the top level following the AS keyword (CREATE FUNCTION/PROCEDURE).
  • Make statementsWithEnds dialect-aware: exclude CREATE_TRIGGER for PostgreSQL/Snowflake, where triggers have no inline body.

The block-based canEnd logic is left intact, so T-SQL bodies (e.g. mssql triggers with IF ... RETURN; before a BEGIN...END) still protect their token-level semicolons.

Tests

Added a multiple-statement describe block covering:

  • the reported string-literal body case
  • dollar-quoted bodies (incl. dollar-quoted plpgsql with internal BEGIN...END)
  • PostgreSQL bodyless triggers
  • a regression guard for mssql BEGIN...END function bodies

All existing tests continue to pass.

CREATE FUNCTION/PROCEDURE/TRIGGER are kept open across semicolons so that
token-level semicolons inside a BEGIN...END body don't terminate them early.
But when the body is supplied as a quoted or dollar-quoted string
(e.g. PostgreSQL `AS 'select 1'` / `AS $$ ... $$`), or when a PostgreSQL
trigger merely references a function, no block ever opens, so `canEnd` was
never set and the statement greedily consumed whatever followed it.

This only surfaced when such a statement was not the last one, since
end-of-input otherwise terminated it.

Fixes:
- Set `canEnd` once a string/dollar-quoted body has been consumed at the top
  level following the `AS` keyword (CREATE FUNCTION/PROCEDURE).
- Make `statementsWithEnds` dialect-aware: exclude CREATE_TRIGGER for
  PostgreSQL/Snowflake, where triggers have no inline body.

The block-based `canEnd` logic is left intact so T-SQL bodies (e.g. mssql
triggers with `IF ... RETURN;` before a BEGIN...END) still protect their
token-level semicolons.
@MasterOdin MasterOdin merged commit f08d033 into coresql:main Jun 10, 2026
9 checks passed
@murrayju murrayju deleted the murrayju/fix-string-bodied-create-function-termination branch June 10, 2026 19:34
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.

2 participants