Skip to content

Commit

Permalink
[#6485] [#7018] Support parsing MySQL / MariaDB COMMENT syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaseder committed Jan 10, 2018
1 parent bd13797 commit f58e7d7
Show file tree
Hide file tree
Showing 12 changed files with 156 additions and 27 deletions.
16 changes: 10 additions & 6 deletions jOOQ/src/main/java/org/jooq/impl/AbstractField.java
Expand Up @@ -63,7 +63,6 @@
import static org.jooq.impl.Tools.EMPTY_STRING; import static org.jooq.impl.Tools.EMPTY_STRING;
import static org.jooq.tools.Convert.FALSE_VALUES; import static org.jooq.tools.Convert.FALSE_VALUES;
import static org.jooq.tools.Convert.TRUE_VALUES; import static org.jooq.tools.Convert.TRUE_VALUES;
import static org.jooq.tools.StringUtils.defaultString;


import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.Timestamp; import java.sql.Timestamp;
Expand All @@ -81,6 +80,7 @@
import org.jooq.CaseValueStep; import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep; import org.jooq.CaseWhenStep;
import org.jooq.Clause; import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.Comparator; import org.jooq.Comparator;
import org.jooq.Condition; import org.jooq.Condition;
import org.jooq.Configuration; import org.jooq.Configuration;
Expand Down Expand Up @@ -114,19 +114,23 @@ abstract class AbstractField<T> extends AbstractQueryPart implements Field<T> {
private static final Clause[] CLAUSES = { FIELD }; private static final Clause[] CLAUSES = { FIELD };


private final Name name; private final Name name;
private final String comment; private final Comment comment;
private final DataType<T> dataType; private final DataType<T> dataType;


AbstractField(Name name, DataType<T> type) { AbstractField(Name name, DataType<T> type) {
this(name, type, null, type.getBinding()); this(name, type, null);
}

AbstractField(Name name, DataType<T> type, Comment comment) {
this(name, type, comment, type.getBinding());
} }


@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
AbstractField(Name name, DataType<T> type, String comment, Binding<?, T> binding) { AbstractField(Name name, DataType<T> type, Comment comment, Binding<?, T> binding) {
super(); super();


this.name = name; this.name = name;
this.comment = defaultString(comment); this.comment = comment == null ? CommentImpl.NO_COMMENT : comment;
this.dataType = type.asConvertedDataType((Binding<T, T>) binding); this.dataType = type.asConvertedDataType((Binding<T, T>) binding);
} }


Expand Down Expand Up @@ -226,7 +230,7 @@ public final Name getUnqualifiedName() {


@Override @Override
public final String getComment() { public final String getComment() {
return comment; return comment.getComment();
} }


@Override @Override
Expand Down
13 changes: 7 additions & 6 deletions jOOQ/src/main/java/org/jooq/impl/AbstractTable.java
Expand Up @@ -68,6 +68,7 @@
import org.jooq.Binding; import org.jooq.Binding;
import org.jooq.Catalog; import org.jooq.Catalog;
import org.jooq.Clause; import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.Comparator; import org.jooq.Comparator;
import org.jooq.Condition; import org.jooq.Condition;
import org.jooq.Context; import org.jooq.Context;
Expand Down Expand Up @@ -113,7 +114,7 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme


private Schema tableschema; private Schema tableschema;
private final Name tablename; private final Name tablename;
private final String tablecomment; private final Comment tablecomment;
private transient DataType<R> type; private transient DataType<R> type;


/** /**
Expand All @@ -137,7 +138,7 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
*/ */
@Deprecated @Deprecated
AbstractTable(String name, Schema schema, String comment) { AbstractTable(String name, Schema schema, String comment) {
this(DSL.name(name), schema, comment); this(DSL.name(name), schema, DSL.comment(comment));
} }


AbstractTable(Name name) { AbstractTable(Name name) {
Expand All @@ -148,10 +149,10 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
this(name, schema, null); this(name, schema, null);
} }


AbstractTable(Name name, Schema schema, String comment) { AbstractTable(Name name, Schema schema, Comment comment) {
this.tableschema = schema; this.tableschema = schema;
this.tablename = name; this.tablename = name;
this.tablecomment = comment; this.tablecomment = comment == null ? CommentImpl.NO_COMMENT : comment;
} }


// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
Expand Down Expand Up @@ -406,7 +407,7 @@ public final Name getUnqualifiedName() {


@Override @Override
public final String getComment() { public final String getComment() {
return tablecomment; return tablecomment.getComment();
} }


/** /**
Expand Down Expand Up @@ -573,7 +574,7 @@ protected static final <R extends Record, T, X, U> TableField<R, U> createField(
: type.asConvertedDataType(actualBinding); : type.asConvertedDataType(actualBinding);


// [#5999] TODO: Allow for user-defined Names // [#5999] TODO: Allow for user-defined Names
final TableFieldImpl<R, U> tableField = new TableFieldImpl<R, U>(DSL.name(name), actualType, table, comment, actualBinding); final TableFieldImpl<R, U> tableField = new TableFieldImpl<R, U>(DSL.name(name), actualType, table, DSL.comment(comment), actualBinding);


// [#1199] The public API of Table returns immutable field lists // [#1199] The public API of Table returns immutable field lists
if (table instanceof TableImpl) { if (table instanceof TableImpl) {
Expand Down
3 changes: 2 additions & 1 deletion jOOQ/src/main/java/org/jooq/impl/CommentImpl.java
Expand Up @@ -52,10 +52,11 @@ final class CommentImpl extends AbstractQueryPart implements Comment {
* Generated UID * Generated UID
*/ */
private static final long serialVersionUID = -5034168783226853829L; private static final long serialVersionUID = -5034168783226853829L;
static final CommentImpl NO_COMMENT = new CommentImpl("");
private final String comment; private final String comment;


CommentImpl(String comment) { CommentImpl(String comment) {
this.comment = comment; this.comment = comment == null ? "" : comment;
} }


@Override @Override
Expand Down
56 changes: 55 additions & 1 deletion jOOQ/src/main/java/org/jooq/impl/DSL.java
Expand Up @@ -75,6 +75,7 @@
import static org.jooq.impl.Tools.EMPTY_QUERYPART; import static org.jooq.impl.Tools.EMPTY_QUERYPART;
import static org.jooq.impl.Tools.combine; import static org.jooq.impl.Tools.combine;
import static org.jooq.impl.Tools.configuration; import static org.jooq.impl.Tools.configuration;
import static org.jooq.tools.StringUtils.isEmpty;


import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
Expand Down Expand Up @@ -5815,7 +5816,7 @@ public static <R extends Record> DeleteWhereStep<R> delete(Table<R> table) {
*/ */
@Support @Support
public static Comment comment(String comment) { public static Comment comment(String comment) {
return new CommentImpl(comment); return isEmpty(comment) ? CommentImpl.NO_COMMENT : new CommentImpl(comment);
} }


// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
Expand Down Expand Up @@ -9123,6 +9124,28 @@ public static Table<Record> table(Name name) {
return new TableImpl<Record>(name); return new TableImpl<Record>(name);
} }


/**
* Create a qualified table, given its table name.
* <p>
* This constructs a table reference given the table's qualified name. jOOQ
* will render the table name according to your
* {@link Settings#getRenderNameStyle()} settings. Choose
* {@link RenderNameStyle#QUOTED} to prevent syntax errors and/or SQL
* injection.
* <p>
* Example: <code><pre>
* // This table...
* tableByName("MY_SCHEMA", "MY_TABLE");
*
* // ... will render this SQL on SQL Server with RenderNameStyle.QUOTED set
* [MY_SCHEMA].[MY_TABLE]
* </pre></code>
*/
@Support
public static Table<Record> table(Name name, Comment comment) {
return new TableImpl<Record>(name, null, null, null, comment);
}

/** /**
* Create a qualified field, given its (qualified) field name. * Create a qualified field, given its (qualified) field name.
* <p> * <p>
Expand Down Expand Up @@ -9329,6 +9352,37 @@ public static <T> Field<T> field(Name name, DataType<T> type) {
return new QualifiedField<T>(name, type); return new QualifiedField<T>(name, type);
} }


/**
* Create a qualified field, given its (qualified) field name.
* <p>
* This constructs a field reference given the field's qualified name. jOOQ
* will render the field name according to your
* {@link Settings#getRenderNameStyle()} settings. Choose
* {@link RenderNameStyle#QUOTED} to prevent syntax errors and/or SQL
* injection.
* <p>
* Example: <code><pre>
* // This field...
* field(name("MY_SCHEMA", "MY_TABLE", "MY_FIELD"));
*
* // ... will render this SQL on SQL Server with RenderNameStyle.QUOTED set
* [MY_SCHEMA].[MY_TABLE].[MY_FIELD]
* </pre></code>
* <p>
* Another example: <code><pre>
* create.select(field("length({1})", Integer.class, field(name("TITLE"))))
* .from(table(name("T_BOOK")))
* .fetch();
*
* // ... will execute this SQL on SQL Server:
* select length([TITLE]) from [T_BOOK]
* </pre></code>
*/
@Support
public static <T> Field<T> field(Name name, DataType<T> type, Comment comment) {
return new QualifiedField<T>(name, type, comment);
}

/** /**
* Create a qualified index reference by name. * Create a qualified index reference by name.
*/ */
Expand Down
59 changes: 55 additions & 4 deletions jOOQ/src/main/java/org/jooq/impl/ParserImpl.java
Expand Up @@ -251,6 +251,8 @@
import org.jooq.CaseConditionStep; import org.jooq.CaseConditionStep;
import org.jooq.CaseValueStep; import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep; import org.jooq.CaseWhenStep;
import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.CommentOnIsStep; import org.jooq.CommentOnIsStep;
import org.jooq.CommonTableExpression; import org.jooq.CommonTableExpression;
import org.jooq.Comparator; import org.jooq.Comparator;
Expand All @@ -259,6 +261,7 @@
import org.jooq.Constraint; import org.jooq.Constraint;
import org.jooq.ConstraintForeignKeyOnStep; import org.jooq.ConstraintForeignKeyOnStep;
import org.jooq.ConstraintTypeStep; import org.jooq.ConstraintTypeStep;
import org.jooq.Context;
import org.jooq.CreateIndexFinalStep; import org.jooq.CreateIndexFinalStep;
import org.jooq.CreateIndexStep; import org.jooq.CreateIndexStep;
import org.jooq.CreateIndexWhereStep; import org.jooq.CreateIndexWhereStep;
Expand Down Expand Up @@ -1598,8 +1601,33 @@ 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) {
final class MutableComment extends AbstractQueryPart implements Comment {

/**
* Generated UID
*/
private static final long serialVersionUID = -5034168783226853829L;
private String comment = "";

@Override
public final void accept(Context<?> c) {
c.visit(inline(comment));
}

@Override
public final Clause[] clauses(Context<?> c) {
return null;
}

@Override
public final String getComment() {
return comment;
}
}

boolean ifNotExists = !temporary && parseKeywordIf(ctx, "IF NOT EXISTS"); boolean ifNotExists = !temporary && parseKeywordIf(ctx, "IF NOT EXISTS");
Table<?> tableName = parseTableName(ctx); MutableComment tableComment = new MutableComment();
Table<?> tableName = DSL.table(parseTableName(ctx).getQualifiedName(), tableComment);
CreateTableStorageStep storageStep; CreateTableStorageStep storageStep;


// [#5309] TODO: Move this after the column specification // [#5309] TODO: Move this after the column specification
Expand All @@ -1624,11 +1652,13 @@ private static final DDLQuery parseCreateTable(ParserContext ctx, boolean tempor
do { do {
Name fieldName = parseIdentifier(ctx); Name fieldName = parseIdentifier(ctx);
DataType<?> type = parseDataType(ctx); DataType<?> type = parseDataType(ctx);
Comment fieldComment = null;


boolean nullable = false; boolean nullable = false;
boolean defaultValue = false; boolean defaultValue = false;
boolean unique = false; boolean unique = false;
boolean identity = type.identity(); boolean identity = type.identity();
boolean comment = false;


for (;;) { for (;;) {
if (!nullable) { if (!nullable) {
Expand Down Expand Up @@ -1739,10 +1769,18 @@ else if (parseKeywordIf(ctx, "UNIQUE")) {
} }
} }



if (!comment) {
if (parseKeywordIf(ctx, "COMMENT")) {
fieldComment = parseComment(ctx);
continue;
}
}

break; break;
} }


fields.add(field(fieldName, type)); fields.add(field(fieldName, type, fieldComment));
} }
while (parseIf(ctx, ',') while (parseIf(ctx, ',')
&& (noConstraint = && (noConstraint =
Expand Down Expand Up @@ -1844,7 +1882,7 @@ else if ((keyword = parseAndGetKeywordIf(ctx, "DEFAULT COLLATE")) != null) {
} }
else if ((keyword = parseAndGetKeywordIf(ctx, "COMMENT")) != null) { else if ((keyword = parseAndGetKeywordIf(ctx, "COMMENT")) != null) {
parseIf(ctx, '='); parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx))); tableComment.comment = parseStringLiteral(ctx);
} }
else if ((keyword = parseAndGetKeywordIf(ctx, "COMPRESSION")) != null) { else if ((keyword = parseAndGetKeywordIf(ctx, "COMPRESSION")) != null) {
parseIf(ctx, '='); parseIf(ctx, '=');
Expand Down Expand Up @@ -2066,10 +2104,12 @@ else if (constraint != null)


Name fieldName = parseIdentifier(ctx); Name fieldName = parseIdentifier(ctx);
DataType type = parseDataType(ctx); DataType type = parseDataType(ctx);
Comment fieldComment = null;


boolean nullable = false; boolean nullable = false;
boolean defaultValue = false; boolean defaultValue = false;
boolean unique = false; boolean unique = false;
boolean comment = false;


for (;;) { for (;;) {
if (!nullable) { if (!nullable) {
Expand Down Expand Up @@ -2102,10 +2142,17 @@ else if (parseKeywordIf(ctx, "UNIQUE"))
if (parseKeywordIf(ctx, "CHECK")) if (parseKeywordIf(ctx, "CHECK"))
throw ctx.unexpectedToken(); throw ctx.unexpectedToken();


if (!comment) {
if (parseKeywordIf(ctx, "COMMENT")) {
fieldComment = parseComment(ctx);
continue;
}
}

break; break;
} }


return s1.add(field(fieldName, type), type); return s1.add(field(fieldName, type, fieldComment), type);
} }
} }
else if (parseKeywordIf(ctx, "ALTER")) { else if (parseKeywordIf(ctx, "ALTER")) {
Expand Down Expand Up @@ -5617,6 +5664,10 @@ private static final Field<?> parseBindVariable(ParserContext ctx) {
} }
} }


private static final Comment parseComment(ParserContext ctx) {
return DSL.comment(parseStringLiteral(ctx));
}

private static final String parseStringLiteral(ParserContext ctx) { private static final String parseStringLiteral(ParserContext ctx) {
parseWhitespaceIf(ctx); parseWhitespaceIf(ctx);


Expand Down
7 changes: 7 additions & 0 deletions jOOQ/src/main/java/org/jooq/impl/QualifiedField.java
Expand Up @@ -37,6 +37,7 @@
*/ */
package org.jooq.impl; package org.jooq.impl;


import org.jooq.Comment;
import org.jooq.Context; import org.jooq.Context;
import org.jooq.DataType; import org.jooq.DataType;
import org.jooq.Field; import org.jooq.Field;
Expand Down Expand Up @@ -68,6 +69,12 @@ final class QualifiedField<T> extends AbstractField<T> implements TableField<Rec
this.name = name; this.name = name;
} }


QualifiedField(Name name, DataType<T> type, Comment comment) {
super(name, type, comment);

this.name = name;
}

// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Field API // Field API
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion jOOQ/src/main/java/org/jooq/impl/RowField.java
Expand Up @@ -68,7 +68,7 @@ final class RowField<ROW extends Row, REC extends Record> extends AbstractField<


@SuppressWarnings({ "serial", "unchecked", "rawtypes" }) @SuppressWarnings({ "serial", "unchecked", "rawtypes" })
RowField(final ROW row, Name as) { RowField(final ROW row, Name as) {
super(as, (DataType) SQLDataType.RECORD, "", binding(new Converter<Object, REC>() { super(as, (DataType) SQLDataType.RECORD, CommentImpl.NO_COMMENT, binding(new Converter<Object, REC>() {
@Override @Override
public REC from(final Object t) { public REC from(final Object t) {
// So far, this is only supported for PostgreSQL // So far, this is only supported for PostgreSQL
Expand Down
2 changes: 1 addition & 1 deletion jOOQ/src/main/java/org/jooq/impl/TableAlias.java
Expand Up @@ -97,7 +97,7 @@ private final Fields<R> init(Name[] fieldAliases) {
? fieldAliases[i] ? fieldAliases[i]
: field.getUnqualifiedName(); : field.getUnqualifiedName();


result.add(new TableFieldImpl(name, field.getDataType(), this, field.getComment(), field.getBinding())); result.add(new TableFieldImpl(name, field.getDataType(), this, DSL.comment(field.getComment()), field.getBinding()));
} }


return new Fields<R>(result); return new Fields<R>(result);
Expand Down

0 comments on commit f58e7d7

Please sign in to comment.