From 1b4f2ba6904d0cda18bec774e1ba32e248972da3 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 14 Apr 2022 14:26:01 +0200 Subject: [PATCH] [jOOQ/jOOQ#1592] [jOOQ/jOOQ#9879] AuditGenerator improvements - Added DataType::computedOnClientStoredOn - Improved DataType Javadoc - AuditGenerator can accept multiple GeneratorStatementType - Made GeneratorContext generic - Added GeneratorContext.field() --- .../java/org/jooq/meta/AbstractDatabase.java | 29 ++- .../meta/AbstractTypedElementDefinition.java | 37 +++- .../java/org/jooq/meta/jaxb/CustomType.java | 172 +++++++++++++++++ .../java/org/jooq/meta/jaxb/ForcedType.java | 180 ++++++++++++++++++ .../org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd | 80 ++++++++ jOOQ/src/main/java/org/jooq/DSLContext.java | 4 +- jOOQ/src/main/java/org/jooq/DataType.java | 33 +++- jOOQ/src/main/java/org/jooq/Field.java | 4 +- jOOQ/src/main/java/org/jooq/Generator.java | 16 +- .../main/java/org/jooq/GeneratorContext.java | 10 +- .../main/java/org/jooq/MergeUsingStep.java | 4 +- jOOQ/src/main/java/org/jooq/SelectQuery.java | 2 +- jOOQ/src/main/java/org/jooq/WithStep.java | 92 ++++----- .../java/org/jooq/impl/AbstractDataType.java | 19 +- jOOQ/src/main/java/org/jooq/impl/DSL.java | 4 +- .../jooq/impl/DefaultGeneratorContext.java | 12 +- .../java/org/jooq/impl/FieldMapForUpdate.java | 1 + .../org/jooq/impl/FieldMapsForInsert.java | 17 ++ 18 files changed, 640 insertions(+), 76 deletions(-) diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/AbstractDatabase.java b/jOOQ-meta/src/main/java/org/jooq/meta/AbstractDatabase.java index 825cb59ebc..05f5ed0b3c 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/AbstractDatabase.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/AbstractDatabase.java @@ -1418,27 +1418,36 @@ public abstract class AbstractDatabase implements Database { } if (StringUtils.isBlank(type.getName())) { - if (StringUtils.isBlank(type.getUserType()) && StringUtils.isBlank(type.getGenerator())) { - if (type.getVisibilityModifier() == null) { - log.warn("Bad configuration for . Either , , , or is required: " + type); + if (StringUtils.isBlank(type.getUserType())) { + if (type.getVisibilityModifier() == null + && StringUtils.isBlank(type.getGenerator()) + && !TRUE.equals(type.isAuditInsertTimestamp()) + && !TRUE.equals(type.isAuditInsertUser()) + && !TRUE.equals(type.isAuditUpdateTimestamp()) + && !TRUE.equals(type.isAuditUpdateUser())) { + log.warn("Bad configuration for . Any of , , , , , , , or is required: " + type); it2.remove(); continue; } else if (!commercial()) { - log.warn(" is a commercial only feature. Please upgrade to the jOOQ Professional Edition or jOOQ Enterprise Edition: " + type); + log.warn(", , , , , and are commercial only features. Please upgrade to the jOOQ Professional Edition or jOOQ Enterprise Edition: " + type); it2.remove(); continue; } } - if (StringUtils.isBlank(type.getBinding()) && - StringUtils.isBlank(type.getConverter()) && - StringUtils.isBlank(type.getGenerator()) && - type.getVisibilityModifier() == null && - !Boolean.TRUE.equals(type.isEnumConverter()) && - type.getLambdaConverter() == null + if (StringUtils.isBlank(type.getBinding()) + && StringUtils.isBlank(type.getConverter()) + && StringUtils.isBlank(type.getGenerator()) + && !TRUE.equals(type.isAuditInsertTimestamp()) + && !TRUE.equals(type.isAuditInsertUser()) + && !TRUE.equals(type.isAuditUpdateTimestamp()) + && !TRUE.equals(type.isAuditUpdateUser()) + && type.getVisibilityModifier() == null + && !Boolean.TRUE.equals(type.isEnumConverter()) + && type.getLambdaConverter() == null ) { log.warn("Bad configuration for . Either , , , , or is required: " + type); diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTypedElementDefinition.java b/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTypedElementDefinition.java index 2e02ea9e60..ce5a8e0e2a 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTypedElementDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTypedElementDefinition.java @@ -39,6 +39,7 @@ package org.jooq.meta; import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; import static org.jooq.tools.Convert.convert; import static org.jooq.tools.StringUtils.isEmpty; @@ -49,10 +50,14 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +// ... import org.jooq.Converter; import org.jooq.DataType; +import org.jooq.GeneratorStatementType; import org.jooq.Name; +// ... import org.jooq.exception.SQLDialectNotSupportedException; +// ... import org.jooq.impl.DateAsTimestampBinding; import org.jooq.impl.DefaultDataType; import org.jooq.impl.EnumConverter; @@ -215,6 +220,12 @@ public abstract class AbstractTypedElementDefinition String converter = null; String binding = result.getBinding(); + + + + + + CustomType customType = customType(db, forcedType); if (customType != null) { uType = (!StringUtils.isBlank(customType.getType())) @@ -224,8 +235,15 @@ public abstract class AbstractTypedElementDefinition if (generator == null) generator = customType.getGenerator(); + + + + + + + // [#5877] [#6567] EnumConverters profit from simplified configuration - if (Boolean.TRUE.equals(customType.isEnumConverter()) || + if (TRUE.equals(customType.isEnumConverter()) || EnumConverter.class.getName().equals(customType.getConverter())) { String tType = tType(db, resolver, definedType); converter = resolver.constructorCall(EnumConverter.class.getName() + "<" + resolver.ref(tType) + ", " + resolver.ref(uType) + ">") + "(" + resolver.classLiteral(tType) + ", " + resolver.classLiteral(uType) + ")"; @@ -243,6 +261,19 @@ public abstract class AbstractTypedElementDefinition binding = customType.getBinding(); } + + + + + + + + + + + + + if (uType != null) { db.markUsed(forcedType); log.info("Forcing type", child + " to " + forcedType); @@ -360,6 +391,10 @@ public abstract class AbstractTypedElementDefinition .withLambdaConverter(forcedType.getLambdaConverter()) .withVisibilityModifier(forcedType.getVisibilityModifier()) .withGenerator(forcedType.getGenerator()) + .withAuditInsertTimestamp(forcedType.isAuditInsertTimestamp()) + .withAuditInsertUser(forcedType.isAuditInsertUser()) + .withAuditUpdateTimestamp(forcedType.isAuditUpdateTimestamp()) + .withAuditUpdateUser(forcedType.isAuditUpdateUser()) .withConverter(forcedType.getConverter()) .withName(name) .withType(forcedType.getUserType()); diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/CustomType.java b/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/CustomType.java index 05693d9d90..bdaafd4a44 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/CustomType.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/CustomType.java @@ -40,6 +40,10 @@ public class CustomType implements Serializable, XMLAppendable protected VisibilityModifier visibilityModifier; @XmlJavaTypeAdapter(StringAdapter.class) protected String generator; + protected Boolean auditInsertTimestamp; + protected Boolean auditInsertUser; + protected Boolean auditUpdateTimestamp; + protected Boolean auditUpdateUser; @XmlJavaTypeAdapter(StringAdapter.class) protected String converter; protected Boolean enumConverter; @@ -119,6 +123,110 @@ public class CustomType implements Serializable, XMLAppendable this.generator = value; } + /** + * @deprecated Use ForcedType only + * + * @return + * possible object is + * {@link Boolean } + * + */ + @Deprecated + public Boolean isAuditInsertTimestamp() { + return auditInsertTimestamp; + } + + /** + * Sets the value of the auditInsertTimestamp property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + @Deprecated + public void setAuditInsertTimestamp(Boolean value) { + this.auditInsertTimestamp = value; + } + + /** + * @deprecated Use ForcedType only + * + * @return + * possible object is + * {@link Boolean } + * + */ + @Deprecated + public Boolean isAuditInsertUser() { + return auditInsertUser; + } + + /** + * Sets the value of the auditInsertUser property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + @Deprecated + public void setAuditInsertUser(Boolean value) { + this.auditInsertUser = value; + } + + /** + * @deprecated Use ForcedType only + * + * @return + * possible object is + * {@link Boolean } + * + */ + @Deprecated + public Boolean isAuditUpdateTimestamp() { + return auditUpdateTimestamp; + } + + /** + * Sets the value of the auditUpdateTimestamp property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + @Deprecated + public void setAuditUpdateTimestamp(Boolean value) { + this.auditUpdateTimestamp = value; + } + + /** + * @deprecated Use ForcedType only + * + * @return + * possible object is + * {@link Boolean } + * + */ + @Deprecated + public Boolean isAuditUpdateUser() { + return auditUpdateUser; + } + + /** + * Sets the value of the auditUpdateUser property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + @Deprecated + public void setAuditUpdateUser(Boolean value) { + this.auditUpdateUser = value; + } + /** * @deprecated Use ForcedType only * @@ -239,6 +347,26 @@ public class CustomType implements Serializable, XMLAppendable return this; } + public CustomType withAuditInsertTimestamp(Boolean value) { + setAuditInsertTimestamp(value); + return this; + } + + public CustomType withAuditInsertUser(Boolean value) { + setAuditInsertUser(value); + return this; + } + + public CustomType withAuditUpdateTimestamp(Boolean value) { + setAuditUpdateTimestamp(value); + return this; + } + + public CustomType withAuditUpdateUser(Boolean value) { + setAuditUpdateUser(value); + return this; + } + /** * @deprecated Use ForcedType only * @@ -280,6 +408,10 @@ public class CustomType implements Serializable, XMLAppendable builder.append("type", type); builder.append("visibilityModifier", visibilityModifier); builder.append("generator", generator); + builder.append("auditInsertTimestamp", auditInsertTimestamp); + builder.append("auditInsertUser", auditInsertUser); + builder.append("auditUpdateTimestamp", auditUpdateTimestamp); + builder.append("auditUpdateUser", auditUpdateUser); builder.append("converter", converter); builder.append("enumConverter", enumConverter); builder.append("lambdaConverter", lambdaConverter); @@ -341,6 +473,42 @@ public class CustomType implements Serializable, XMLAppendable return false; } } + if (auditInsertTimestamp == null) { + if (other.auditInsertTimestamp!= null) { + return false; + } + } else { + if (!auditInsertTimestamp.equals(other.auditInsertTimestamp)) { + return false; + } + } + if (auditInsertUser == null) { + if (other.auditInsertUser!= null) { + return false; + } + } else { + if (!auditInsertUser.equals(other.auditInsertUser)) { + return false; + } + } + if (auditUpdateTimestamp == null) { + if (other.auditUpdateTimestamp!= null) { + return false; + } + } else { + if (!auditUpdateTimestamp.equals(other.auditUpdateTimestamp)) { + return false; + } + } + if (auditUpdateUser == null) { + if (other.auditUpdateUser!= null) { + return false; + } + } else { + if (!auditUpdateUser.equals(other.auditUpdateUser)) { + return false; + } + } if (converter == null) { if (other.converter!= null) { return false; @@ -388,6 +556,10 @@ public class CustomType implements Serializable, XMLAppendable result = ((prime*result)+((type == null)? 0 :type.hashCode())); result = ((prime*result)+((visibilityModifier == null)? 0 :visibilityModifier.hashCode())); result = ((prime*result)+((generator == null)? 0 :generator.hashCode())); + result = ((prime*result)+((auditInsertTimestamp == null)? 0 :auditInsertTimestamp.hashCode())); + result = ((prime*result)+((auditInsertUser == null)? 0 :auditInsertUser.hashCode())); + result = ((prime*result)+((auditUpdateTimestamp == null)? 0 :auditUpdateTimestamp.hashCode())); + result = ((prime*result)+((auditUpdateUser == null)? 0 :auditUpdateUser.hashCode())); result = ((prime*result)+((converter == null)? 0 :converter.hashCode())); result = ((prime*result)+((enumConverter == null)? 0 :enumConverter.hashCode())); result = ((prime*result)+((lambdaConverter == null)? 0 :lambdaConverter.hashCode())); diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/ForcedType.java b/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/ForcedType.java index 052010f30d..a265ad0fc5 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/ForcedType.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/jaxb/ForcedType.java @@ -40,6 +40,10 @@ public class ForcedType implements Serializable, XMLAppendable protected VisibilityModifier visibilityModifier; @XmlJavaTypeAdapter(StringAdapter.class) protected String generator; + protected Boolean auditInsertTimestamp; + protected Boolean auditInsertUser; + protected Boolean auditUpdateTimestamp; + protected Boolean auditUpdateUser; @XmlJavaTypeAdapter(StringAdapter.class) protected String converter; protected Boolean enumConverter; @@ -171,6 +175,118 @@ public class ForcedType implements Serializable, XMLAppendable this.generator = value; } + /** + * Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#INSERT} timestamp. + *

+ * This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. + *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isAuditInsertTimestamp() { + return auditInsertTimestamp; + } + + /** + * Sets the value of the auditInsertTimestamp property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setAuditInsertTimestamp(Boolean value) { + this.auditInsertTimestamp = value; + } + + /** + * Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#INSERT} timestamp. + *

+ * This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. + *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isAuditInsertUser() { + return auditInsertUser; + } + + /** + * Sets the value of the auditInsertUser property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setAuditInsertUser(Boolean value) { + this.auditInsertUser = value; + } + + /** + * Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#UPDATE} timestamp. + *

+ * This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. + *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isAuditUpdateTimestamp() { + return auditUpdateTimestamp; + } + + /** + * Sets the value of the auditUpdateTimestamp property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setAuditUpdateTimestamp(Boolean value) { + this.auditUpdateTimestamp = value; + } + + /** + * Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#UPDATE} timestamp. + *

+ * This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. + *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isAuditUpdateUser() { + return auditUpdateUser; + } + + /** + * Sets the value of the auditUpdateUser property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setAuditUpdateUser(Boolean value) { + this.auditUpdateUser = value; + } + /** * A converter implementation for the {@link #getUserType()}. * @@ -473,6 +589,26 @@ public class ForcedType implements Serializable, XMLAppendable return this; } + public ForcedType withAuditInsertTimestamp(Boolean value) { + setAuditInsertTimestamp(value); + return this; + } + + public ForcedType withAuditInsertUser(Boolean value) { + setAuditInsertUser(value); + return this; + } + + public ForcedType withAuditUpdateTimestamp(Boolean value) { + setAuditUpdateTimestamp(value); + return this; + } + + public ForcedType withAuditUpdateUser(Boolean value) { + setAuditUpdateUser(value); + return this; + } + /** * A converter implementation for the {@link #getUserType()}. * @@ -609,6 +745,10 @@ public class ForcedType implements Serializable, XMLAppendable builder.append("userType", userType); builder.append("visibilityModifier", visibilityModifier); builder.append("generator", generator); + builder.append("auditInsertTimestamp", auditInsertTimestamp); + builder.append("auditInsertUser", auditInsertUser); + builder.append("auditUpdateTimestamp", auditUpdateTimestamp); + builder.append("auditUpdateUser", auditUpdateUser); builder.append("converter", converter); builder.append("enumConverter", enumConverter); builder.append("lambdaConverter", lambdaConverter); @@ -689,6 +829,42 @@ public class ForcedType implements Serializable, XMLAppendable return false; } } + if (auditInsertTimestamp == null) { + if (other.auditInsertTimestamp!= null) { + return false; + } + } else { + if (!auditInsertTimestamp.equals(other.auditInsertTimestamp)) { + return false; + } + } + if (auditInsertUser == null) { + if (other.auditInsertUser!= null) { + return false; + } + } else { + if (!auditInsertUser.equals(other.auditInsertUser)) { + return false; + } + } + if (auditUpdateTimestamp == null) { + if (other.auditUpdateTimestamp!= null) { + return false; + } + } else { + if (!auditUpdateTimestamp.equals(other.auditUpdateTimestamp)) { + return false; + } + } + if (auditUpdateUser == null) { + if (other.auditUpdateUser!= null) { + return false; + } + } else { + if (!auditUpdateUser.equals(other.auditUpdateUser)) { + return false; + } + } if (converter == null) { if (other.converter!= null) { return false; @@ -827,6 +1003,10 @@ public class ForcedType implements Serializable, XMLAppendable result = ((prime*result)+((userType == null)? 0 :userType.hashCode())); result = ((prime*result)+((visibilityModifier == null)? 0 :visibilityModifier.hashCode())); result = ((prime*result)+((generator == null)? 0 :generator.hashCode())); + result = ((prime*result)+((auditInsertTimestamp == null)? 0 :auditInsertTimestamp.hashCode())); + result = ((prime*result)+((auditInsertUser == null)? 0 :auditInsertUser.hashCode())); + result = ((prime*result)+((auditUpdateTimestamp == null)? 0 :auditUpdateTimestamp.hashCode())); + result = ((prime*result)+((auditUpdateUser == null)? 0 :auditUpdateUser.hashCode())); result = ((prime*result)+((converter == null)? 0 :converter.hashCode())); result = ((prime*result)+((enumConverter == null)? 0 :enumConverter.hashCode())); result = ((prime*result)+((lambdaConverter == null)? 0 :lambdaConverter.hashCode())); diff --git a/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd b/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd index aa4322887a..bfebdb315a 100644 --- a/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd +++ b/jOOQ-meta/src/main/resources/org/jooq/meta/xsd/jooq-codegen-3.17.0.xsd @@ -1393,6 +1393,54 @@ This feature is available in the commercial distribution only.]]>< + + + + + + + + @java.lang.Deprecated + @java.lang.Deprecated + + + + + + + + + + + @java.lang.Deprecated + @java.lang.Deprecated + + + + + + + + + + + @java.lang.Deprecated + @java.lang.Deprecated + + + + + + + + + + + @java.lang.Deprecated + @java.lang.Deprecated + + + @@ -1542,6 +1590,38 @@ This feature is available in the commercial distribution only.]]><

This has no effect on matched objects that are not columns.

+This feature is available in the commercial distribution only.]]> + + + + +This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. +

+This feature is available in the commercial distribution only.]]> + + + + +This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. +

+This feature is available in the commercial distribution only.]]> + + + + +This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. +

+This feature is available in the commercial distribution only.]]> + + + + +This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive. +

This feature is available in the commercial distribution only.]]> diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java index 9aadd54608..11dea8e32d 100644 --- a/jOOQ/src/main/java/org/jooq/DSLContext.java +++ b/jOOQ/src/main/java/org/jooq/DSLContext.java @@ -8599,8 +8599,8 @@ public interface DSLContext extends Scope { * * H2 * H2 natively supports this special syntax - * http://www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * HANA diff --git a/jOOQ/src/main/java/org/jooq/DataType.java b/jOOQ/src/main/java/org/jooq/DataType.java index 5e8ecbb17f..881d6694ce 100644 --- a/jOOQ/src/main/java/org/jooq/DataType.java +++ b/jOOQ/src/main/java/org/jooq/DataType.java @@ -506,7 +506,8 @@ public interface DataType extends Named { * This is true only if all of these hold true: *

    *
  • {@link #computed()}
  • - *
  • {@link #generationLocation()} == {@link GenerationLocation#CLIENT}
  • + *
  • {@link #generationLocation()} == + * {@link GenerationLocation#CLIENT}
  • *

    * This feature is implemented in commercial distributions only. */ @@ -518,8 +519,13 @@ public interface DataType extends Named { * This is true only if all of these hold true: *

      *
    • {@link #computed()}
    • - *
    • {@link #generationLocation()} == {@link GenerationLocation#CLIENT}
    • + *
    • {@link #generationLocation()} == + * {@link GenerationLocation#CLIENT}
    • *
    • {@link #generationOption()} == {@link GenerationOption#STORED}
    • + *
    • {@link #generatedAlwaysAsGenerator()} produces a generator that + * {@link Generator#supports(GeneratorStatementType)} any of + * {@link GeneratorStatementType#INSERT} or + * {@link GeneratorStatementType#UPDATE}
    • *

      * This feature is implemented in commercial distributions only. */ @@ -531,8 +537,29 @@ public interface DataType extends Named { * This is true only if all of these hold true: *

        *
      • {@link #computed()}
      • - *
      • {@link #generationLocation()} == {@link GenerationLocation#CLIENT}
      • + *
      • {@link #generationLocation()} == + * {@link GenerationLocation#CLIENT}
      • + *
      • {@link #generationOption()} == {@link GenerationOption#STORED}
      • + *
      • {@link #generatedAlwaysAsGenerator()} produces a generator that + * {@link Generator#supports(GeneratorStatementType)} the argument + * statementType
      • + *

        + * This feature is implemented in commercial distributions only. + */ + boolean computedOnClientStoredOn(GeneratorStatementType statementType); + + /** + * Whether this column is computed on the client. + *

        + * This is true only if all of these hold true: + *

          + *
        • {@link #computed()}
        • + *
        • {@link #generationLocation()} == + * {@link GenerationLocation#CLIENT}
        • *
        • {@link #generationOption()} == {@link GenerationOption#VIRTUAL}
        • + *
        • {@link #generatedAlwaysAsGenerator()} produces a generator that + * {@link Generator#supports(GeneratorStatementType)} the type + * {@link GeneratorStatementType#SELECT}
        • *

          * This feature is implemented in commercial distributions only. */ diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java index ef7663840c..c2c4c37305 100644 --- a/jOOQ/src/main/java/org/jooq/Field.java +++ b/jOOQ/src/main/java/org/jooq/Field.java @@ -1954,8 +1954,8 @@ extends * [search] REGEXP [pattern] * Java * http + * "https://www.h2database.com/html/grammar.html#condition_right_hand_side" + * >https * ://www.h2database.com/html/grammar.html#condition_right_hand_side * * diff --git a/jOOQ/src/main/java/org/jooq/Generator.java b/jOOQ/src/main/java/org/jooq/Generator.java index 137bfb5608..793ed75357 100644 --- a/jOOQ/src/main/java/org/jooq/Generator.java +++ b/jOOQ/src/main/java/org/jooq/Generator.java @@ -50,4 +50,18 @@ import java.util.function.Function; * @author Lukas Eder */ @FunctionalInterface -public interface Generator extends Function>, Serializable {} +public interface Generator extends Function, Field>, Serializable { + + /** + * Whether this generator supports a given statement type. + *

          + * Implementations may choose to deactivate themselves for some statement + * types, e.g. if they want to be invoked only for + * {@link GeneratorStatementType#INSERT}. + * + * @param statementType The statement type. + */ + default boolean supports(GeneratorStatementType statementType) { + return true; + } +} diff --git a/jOOQ/src/main/java/org/jooq/GeneratorContext.java b/jOOQ/src/main/java/org/jooq/GeneratorContext.java index 8b1a68a29c..bbc39f49a2 100644 --- a/jOOQ/src/main/java/org/jooq/GeneratorContext.java +++ b/jOOQ/src/main/java/org/jooq/GeneratorContext.java @@ -37,6 +37,7 @@ */ package org.jooq; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -48,7 +49,14 @@ import org.jetbrains.annotations.Nullable; * * @author Lukas Eder */ -public interface GeneratorContext extends Scope { +public interface GeneratorContext extends Scope { + + /** + * The target field whose contents are being generated, or null + * when the field is unknown / not applicable. + */ + @Nullable + Field field(); /** * The statement type in which the {@link Generator} is being invoked, or diff --git a/jOOQ/src/main/java/org/jooq/MergeUsingStep.java b/jOOQ/src/main/java/org/jooq/MergeUsingStep.java index a9dd1b5073..398439d625 100644 --- a/jOOQ/src/main/java/org/jooq/MergeUsingStep.java +++ b/jOOQ/src/main/java/org/jooq/MergeUsingStep.java @@ -135,8 +135,8 @@ public interface MergeUsingStep extends MergeKeyStepN { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * HANA diff --git a/jOOQ/src/main/java/org/jooq/SelectQuery.java b/jOOQ/src/main/java/org/jooq/SelectQuery.java index 41f092ee61..5889753e67 100644 --- a/jOOQ/src/main/java/org/jooq/SelectQuery.java +++ b/jOOQ/src/main/java/org/jooq/SelectQuery.java @@ -846,7 +846,7 @@ public interface SelectQuery extends Select, ConditionProvi *

        • Derby's * FOR UPDATE clause
        • - *
        • H2's FOR + *
        • H2's FOR * UPDATE clause
        • *
        • * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2823,8 +2823,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2849,8 +2849,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2875,8 +2875,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2901,8 +2901,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2927,8 +2927,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2953,8 +2953,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -2979,8 +2979,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3005,8 +3005,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3031,8 +3031,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3057,8 +3057,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3083,8 +3083,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3109,8 +3109,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3135,8 +3135,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3161,8 +3161,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3187,8 +3187,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3213,8 +3213,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3239,8 +3239,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3265,8 +3265,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3291,8 +3291,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3317,8 +3317,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3343,8 +3343,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere @@ -3371,8 +3371,8 @@ public interface WithStep extends QueryPart { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java index 0b27c38620..1bb563a8dd 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDataType.java @@ -89,6 +89,7 @@ import org.jooq.EmbeddableRecord; import org.jooq.EnumType; import org.jooq.Field; import org.jooq.Generator; +import org.jooq.GeneratorStatementType; import org.jooq.Geography; import org.jooq.Geometry; import org.jooq.JSON; @@ -175,12 +176,24 @@ implements @Override public final boolean computedOnClientStored() { - return computedOnClient() && generationOption() == GenerationOption.STORED; + return computedOnClient() + && generationOption() == GenerationOption.STORED + && (generatedAlwaysAsGenerator().supports(GeneratorStatementType.INSERT) || + generatedAlwaysAsGenerator().supports(GeneratorStatementType.UPDATE)); + } + + @Override + public final boolean computedOnClientStoredOn(GeneratorStatementType statementType) { + return computedOnClient() + && generationOption() == GenerationOption.STORED + && generatedAlwaysAsGenerator().supports(statementType); } @Override public final boolean computedOnClientVirtual() { - return computedOnClient() && generationOption() == GenerationOption.VIRTUAL; + return computedOnClient() + && generationOption() == GenerationOption.VIRTUAL + && generatedAlwaysAsGenerator().supports(GeneratorStatementType.SELECT); } @Override @@ -199,7 +212,7 @@ implements @Override public final Field generatedAlwaysAs() { Generator s = generatedAlwaysAsGenerator(); - return s == null ? null : s.apply(new DefaultGeneratorContext(CONFIG, null)); + return s == null ? null : s.apply(new DefaultGeneratorContext(CONFIG, null, null)); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 0a919ce07c..33044cf154 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -6276,8 +6276,8 @@ public class DSL { * * H2 * H2 natively supports this special syntax - * www.h2database.com/html/grammar.html#merge + * https://www.h2database.com/html/commands.html#merge_into * * * DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultGeneratorContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultGeneratorContext.java index 9f78b7641c..95bbeed250 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultGeneratorContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultGeneratorContext.java @@ -38,22 +38,30 @@ package org.jooq.impl; import org.jooq.Configuration; +import org.jooq.Field; import org.jooq.GeneratorContext; import org.jooq.GeneratorStatementType; /** * @author Lukas Eder */ -final class DefaultGeneratorContext extends AbstractScope implements GeneratorContext { +final class DefaultGeneratorContext extends AbstractScope implements GeneratorContext { + final Field field; final GeneratorStatementType statementType; - DefaultGeneratorContext(Configuration configuration, GeneratorStatementType statementType) { + DefaultGeneratorContext(Configuration configuration, Field field, GeneratorStatementType statementType) { super(configuration); + this.field = field; this.statementType = statementType; } + @Override + public final Field field() { + return field; + } + @Override public final GeneratorStatementType statementType() { return statementType; diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java index d65d284e52..b4695f0100 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java @@ -80,6 +80,7 @@ import static org.jooq.impl.DSL.table; import static org.jooq.impl.DSL.when; import static org.jooq.impl.Keywords.K_ROW; import static org.jooq.impl.Tools.anyMatch; +import static org.jooq.impl.Tools.apply; import static org.jooq.impl.Tools.collect; import static org.jooq.impl.Tools.fieldName; import static org.jooq.impl.Tools.filter; diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java index c1b1d7de95..c75b5af39a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java @@ -270,6 +270,23 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple + + + + + + + + + + + + + + + + +