Skip to content

Commit

Permalink
[#6485] [#6708] Support MySQL-specific storage clauses
Browse files Browse the repository at this point in the history
- [#6485] MySQL-specific storage clauses
- [#6708] DDLDatabase fails when engine=InnoDB is specified
  • Loading branch information
lukaseder committed Oct 19, 2017
1 parent 2f51756 commit 4177e25
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 10 deletions.
216 changes: 206 additions & 10 deletions jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
Expand Up @@ -69,6 +69,7 @@
import static org.jooq.impl.DSL.currentUser; import static org.jooq.impl.DSL.currentUser;
import static org.jooq.impl.DSL.date; import static org.jooq.impl.DSL.date;
import static org.jooq.impl.DSL.day; import static org.jooq.impl.DSL.day;
import static org.jooq.impl.DSL.defaultValue;
import static org.jooq.impl.DSL.deg; import static org.jooq.impl.DSL.deg;
import static org.jooq.impl.DSL.denseRank; import static org.jooq.impl.DSL.denseRank;
import static org.jooq.impl.DSL.every; import static org.jooq.impl.DSL.every;
Expand All @@ -87,6 +88,7 @@
import static org.jooq.impl.DSL.ifnull; import static org.jooq.impl.DSL.ifnull;
import static org.jooq.impl.DSL.inline; import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.isnull; import static org.jooq.impl.DSL.isnull;
import static org.jooq.impl.DSL.keyword;
import static org.jooq.impl.DSL.lag; import static org.jooq.impl.DSL.lag;
import static org.jooq.impl.DSL.lastValue; import static org.jooq.impl.DSL.lastValue;
import static org.jooq.impl.DSL.lateral; import static org.jooq.impl.DSL.lateral;
Expand All @@ -95,6 +97,7 @@
import static org.jooq.impl.DSL.left; import static org.jooq.impl.DSL.left;
import static org.jooq.impl.DSL.length; import static org.jooq.impl.DSL.length;
import static org.jooq.impl.DSL.level; import static org.jooq.impl.DSL.level;
import static org.jooq.impl.DSL.list;
import static org.jooq.impl.DSL.listAgg; import static org.jooq.impl.DSL.listAgg;
import static org.jooq.impl.DSL.ln; import static org.jooq.impl.DSL.ln;
import static org.jooq.impl.DSL.log; import static org.jooq.impl.DSL.log;
Expand All @@ -117,6 +120,7 @@
import static org.jooq.impl.DSL.nvl; import static org.jooq.impl.DSL.nvl;
import static org.jooq.impl.DSL.nvl2; import static org.jooq.impl.DSL.nvl2;
import static org.jooq.impl.DSL.octetLength; import static org.jooq.impl.DSL.octetLength;
import static org.jooq.impl.DSL.one;
import static org.jooq.impl.DSL.orderBy; import static org.jooq.impl.DSL.orderBy;
import static org.jooq.impl.DSL.partitionBy; import static org.jooq.impl.DSL.partitionBy;
import static org.jooq.impl.DSL.percentRank; import static org.jooq.impl.DSL.percentRank;
Expand Down Expand Up @@ -174,6 +178,7 @@
import static org.jooq.impl.DSL.sin; import static org.jooq.impl.DSL.sin;
import static org.jooq.impl.DSL.sinh; import static org.jooq.impl.DSL.sinh;
import static org.jooq.impl.DSL.space; import static org.jooq.impl.DSL.space;
import static org.jooq.impl.DSL.sql;
import static org.jooq.impl.DSL.sqrt; import static org.jooq.impl.DSL.sqrt;
import static org.jooq.impl.DSL.stddevPop; import static org.jooq.impl.DSL.stddevPop;
import static org.jooq.impl.DSL.stddevSamp; import static org.jooq.impl.DSL.stddevSamp;
Expand All @@ -192,17 +197,20 @@
import static org.jooq.impl.DSL.varSamp; import static org.jooq.impl.DSL.varSamp;
import static org.jooq.impl.DSL.when; import static org.jooq.impl.DSL.when;
import static org.jooq.impl.DSL.year; import static org.jooq.impl.DSL.year;
import static org.jooq.impl.DSL.zero;
import static org.jooq.impl.ParserImpl.Type.A; import static org.jooq.impl.ParserImpl.Type.A;
import static org.jooq.impl.ParserImpl.Type.B; import static org.jooq.impl.ParserImpl.Type.B;
import static org.jooq.impl.ParserImpl.Type.D; import static org.jooq.impl.ParserImpl.Type.D;
import static org.jooq.impl.ParserImpl.Type.N; import static org.jooq.impl.ParserImpl.Type.N;
import static org.jooq.impl.ParserImpl.Type.S; import static org.jooq.impl.ParserImpl.Type.S;
import static org.jooq.impl.ParserImpl.Type.X; import static org.jooq.impl.ParserImpl.Type.X;
import static org.jooq.impl.SQLDataType.INTEGER;
import static org.jooq.impl.Tools.EMPTY_BYTE; import static org.jooq.impl.Tools.EMPTY_BYTE;
import static org.jooq.impl.Tools.EMPTY_COLLECTION; import static org.jooq.impl.Tools.EMPTY_COLLECTION;
import static org.jooq.impl.Tools.EMPTY_COMMON_TABLE_EXPRESSION; import static org.jooq.impl.Tools.EMPTY_COMMON_TABLE_EXPRESSION;
import static org.jooq.impl.Tools.EMPTY_FIELD; import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.EMPTY_NAME; import static org.jooq.impl.Tools.EMPTY_NAME;
import static org.jooq.impl.Tools.EMPTY_QUERYPART;


import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
Expand Down Expand Up @@ -245,7 +253,7 @@
import org.jooq.CreateTableAsStep; import org.jooq.CreateTableAsStep;
import org.jooq.CreateTableColumnStep; import org.jooq.CreateTableColumnStep;
import org.jooq.CreateTableConstraintStep; import org.jooq.CreateTableConstraintStep;
import org.jooq.CreateTableFinalStep; import org.jooq.CreateTableStorageStep;
import org.jooq.DDLQuery; import org.jooq.DDLQuery;
import org.jooq.DSLContext; import org.jooq.DSLContext;
import org.jooq.DataType; import org.jooq.DataType;
Expand Down Expand Up @@ -274,6 +282,7 @@
import org.jooq.InsertSetStep; import org.jooq.InsertSetStep;
import org.jooq.InsertValuesStepN; import org.jooq.InsertValuesStepN;
import org.jooq.JoinType; import org.jooq.JoinType;
import org.jooq.Keyword;
import org.jooq.Merge; import org.jooq.Merge;
import org.jooq.MergeFinalStep; import org.jooq.MergeFinalStep;
import org.jooq.MergeMatchedStep; import org.jooq.MergeMatchedStep;
Expand All @@ -291,6 +300,7 @@
import org.jooq.Row; import org.jooq.Row;
import org.jooq.Row2; import org.jooq.Row2;
import org.jooq.RowN; import org.jooq.RowN;
import org.jooq.SQL;
import org.jooq.Schema; import org.jooq.Schema;
import org.jooq.Select; import org.jooq.Select;
import org.jooq.Sequence; import org.jooq.Sequence;
Expand Down Expand Up @@ -1324,6 +1334,7 @@ private static final DDLQuery parseDropSequence(ParserContext ctx) {
private static final DDLQuery parseCreateTable(ParserContext ctx, boolean temporary) { private static final DDLQuery parseCreateTable(ParserContext ctx, boolean temporary) {
boolean ifNotExists = !temporary && parseKeywordIf(ctx, "IF NOT EXISTS"); boolean ifNotExists = !temporary && parseKeywordIf(ctx, "IF NOT EXISTS");
Table<?> tableName = parseTableName(ctx); Table<?> tableName = parseTableName(ctx);
CreateTableStorageStep storageStep;


// [#5309] TODO: Move this after the column specification // [#5309] TODO: Move this after the column specification
if (parseKeywordIf(ctx, "AS")) { if (parseKeywordIf(ctx, "AS")) {
Expand All @@ -1335,8 +1346,7 @@ private static final DDLQuery parseCreateTable(ParserContext ctx, boolean tempor
? ctx.dsl.createTemporaryTable(tableName) ? ctx.dsl.createTemporaryTable(tableName)
: ctx.dsl.createTable(tableName); : ctx.dsl.createTable(tableName);


CreateTableFinalStep s2 = s1.as(select); storageStep = s1.as(select);
return s2;
} }
else { else {
List<Field<?>> fields = new ArrayList<Field<?>>(); List<Field<?>> fields = new ArrayList<Field<?>>();
Expand Down Expand Up @@ -1514,7 +1524,7 @@ else if (parseKeywordIf(ctx, "CHECK"))
CreateTableConstraintStep s3 = constraints.isEmpty() CreateTableConstraintStep s3 = constraints.isEmpty()
? s2 ? s2
: s2.constraints(constraints); : s2.constraints(constraints);
CreateTableFinalStep s4 = s3; CreateTableStorageStep s4 = s3;


if (temporary && parseKeywordIf(ctx, "ON COMMIT")) { if (temporary && parseKeywordIf(ctx, "ON COMMIT")) {
if (parseKeywordIf(ctx, "DELETE ROWS")) if (parseKeywordIf(ctx, "DELETE ROWS"))
Expand All @@ -1527,8 +1537,139 @@ else if (parseKeywordIf(ctx, "PRESERVE ROWS"))
throw ctx.unexpectedToken(); throw ctx.unexpectedToken();
} }


return s4; storageStep = s4;
}

List<SQL> storage = new ArrayList<SQL>();

storageLoop:
for (boolean first = true;; first = false) {
boolean optional = first || !parseIf(ctx, ',');
Keyword keyword = null;

// MySQL storage clauses (see: https://dev.mysql.com/doc/refman/5.7/en/create-table.html)
if ((keyword = parseAndGetKeywordIf(ctx, "AUTO_INCREMENT")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseFieldUnsignedNumericLiteral(ctx, Sign.NONE)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "AVG_ROW_LENGTH")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseFieldUnsignedNumericLiteral(ctx, Sign.NONE)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "CHARACTER SET")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseIdentifier(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "DEFAULT CHARACTER SET")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseIdentifier(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "CHECKSUM")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseZeroOne(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "COLLATE")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseIdentifier(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "DEFAULT COLLATE")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseIdentifier(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "COMMENT")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "COMPRESSION")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "CONNECTION")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "DATA DIRECTORY")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "INDEX DIRECTORY")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "DELAY_KEY_WRITE")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseZeroOne(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "ENCRYPTION")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "ENGINE")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseIdentifier(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "INSERT_METHOD")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseAndGetKeyword(ctx, "NO", "FIRST", "LAST")));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "KEY_BLOCK_SIZE")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseFieldUnsignedNumericLiteral(ctx, Sign.NONE)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "MAX_ROWS")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseFieldUnsignedNumericLiteral(ctx, Sign.NONE)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "MIN_ROWS")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseFieldUnsignedNumericLiteral(ctx, Sign.NONE)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "PACK_KEYS")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseZeroOneDefault(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "PASSWORD")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "ROW_FORMAT")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseAndGetKeyword(ctx, "DEFAULT", "DYNAMIC", "FIXED", "COMPRESSED", "REDUNDANT", "COMPACT")));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "STATS_AUTO_RECALC")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseZeroOneDefault(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "STATS_PERSISTENT")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseZeroOneDefault(ctx)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "STATS_SAMPLE_PAGES")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseFieldUnsignedNumericLiteral(ctx, Sign.NONE)));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "TABLESPACE")) != null) {
storage.add(sql("{0} {1}", keyword, parseIdentifier(ctx)));

if ((keyword = parseAndGetKeywordIf(ctx, "STORAGE")) != null)
storage.add(sql("{0} {1}", keyword, parseAndGetKeyword(ctx, "DISK", "MEMORY", "DEFAULT")));
}
else if ((keyword = parseAndGetKeywordIf(ctx, "UNION")) != null) {
parseIf(ctx, '=');
parse(ctx, '(');
storage.add(sql("{0} ({1})", keyword, list(parseIdentifiers(ctx))));
parse(ctx, ')');
}
else if (optional)
break storageLoop;
else
throw ctx.expected("storage clause after ','");
} }

if (storage.size() > 0)
return storageStep.storage(new SQLConcatenationImpl(storage.toArray(EMPTY_QUERYPART)));
else
return storageStep;
} }


private static final Constraint parsePrimaryKeySpecification(ParserContext ctx, ConstraintTypeStep constraint) { private static final Constraint parsePrimaryKeySpecification(ParserContext ctx, ConstraintTypeStep constraint) {
Expand Down Expand Up @@ -5264,6 +5405,8 @@ private static final Field<Number> parseFieldUnsignedNumericLiteralIf(ParserCont
} }


private static final Number parseUnsignedNumericLiteralIf(ParserContext ctx, Sign sign) { private static final Number parseUnsignedNumericLiteralIf(ParserContext ctx, Sign sign) {
parseWhitespaceIf(ctx);

StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
char c; char c;


Expand Down Expand Up @@ -5316,6 +5459,26 @@ private static final Number parseUnsignedNumericLiteralIf(ParserContext ctx, Sig
// TODO add floating point support // TODO add floating point support
} }


private static final Field<Integer> parseZeroOne(ParserContext ctx) {
if (parseIf(ctx, '0'))
return zero();
else if (parseIf(ctx, '1'))
return one();
else
throw ctx.expected("0 or 1");
}

private static final Field<Integer> parseZeroOneDefault(ParserContext ctx) {
if (parseIf(ctx, '0'))
return zero();
else if (parseIf(ctx, '1'))
return one();
else if (parseKeywordIf(ctx, "DEFAULT"))
return defaultValue(INTEGER);
else
throw ctx.expected("0 or 1");
}

private static final Long parseSignedInteger(ParserContext ctx) { private static final Long parseSignedInteger(ParserContext ctx) {
Long result = parseSignedIntegerIf(ctx); Long result = parseSignedIntegerIf(ctx);


Expand Down Expand Up @@ -5581,22 +5744,55 @@ private static final boolean parseFunctionNameIf(ParserContext ctx, String strin
return peekKeyword(ctx, string, true, false, true); return peekKeyword(ctx, string, true, false, true);
} }


private static final void parseKeyword(ParserContext ctx, String string) { private static final void parseKeyword(ParserContext ctx, String keyword) {
if (!parseKeywordIf(ctx, string)) if (!parseKeywordIf(ctx, keyword))
throw ctx.unexpectedToken(); throw ctx.unexpectedToken();
} }


private static final boolean parseKeywordIf(ParserContext ctx, String string) { private static final boolean parseKeywordIf(ParserContext ctx, String keyword) {
ctx.expectedTokens.add(string); ctx.expectedTokens.add(keyword);


if (peekKeyword(ctx, string, true, false, false)) if (peekKeyword(ctx, keyword, true, false, false))
ctx.expectedTokens.clear(); ctx.expectedTokens.clear();
else else
return false; return false;


return true; return true;
} }


private static final Keyword parseAndGetKeyword(ParserContext ctx, String... keywords) {
Keyword result = parseAndGetKeywordIf(ctx, keywords);

if (result == null)
throw ctx.unexpectedToken();

return result;
}

private static final Keyword parseAndGetKeyword(ParserContext ctx, String keyword) {
Keyword result = parseAndGetKeywordIf(ctx, keyword);

if (result == null)
throw ctx.unexpectedToken();

return result;
}

private static final Keyword parseAndGetKeywordIf(ParserContext ctx, String... keywords) {
for (String keyword : keywords)
if (parseKeywordIf(ctx, keyword))
return keyword(keyword.toLowerCase());

return null;
}

private static final Keyword parseAndGetKeywordIf(ParserContext ctx, String keyword) {
if (parseKeywordIf(ctx, keyword))
return keyword(keyword.toLowerCase());

return null;
}

private static final boolean peekKeyword(ParserContext ctx, String... keywords) { private static final boolean peekKeyword(ParserContext ctx, String... keywords) {
for (String keyword : keywords) for (String keyword : keywords)
if (peekKeyword(ctx, keyword)) if (peekKeyword(ctx, keyword))
Expand Down

0 comments on commit 4177e25

Please sign in to comment.