Skip to content

feat: support CREATE DATABASE (#2070) - #2471

Open
fudianchn wants to merge 1 commit into
JSQLParser:masterfrom
fudianchn:feat/create-database-2070
Open

feat: support CREATE DATABASE (#2070)#2471
fudianchn wants to merge 1 commit into
JSQLParser:masterfrom
fudianchn:feat/create-database-2070

Conversation

@fudianchn

@fudianchn fudianchn commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

What

Adds a typed CreateDatabase statement for CREATE DATABASE [IF NOT EXISTS] <name> [options], which previously fell through to the generic UnsupportedStatement capture.

Why

The grammar has no production for CREATE DATABASE (#2070), so users cannot access the database name from the AST. CREATE SCHEMA already has a typed statement and MySQL treats CREATE SCHEMA as a synonym of CREATE DATABASE.

How

  • New CreateDatabase() production dispatched from Create() right after CreateSchema(), following the same shape: LOOKAHEAD(2)-guarded IF NOT EXISTS and RelObjectName() for the name.
  • Vendor-specific options after the name are captured verbatim via the existing captureRest() helper (same approach as UnsupportedStatement and CreateFunctionalStatement), so CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 keeps parsing and round-trips unchanged instead of failing.
  • AST class net.sf.jsqlparser.statement.create.database.CreateDatabase plus wiring in StatementVisitor, StatementVisitorAdapter, StatementDeParser, StatementValidator (new Feature.createDatabase validated against NamedObject.database) and TablesNamesFinder.

Root cause

Missing feature: CREATE DATABASE had no grammar production and always hit the captureRest() fallback.

Testing

  • New CreateDatabaseTest (5 cases): the issue's SQL, IF NOT EXISTS, quoted names, options capture with AST assertions; ./gradlew test --tests ...CreateDatabaseTest passes.
  • Full local suite on the branch: 4801 tests, 0 failures.

Verification of the original issue

Before (master 406a4d4): CCJSqlParserUtil.parse("CREATE DATABASE USERS") returns UnsupportedStatement with no access to the database name.
After: returns CreateDatabase with getDatabaseName() = "USERS" and the deparse round-trips; same for CREATE DATABASE IF NOT EXISTS mydb DEFAULT CHARACTER SET utf8mb4.

Grammar change, paired gradle jmh run (JSQLParserBenchmark.parseSQLStatements on performance.sql, version=latest, 10 forks x 10 iterations = 100 samples, 32-core host):

build ms/op
master 406a4d4 3.734 ± 0.030
this PR 3.725 ± 0.028

Delta within the confidence intervals -> no regression.

Limitation: options are kept as raw tokens rather than structured AST nodes (the option sets differ heavily between MySQL and PostgreSQL); they can be modelled individually in a follow-up if preferred. The bare form CREATE DATABASE (no name) now throws a ParseException instead of returning UnsupportedStatement; both MySQL and PostgreSQL require the name.

Fixes #2070

Parse CREATE DATABASE [IF NOT EXISTS] <name> into a typed
CreateDatabase statement instead of the generic UnsupportedStatement
fallback. Vendor-specific options after the name (e.g. MySQL's
DEFAULT CHARACTER SET / COLLATE) are captured verbatim and
round-trip unchanged.

Signed-off-by: 付典 <fudianchn@gmail.com>
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.

How to parse CREATE DATABASE DATABASE_NAME ?

1 participant