Skip to content

Parse PostgreSQL event triggers, REINDEX, SECURITY LABEL and schema elements - #2818

Open
minleejae wants to merge 1 commit into
JSQLParser:masterfrom
minleejae:feat/postgresql-admin-statements-20261014
Open

minleejae wants to merge 1 commit into
JSQLParser:masterfrom
minleejae:feat/postgresql-admin-statements-20261014

Conversation

@minleejae

@minleejae minleejae commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Parse PostgreSQL administration statements that fail in every configuration today. pg_dump output and maintenance scripts contain them, for example:

  • CREATE EVENT TRIGGER etg ON ddl_command_start WHEN TAG IN ('CREATE TABLE') EXECUTE FUNCTION abort_any_command()
  • ALTER EVENT TRIGGER etg ENABLE ALWAYS
  • REINDEX INDEX CONCURRENTLY idx
  • SECURITY LABEL FOR selinux ON TABLE t1 IS 'system_u:object_r:sepgsql_table_t:s0'
  • CREATE SCHEMA hollywood CREATE TABLE films (…) CREATE VIEW winners AS SELECT …

Current design (As-is)

  • The statement grammar has no alternative for REINDEX or SECURITY LABEL.
  • CREATE EVENT … and ALTER EVENT … reach only the MySQL event productions, which fail at the trigger name.
  • CREATE SCHEMA handles schema elements only partly:
    • It accepts one CREATE TABLE element, and also a VIEW … element without CREATE. A second CREATE element fails.
    • toString() and StatementDeParser drop all elements and the PATH clause.
    • The parser rewrites each CREATE TABLE element's name to carry the schema name.
    • TablesNamesFinder throws for every CREATE SCHEMA.

Target design (To-be)

  • CreateEventTrigger (statement.create.trigger) records:
    • the name and the event name;
    • the WHEN filters in source order, each a variable with its string values;
    • the invoked function. It reuses CreateTrigger.ExecuteKeyword and the Function reference of CREATE TRIGGER, with an empty argument list.
    • Rejected: arguments, OR REPLACE, and empty or non-string tag lists.
  • AlterEventTrigger (statement.alter):
    • ENABLE [REPLICA | ALWAYS] and DISABLE reuse RelationAlterAction.EnableState and the PostgreSqlEnableState() production from Share PostgreSQL trigger and rule enable states #2718.
    • It also covers OWNER TO and RENAME TO.
    • Each non-null setter selects its action and discards the values of the other actions.
  • Telling event triggers from MySQL events: EVENT TRIGGER starts a PostgreSQL event trigger only when the name is followed by ON (CREATE) or by an action keyword (ALTER). A MySQL event named trigger still parses to CreateEvent/AlterEvent.
  • Reindex (new statement.reindex package) records:
    • the Target (INDEX, TABLE, SCHEMA, DATABASE, SYSTEM) and the CONCURRENTLY keyword;
    • the parenthesized CONCURRENTLY, TABLESPACE and VERBOSE options, with values as written;
    • the name. Only DATABASE and SYSTEM may omit it.
    • REINDEX becomes a non-reserved token. A statement that starts with a plain identifier adds choice conflicts at several optional trailing identifiers, so it needs a token, like NOTIFY in Support PostgreSQL rewrite rules with reusable statement actions #2723. The word remains usable as an identifier, and KeywordsTest covers it.
  • SecurityLabel (new statement.securitylabel package) records the provider as written and one target. getObjectType() covers all 21 object kinds that PostgreSQL documents:
    • named objects as Table;
    • a qualified COLUMN;
    • FUNCTION/PROCEDURE/ROUTINE/AGGREGATE signatures, using the shared RoutineReference;
    • LARGE OBJECT OIDs.
    • IS NULL is a null label.
    • It does not reuse CommentTarget, which has no TABLE/COLUMN/VIEW kinds and is being extended by the COMMENT ON targets PR. Qualified names reuse CommentObjectName().
  • CREATE SCHEMA elements:
    • A new SchemaElement() production reuses Create() and Grant(). It accepts PostgreSQL's element kinds: CREATE TABLE, VIEW, INDEX, SEQUENCE, TRIGGER and GRANT.
    • It rejects materialized views, other CREATE statements, the VIEW form without CREATE, and elements after IF NOT EXISTS.
    • Behavior change: elements keep their names as written. The parser no longer writes the schema name into CREATE TABLE elements.
    • toString() and StatementDeParser render PATH and the elements. TablesNamesFinder and StatementVisitorAdapter traverse the elements.
    • Inside an element, GRANT is never read as an implicit alias (… FROM films GRANT SELECT …). Elsewhere grant remains an alias.
  • Wiring:
    • StatementVisitor defaults, the adapter, StatementDeParser, TablesNamesFinder, StatementValidator and StatementFeatureVisitor.
    • Feature analysis: schema change; REINDEX also reads data.
    • With unsupported statements enabled, the statement-start check recognizes REINDEX and SECURITY LABEL instead of capturing them as opaque.
    • New features createEventTrigger, alterEventTrigger, reindex, reindexConcurrently (PostgreSQL 12) and securityLabel. They are in PostgresqlVersion, and the event trigger features are also in FeaturesAllowed.CREATE/ALTER.
    • The usage guide, README and index list the statements.

Validation

  • 100 new tests:
    • PostgreSqlEventTriggerTest 23, ReindexTest 27, SecurityLabelTest 39, and 11 more in CreateSchemaTest.
    • Every form: parse, deparse and reparse with Dialect.POSTGRESQL, plus the AST fields.
    • Rejected forms, builder and setter round trips, and table discovery.
    • MySQL events named trigger, and the new words used as identifiers.
    • Statements among unsupported statements, validation capabilities and statement features.
    • The existing CREATE SCHEMA tests pass unchanged.
  • Java 17 offline Gradle spotlessApply check: 10,477 tests, 10,452 passed, 25 skipped, zero failures or 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:
    • Fixed with Dialect.POSTGRESQL and without a dialect: CREATE EVENT TRIGGER, REINDEX INDEX CONCURRENTLY, REINDEX TABLE, SECURITY LABEL and CREATE SCHEMA with schema elements. Each renders identically to the source.
    • 0 regressed and 0 changed across the MySQL and PostgreSQL corpora, the keyword sweeps (reindex, security and label as names), the variants and the scripts.
  • 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 205 MySQL and 332 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.

…hema elements

Add typed CreateEventTrigger, AlterEventTrigger, Reindex and SecurityLabel
statements. Event triggers reuse the CREATE TRIGGER routine invocation and
the shared trigger and rule enable states; SECURITY LABEL addresses routines
through RoutineReference. REINDEX becomes a non-reserved keyword.

CREATE SCHEMA parses PostgreSQL schema elements (CREATE TABLE, VIEW, INDEX,
SEQUENCE, TRIGGER and GRANT), keeps their names as written and renders them,
together with the PATH clause, in toString() and StatementDeParser.

Signed-off-by: minleejae <mmj9808@gmail.com>

This branch has not been deployed

No deployments
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