[jOOQ/jOOQ#10932] Support MySQL 8.0.16 CHECK constraints

This commit is contained in:
Lukas Eder 2020-11-13 09:14:35 +01:00
parent 321c2a927f
commit 67e0d284f9
12 changed files with 177 additions and 246 deletions

View File

@ -40,52 +40,46 @@ package org.jooq;
import org.jetbrains.annotations.*;
import static org.jooq.SQLDialect.*;
/**
* The step in the <code>ALTER TABLE</code> DSL used to <code>ALTER</code>
* constraints.
* <p>
* <h3>Referencing <code>XYZ*Step</code> types directly from client code</h3>
* <p>
* It is usually not recommended to reference any <code>XYZ*Step</code> types
* directly from client code, or assign them to local variables. When writing
* dynamic SQL, creating a statement's components dynamically, and passing them
* to the DSL API statically is usually a better choice. See the manual's
* section about dynamic SQL for details: <a href=
* "https://www.jooq.org/doc/latest/manual/sql-building/dynamic-sql">https://www.jooq.org/doc/latest/manual/sql-building/dynamic-sql</a>.
* <p>
* Drawbacks of referencing the <code>XYZ*Step</code> types directly:
* <ul>
* <li>They're operating on mutable implementations (as of jOOQ 3.x)</li>
* <li>They're less composable and not easy to get right when dynamic SQL gets
* complex</li>
* <li>They're less readable</li>
* <li>They might have binary incompatible changes between minor releases</li>
* </ul>
*
* @author Lukas Eder
*/
public interface AlterTableAlterConstraintStep {
/**
* Add the <code>ENFORCED</code> clause to the constraint.
*/
@NotNull
@Support({ MYSQL })
AlterTableFinalStep enforced();
/**
* Add the <code>NOT ENFORCED</code> clause to the constraint.
*/
@NotNull
@Support({ MYSQL })
AlterTableFinalStep notEnforced();
}

View File

@ -55,6 +55,7 @@ import static org.jooq.SQLDialect.MARIADB;
// ...
import static org.jooq.SQLDialect.MYSQL;
// ...
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
@ -214,20 +215,15 @@ public interface AlterTableStep {
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
AlterTableRenameConstraintToStep renameConstraint(String oldName);
/**
* Add an <code>ALTER CONSTRAINT</code> clause to the <code>ALTER TABLE</code>
* statement.
* <p>
* This is an alias for {@link #alterConstraint(Constraint)}.
*/
@NotNull
@Support({ MYSQL })
AlterTableAlterConstraintStep alter(Constraint constraint);
/**
* Add an <code>ALTER COLUMN</code> clause to the <code>ALTER TABLE</code>
@ -283,36 +279,29 @@ public interface AlterTableStep {
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
AlterTableAlterStep<Object> alterColumn(String field);
/**
* Add an <code>ALTER CONSTRAINT</code> clause to the <code>ALTER TABLE</code>
* statement.
*/
@NotNull
@Support({ MYSQL })
AlterTableAlterConstraintStep alterConstraint(Constraint constraint);
/**
* Add an <code>ALTER CONSTRAINT</code> clause to the <code>ALTER TABLE</code>
* statement.
*/
@NotNull
@Support({ MYSQL })
AlterTableAlterConstraintStep alterConstraint(Name constraint);
/**
* Add an <code>ALTER CONSTRAINT</code> clause to the <code>ALTER TABLE</code>
* statement.
*/
@NotNull
@Support({ MYSQL })
AlterTableAlterConstraintStep alterConstraint(String constraint);
/**
* Add an <code>ADD COLUMN</code> clause to the <code>ALTER TABLE</code>

View File

@ -37,12 +37,12 @@
*/
package org.jooq;
import org.jetbrains.annotations.*;
// ...
import static org.jooq.SQLDialect.MYSQL;
// ...
import org.jetbrains.annotations.NotNull;
/**
* The step in the {@link Constraint} construction DSL API that allows for
* adding <code>ENFORCED</code> and <code>NOT ENFORCED</code> clauses.
@ -70,23 +70,17 @@ import org.jetbrains.annotations.*;
*/
public interface ConstraintEnforcementStep extends ConstraintFinalStep {
/**
* Add the <code>ENFORCED</code> clause to the constraint.
*/
@NotNull
@Support({ MYSQL })
ConstraintFinalStep enforced();
/**
* Add the <code>NOT ENFORCED</code> clause to the constraint.
*/
@NotNull
@Support({ MYSQL })
ConstraintFinalStep notEnforced();
}

View File

@ -54,6 +54,7 @@ import static org.jooq.SQLDialect.HSQLDB;
// ...
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
@ -621,6 +622,6 @@ public interface ConstraintTypeStep extends ConstraintFinalStep {
* Create a <code>CHECK</code> constraint.
*/
@NotNull
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, MARIADB, POSTGRES, SQLITE })
@Support
ConstraintEnforcementStep check(Condition condition);
}

View File

@ -110,12 +110,7 @@ abstract class AbstractKey<R extends Record> extends AbstractNamed implements Ke
}
private final Constraint enforced(ConstraintEnforcementStep key) {
return key;
return enforced() ? key : key.notEnforced();
}
@Override

View File

@ -165,7 +165,7 @@ import java.util.List;
import java.util.Set;
import org.jooq.AlterTableAddStep;
// ...
import org.jooq.AlterTableAlterConstraintStep;
import org.jooq.AlterTableAlterStep;
import org.jooq.AlterTableDropStep;
import org.jooq.AlterTableFinalStep;
@ -205,9 +205,7 @@ final class AlterTableImpl extends AbstractRowCountQuery implements
AlterTableAddStep,
AlterTableDropStep,
AlterTableAlterStep,
AlterTableAlterConstraintStep,
AlterTableUsingIndexStep,
AlterTableRenameColumnToStep,
AlterTableRenameIndexToStep,
@ -266,10 +264,8 @@ final class AlterTableImpl extends AbstractRowCountQuery implements
private Constraint alterConstraint;
private boolean alterConstraintEnforced;
private Field<?> alterColumn;
private Nullability alterColumnNullability;
private DataType<?> alterColumnType;
@ -308,12 +304,8 @@ final class AlterTableImpl extends AbstractRowCountQuery implements
final DataType<?> $alterColumnType() { return alterColumnType; }
final Field<?> $alterColumnDefault() { return alterColumnDefault; }
final boolean $alterColumnDropDefault() { return alterColumnDropDefault; }
final Constraint $alterConstraint() { return alterConstraint; }
final boolean $alterConstraintEnforced() { return alterConstraintEnforced; }
final Table<?> $renameTo() { return renameTo; }
final Field<?> $renameColumn() { return renameColumn; }
final Field<?> $renameColumnTo() { return renameColumnTo; }
@ -652,42 +644,38 @@ final class AlterTableImpl extends AbstractRowCountQuery implements
return this;
}
@Override
public final AlterTableImpl alter(Constraint constraint) {
return alterConstraint(constraint);
}
@Override
public final AlterTableImpl alterConstraint(Name constraint) {
return alterConstraint(constraint(constraint));
}
@Override
public final AlterTableImpl alterConstraint(String constraint) {
return alterConstraint(constraint(constraint));
}
@Override
public final AlterTableImpl alterConstraint(Constraint constraint) {
alterConstraint = constraint;
return this;
}
@Override
public final AlterTableImpl enforced() {
alterConstraintEnforced = true;
return this;
}
@Override
public final AlterTableImpl notEnforced() {
alterConstraintEnforced = false;
return this;
}
@Override
public final AlterTableImpl set(DataType type) {
@ -1397,28 +1385,28 @@ final class AlterTableImpl extends AbstractRowCountQuery implements
ctx.end(ALTER_TABLE_ADD);
}
else if (alterConstraint != null) {
ctx.start(ALTER_TABLE_ALTER);
ctx.data(DATA_CONSTRAINT_REFERENCE, true);
switch (family) {
default:
ctx.visit(K_ALTER);
break;
}
ctx.sql(' ').visit(K_CONSTRAINT).sql(' ').visit(alterConstraint);
ConstraintImpl.acceptEnforced(ctx, alterConstraintEnforced);
ctx.data().remove(DATA_CONSTRAINT_REFERENCE);
ctx.end(ALTER_TABLE_ALTER);
}
else if (alterColumn != null) {
ctx.start(ALTER_TABLE_ALTER);

View File

@ -88,12 +88,7 @@ final class CheckImpl<R extends Record> extends AbstractNamed implements Check<R
}
private final Constraint enforced(ConstraintEnforcementStep key) {
return key;
return enforced() ? key : key.notEnforced();
}
@Override

View File

@ -164,10 +164,7 @@ implements
private Action onDelete;
private Action onUpdate;
private Condition check;
private boolean enforced = true;
ConstraintImpl() {
this(null);
@ -185,10 +182,7 @@ implements
final Action $onDelete() { return onDelete; }
final Action $onUpdate() { return onUpdate; }
final Condition $check() { return check; }
final boolean $enforced() { return enforced; }
// ------------------------------------------------------------------------
// XXX: QueryPart API
@ -291,10 +285,8 @@ implements
.sql(')');
}
if (!enforced)
acceptEnforced(ctx, enforced);
if (named) {
@ -312,6 +304,8 @@ implements
}
}
static void acceptEnforced(Context<?> ctx, boolean enforced) {
switch (ctx.family()) {
@ -325,16 +319,16 @@ implements
case MYSQL:
default:
if (enforced)
ctx.sql(' ').visit(K_ENFORCED);
else
ctx.sql(' ').visit(K_NOT).sql(' ').visit(K_ENFORCED);
break;
}
}
// ------------------------------------------------------------------------
// XXX: Constraint API
@ -1150,21 +1144,17 @@ implements
@Override
public final ConstraintImpl enforced() {
this.enforced = true;
return this;
}
@Override
public final ConstraintImpl notEnforced() {
this.enforced = false;
return this;
}
enum Action {
NO_ACTION("no action"),

View File

@ -446,11 +446,6 @@ final class DDL {
}
private final Constraint enforced(ConstraintEnforcementStep check, boolean enforced) {
return check;
return enforced ? check : check.notEnforced();
}
}

View File

@ -7059,7 +7059,7 @@ public class DSL {
* Create an unnamed (system named) <code>CHECK</code> constraint.
*/
@NotNull
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, POSTGRES, SQLITE })
@Support
public static ConstraintEnforcementStep check(Condition condition) {
return constraint().check(condition);
}

View File

@ -384,9 +384,8 @@ final class Interpreter {
if (mu == null)
throw primaryKeyNotExists(impl.$referencesTable());
boolean enforced = true ;
mt.foreignKeys.add(new MutableForeignKey(
(UnqualifiedName) impl.getUnqualifiedName(), mt, mfs, mu, impl.$onDelete(), impl.$onUpdate(), enforced
(UnqualifiedName) impl.getUnqualifiedName(), mt, mfs, mu, impl.$onDelete(), impl.$onUpdate(), impl.$enforced()
));
}
@ -592,11 +591,9 @@ final class Interpreter {
else
mc.name((UnqualifiedName) query.$renameConstraintTo().getUnqualifiedName());
}
else if (query.$alterConstraint() != null) {
existing.constraint(query.$alterConstraint(), true).enforced = query.$alterConstraintEnforced();
}
else if (query.$dropColumns() != null) {
List<MutableField> fields = existing.fields(query.$dropColumns().toArray(EMPTY_FIELD), false);
@ -746,18 +743,17 @@ final class Interpreter {
if (!impl.getUnqualifiedName().empty() && existing.constraint(impl) != null)
throw alreadyExists(impl);
boolean enforced = true ;
if (impl.$primaryKey() != null)
if (existing.primaryKey != null)
throw alreadyExists(impl);
else
existing.primaryKey = new MutableUniqueKey((UnqualifiedName) impl.getUnqualifiedName(), existing, existing.fields(impl.$primaryKey(), true), enforced);
existing.primaryKey = new MutableUniqueKey((UnqualifiedName) impl.getUnqualifiedName(), existing, existing.fields(impl.$primaryKey(), true), impl.$enforced());
else if (impl.$unique() != null)
existing.uniqueKeys.add(new MutableUniqueKey((UnqualifiedName) impl.getUnqualifiedName(), existing, existing.fields(impl.$unique(), true), enforced));
existing.uniqueKeys.add(new MutableUniqueKey((UnqualifiedName) impl.getUnqualifiedName(), existing, existing.fields(impl.$unique(), true), impl.$enforced()));
else if (impl.$foreignKey() != null)
addForeignKey(existing, impl);
else if (impl.$check() != null)
existing.checks.add(new MutableCheck((UnqualifiedName) impl.getUnqualifiedName(), existing, impl.$check(), enforced));
existing.checks.add(new MutableCheck((UnqualifiedName) impl.getUnqualifiedName(), existing, impl.$check(), impl.$enforced()));
else
throw unsupportedQuery(query);
}
@ -1985,7 +1981,7 @@ final class Interpreter {
(UnqualifiedName) constraint.getUnqualifiedName(),
null,
((ConstraintImpl) constraint).$check(),
true
((ConstraintImpl) constraint).$enforced()
);
}

View File

@ -4197,18 +4197,12 @@ final class ParserImpl implements Parser {
if (!deferrable)
parseConstraintDeferrableIf(ctx);
if ((parseKeywordIf(ctx, "ENABLE") || parseKeywordIf(ctx, "ENFORCED")) && ctx.requireProEdition())
;
else if ((parseKeywordIf(ctx, "DISABLE") || parseKeywordIf(ctx, "NOT ENFORCED")) && ctx.requireProEdition())
;
return e;
if ((parseKeywordIf(ctx, "ENABLE") || parseKeywordIf(ctx, "ENFORCED")))
return e.enforced();
else if ((parseKeywordIf(ctx, "DISABLE") || parseKeywordIf(ctx, "NOT ENFORCED")))
return e.notEnforced();
else
return e;
}
private static final boolean parseConstraintDeferrableIf(ParserContext ctx) {