Skip to content

fix: reuse table constraints for ALTER TABLE ADD in every dialect - #2847

Open
minleejae wants to merge 3 commits into
JSQLParser:masterfrom
minleejae:fix/alter-add-shared-constraints-20261023
Open

minleejae wants to merge 3 commits into
JSQLParser:masterfrom
minleejae:fix/alter-add-shared-constraints-20261023

Conversation

@minleejae

Copy link
Copy Markdown
Contributor

ALTER TABLE ADD parses table constraints with the CREATE TABLE production only for Dialect.MYSQL and Dialect.POSTGRESQL (#2612, #2654). Without either dialect, the generic ALTER branches reject forms that CREATE TABLE accepts in every dialect:

  • ALTER TABLE t ADD CHECK (c > 0)
  • ALTER TABLE t ADD CONSTRAINT ck CHECK (c > 0) NOT VALID
  • ALTER TABLE t ADD FOREIGN KEY (id) REFERENCES parent (id) DEFERRABLE INITIALLY DEFERRED
  • ALTER TABLE t ADD CONSTRAINT pk PRIMARY KEY (id) DEFERRABLE INITIALLY DEFERRED
  • ALTER TABLE t ADD CONSTRAINT ex EXCLUDE USING gist (r WITH &&)

An ADD now uses the shared production in every dialect when it contains a form that only that production accepts: an unnamed CHECK, FOREIGN KEY, EXCLUDE, or INITIALLY IMMEDIATE|DEFERRED, NOT VALID or ENFORCED outside a CHECK. Statements that already parsed keep their generic representation, accessors and output. The PostgreSQL-only UNIQUE USING INDEX and NOT NULL constraints still require Dialect.POSTGRESQL. The scan lives in the package-private AlterConstraintLookahead, like RoutineBodyBoundary, so that it adds little to CCJSqlParser.

The second commit makes VALIDATE CONSTRAINT a structured RelationAlterAction in every dialect. Outside PostgreSQL it was an UNSPECIFIC expression, so its constraint name was not accessible. Its output is unchanged.

Existing parser result classes and public method signatures are retained.

Syntax reference: PostgreSQL 18 ALTER TABLE.

Validation:

  • AlterAddTableConstraintTest compares CREATE TABLE and ALTER ADD for eight definitions without a dialect and with ANSI_SQL, ORACLE, SQLSERVER and H2, and pins the representation of forms that already parsed. 10 of its 13 cases fail on master. PostgreSqlRelationAlterTest covers VALIDATE CONSTRAINT without the PostgreSQL dialect.
  • Removing the dialect test from the gate instead failed 24 existing tests (Oracle constraint states, USING INDEX, legacy key accessors), so only forms that do not parse today are rerouted.
  • Java 17 Gradle check: 12,091 tests, 0 failures, 25 skipped; grammar ambiguity, formatting (Spotless ratchet against upstream/master), Checkstyle, PMD, SpotBugs and JaCoCo pass.
  • PostgreSQL 18.3: the statements above, VALIDATE CONSTRAINT and the PR's other cases (17 statements) give the same results for the original SQL and for the SQL rendered without a dialect and with Dialect.POSTGRESQL.

ALTER TABLE ADD parsed table constraints with the shared CREATE TABLE
production only for the MySQL and PostgreSQL dialects (JSQLParser#2612, JSQLParser#2654).
Without one of them, the generic ALTER branches rejected forms that
CREATE TABLE accepts in every dialect: an unnamed CHECK (c > 0),
NOT VALID, DEFERRABLE INITIALLY DEFERRED, an unnamed FOREIGN KEY with
attributes and EXCLUDE.

Route an ADD to the shared production in every dialect when it uses a
form that only that production accepts: an unnamed CHECK, FOREIGN KEY,
EXCLUDE, or INITIALLY IMMEDIATE|DEFERRED, NOT VALID or ENFORCED outside
a CHECK before the end of the action. Forms that already parsed keep
their generic representation, accessors and output; the PostgreSQL-only
UNIQUE USING INDEX and NOT NULL constraints still need that dialect.

The scan lives in the package-private AlterConstraintLookahead, like
RoutineBodyBoundary, because the generated CCJSqlParser class is close
to the size JaCoCo can still instrument.

Signed-off-by: minleejae <mmj9808@gmail.com>
ALTER TABLE t VALIDATE CONSTRAINT ck was a structured RelationAlterAction
only with the PostgreSQL dialect. Elsewhere the remaining text became
an UNSPECIFIC expression, so the constraint name could not be read and
the action could not follow an ADD that now parses in every dialect.

VALIDATE CONSTRAINT starts no other ALTER TABLE action, so recognise it
in every dialect. Its output is unchanged.

Signed-off-by: minleejae <mmj9808@gmail.com>
Move AlterConstraintLookahead from its own file into the grammar as a
private nested class, as done for TokenNesting in JSQLParser#2849. Split
needsSharedTableConstraint into a check for the forms only the shared
production accepts and a scan for constraint attributes. Codacy's PMD
reported an NPath complexity of 440 for the combined method; the
largest part is now 14. The nested class keeps its branches out of
CCJSqlParser.class. Behaviour does not change.

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