GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Parse ALTER FUNCTION, PROCEDURE and TRIGGER actions and MySQL routine definers by minleejae · Pull Request #2812 · JSQLParser/JSqlParser

Conversation

@minleejae

@minleejae minleejae commented Oct 14, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Builds on #2811, which adds ConfigurationParameterChange; please review that PR first. This PR is the second commit on top of it.

Purpose

Parse the routine and trigger changes that PostgreSQL and MySQL dumps and migrations emit:

  • PostgreSQL ALTER FUNCTION, ALTER PROCEDURE and ALTER ROUTINE, and ALTER TRIGGER, are UnsupportedStatements. pg_dump writes ALTER FUNCTION f(int) OWNER TO role for every function.
  • MySQL ALTER FUNCTION/ALTER PROCEDURE characteristics, such as ALTER PROCEDURE p COMMENT 'x' SQL SECURITY INVOKER, are UnsupportedStatements.
  • MySQL CREATE DEFINER = ... FUNCTION|PROCEDURE and CREATE TRIGGER IF NOT EXISTS fail.
  • A MySQL trigger with a procedural body, such as FOR EACH ROW BEGIN IF ... END IF; END, fails. A body of plain statements parses, but it takes the ; after END, so a script fails at the next statement.

Current design (As-is)

  • Alter() has no alternative for these statements, so its fallback captures them as UnsupportedStatements.
  • Create() sends every DEFINER prefix to CreateTrigger(), so CREATE DEFINER = ... FUNCTION fails. CreateFunctionalStatement has no definer.
  • The MySQL CreateTrigger() reads its body with SingleStatement() | Block(). Block() accepts SQL statements only and consumes a following semicolon. The MySQL trigger path also drops OR REPLACE.

Target design (To-be)

  • Add AlterRoutine for PostgreSQL ALTER FUNCTION|PROCEDURE|ROUTINE and MySQL ALTER FUNCTION|PROCEDURE. Both dialects share one statement because they change the same routine characteristics; only the spelling differs.
    • getRoutineType() and getRoutine(), the existing RoutineReference with the optional PostgreSQL argument types.
    • Action: CHARACTERISTICS (the default), RENAME, OWNER, SET_SCHEMA and DEPENDS_ON_EXTENSION with isNoDependency(). Payloads of other actions are kept, as in AlterDatabase.
    • getCharacteristics(): a mutable list of the new RoutineCharacteristic in source order, plus PostgreSQL's isRestrict().
  • RoutineCharacteristic.Kind has one value per characteristic, and each renders its own keywords:
    • PostgreSQL: IMMUTABLE, STABLE, VOLATILE, CALLED_ON_NULL_INPUT, RETURNS_NULL_ON_NULL_INPUT, STRICT, [NOT_]LEAKPROOF, PARALLEL_*, COST, ROWS, SUPPORT and CONFIGURATION_PARAMETER;
    • MySQL: COMMENT, LANGUAGE_SQL, CONTAINS_SQL, NO_SQL, READS_SQL_DATA and MODIFIES_SQL_DATA;
    • shared: SECURITY_DEFINER and SECURITY_INVOKER. getSecurityClause() keeps the SECURITY, EXTERNAL SECURITY or MySQL SQL SECURITY spelling.
    • COST, ROWS, SUPPORT and COMMENT keep their value as SQL text in getValue(). getComment() returns the COMMENT literal as a StringValue, read with the parser's dialect escaping, so getNotExcapedValue() is the text MySQL stores. SET/RESET reuse ConfigurationParameterChange and its grammar production from Parse PostgreSQL ALTER DATABASE and share typed database options #2811.
  • Add AlterTrigger for PostgreSQL ALTER TRIGGER name ON table RENAME TO | [NO] DEPENDS ON EXTENSION, with the table as a Table.
  • Grammar:
    • A semantic lookahead selects AlterRoutine only when a known alteration follows the routine name and signature. Other forms, such as Oracle's COMPILE, DB2's NOT FENCED or SQL Server definitions without the SQL Server dialect, remain UnsupportedStatements; with Dialect.SQLSERVER they are still CreateFunctionalStatements.
    • A statement's characteristics belong to one dialect. PostgreSQL characteristics are space-separated and may end with RESTRICT; MySQL characteristics take no argument list and no ALTER ROUTINE. Invalid combinations, such as commas or RENAME TO g RESTRICT, are errors.
    • ALTER TRIGGER is selected only when the whole statement matches.
    • No new reserved words; characteristic words are matched as identifiers.
  • MySQL CREATE:
    • CreateFunctionalStatement.getDefiner() holds the DEFINER account as the MySqlDefiner that views and triggers use. Create() now picks the trigger or routine after the definer.
    • CreateTrigger.isIfNotExists() records IF NOT EXISTS. MariaDB's OR REPLACE is kept on the MySQL path; combining it with IF NOT EXISTS is an error.
    • A BEGIN ... END trigger body with only SQL statements remains a Block. Other compound bodies (IF, CASE, loops, DECLARE, labels) are captured with the existing RoutineBodyBoundary, as for CREATE PROCEDURE, and kept as an UnsupportedStatement body. Both leave the ; after END to separate statements. Block() now uses a shared BeginEndBlock() production; its behavior is unchanged.
  • Wiring:
    • StatementVisitor defaults, StatementVisitorAdapter, StatementDeParser (SET values through the expression deparser) and TablesNamesFinder (the ALTER TRIGGER table);
    • validation: the existing alterFunction and alterProcedure features and new alterRoutine and alterTrigger. PostgreSQL enables all four, MySQL and MariaDB the first two;
    • statement feature analysis reports MODIFIES_SCHEMA;
    • usage guide, README and index.

Validation

  • New and extended tests (26 methods, 125 cases) cover:
    • parse, toString, deparse and reparse with Dialect.POSTGRESQL, Dialect.MYSQL, Dialect.MARIADB and without a dialect, plus statement boundaries in scripts;
    • the AST of every action, characteristic kind, security spelling and signature;
    • MySQL COMMENT literals ('it\'s', 'it''s', "dq", backslash escapes, Korean text and emoji) against the text MySQL stores;
    • unmodelled forms that remain UnsupportedStatement, rejected combinations, and unchanged SQL Server routines;
    • definer accounts, trigger IF NOT EXISTS/OR REPLACE, structured and procedural trigger bodies, and unterminated bodies;
    • visitor dispatch, table discovery, validation capabilities and statement features.
  • Java 17 offline Gradle spotlessApply check: 10,550 tests, 10,525 passed, 25 skipped, zero failures/errors. The grammar choice conflict check passes.
  • Compared with master (bdf8ac31) on a corpus of 635 MySQL 8.4 and PostgreSQL 18 DDL/DCL statements, each accepted by the server, plus variants (the ALTER DATABASE/CHARSET fixes come from Parse PostgreSQL ALTER DATABASE and share typed database options #2811):
    • Fixed with Dialect.POSTGRESQL and without a dialect: ALTER FUNCTION f2(int) OWNER TO/RENAME TO/SET search_path = ..., ALTER PROCEDURE p1(int) SECURITY DEFINER, ALTER ROUTINE f2(int) IMMUTABLE and ALTER TRIGGER trg ON users RENAME TO trg_new.
    • Fixed with Dialect.MYSQL and without a dialect: ALTER PROCEDURE ... COMMENT ... SQL SECURITY INVOKER, ALTER FUNCTION ... READS SQL DATA, CREATE DEFINER = ... FUNCTION|PROCEDURE, CREATE [DEFINER = ...] TRIGGER IF NOT EXISTS and the trigger with an IF body.
    • The script with a trigger compound body now splits into its two statements.
    • No regressions. Compared with Parse PostgreSQL ALTER DATABASE and share typed database options #2811, only these cases change in the AST or rendered SQL.
  • MySQL 8.4 and PostgreSQL 18.3: every corpus statement this branch parses ran as written on one server and as rendered by toString() on a second, identical server, in the same order. All 211 MySQL and 338 PostgreSQL statements give the same result (success, or the same error).

Integration validation

Applied #2806–#2819 together on master (bdf8ac31), with the stacked PRs on top of their bases (#2806 → #2807 → #2808, #2806 → #2809 → #2810 and #2811 → #2812).

  • Each branch merges cleanly into master. Between the branches, conflicts are limited to adjacent additions (README/index rows, usage sections, imports, visitor and feature lists, one enum line and one alias guard).
  • The integrated build passes Java 17 offline Gradle spotlessApply check: 11,494 tests, 11,469 passed, 25 skipped, zero failures/errors. The grammar choice conflict check passes.
  • On a corpus of 635 MySQL 8.4 and PostgreSQL 18 DDL/DCL statements, each accepted by the server, the integrated build parses 265 of 271 MySQL statements (master: 206) and 363 of 364 PostgreSQL statements (master: 328). Every MySQL 8.4 non-reserved word and PostgreSQL 18 unreserved or column-name keyword parses as a column and table name.
  • On paired MySQL 8.4 and PostgreSQL 18.3 servers, all 263 MySQL and 362 PostgreSQL statements rendered by the integrated build give the same results as the originals.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
This was referenced Oct 14, 2026
Share MySQL account names across CREATE USER and DEFINER #2806
Merged
Parse MySQL GRANT and REVOKE privilege levels, privileges and accounts #2807
Merged
Parse MySQL ALTER USER, RENAME USER and role statements with shared user options #2808
Merged
Keep routine signatures and owning tables in DROP statements #2809
Merged
Share typed MySQL index options across CREATE INDEX and table definitions #2810
Merged
Parse PostgreSQL ALTER DATABASE and share typed database options #2811
Merged
Model MySQL column positions and attributes #2813
Merged
Model PostgreSQL ON COMMIT, access method and DROP behavior #2814
Merged
Allow more MySQL and PostgreSQL keywords as unquoted identifiers #2815
Merged
Extend PostgreSQL COMMENT ON targets #2816
Merged
Parse MySQL and PostgreSQL CREATE and ALTER TABLESPACE #2817
Merged
Parse PostgreSQL event triggers, REINDEX, SECURITY LABEL and schema elements #2818
Merged
Render single spaces in ALTER visibility, FORCE and row level security actions #2819
Merged
@minleejae
minleejae force-pushed the feat/routine-alterations-20261014 branch from e9df9d9 to c458ecb Compare October 14, 2026 09:24
This was referenced Oct 14, 2026
Expose MySQL table and partition comments as string values #2821
Merged
Model MySQL CREATE FUNCTION and PROCEDURE characteristics #2823
Merged
Parse PostgreSQL Unicode escape string constants #2820
Merged
Parse COMMENT ON operators, operator classes, text search objects and large objects #2822
Merged
Parse MySQL SHOW FULL COLUMNS, SHOW TABLE STATUS and SHOW CREATE statements #2824
Merged
@minleejae
feat: parse ALTER FUNCTION, PROCEDURE and TRIGGER actions and MySQL r…
d7b398c
…outine definers

Model PostgreSQL ALTER FUNCTION/PROCEDURE/ROUTINE and MySQL ALTER
FUNCTION/PROCEDURE as AlterRoutine with typed RoutineCharacteristic
items shared by both dialects; SET/RESET reuse
ConfigurationParameterChange and the MySQL COMMENT keeps its literal as
a StringValue. Add PostgreSQL ALTER TRIGGER as AlterTrigger. Unmodelled
forms remain unsupported statements.

Keep the MySQL DEFINER of CREATE FUNCTION/PROCEDURE, accept CREATE
TRIGGER IF NOT EXISTS, keep MariaDB's OR REPLACE, and capture
procedural trigger bodies with the routine body boundary so the next
statement is split correctly.

Signed-off-by: minleejae <[email protected]>
@minleejae
minleejae force-pushed the feat/routine-alterations-20261014 branch from c458ecb to d7b398c Compare October 18, 2026 13:44
@manticore-projects
manticore-projects merged commit f545bff into JSQLParser:master Oct 21, 2026
10 checks passed

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@minleejae @manticore-projects
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.