Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
Expand All @@ -27,6 +28,7 @@ public class CreateDatabase implements Statement {
private String databaseName;
private boolean hasIfNotExists = false;
private List<String> databaseOptions = null;
private List<DatabaseOption> options;

@Override
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
Expand Down Expand Up @@ -67,9 +69,27 @@ public List<String> getDatabaseOptions() {

public CreateDatabase setDatabaseOptions(List<String> databaseOptions) {
this.databaseOptions = databaseOptions;
this.options = null;
return this;
}

public List<DatabaseOption> getOptions() {
return options;
}

public CreateDatabase setOptions(List<DatabaseOption> options) {
this.options = options;
this.databaseOptions = options == null ? null
: options.stream().flatMap(option -> option.getTokens().stream())
.collect(Collectors.toList());
return this;
}

public Optional<DatabaseOption> getOption(DatabaseOption.Kind kind) {
return Optional.ofNullable(options).orElseGet(Collections::emptyList).stream()
.filter(option -> option.getKind() == kind).findFirst();
}

public CreateDatabase withDatabaseName(String databaseName) {
return this.setDatabaseName(databaseName);
}
Expand All @@ -82,6 +102,17 @@ public CreateDatabase withDatabaseOptions(List<String> databaseOptions) {
return this.setDatabaseOptions(databaseOptions);
}

public CreateDatabase withOptions(List<DatabaseOption> options) {
return setOptions(options);
}

public CreateDatabase addOptions(DatabaseOption... options) {
List<DatabaseOption> collection =
Optional.ofNullable(getOptions()).orElseGet(ArrayList::new);
Collections.addAll(collection, options);
return withOptions(collection);
}

public CreateDatabase addDatabaseOptions(String... databaseOptions) {
List<String> collection =
Optional.ofNullable(getDatabaseOptions()).orElseGet(ArrayList::new);
Expand All @@ -105,7 +136,9 @@ public String toString() {
if (databaseName != null) {
sql += " " + databaseName;
}
if (databaseOptions != null && !databaseOptions.isEmpty()) {
if (options != null && !options.isEmpty()) {
sql += " " + options.stream().map(Object::toString).collect(Collectors.joining(" "));
} else if (databaseOptions != null && !databaseOptions.isEmpty()) {
sql += " " + String.join(" ", databaseOptions);
}
return sql;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.create.database;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/** A structured option shared by MySQL {@code CREATE DATABASE} and {@code CREATE SCHEMA}. */
public class DatabaseOption implements Serializable {

public enum Kind {
CHARACTER_SET, COLLATE, ENCRYPTION, OTHER
}

private Kind kind = Kind.OTHER;
private String name;
private String value;
private boolean useDefault;
private boolean useEquals;
private List<String> rawTokens;

public DatabaseOption() {}

public DatabaseOption(Kind kind, String name, String value, boolean useDefault,
boolean useEquals) {
this.kind = kind;
this.name = name;
this.value = value;
this.useDefault = useDefault;
this.useEquals = useEquals;
}

public static DatabaseOption raw(List<String> tokens) {
DatabaseOption option = new DatabaseOption();
option.setRawTokens(tokens);
return option;
}

public Kind getKind() {
return kind;
}

public void setKind(Kind kind) {
this.kind = kind;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public boolean isUseDefault() {
return useDefault;
}

public void setUseDefault(boolean useDefault) {
this.useDefault = useDefault;
}

public boolean isUseEquals() {
return useEquals;
}

public void setUseEquals(boolean useEquals) {
this.useEquals = useEquals;
}

public List<String> getRawTokens() {
return rawTokens;
}

public void setRawTokens(List<String> rawTokens) {
this.rawTokens = rawTokens;
}

/** Returns this option in the legacy flat-token representation. */
public List<String> getTokens() {
if (rawTokens != null) {
return Collections.unmodifiableList(rawTokens);
}
List<String> tokens = new ArrayList<>();
if (useDefault) {
tokens.add("DEFAULT");
}
Collections.addAll(tokens, name.split(" "));
if (useEquals) {
tokens.add("=");
}
tokens.add(value);
return tokens;
}

@Override
public String toString() {
return String.join(" ", getTokens());
}

public DatabaseOption withKind(Kind kind) {
setKind(kind);
return this;
}

public DatabaseOption withName(String name) {
setName(name);
return this;
}

public DatabaseOption withValue(String value) {
setValue(value);
return this;
}

public DatabaseOption withUseDefault(boolean useDefault) {
setUseDefault(useDefault);
return this;
}

public DatabaseOption withUseEquals(boolean useEquals) {
setUseEquals(useEquals);
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.create.database.DatabaseOption;

public class CreateSchema implements Statement {

Expand All @@ -25,6 +27,7 @@ public class CreateSchema implements Statement {
private String schemaName;
private List<String> schemaPath;
private List<Statement> statements = new ArrayList<>();
private List<DatabaseOption> databaseOptions;
private boolean hasIfNotExists = false;

@Override
Expand Down Expand Up @@ -114,6 +117,19 @@ public List<Statement> getStatements() {
return statements;
}

public List<DatabaseOption> getDatabaseOptions() {
return databaseOptions;
}

public void setDatabaseOptions(List<DatabaseOption> databaseOptions) {
this.databaseOptions = databaseOptions;
}

public Optional<DatabaseOption> getDatabaseOption(DatabaseOption.Kind kind) {
return Optional.ofNullable(databaseOptions).orElseGet(Collections::emptyList).stream()
.filter(option -> option.getKind() == kind).findFirst();
}

public boolean hasIfNotExists() {
return hasIfNotExists;
}
Expand All @@ -131,11 +147,15 @@ public String toString() {
if (schemaName != null) {
sql += " ";

if (catalogName!=null) {
if (catalogName != null) {
sql += catalogName + ".";
}
sql += schemaName;
}
if (databaseOptions != null && !databaseOptions.isEmpty()) {
sql += " " + databaseOptions.stream().map(Object::toString)
.collect(Collectors.joining(" "));
}
if (authorization != null) {
sql += " AUTHORIZATION " + authorization;
}
Expand All @@ -157,6 +177,18 @@ public CreateSchema withSchemaPath(List<String> schemaPath) {
return this;
}

public CreateSchema withDatabaseOptions(List<DatabaseOption> databaseOptions) {
setDatabaseOptions(databaseOptions);
return this;
}

public CreateSchema addDatabaseOptions(DatabaseOption... databaseOptions) {
List<DatabaseOption> collection =
Optional.ofNullable(getDatabaseOptions()).orElseGet(ArrayList::new);
Collections.addAll(collection, databaseOptions);
return withDatabaseOptions(collection);
}

public CreateSchema addSchemaPath(String... schemaPath) {
List<String> collection = Optional.ofNullable(getSchemaPath()).orElseGet(ArrayList::new);
Collections.addAll(collection, schemaPath);
Expand Down
53 changes: 52 additions & 1 deletion src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
return jjtree.rootNode();
}

private boolean isMySqlDatabaseOptionAhead() {
int offset = getToken(1).kind == K_DEFAULT ? 2 : 1;
int kind = getToken(offset).kind;
return kind == K_CHARACTER || kind == K_COLLATE || kind == K_ENCRYPTION;
}

private static class ObjectNames {

private final List<String> names;
Expand Down Expand Up @@ -11448,6 +11454,7 @@ CreateSchema CreateSchema():
CreateSchema schema = new CreateSchema();
List<String> schemaPath = null;
List<Statement> statements = new ArrayList<Statement>();
DatabaseOption databaseOption = null;
}
{
<K_SCHEMA>
Expand All @@ -11461,6 +11468,11 @@ CreateSchema CreateSchema():
)?
]

(
LOOKAHEAD({ isMySqlDatabaseOptionAhead() })
databaseOption=MySqlDatabaseOption() { schema.addDatabaseOptions(databaseOption); }
)*

[ <K_AUTHORIZATION>
(tk=<S_IDENTIFIER> | tk=<S_QUOTED_IDENTIFIER>) { schema.setAuthorization(tk.image); }
]
Expand Down Expand Up @@ -11489,6 +11501,38 @@ CreateSchema CreateSchema():
}
}

DatabaseOption MySqlDatabaseOption():
{
boolean useDefault = false;
boolean useEquals = false;
DatabaseOption.Kind kind = DatabaseOption.Kind.OTHER;
String name = null;
String value = null;
Token valueToken = null;
}
{
[ <K_DEFAULT> { useDefault = true; } ]
(
<K_CHARACTER> <K_SET> {
kind = DatabaseOption.Kind.CHARACTER_SET;
name = "CHARACTER SET";
}
|
<K_COLLATE> {
kind = DatabaseOption.Kind.COLLATE;
name = "COLLATE";
}
|
<K_ENCRYPTION> {
kind = DatabaseOption.Kind.ENCRYPTION;
name = "ENCRYPTION";
}
)
[ "=" { useEquals = true; } ]
( value=RelObjectName() | valueToken=<S_CHAR_LITERAL> { value = valueToken.image; } )
{ return new DatabaseOption(kind, name, value, useDefault, useEquals); }
}

List<String> PathSpecification():
{
Token tk;
Expand All @@ -11507,12 +11551,19 @@ CreateDatabase CreateDatabase():
CreateDatabase createDatabase = new CreateDatabase();
String databaseName = null;
List<String> databaseOptions = null;
DatabaseOption databaseOption = null;
}
{
<K_DATABASE>
[ LOOKAHEAD(2) <K_IF> <K_NOT> <K_EXISTS> { createDatabase.setIfNotExists(true); } ]
databaseName = RelObjectName() { createDatabase.setDatabaseName(databaseName); }
[ databaseOptions = captureRest() { createDatabase.setDatabaseOptions(databaseOptions); } ]
(
LOOKAHEAD({ isMySqlDatabaseOptionAhead() })
databaseOption=MySqlDatabaseOption() { createDatabase.addOptions(databaseOption); }
)*
[ databaseOptions = captureRest() {
createDatabase.addOptions(DatabaseOption.raw(databaseOptions));
} ]
{
return createDatabase;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ void testCreateDatabaseWithOptions() throws JSQLParserException {
Arrays.asList("DEFAULT", "CHARACTER", "SET", "utf8mb4", "COLLATE",
"utf8mb4_unicode_ci"),
createDatabase.getDatabaseOptions());
DatabaseOption characterSet =
createDatabase.getOption(DatabaseOption.Kind.CHARACTER_SET).orElseThrow();
assertEquals("utf8mb4", characterSet.getValue());
assertTrue(characterSet.isUseDefault());
assertEquals("utf8mb4_unicode_ci",
createDatabase.getOption(DatabaseOption.Kind.COLLATE).orElseThrow().getValue());
}

@Test
Expand Down
Loading
Loading