[#6485] [#7018] Support parsing MySQL / MariaDB COMMENT syntax

This commit is contained in:
lukaseder 2018-01-10 15:46:38 +01:00
parent bd13797ad5
commit f58e7d7ef6
12 changed files with 156 additions and 27 deletions

View File

@ -63,7 +63,6 @@ import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.EMPTY_STRING;
import static org.jooq.tools.Convert.FALSE_VALUES;
import static org.jooq.tools.Convert.TRUE_VALUES;
import static org.jooq.tools.StringUtils.defaultString;
import java.math.BigDecimal;
import java.sql.Timestamp;
@ -81,6 +80,7 @@ import org.jooq.Binding;
import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep;
import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
@ -114,19 +114,23 @@ abstract class AbstractField<T> extends AbstractQueryPart implements Field<T> {
private static final Clause[] CLAUSES = { FIELD };
private final Name name;
private final String comment;
private final Comment comment;
private final DataType<T> dataType;
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")
AbstractField(Name name, DataType<T> type, String comment, Binding<?, T> binding) {
AbstractField(Name name, DataType<T> type, Comment comment, Binding<?, T> binding) {
super();
this.name = name;
this.comment = defaultString(comment);
this.comment = comment == null ? CommentImpl.NO_COMMENT : comment;
this.dataType = type.asConvertedDataType((Binding<T, T>) binding);
}
@ -226,7 +230,7 @@ abstract class AbstractField<T> extends AbstractQueryPart implements Field<T> {
@Override
public final String getComment() {
return comment;
return comment.getComment();
}
@Override

View File

@ -68,6 +68,7 @@ import java.util.stream.Stream;
import org.jooq.Binding;
import org.jooq.Catalog;
import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Context;
@ -113,7 +114,7 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
private Schema tableschema;
private final Name tablename;
private final String tablecomment;
private final Comment tablecomment;
private transient DataType<R> type;
/**
@ -137,7 +138,7 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
*/
@Deprecated
AbstractTable(String name, Schema schema, String comment) {
this(DSL.name(name), schema, comment);
this(DSL.name(name), schema, DSL.comment(comment));
}
AbstractTable(Name name) {
@ -148,10 +149,10 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
this(name, schema, null);
}
AbstractTable(Name name, Schema schema, String comment) {
AbstractTable(Name name, Schema schema, Comment comment) {
this.tableschema = schema;
this.tablename = name;
this.tablecomment = comment;
this.tablecomment = comment == null ? CommentImpl.NO_COMMENT : comment;
}
// ------------------------------------------------------------------------
@ -406,7 +407,7 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
@Override
public final String getComment() {
return tablecomment;
return tablecomment.getComment();
}
/**
@ -573,7 +574,7 @@ abstract class AbstractTable<R extends Record> extends AbstractQueryPart impleme
: type.asConvertedDataType(actualBinding);
// [#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
if (table instanceof TableImpl) {

View File

@ -52,10 +52,11 @@ final class CommentImpl extends AbstractQueryPart implements Comment {
* Generated UID
*/
private static final long serialVersionUID = -5034168783226853829L;
static final CommentImpl NO_COMMENT = new CommentImpl("");
private final String comment;
CommentImpl(String comment) {
this.comment = comment;
this.comment = comment == null ? "" : comment;
}
@Override

View File

@ -75,6 +75,7 @@ import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.EMPTY_QUERYPART;
import static org.jooq.impl.Tools.combine;
import static org.jooq.impl.Tools.configuration;
import static org.jooq.tools.StringUtils.isEmpty;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -5815,7 +5816,7 @@ public class DSL {
*/
@Support
public static Comment comment(String comment) {
return new CommentImpl(comment);
return isEmpty(comment) ? CommentImpl.NO_COMMENT : new CommentImpl(comment);
}
// -------------------------------------------------------------------------
@ -9123,6 +9124,28 @@ public class DSL {
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.
* <p>
@ -9329,6 +9352,37 @@ public class DSL {
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.
*/

View File

@ -251,6 +251,8 @@ import org.jooq.Block;
import org.jooq.CaseConditionStep;
import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep;
import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.CommentOnIsStep;
import org.jooq.CommonTableExpression;
import org.jooq.Comparator;
@ -259,6 +261,7 @@ import org.jooq.Configuration;
import org.jooq.Constraint;
import org.jooq.ConstraintForeignKeyOnStep;
import org.jooq.ConstraintTypeStep;
import org.jooq.Context;
import org.jooq.CreateIndexFinalStep;
import org.jooq.CreateIndexStep;
import org.jooq.CreateIndexWhereStep;
@ -1598,8 +1601,33 @@ final class ParserImpl implements Parser {
}
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");
Table<?> tableName = parseTableName(ctx);
MutableComment tableComment = new MutableComment();
Table<?> tableName = DSL.table(parseTableName(ctx).getQualifiedName(), tableComment);
CreateTableStorageStep storageStep;
// [#5309] TODO: Move this after the column specification
@ -1624,11 +1652,13 @@ final class ParserImpl implements Parser {
do {
Name fieldName = parseIdentifier(ctx);
DataType<?> type = parseDataType(ctx);
Comment fieldComment = null;
boolean nullable = false;
boolean defaultValue = false;
boolean unique = false;
boolean identity = type.identity();
boolean comment = false;
for (;;) {
if (!nullable) {
@ -1739,10 +1769,18 @@ final class ParserImpl implements Parser {
}
}
if (!comment) {
if (parseKeywordIf(ctx, "COMMENT")) {
fieldComment = parseComment(ctx);
continue;
}
}
break;
}
fields.add(field(fieldName, type));
fields.add(field(fieldName, type, fieldComment));
}
while (parseIf(ctx, ',')
&& (noConstraint =
@ -1844,7 +1882,7 @@ final class ParserImpl implements Parser {
}
else if ((keyword = parseAndGetKeywordIf(ctx, "COMMENT")) != null) {
parseIf(ctx, '=');
storage.add(sql("{0} {1}", keyword, parseStringLiteral(ctx)));
tableComment.comment = parseStringLiteral(ctx);
}
else if ((keyword = parseAndGetKeywordIf(ctx, "COMPRESSION")) != null) {
parseIf(ctx, '=');
@ -2066,10 +2104,12 @@ final class ParserImpl implements Parser {
Name fieldName = parseIdentifier(ctx);
DataType type = parseDataType(ctx);
Comment fieldComment = null;
boolean nullable = false;
boolean defaultValue = false;
boolean unique = false;
boolean comment = false;
for (;;) {
if (!nullable) {
@ -2102,10 +2142,17 @@ final class ParserImpl implements Parser {
if (parseKeywordIf(ctx, "CHECK"))
throw ctx.unexpectedToken();
if (!comment) {
if (parseKeywordIf(ctx, "COMMENT")) {
fieldComment = parseComment(ctx);
continue;
}
}
break;
}
return s1.add(field(fieldName, type), type);
return s1.add(field(fieldName, type, fieldComment), type);
}
}
else if (parseKeywordIf(ctx, "ALTER")) {
@ -5617,6 +5664,10 @@ final class ParserImpl implements Parser {
}
}
private static final Comment parseComment(ParserContext ctx) {
return DSL.comment(parseStringLiteral(ctx));
}
private static final String parseStringLiteral(ParserContext ctx) {
parseWhitespaceIf(ctx);

View File

@ -37,6 +37,7 @@
*/
package org.jooq.impl;
import org.jooq.Comment;
import org.jooq.Context;
import org.jooq.DataType;
import org.jooq.Field;
@ -68,6 +69,12 @@ final class QualifiedField<T> extends AbstractField<T> implements TableField<Rec
this.name = name;
}
QualifiedField(Name name, DataType<T> type, Comment comment) {
super(name, type, comment);
this.name = name;
}
// ------------------------------------------------------------------------
// Field API
// ------------------------------------------------------------------------

View File

@ -68,7 +68,7 @@ final class RowField<ROW extends Row, REC extends Record> extends AbstractField<
@SuppressWarnings({ "serial", "unchecked", "rawtypes" })
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
public REC from(final Object t) {
// So far, this is only supported for PostgreSQL

View File

@ -97,7 +97,7 @@ final class TableAlias<R extends Record> extends AbstractTable<R> {
? fieldAliases[i]
: 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);

View File

@ -44,6 +44,7 @@ import static org.jooq.impl.Tools.DataKey.DATA_OMIT_CLAUSE_EVENT_EMISSION;
import org.jooq.Binding;
import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.Context;
import org.jooq.DataType;
import org.jooq.Name;
@ -64,7 +65,7 @@ final class TableFieldImpl<R extends Record, T> extends AbstractField<T> impleme
private final Table<R> table;
TableFieldImpl(Name name, DataType<T> type, Table<R> table, String comment, Binding<?, T> binding) {
TableFieldImpl(Name name, DataType<T> type, Table<R> table, Comment comment, Binding<?, T> binding) {
super(name, type, comment, binding);
this.table = table;

View File

@ -50,6 +50,7 @@ import java.util.Arrays;
import java.util.EnumSet;
import org.jooq.Clause;
import org.jooq.Comment;
import org.jooq.Context;
import org.jooq.Field;
import org.jooq.Name;
@ -124,22 +125,30 @@ public class TableImpl<R extends Record> extends AbstractTable<R> {
}
public TableImpl(Name name) {
this(name, null, null, null, null);
this(name, null, null, null, (Comment) null);
}
public TableImpl(Name name, Schema schema) {
this(name, schema, null, null, null);
this(name, schema, null, null, (Comment) null);
}
public TableImpl(Name name, Schema schema, Table<R> aliased) {
this(name, schema, aliased, null, null);
this(name, schema, aliased, null, (Comment) null);
}
public TableImpl(Name name, Schema schema, Table<R> aliased, Field<?>[] parameters) {
this(name, schema, aliased, parameters, null);
this(name, schema, aliased, parameters, (Comment) null);
}
/**
* @deprecated - 3.11 - [#7027] - Use {@link #TableImpl(Name, Schema, Table, Field[], Comment)} instead.
*/
@Deprecated
public TableImpl(Name name, Schema schema, Table<R> aliased, Field<?>[] parameters, String comment) {
this(name, schema, aliased, parameters, DSL.comment(comment));
}
public TableImpl(Name name, Schema schema, Table<R> aliased, Field<?>[] parameters, Comment comment) {
super(name, schema, comment);
this.fields = new Fields<R>();

View File

@ -39,6 +39,7 @@
package org.jooq.impl;
import org.jooq.Binding;
import org.jooq.Comment;
import org.jooq.Context;
import org.jooq.DataType;
import org.jooq.Name;
@ -57,7 +58,7 @@ final class UDTFieldImpl<R extends UDTRecord<R>, T> extends AbstractField<T> imp
private final UDT<R> udt;
UDTFieldImpl(Name name, DataType<T> type, UDT<R> udt, String comment, Binding<?, T> binding) {
UDTFieldImpl(Name name, DataType<T> type, UDT<R> udt, Comment comment, Binding<?, T> binding) {
super(name, type, comment, binding);
this.udt = udt;

View File

@ -285,7 +285,7 @@ public class UDTImpl<R extends UDTRecord<R>> extends AbstractQueryPart implement
: type.asConvertedDataType(actualBinding);
// [#5999] TODO: Allow for user-defined Names
final UDTFieldImpl<R, U> udtField = new UDTFieldImpl<R, U>(DSL.name(name), actualType, udt, comment, actualBinding);
final UDTFieldImpl<R, U> udtField = new UDTFieldImpl<R, U>(DSL.name(name), actualType, udt, DSL.comment(comment), actualBinding);
return udtField;
}