[jOOQ/jOOQ#1592] [jOOQ/jOOQ#9879] AuditGenerator improvements

- Added DataType::computedOnClientStoredOn
- Improved DataType Javadoc
- AuditGenerator can accept multiple GeneratorStatementType
- Made GeneratorContext<T> generic
- Added GeneratorContext.field()
This commit is contained in:
Lukas Eder 2022-04-14 14:26:01 +02:00
parent bd064a7be9
commit 1b4f2ba690
18 changed files with 640 additions and 76 deletions

View File

@ -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 <forcedType/>. Either <name/>, <userType/>, <generator/>, or <visibilityModifier/> 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 <forcedType/>. Any of <name/>, <userType/>, <generator/>, <auditInsertTimestamp/>, <auditInsertUser/>, <auditUpdateTimestamp/>, <auditUpdateUser/>, or <visibilityModifier/> is required: " + type);
it2.remove();
continue;
}
else if (!commercial()) {
log.warn("<visibilityModifier/> is a commercial only feature. Please upgrade to the jOOQ Professional Edition or jOOQ Enterprise Edition: " + type);
log.warn("<generator/>, <auditInsertTimestamp/>, <auditInsertUser/>, <auditUpdateTimestamp/>, <auditUpdateUser/>, and <visibilityModifier/> 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 <forcedType/>. Either <binding/>, <converter/>, <enumConverter/>, <lambdaConverter/>, or <generator/> is required: " + type);

View File

@ -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<T extends Definition>
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<T extends Definition>
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<T extends Definition>
binding = customType.getBinding();
}
if (uType != null) {
db.markUsed(forcedType);
log.info("Forcing type", child + " to " + forcedType);
@ -360,6 +391,10 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
.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());

View File

@ -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()));

View File

@ -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.
* <p>
* This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
* <p>
* 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.
* <p>
* This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
* <p>
* 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.
* <p>
* This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
* <p>
* 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.
* <p>
* This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
* <p>
* 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()));

View File

@ -1393,6 +1393,54 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
</appinfo>
</annotation>
</element>
<element name="auditInsertTimestamp" type="boolean" minOccurs="0" maxOccurs="1">
<annotation>
<appinfo>
<jxb:property>
<jxb:javadoc><![CDATA[@deprecated Use ForcedType only]]></jxb:javadoc>
</jxb:property>
<annox:annotate target="getter">@java.lang.Deprecated</annox:annotate>
<annox:annotate target="setter">@java.lang.Deprecated</annox:annotate>
</appinfo>
</annotation>
</element>
<element name="auditInsertUser" type="boolean" minOccurs="0" maxOccurs="1">
<annotation>
<appinfo>
<jxb:property>
<jxb:javadoc><![CDATA[@deprecated Use ForcedType only]]></jxb:javadoc>
</jxb:property>
<annox:annotate target="getter">@java.lang.Deprecated</annox:annotate>
<annox:annotate target="setter">@java.lang.Deprecated</annox:annotate>
</appinfo>
</annotation>
</element>
<element name="auditUpdateTimestamp" type="boolean" minOccurs="0" maxOccurs="1">
<annotation>
<appinfo>
<jxb:property>
<jxb:javadoc><![CDATA[@deprecated Use ForcedType only]]></jxb:javadoc>
</jxb:property>
<annox:annotate target="getter">@java.lang.Deprecated</annox:annotate>
<annox:annotate target="setter">@java.lang.Deprecated</annox:annotate>
</appinfo>
</annotation>
</element>
<element name="auditUpdateUser" type="boolean" minOccurs="0" maxOccurs="1">
<annotation>
<appinfo>
<jxb:property>
<jxb:javadoc><![CDATA[@deprecated Use ForcedType only]]></jxb:javadoc>
</jxb:property>
<annox:annotate target="getter">@java.lang.Deprecated</annox:annotate>
<annox:annotate target="setter">@java.lang.Deprecated</annox:annotate>
</appinfo>
</annotation>
</element>
<element name="converter" type="string" minOccurs="0" maxOccurs="1">
<annotation>
@ -1542,6 +1590,38 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
<p>
This has no effect on matched objects that are not columns.
<p>
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="auditInsertTimestamp" type="boolean" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#INSERT} timestamp.
<p>
This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
<p>
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="auditInsertUser" type="boolean" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#INSERT} timestamp.
<p>
This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
<p>
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="auditUpdateTimestamp" type="boolean" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#UPDATE} timestamp.
<p>
This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
<p>
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="auditUpdateUser" type="boolean" minOccurs="0" maxOccurs="1">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Whether this column acts as an audit {@link org.jooq.GeneratorStatementType#UPDATE} timestamp.
<p>
This flag produces a {@link #generator} configuration, so it cannot be combined with a custom generator. The different audit flags are mutually exclusive.
<p>
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>

View File

@ -8599,8 +8599,8 @@ public interface DSLContext extends Scope {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href="http://www.h2database.com/html/grammar.html#merge"
* >http://www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>HANA</td>

View File

@ -506,7 +506,8 @@ public interface DataType<T> extends Named {
* This is true only if all of these hold true:
* <ul>
* <li>{@link #computed()}</li>
* <li>{@link #generationLocation()} == {@link GenerationLocation#CLIENT}</li>
* <li>{@link #generationLocation()} ==
* {@link GenerationLocation#CLIENT}</li>
* <p>
* This feature is implemented in commercial distributions only.
*/
@ -518,8 +519,13 @@ public interface DataType<T> extends Named {
* This is true only if all of these hold true:
* <ul>
* <li>{@link #computed()}</li>
* <li>{@link #generationLocation()} == {@link GenerationLocation#CLIENT}</li>
* <li>{@link #generationLocation()} ==
* {@link GenerationLocation#CLIENT}</li>
* <li>{@link #generationOption()} == {@link GenerationOption#STORED}</li>
* <li>{@link #generatedAlwaysAsGenerator()} produces a generator that
* {@link Generator#supports(GeneratorStatementType)} any of
* {@link GeneratorStatementType#INSERT} or
* {@link GeneratorStatementType#UPDATE}</li>
* <p>
* This feature is implemented in commercial distributions only.
*/
@ -531,8 +537,29 @@ public interface DataType<T> extends Named {
* This is true only if all of these hold true:
* <ul>
* <li>{@link #computed()}</li>
* <li>{@link #generationLocation()} == {@link GenerationLocation#CLIENT}</li>
* <li>{@link #generationLocation()} ==
* {@link GenerationLocation#CLIENT}</li>
* <li>{@link #generationOption()} == {@link GenerationOption#STORED}</li>
* <li>{@link #generatedAlwaysAsGenerator()} produces a generator that
* {@link Generator#supports(GeneratorStatementType)} the argument
* <code>statementType</code></li>
* <p>
* This feature is implemented in commercial distributions only.
*/
boolean computedOnClientStoredOn(GeneratorStatementType statementType);
/**
* Whether this column is computed on the client.
* <p>
* This is true only if all of these hold true:
* <ul>
* <li>{@link #computed()}</li>
* <li>{@link #generationLocation()} ==
* {@link GenerationLocation#CLIENT}</li>
* <li>{@link #generationOption()} == {@link GenerationOption#VIRTUAL}</li>
* <li>{@link #generatedAlwaysAsGenerator()} produces a generator that
* {@link Generator#supports(GeneratorStatementType)} the type
* {@link GeneratorStatementType#SELECT}</li>
* <p>
* This feature is implemented in commercial distributions only.
*/

View File

@ -1954,8 +1954,8 @@ extends
* <td><code>[search] REGEXP [pattern]</code></td>
* <td>Java</td>
* <td><a href=
* "http://www.h2database.com/html/grammar.html#condition_right_hand_side"
* >http
* "https://www.h2database.com/html/grammar.html#condition_right_hand_side"
* >https
* ://www.h2database.com/html/grammar.html#condition_right_hand_side</a></td>
* </tr>
* <tr>

View File

@ -50,4 +50,18 @@ import java.util.function.Function;
* @author Lukas Eder
*/
@FunctionalInterface
public interface Generator<T> extends Function<GeneratorContext, Field<T>>, Serializable {}
public interface Generator<T> extends Function<GeneratorContext<T>, Field<T>>, Serializable {
/**
* Whether this generator supports a given statement type.
* <p>
* 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;
}
}

View File

@ -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<T> extends Scope {
/**
* The target field whose contents are being generated, or <code>null</code>
* when the field is unknown / not applicable.
*/
@Nullable
Field<T> field();
/**
* The statement type in which the {@link Generator} is being invoked, or

View File

@ -135,8 +135,8 @@ public interface MergeUsingStep<R extends Record> extends MergeKeyStepN<R> {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>HANA</td>

View File

@ -846,7 +846,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
* <li><a href=
* "http://db.apache.org/derby/docs/10.7/ref/rrefsqlj31783.html"> Derby's
* FOR UPDATE clause</a></li>
* <li><a href="http://www.h2database.com/html/grammar.html#select">H2's FOR
* <li><a href="https://www.h2database.com/html/grammar.html#select">H2's FOR
* UPDATE clause</a></li>
* <li><a href=
* "http://www.hsqldb.org/doc/2.0/guide/dataaccess-chapt.html#N11DA9"

View File

@ -2797,8 +2797,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2823,8 +2823,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2849,8 +2849,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2875,8 +2875,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2901,8 +2901,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2927,8 +2927,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2953,8 +2953,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -2979,8 +2979,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3005,8 +3005,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3031,8 +3031,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3057,8 +3057,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3083,8 +3083,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3109,8 +3109,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3135,8 +3135,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3161,8 +3161,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3187,8 +3187,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3213,8 +3213,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3239,8 +3239,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3265,8 +3265,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3291,8 +3291,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3317,8 +3317,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3343,8 +3343,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>
@ -3371,8 +3371,8 @@ public interface WithStep extends QueryPart {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href= "https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>

View File

@ -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<T> generatedAlwaysAs() {
Generator<T> s = generatedAlwaysAsGenerator();
return s == null ? null : s.apply(new DefaultGeneratorContext(CONFIG, null));
return s == null ? null : s.apply(new DefaultGeneratorContext(CONFIG, null, null));
}
@Override

View File

@ -6276,8 +6276,8 @@ public class DSL {
* <tr>
* <td>H2</td>
* <td>H2 natively supports this special syntax</td>
* <td><a href= "www.h2database.com/html/grammar.html#merge"
* >www.h2database.com/html/grammar.html#merge</a></td>
* <td><a href="https://www.h2database.com/html/commands.html#merge_into"
* >https://www.h2database.com/html/commands.html#merge_into</a></td>
* </tr>
* <tr>
* <td>DB2, HSQLDB, Oracle, SQL Server, Sybase SQL Anywhere</td>

View File

@ -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<T> extends AbstractScope implements GeneratorContext<T> {
final Field<T> field;
final GeneratorStatementType statementType;
DefaultGeneratorContext(Configuration configuration, GeneratorStatementType statementType) {
DefaultGeneratorContext(Configuration configuration, Field<T> field, GeneratorStatementType statementType) {
super(configuration);
this.field = field;
this.statementType = statementType;
}
@Override
public final Field<T> field() {
return field;
}
@Override
public final GeneratorStatementType statementType() {
return statementType;

View File

@ -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;

View File

@ -270,6 +270,23 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple