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 — Fix parsing of table check constraints in CREATE TABLE by xmaks82 · Pull Request #684 · phpmyadmin/sql-parser

Conversation

@xmaks82

@xmaks82 xmaks82 commented Oct 23, 2026

Copy link
Copy Markdown

Ref #167

A table level check constraint broke parsing of the whole CREATE TABLE, with any context (MySQL 8.0.16+ and MariaDB 10.2.1+ both print it in SHOW CREATE TABLE):

CREATE TABLE t (a INT, b INT, CONSTRAINT `chk_ab` CHECK (a < b), c INT)

Before:

A symbol name was expected! A reserved keyword can not be used as a column name without backquotes. (near "CHECK")
Unexpected beginning of statement. (near "a")
Unexpected beginning of statement. (near "b")
Unexpected beginning of statement. (near "c")
Unrecognized statement type. (near "INT")

and build() gave CREATE TABLE t (`a` int, `b` int): the constraint and column c were lost. The same happens for an unnamed CHECK (a > 0) and for CONSTRAINT CHECK (...).

Now CreateDefinition accepts [CONSTRAINT [symbol]] CHECK (expr) and stores it like a column check: name is the constraint symbol (or null), isConstraint is set for CONSTRAINT, and the expression is in options (the existing CHECK field option, so [NOT] ENFORCED works too). Utils\Table::getFields() skips it because it has no type.

Column level CHECK and ALTER TABLE ... ADD CONSTRAINT ... CHECK are not changed.

Docs:

  • https://mariadb.com/docs/server/reference/sql-statements/data-definition/constraint
  • https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html

Tests: parser fixture parseCreateTableCheckConstraint (named, unnamed, CONSTRAINT CHECK, NOT ENFORCED, the example from #167, a column after the constraints) and a round-trip test in tests/Builder/CreateStatementTest.php.

Sorry, something went wrong.

Uh oh!

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

All reactions
Магда М.Г.
Fix parsing of table check constraints in CREATE TABLE
a3cfebf
A table level [CONSTRAINT [symbol]] CHECK (expr) definition was
reported as a column named CHECK, and the rest of the statement
was lost. Parse it as a create definition with the CHECK option.

Ref phpmyadmin#167

Signed-off-by: Магда М.Г. <[email protected]>
by-ae
by-ae reviewed Oct 28, 2026
View reviewed changes

@by-ae by-ae left a comment •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this out and ran phpunit on the branch: 1065 tests, all pass.

I also fed it a few real SHOW CREATE TABLE shapes that aren't in the new fixture, and they all parse with no errors and build back unchanged:

  • MySQL 8 output with doubled parens and the version comment: CONSTRAINT `chk` CHECK ((`a` < `b`)) /*!80016 NOT ENFORCED */ builds as CONSTRAINT `chk` CHECK ((`a` < `b`)) NOT ENFORCED. On 5.11.x the same statement gives 4 errors and drops the constraint.
  • MariaDB output that mixes a column-level CHECK (json_valid(`j`)) with a table-level CONSTRAINT `CONSTRAINT_1` CHECK (`a` > 0).
  • Nested parens in an unnamed check, CHECK (a IN (1,2) AND (b > 0)), followed by another column.
  • CONSTRAINT c1 CHECK (a > 0) ENFORCED, and CONSTRAINT CHECK (...) followed by PRIMARY KEY (a).

Since the check constraint now shows up in $statement->fields with no type or key, I made sure the helpers in Utils\Table still behave. On a table that has a FOREIGN KEY and a CHECK constraint, Table::getFields() returns just the real columns (j,a,b) and Table::getForeignKeys() returns only fk, the same as on 5.11.x. Both skip entries with an empty type/key, so the new entry doesn't leak into either one.

Sorry, something went wrong.

Uh oh!

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

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

Reviewers

1 more reviewer
@by-ae by-ae by-ae left review comments
Reviewers whose approvals may not affect merge requirements

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

@xmaks82 @by-ae
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.