[jOOQ/jOOQ#7597] Do generate a check constraint for non-stored enums

This commit is contained in:
Lukas Eder 2019-07-11 15:41:01 +02:00
parent 1f0a1ab479
commit 2dc8720fcd
2 changed files with 47 additions and 26 deletions

View File

@ -97,6 +97,8 @@ import static org.jooq.impl.Tools.begin;
import static org.jooq.impl.Tools.beginExecuteImmediate;
import static org.jooq.impl.Tools.end;
import static org.jooq.impl.Tools.endExecuteImmediate;
import static org.jooq.impl.Tools.enumLiterals;
import static org.jooq.impl.Tools.storedEnumType;
import static org.jooq.impl.Tools.BooleanDataKey.DATA_SELECT_NO_DATA;
import static org.jooq.impl.Tools.DataKey.DATA_SELECT_INTO_TABLE;
@ -137,16 +139,17 @@ final class CreateTableImpl extends AbstractRowCountQuery implements
/**
* Generated UID
*/
private static final long serialVersionUID = 8904572826501186329L;
private static final EnumSet<SQLDialect> NO_SUPPORT_IF_NOT_EXISTS = EnumSet.of(DERBY, FIREBIRD);
private static final EnumSet<SQLDialect> NO_SUPPORT_WITH_DATA = EnumSet.of(H2, MARIADB, MYSQL, SQLITE);
private static final EnumSet<SQLDialect> NO_SUPPORT_CTAS_COLUMN_NAMES = EnumSet.of(H2);
private static final EnumSet<SQLDialect> EMULATE_INDEXES_IN_BLOCK = EnumSet.of(POSTGRES);
private static final EnumSet<SQLDialect> EMULATE_ENUM_TYPES_AS_CHECK = EnumSet.of(CUBRID, DERBY, FIREBIRD, HSQLDB, SQLITE);
private static final EnumSet<SQLDialect> REQUIRES_WITH_DATA = EnumSet.of(HSQLDB);
private static final EnumSet<SQLDialect> WRAP_SELECT_IN_PARENS = EnumSet.of(HSQLDB);
private static final EnumSet<SQLDialect> SUPPORT_TEMPORARY = EnumSet.of(MARIADB, MYSQL, POSTGRES);
private static final EnumSet<SQLDialect> EMULATE_COMMENT_IN_BLOCK = EnumSet.of(POSTGRES);
private static final long serialVersionUID = 8904572826501186329L;
private static final EnumSet<SQLDialect> NO_SUPPORT_IF_NOT_EXISTS = EnumSet.of(DERBY, FIREBIRD);
private static final EnumSet<SQLDialect> NO_SUPPORT_WITH_DATA = EnumSet.of(H2, MARIADB, MYSQL, SQLITE);
private static final EnumSet<SQLDialect> NO_SUPPORT_CTAS_COLUMN_NAMES = EnumSet.of(H2);
private static final EnumSet<SQLDialect> EMULATE_INDEXES_IN_BLOCK = EnumSet.of(POSTGRES);
private static final EnumSet<SQLDialect> EMULATE_SOME_ENUM_TYPES_AS_CHECK = EnumSet.of(CUBRID, DERBY, FIREBIRD, HSQLDB, POSTGRES, SQLITE);
private static final EnumSet<SQLDialect> EMULATE_STORED_ENUM_TYPES_AS_CHECK = EnumSet.of(CUBRID, DERBY, FIREBIRD, HSQLDB, SQLITE);
private static final EnumSet<SQLDialect> REQUIRES_WITH_DATA = EnumSet.of(HSQLDB);
private static final EnumSet<SQLDialect> WRAP_SELECT_IN_PARENS = EnumSet.of(HSQLDB);
private static final EnumSet<SQLDialect> SUPPORT_TEMPORARY = EnumSet.of(MARIADB, MYSQL, POSTGRES);
private static final EnumSet<SQLDialect> EMULATE_COMMENT_IN_BLOCK = EnumSet.of(POSTGRES);
@ -495,17 +498,23 @@ final class CreateTableImpl extends AbstractRowCountQuery implements
.formatSeparator()
.visit(constraint);
if (EMULATE_ENUM_TYPES_AS_CHECK.contains(ctx.family())) {
if (EMULATE_SOME_ENUM_TYPES_AS_CHECK.contains(ctx.family())) {
for (int i = 0; i < columnFields.size(); i++) {
DataType<?> type = columnTypes.get(i);
if (EnumType.class.isAssignableFrom(type.getType())) {
Field<?> field = columnFields.get(i);
ctx.sql(',')
.formatSeparator()
.visit(DSL.constraint(table.getName() + "_" + field.getName() + "_chk")
.check(((Field) field).in(Tools.inline(Tools.enumLiterals((Class<EnumType>) type.getType())))));
@SuppressWarnings("unchecked")
DataType<EnumType> enumType = (DataType<EnumType>) type;
if (EMULATE_STORED_ENUM_TYPES_AS_CHECK.contains(ctx.family()) || !storedEnumType(enumType)) {
Field<?> field = columnFields.get(i);
ctx.sql(',')
.formatSeparator()
.visit(DSL.constraint(table.getName() + "_" + field.getName() + "_chk")
.check(((Field) field).in(Tools.inline(enumLiterals(enumType.getType())))));
}
}
}
}

View File

@ -4682,8 +4682,8 @@ final class Tools {
ctx.visit(K_ENUM).sql('(');
String separator = "";
for (Object e : enumConstants(enumType)) {
ctx.sql(separator).visit(DSL.inline(((EnumType) e).getLiteral()));
for (EnumType e : enumConstants(enumType)) {
ctx.sql(separator).visit(DSL.inline(e.getLiteral()));
separator = ", ";
}
@ -4695,11 +4695,18 @@ final class Tools {
case POSTGRES:
case POSTGRES: {
// [#7597] but only if the EnumType.getSchema() value is present
// i.e. when it is a known, stored enum type
if (!storedEnumType(enumType))
type = emulateEnumType(enumType);
break;
}
default: {
type = emulateEnumType(enumType, enumConstants(enumType));
type = emulateEnumType(enumType);
break;
}
}
@ -4761,8 +4768,12 @@ final class Tools {
ctx.sql(' ').visit(K_COLLATE).sql(' ').visit(type.collation());
}
private static Object[] enumConstants(DataType<? extends EnumType> type) {
Object[] enums = type.getType().getEnumConstants();
static boolean storedEnumType(DataType<EnumType> enumType) {
return enumConstants(enumType)[0].getSchema() != null;
}
private static EnumType[] enumConstants(DataType<? extends EnumType> type) {
EnumType[] enums = type.getType().getEnumConstants();
if (enums == null)
throw new DataTypeException("EnumType must be a Java enum");
@ -4774,11 +4785,12 @@ final class Tools {
return emulateEnumType(type, enumConstants(type));
}
static final DataType<String> emulateEnumType(DataType<? extends EnumType> type, Object[] enums) {
@SuppressWarnings({ "unchecked", "rawtypes" })
private static final DataType<String> emulateEnumType(DataType<? extends EnumType> type, EnumType[] enums) {
int length = 0;
for (Object e : enums)
if (((EnumType) e).getLiteral() != null)
length = Math.max(length, ((EnumType) e).getLiteral().length());
for (EnumType e : enums)
if (e.getLiteral() != null)
length = Math.max(length, e.getLiteral().length());
return VARCHAR(length).nullability(type.nullability()).defaultValue((Field) type.defaultValue());
}