[jOOQ/jOOQ#9879] Add support for client side GENERATED ALWAYS AS - WIP
This commit is contained in:
parent
11dbdbb75e
commit
02df3dced5
@ -548,7 +548,7 @@ class GenerationUtil {
|
||||
}
|
||||
|
||||
static ExpressionType expressionType(String expression) {
|
||||
if (TYPE_REFERENCE_PATTERN.matcher(expression).matches())
|
||||
if (!"null".equals(expression) && TYPE_REFERENCE_PATTERN.matcher(expression).matches())
|
||||
return CONSTRUCTOR_REFERENCE;
|
||||
else
|
||||
return EXPRESSION;
|
||||
|
||||
@ -5796,6 +5796,20 @@ public class JavaGenerator extends AbstractGenerator {
|
||||
final String columnName = column.getName();
|
||||
final List<String> converter = out.ref(list(column.getType(resolver(out)).getConverter()));
|
||||
final List<String> binding = out.ref(list(column.getType(resolver(out)).getBinding()));
|
||||
final List<String> generator = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
final String columnVisibility =
|
||||
|
||||
|
||||
@ -5807,19 +5821,19 @@ public class JavaGenerator extends AbstractGenerator {
|
||||
out.javadoc("The column <code>%s</code>.[[before= ][%s]]", column.getQualifiedOutputName(), list(escapeEntities(comment(column))));
|
||||
|
||||
if (scala) {
|
||||
out.println("%sval %s: %s[%s, %s] = createField(%s.name(\"%s\"), %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ")",
|
||||
columnVisibility, scalaWhitespaceSuffix(columnId), TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding);
|
||||
out.println("%sval %s: %s[%s, %s] = createField(%s.name(\"%s\"), %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + converterTemplate(generator) + ")",
|
||||
columnVisibility, scalaWhitespaceSuffix(columnId), TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding, generator);
|
||||
}
|
||||
else if (kotlin) {
|
||||
out.println("%sval %s: %s<%s, %s?> = createField(%s.name(\"%s\"), %s, this, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ")",
|
||||
columnVisibility, columnId, TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding);
|
||||
out.println("%sval %s: %s<%s, %s?> = createField(%s.name(\"%s\"), %s, this, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + converterTemplate(generator) + ")",
|
||||
columnVisibility, columnId, TableField.class, recordType, columnType, DSL.class, columnName, columnTypeRef, escapeString(comment(column)), converter, binding, generator);
|
||||
}
|
||||
else {
|
||||
String isStatic = generateInstanceFields() ? "" : "static ";
|
||||
String tableRef = generateInstanceFields() ? "this" : out.ref(getStrategy().getJavaIdentifier(table), 2);
|
||||
|
||||
out.println("%s%sfinal %s<%s, %s> %s = createField(%s.name(\"%s\"), %s, %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + ");",
|
||||
columnVisibility, isStatic, TableField.class, recordType, columnType, columnId, DSL.class, columnName, columnTypeRef, tableRef, escapeString(comment(column)), converter, binding);
|
||||
out.println("%s%sfinal %s<%s, %s> %s = createField(%s.name(\"%s\"), %s, %s, \"%s\"" + converterTemplate(converter) + converterTemplate(binding) + converterTemplate(generator) + ");",
|
||||
columnVisibility, isStatic, TableField.class, recordType, columnType, columnId, DSL.class, columnName, columnTypeRef, tableRef, escapeString(comment(column)), converter, binding, generator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1403,8 +1403,8 @@ public abstract class AbstractDatabase implements Database {
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(type.getName())) {
|
||||
if (StringUtils.isBlank(type.getUserType())) {
|
||||
log.warn("Bad configuration for <forcedType/>. Either <name/> or <userType/> is required: " + type);
|
||||
if (StringUtils.isBlank(type.getUserType()) && StringUtils.isBlank(type.getGenerator())) {
|
||||
log.warn("Bad configuration for <forcedType/>. Either <name/>, <userType/>, or <generator/> is required: " + type);
|
||||
|
||||
it2.remove();
|
||||
continue;
|
||||
@ -1412,9 +1412,10 @@ public abstract class AbstractDatabase implements Database {
|
||||
|
||||
if (StringUtils.isBlank(type.getBinding()) &&
|
||||
StringUtils.isBlank(type.getConverter()) &&
|
||||
StringUtils.isBlank(type.getGenerator()) &&
|
||||
!Boolean.TRUE.equals(type.isEnumConverter()) &&
|
||||
type.getLambdaConverter() == null) {
|
||||
log.warn("Bad configuration for <forcedType/>. Either <binding/> or <converter/> or <enumConverter/> or <lambdaConverter/> is required: " + type);
|
||||
log.warn("Bad configuration for <forcedType/>. Either <binding/>, <converter/>, <enumConverter/>, <lambdaConverter/>, or <generator/> is required: " + type);
|
||||
|
||||
it2.remove();
|
||||
continue;
|
||||
|
||||
@ -210,6 +210,7 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
|
||||
ForcedType forcedType = db.getConfiguredForcedType(child, definedType);
|
||||
if (forcedType != null) {
|
||||
String uType = forcedType.getName();
|
||||
String generator = forcedType.getGenerator();
|
||||
String converter = null;
|
||||
String binding = result.getBinding();
|
||||
|
||||
@ -219,6 +220,9 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
|
||||
? customType.getType()
|
||||
: customType.getName();
|
||||
|
||||
if (generator == null)
|
||||
generator = customType.getGenerator();
|
||||
|
||||
// [#5877] [#6567] EnumConverters profit from simplified configuration
|
||||
if (Boolean.TRUE.equals(customType.isEnumConverter()) ||
|
||||
EnumConverter.class.getName().equals(customType.getConverter())) {
|
||||
@ -277,7 +281,7 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
|
||||
if (customType != null)
|
||||
log.warn("Custom type conflict", child + " has custom type " + customType + " forced by " + forcedType + " but a data type rewrite applies");
|
||||
|
||||
result = new DefaultDataTypeDefinition(db, child.getSchema(), uType, l, p, s, n, r, g, d, i, (Name) null, converter, binding, null);
|
||||
result = new DefaultDataTypeDefinition(db, child.getSchema(), uType, l, p, s, n, r, g, d, i, (Name) null, generator, converter, binding, null);
|
||||
}
|
||||
|
||||
// Other forced types are UDT's, enums, etc.
|
||||
@ -287,7 +291,7 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
|
||||
s = result.getScale();
|
||||
String t = result.getType();
|
||||
Name u = result.getQualifiedUserType();
|
||||
result = new DefaultDataTypeDefinition(db, definedType.getSchema(), t, l, p, s, n, r, g, d, i, u, converter, binding, uType);
|
||||
result = new DefaultDataTypeDefinition(db, definedType.getSchema(), t, l, p, s, n, r, g, d, i, u, generator, converter, binding, uType);
|
||||
}
|
||||
|
||||
// [#4597] If we don't have a type-rewrite (forcedDataType) or a
|
||||
@ -302,6 +306,9 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
|
||||
log.warn("Bad configuration for <forcedType/> " + forcedType.getName() + ". No matching <customType/> found, and no matching SQLDataType found: " + forcedType);
|
||||
}
|
||||
}
|
||||
|
||||
if (generator != null)
|
||||
((DefaultDataTypeDefinition) result).generator(generator);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -341,6 +348,7 @@ public abstract class AbstractTypedElementDefinition<T extends Definition>
|
||||
.withBinding(forcedType.getBinding())
|
||||
.withEnumConverter(forcedType.isEnumConverter())
|
||||
.withLambdaConverter(forcedType.getLambdaConverter())
|
||||
.withGenerator(forcedType.getGenerator())
|
||||
.withConverter(forcedType.getConverter())
|
||||
.withName(name)
|
||||
.withType(forcedType.getUserType());
|
||||
|
||||
@ -41,9 +41,12 @@ import java.util.List;
|
||||
|
||||
// ...
|
||||
import org.jooq.Name;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.meta.jaxb.ForcedType;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A definition for a data type object.
|
||||
*
|
||||
@ -56,16 +59,25 @@ public interface DataTypeDefinition {
|
||||
*/
|
||||
String getType();
|
||||
|
||||
/**
|
||||
* The generator type that is applied to this data type, or
|
||||
* <code>null</code>, if no such generator type is configured.
|
||||
*/
|
||||
@Nullable
|
||||
String getGenerator();
|
||||
|
||||
/**
|
||||
* The converter type that is applied to this data type, or
|
||||
* <code>null</code>, if no such converter type is configured.
|
||||
*/
|
||||
@Nullable
|
||||
String getConverter();
|
||||
|
||||
/**
|
||||
* The binding type that is applied to this data type, or
|
||||
* <code>null</code>, if no such binding type is configured.
|
||||
*/
|
||||
@Nullable
|
||||
String getBinding();
|
||||
|
||||
/**
|
||||
@ -131,6 +143,11 @@ public interface DataTypeDefinition {
|
||||
*/
|
||||
GenerationOption getGenerationOption();
|
||||
|
||||
/**
|
||||
* The computed column generation location.
|
||||
*/
|
||||
GenerationLocation getGenerationLocation();
|
||||
|
||||
/**
|
||||
* Whether this data type is an identity.
|
||||
*/
|
||||
|
||||
@ -51,6 +51,7 @@ import java.util.Set;
|
||||
|
||||
import org.jooq.Name;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
import org.jooq.tools.StringUtils;
|
||||
@ -71,6 +72,7 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
|
||||
private final String type;
|
||||
private final Name userType;
|
||||
private final String javaType;
|
||||
private String generator;
|
||||
private final String converter;
|
||||
private final String binding;
|
||||
private final boolean nullable;
|
||||
@ -196,6 +198,10 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
|
||||
}
|
||||
|
||||
public DefaultDataTypeDefinition(Database database, SchemaDefinition schema, String typeName, Number length, Number precision, Number scale, Boolean nullable, boolean readonly, String generatedAlwaysAs, String defaultValue, boolean identity, Name userType, String converter, String binding, String javaType) {
|
||||
this(database, schema, typeName, length, precision, scale, nullable, readonly, generatedAlwaysAs, defaultValue, identity, userType, null, converter, binding, javaType);
|
||||
}
|
||||
|
||||
public DefaultDataTypeDefinition(Database database, SchemaDefinition schema, String typeName, Number length, Number precision, Number scale, Boolean nullable, boolean readonly, String generatedAlwaysAs, String defaultValue, boolean identity, Name userType, String generator, String converter, String binding, String javaType) {
|
||||
this.database = database;
|
||||
this.schema = schema;
|
||||
|
||||
@ -203,6 +209,7 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
|
||||
this.type = typeName == null ? "OTHER" : typeName;
|
||||
this.userType = userType;
|
||||
this.javaType = javaType;
|
||||
this.generator = generator;
|
||||
this.converter = converter;
|
||||
this.binding = binding;
|
||||
|
||||
@ -228,6 +235,9 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
|
||||
this.generatedAlwaysAs = generatedAlwaysAs;
|
||||
this.defaultValue = defaultValue;
|
||||
this.identity = identity;
|
||||
|
||||
if (generator != null)
|
||||
database.create().configuration().commercial(() -> "Client side computed columns are a commercial only feature. Please consider upgrading to the jOOQ Professional Edition or jOOQ Enterprise Edition.");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -284,6 +294,21 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
|
||||
return generationOption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenerationLocation getGenerationLocation() {
|
||||
return generator == null ? GenerationLocation.SERVER : GenerationLocation.CLIENT;
|
||||
}
|
||||
|
||||
private static final JooqLogger logGenerator = JooqLogger.getLogger(DefaultDataTypeDefinition.class, "logGenerator", 1);
|
||||
|
||||
public final DefaultDataTypeDefinition generator(String g) {
|
||||
if (g != null && !database.create().configuration().commercial())
|
||||
logGenerator.info("Computed columns", "Client side computed columns are a commercial only jOOQ feature. If you wish to profit from this feature, please upgrade to the jOOQ Professional Edition");
|
||||
|
||||
this.generator = g;
|
||||
return this;
|
||||
}
|
||||
|
||||
public final DefaultDataTypeDefinition generationOption(GenerationOption go) {
|
||||
this.generationOption = go;
|
||||
return this;
|
||||
@ -335,6 +360,11 @@ public class DefaultDataTypeDefinition implements DataTypeDefinition {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getConverter() {
|
||||
return converter;
|
||||
|
||||
@ -36,6 +36,8 @@ public class CustomType implements Serializable, XMLAppendable
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String type;
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String generator;
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String converter;
|
||||
protected Boolean enumConverter;
|
||||
protected LambdaConverter lambdaConverter;
|
||||
@ -78,6 +80,24 @@ public class CustomType implements Serializable, XMLAppendable
|
||||
this.type = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use ForcedType only
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public String getGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use ForcedType only
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public void setGenerator(String value) {
|
||||
this.generator = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use ForcedType only
|
||||
*
|
||||
@ -178,6 +198,16 @@ public class CustomType implements Serializable, XMLAppendable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use ForcedType only
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public CustomType withGenerator(String value) {
|
||||
setGenerator(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use ForcedType only
|
||||
*
|
||||
@ -217,6 +247,7 @@ public class CustomType implements Serializable, XMLAppendable
|
||||
public final void appendTo(XMLBuilder builder) {
|
||||
builder.append("name", name);
|
||||
builder.append("type", type);
|
||||
builder.append("generator", generator);
|
||||
builder.append("converter", converter);
|
||||
builder.append("enumConverter", enumConverter);
|
||||
builder.append("lambdaConverter", lambdaConverter);
|
||||
@ -260,6 +291,15 @@ public class CustomType implements Serializable, XMLAppendable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (generator == null) {
|
||||
if (other.generator!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!generator.equals(other.generator)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (converter == null) {
|
||||
if (other.converter!= null) {
|
||||
return false;
|
||||
@ -305,6 +345,7 @@ public class CustomType implements Serializable, XMLAppendable
|
||||
int result = 1;
|
||||
result = ((prime*result)+((name == null)? 0 :name.hashCode()));
|
||||
result = ((prime*result)+((type == null)? 0 :type.hashCode()));
|
||||
result = ((prime*result)+((generator == null)? 0 :generator.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()));
|
||||
|
||||
@ -37,6 +37,8 @@ public class ForcedType implements Serializable, XMLAppendable
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String userType;
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String generator;
|
||||
@XmlJavaTypeAdapter(StringAdapter.class)
|
||||
protected String converter;
|
||||
protected Boolean enumConverter;
|
||||
protected LambdaConverter lambdaConverter;
|
||||
@ -119,6 +121,26 @@ public class ForcedType implements Serializable, XMLAppendable
|
||||
this.userType = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link org.jooq.Generator} implementation used for client-side computed columns.
|
||||
* <p>
|
||||
* This feature is available in the commercial distribution only.
|
||||
*
|
||||
*/
|
||||
public String getGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link org.jooq.Generator} implementation used for client-side computed columns.
|
||||
* <p>
|
||||
* This feature is available in the commercial distribution only.
|
||||
*
|
||||
*/
|
||||
public void setGenerator(String value) {
|
||||
this.generator = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A converter implementation for the {@link #getUserType()}.
|
||||
*
|
||||
@ -395,6 +417,17 @@ public class ForcedType implements Serializable, XMLAppendable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link org.jooq.Generator} implementation used for client-side computed columns.
|
||||
* <p>
|
||||
* This feature is available in the commercial distribution only.
|
||||
*
|
||||
*/
|
||||
public ForcedType withGenerator(String value) {
|
||||
setGenerator(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A converter implementation for the {@link #getUserType()}.
|
||||
*
|
||||
@ -529,6 +562,7 @@ public class ForcedType implements Serializable, XMLAppendable
|
||||
builder.append("priority", priority);
|
||||
builder.append("name", name);
|
||||
builder.append("userType", userType);
|
||||
builder.append("generator", generator);
|
||||
builder.append("converter", converter);
|
||||
builder.append("enumConverter", enumConverter);
|
||||
builder.append("lambdaConverter", lambdaConverter);
|
||||
@ -591,6 +625,15 @@ public class ForcedType implements Serializable, XMLAppendable
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (generator == null) {
|
||||
if (other.generator!= null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!generator.equals(other.generator)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (converter == null) {
|
||||
if (other.converter!= null) {
|
||||
return false;
|
||||
@ -727,6 +770,7 @@ public class ForcedType implements Serializable, XMLAppendable
|
||||
result = ((prime*result)+((priority == null)? 0 :priority.hashCode()));
|
||||
result = ((prime*result)+((name == null)? 0 :name.hashCode()));
|
||||
result = ((prime*result)+((userType == null)? 0 :userType.hashCode()));
|
||||
result = ((prime*result)+((generator == null)? 0 :generator.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()));
|
||||
|
||||
@ -1339,6 +1339,18 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
|
||||
</annotation>
|
||||
</element>
|
||||
|
||||
<element name="generator" type="string" 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>
|
||||
<appinfo>
|
||||
@ -1473,6 +1485,12 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
|
||||
If provided, {@link #getName()} will be ignored, and either {@link #getConverter()}
|
||||
or {@link #getBinding()} is required]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="generator" type="string" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A {@link org.jooq.Generator} implementation used for client-side computed columns.
|
||||
<p>
|
||||
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="converter" type="string" minOccurs="0" maxOccurs="1">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[A converter implementation for the {@link #getUserType()}.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
|
||||
@ -77,9 +77,9 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jooq.Converters.UnknownType;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.DSL;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.impl.SQLDataType;
|
||||
import org.jooq.types.DayToSecond;
|
||||
@ -467,6 +467,32 @@ public interface DataType<T> extends Named {
|
||||
*/
|
||||
boolean readonly();
|
||||
|
||||
/**
|
||||
* Get the readonly attribute of this data type, combined with other flags
|
||||
* that influence readonly behaviour.
|
||||
* <p>
|
||||
* A column may be marked as {@link #readonly()} for various reasons,
|
||||
* including:
|
||||
* <ul>
|
||||
* <li>When it is marked as readonly explicitly by the code generator.</li>
|
||||
* <li>When it is marked as readonly implicitly because it's a computed
|
||||
* column with {@link #generationLocation()} being
|
||||
* {@link GenerationLocation#SERVER}.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Some columns are readonly for users, meaning users of the jOOQ API cannot
|
||||
* write to them, but jOOQ, internally, may still write to those columns.
|
||||
* Such columns may include:
|
||||
* <ul>
|
||||
* <li>Columns that are computed with {@link #generationLocation()} being
|
||||
* {@link GenerationLocation#CLIENT}</li>
|
||||
* <li>Columns used for optimistic locking</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
boolean readonlyInternal();
|
||||
|
||||
/**
|
||||
* Whether this column is computed.
|
||||
* <p>
|
||||
@ -475,7 +501,17 @@ public interface DataType<T> extends Named {
|
||||
boolean computed();
|
||||
|
||||
/**
|
||||
* Set the computed column expression of this data type.
|
||||
* Whether this column is computed on the client.
|
||||
* <p>
|
||||
* This is true only if {@link #computed()} and
|
||||
* {@link #generationLocation()} == {@link GenerationLocation#CLIENT}.
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
boolean computedOnClient();
|
||||
|
||||
/**
|
||||
* Set the computed column expression of this data type to a constant value.
|
||||
* <p>
|
||||
* This implicitly sets {@link #readonly()} to <code>true</code>.
|
||||
* <p>
|
||||
@ -486,7 +522,8 @@ public interface DataType<T> extends Named {
|
||||
DataType<T> generatedAlwaysAs(T generatedAlwaysAsValue);
|
||||
|
||||
/**
|
||||
* Set the computed column expression of this data type.
|
||||
* Set the computed column expression of this data type to a constant
|
||||
* expression.
|
||||
* <p>
|
||||
* This implicitly sets {@link #readonly()} to <code>true</code>.
|
||||
* <p>
|
||||
@ -496,14 +533,50 @@ public interface DataType<T> extends Named {
|
||||
@Support({ DERBY, FIREBIRD, H2, HSQLDB, MARIADB, MYSQL, POSTGRES })
|
||||
DataType<T> generatedAlwaysAs(Field<T> generatedAlwaysAsValue);
|
||||
|
||||
/**
|
||||
* Set the computed column expression of this data type to a dynamic
|
||||
* expression.
|
||||
* <p>
|
||||
* Unlike {@link #generatedAlwaysAs(Object)} and
|
||||
* {@link #generatedAlwaysAs(Field)}, which produce a constant value or
|
||||
* expression, this allows for generating a dynamic expression if used along
|
||||
* with {@link #generationLocation()} and {@link GenerationLocation#CLIENT},
|
||||
* in order to implement client side computed columns.
|
||||
* <p>
|
||||
* If {@link #generationLocation()} is {@link GenerationLocation#SERVER},
|
||||
* then this does not affect generated DML statements, and will be evaluated
|
||||
* only in DDL statements, when creating the table.
|
||||
* <p>
|
||||
* This implicitly sets {@link #readonly()} to <code>true</code>.
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
@NotNull
|
||||
DataType<T> generatedAlwaysAs(Generator<T> generatedAlwaysAsValue);
|
||||
|
||||
/**
|
||||
* Get the computed column expression of this data type, if any.
|
||||
* <p>
|
||||
* This eagerly evaluates the {@link #generatedAlwaysAsGenerator()}
|
||||
* generator, which may not produce the same expression upon execution of a
|
||||
* query, in case {@link #generationLocation()} is
|
||||
* {@link GenerationLocation#CLIENT}. The behaviour of
|
||||
* {@link GenerationLocation#SERVER} is not affected. The method has been
|
||||
* left unmodified for backwards compatibility with jOOQ 3.16.
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
@Nullable
|
||||
Field<T> generatedAlwaysAs();
|
||||
|
||||
/**
|
||||
* Get the computed column expression of this data type, if any.
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
@Nullable
|
||||
Generator<T> generatedAlwaysAsGenerator();
|
||||
|
||||
/**
|
||||
* Set the {@link #generationOption()} of the computed column expression to
|
||||
* {@link GenerationOption#STORED}.
|
||||
@ -549,6 +622,46 @@ public interface DataType<T> extends Named {
|
||||
@Support
|
||||
GenerationOption generationOption();
|
||||
|
||||
/**
|
||||
* Set the {@link #generationLocation()} of the computed column expression.
|
||||
* <p>
|
||||
* Specifies whether the {@link #generatedAlwaysAs()} expression is computed
|
||||
* on the {@link GenerationLocation#SERVER} (by default) or in the
|
||||
* {@link GenerationLocation#CLIENT}. The latter is supported in all
|
||||
* dialects, the former only in relevant dialects.
|
||||
* <p>
|
||||
* The computation happens in {@link Insert}, {@link Update}, or
|
||||
* {@link Merge} statements in case {@link #generationOption()} is
|
||||
* {@link GenerationOption#STORED}, or in {@link Select} in case the
|
||||
* {@link #generationOption()} is {@link GenerationOption#VIRTUAL}.
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
@NotNull
|
||||
@Support
|
||||
DataType<T> generationLocation(GenerationLocation generationOption);
|
||||
|
||||
/**
|
||||
* Get the {@link GenerationLocation} of the computed column expression of
|
||||
* this data type, if any.
|
||||
* <p>
|
||||
* Specifies whether the {@link #generatedAlwaysAs()} expression is computed
|
||||
* on the {@link GenerationLocation#SERVER} (by default) or in the
|
||||
* {@link GenerationLocation#CLIENT}. The latter is supported in all
|
||||
* dialects, the former only in relevant dialects.
|
||||
* <p>
|
||||
* The computation happens in {@link Insert}, {@link Update}, or
|
||||
* {@link Merge} statements in case {@link #generationOption()} is
|
||||
* {@link GenerationOption#STORED}, or in {@link Select} in case the
|
||||
* {@link #generationOption()} is {@link GenerationOption#VIRTUAL}.
|
||||
* <p>
|
||||
* <p>
|
||||
* This feature is implemented in commercial distributions only.
|
||||
*/
|
||||
@NotNull
|
||||
@Support
|
||||
GenerationLocation generationLocation();
|
||||
|
||||
/**
|
||||
* Synonym for {@link #nullable(boolean)}, passing <code>true</code> as an
|
||||
* argument.
|
||||
|
||||
48
jOOQ/src/main/java/org/jooq/Generator.java
Normal file
48
jOOQ/src/main/java/org/jooq/Generator.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A generator can be used with {@link DataType#generatedAlwaysAs(Generator)} to
|
||||
* implement dynamic, client side computed columns.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Generator<T> extends Supplier<Field<T>>, Serializable {}
|
||||
@ -195,8 +195,8 @@ abstract class AbstractDMLQuery<R extends Record> extends AbstractRowCountQuery
|
||||
|
||||
|
||||
|
||||
private final WithImpl with;
|
||||
private final Table<R> table;
|
||||
final WithImpl with;
|
||||
final Table<R> table;
|
||||
final SelectFieldList<SelectFieldOrAsterisk> returning;
|
||||
final List<Field<?>> returningResolvedAsterisks;
|
||||
Result<Record> returnedResult;
|
||||
|
||||
@ -70,6 +70,7 @@ import java.time.OffsetTime;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
// ...
|
||||
// ...
|
||||
@ -85,6 +86,7 @@ import org.jooq.Domain;
|
||||
import org.jooq.EmbeddableRecord;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Geography;
|
||||
import org.jooq.Geometry;
|
||||
import org.jooq.JSON;
|
||||
@ -98,11 +100,13 @@ import org.jooq.Result;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.XML;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.impl.QOM.UEmpty;
|
||||
import org.jooq.types.Interval;
|
||||
import org.jooq.types.UNumber;
|
||||
|
||||
import jakarta.persistence.GenerationType;
|
||||
// ...
|
||||
|
||||
/**
|
||||
@ -149,12 +153,22 @@ implements
|
||||
@Override
|
||||
public abstract boolean readonly();
|
||||
|
||||
@Override
|
||||
public final boolean readonlyInternal() {
|
||||
return readonly() && !computedOnClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract DataType<T> readonly(boolean r);
|
||||
|
||||
@Override
|
||||
public final boolean computed() {
|
||||
return generatedAlwaysAs() != null;
|
||||
return generatedAlwaysAsGenerator() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean computedOnClient() {
|
||||
return computed() && generationLocation() == GenerationLocation.CLIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -163,10 +177,21 @@ implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract DataType<T> generatedAlwaysAs(Field<T> generatedAlwaysAsValue);
|
||||
public final DataType<T> generatedAlwaysAs(Field<T> generatedAlwaysAsValue) {
|
||||
return generatedAlwaysAs(() -> generatedAlwaysAsValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Field<T> generatedAlwaysAs();
|
||||
public abstract DataType<T> generatedAlwaysAs(Generator<T> generatedAlwaysAsValue);
|
||||
|
||||
@Override
|
||||
public final Field<T> generatedAlwaysAs() {
|
||||
Generator<T> s = generatedAlwaysAsGenerator();
|
||||
return s == null ? null : s.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Generator<T> generatedAlwaysAsGenerator();
|
||||
|
||||
@Override
|
||||
public final DataType<T> stored() {
|
||||
@ -184,6 +209,12 @@ implements
|
||||
@Override
|
||||
public abstract GenerationOption generationOption();
|
||||
|
||||
@Override
|
||||
public abstract DataType<T> generationLocation(GenerationLocation generationLocation);
|
||||
|
||||
@Override
|
||||
public abstract GenerationLocation generationLocation();
|
||||
|
||||
@Override
|
||||
public abstract DataType<T> collation(Collation c);
|
||||
|
||||
|
||||
@ -40,13 +40,17 @@ package org.jooq.impl;
|
||||
import static org.jooq.Nullability.NOT_NULL;
|
||||
import static org.jooq.impl.Tools.CONFIG;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jooq.CharacterSet;
|
||||
import org.jooq.Collation;
|
||||
import org.jooq.Comment;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
|
||||
@ -69,8 +73,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
Integer newLength,
|
||||
Nullability newNullability,
|
||||
boolean newReadonly,
|
||||
Field<T> newGeneratedAlwaysAs,
|
||||
Generator<T> newGeneratedAlwaysAs,
|
||||
GenerationOption newGenerationOption,
|
||||
GenerationLocation newGenerationLocation,
|
||||
Collation newCollation,
|
||||
CharacterSet newCharacterSet,
|
||||
boolean newIdentity,
|
||||
@ -85,8 +90,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
n,
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
!n.nullable() && identity(),
|
||||
@ -105,8 +111,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
r,
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
@ -117,7 +124,7 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
private static final JooqLogger logGeneratedAlwaysAs = JooqLogger.getLogger(AbstractDataTypeX.class, "generateAlwaysAs", 1);
|
||||
|
||||
@Override
|
||||
public final DataType<T> generatedAlwaysAs(Field<T> g) {
|
||||
public final DataType<T> generatedAlwaysAs(Generator<T> g) {
|
||||
if (g != null && !CONFIG.commercial())
|
||||
logGeneratedAlwaysAs.info("Computed columns", "Computed columns are a commercial only jOOQ feature. If you wish to profit from this feature, please upgrade to the jOOQ Professional Edition");
|
||||
|
||||
@ -129,6 +136,7 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
g != null ? true : readonly(),
|
||||
g,
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
@ -147,7 +155,29 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
g,
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
defaultValue()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DataType<T> generationLocation(GenerationLocation g) {
|
||||
if (g != null && !CONFIG.commercial())
|
||||
logGeneratedAlwaysAs.info("Computed columns", "Computed columns are a commercial only jOOQ feature. If you wish to profit from this feature, please upgrade to the jOOQ Professional Edition");
|
||||
|
||||
return construct(
|
||||
precision0(),
|
||||
scale0(),
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
g,
|
||||
collation(),
|
||||
characterSet(),
|
||||
@ -164,8 +194,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
c,
|
||||
characterSet(),
|
||||
identity(),
|
||||
@ -181,8 +212,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
c,
|
||||
identity(),
|
||||
@ -198,8 +230,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
i ? NOT_NULL : nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
i,
|
||||
@ -215,8 +248,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
d != null ? null : generatedAlwaysAs(),
|
||||
d != null ? null : generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
@ -232,8 +266,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
@ -249,8 +284,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
length0(),
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
@ -266,8 +302,9 @@ abstract class AbstractDataTypeX<T> extends AbstractDataType<T> {
|
||||
l,
|
||||
nullability(),
|
||||
readonly(),
|
||||
generatedAlwaysAs(),
|
||||
generatedAlwaysAsGenerator(),
|
||||
generationOption(),
|
||||
generationLocation(),
|
||||
collation(),
|
||||
characterSet(),
|
||||
identity(),
|
||||
|
||||
@ -87,6 +87,7 @@ import org.jooq.DataType;
|
||||
import org.jooq.DivideByOnStep;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.ForeignKey;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Identity;
|
||||
import org.jooq.Index;
|
||||
import org.jooq.JoinType;
|
||||
@ -118,6 +119,7 @@ import org.jooq.TablePartitionByStep;
|
||||
import org.jooq.UniqueKey;
|
||||
// ...
|
||||
// ...
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -756,16 +758,30 @@ abstract class AbstractTable<R extends Record> extends AbstractNamed implements
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static final <R extends Record, T, X, U> TableField<R, U> createField(Name name, DataType<T> type, Table<R> table, String comment, Converter<X, U> converter, Binding<T, X> binding) {
|
||||
final Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
|
||||
final DataType<U> actualType =
|
||||
return createField(name, type, table, comment, converter, binding, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may call this method to create {@link TableField} objects that
|
||||
* are linked to this table.
|
||||
*
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static final <R extends Record, T, X, U> TableField<R, U> createField(Name name, DataType<T> type, Table<R> table, String comment, Converter<X, U> converter, Binding<T, X> binding, Generator<U> generator) {
|
||||
Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
|
||||
DataType<U> actualType =
|
||||
converter == null && binding == null
|
||||
? (DataType<U>) type
|
||||
: type.asConvertedDataType(actualBinding);
|
||||
|
||||
if (generator != null)
|
||||
actualType = actualType.generatedAlwaysAs(generator).generationLocation(GenerationLocation.CLIENT);
|
||||
|
||||
// [#5999] TODO: Allow for user-defined Names
|
||||
final TableFieldImpl<R, U> tableField = new TableFieldImpl<>(name, actualType, table, DSL.comment(comment), actualBinding);
|
||||
TableFieldImpl<R, U> tableField = new TableFieldImpl<>(name, actualType, table, DSL.comment(comment), actualBinding);
|
||||
|
||||
// [#1199] The public API of Table returns immutable field lists
|
||||
if (table instanceof TableImpl)
|
||||
|
||||
@ -38,15 +38,16 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Tools.CONFIG;
|
||||
import static org.jooq.impl.Tools.CTX;
|
||||
|
||||
import org.jooq.CharacterSet;
|
||||
import org.jooq.Collation;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
|
||||
/**
|
||||
@ -75,14 +76,15 @@ final class ArrayDataType<T> extends DefaultDataType<T[]> {
|
||||
Integer length,
|
||||
Nullability nullability,
|
||||
boolean readonly,
|
||||
Field<T[]> generatedAlwaysAs,
|
||||
Generator<T[]> generatedAlwaysAs,
|
||||
GenerationOption generationOption,
|
||||
GenerationLocation generationLocation,
|
||||
Collation collation,
|
||||
CharacterSet characterSet,
|
||||
boolean identity,
|
||||
Field<T[]> defaultValue
|
||||
) {
|
||||
super(t, precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, collation, characterSet, identity, defaultValue);
|
||||
super(t, precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, generationLocation, collation, characterSet, identity, defaultValue);
|
||||
|
||||
this.elementType = elementType;
|
||||
}
|
||||
@ -95,8 +97,9 @@ final class ArrayDataType<T> extends DefaultDataType<T[]> {
|
||||
Integer newLength,
|
||||
Nullability newNullability,
|
||||
boolean newReadonly,
|
||||
Field<T[]> newGeneratedAlwaysAs,
|
||||
Generator<T[]> newGeneratedAlwaysAs,
|
||||
GenerationOption newGenerationOption,
|
||||
GenerationLocation newGenerationLocation,
|
||||
Collation newCollation,
|
||||
CharacterSet newCharacterSet,
|
||||
boolean newIdentity,
|
||||
@ -112,6 +115,7 @@ final class ArrayDataType<T> extends DefaultDataType<T[]> {
|
||||
newReadonly,
|
||||
newGeneratedAlwaysAs,
|
||||
newGenerationOption,
|
||||
newGenerationLocation,
|
||||
newCollation,
|
||||
newCharacterSet,
|
||||
newIdentity,
|
||||
|
||||
@ -48,6 +48,7 @@ import org.jooq.Converter;
|
||||
import org.jooq.Converters;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
@ -55,11 +56,9 @@ import org.jooq.Row;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.DefaultBinding.InternalBinding;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A <code>DataType</code> used for converted types using {@link Converter}
|
||||
*
|
||||
@ -89,8 +88,9 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
|
||||
Integer newLength,
|
||||
Nullability newNullability,
|
||||
boolean newReadonly,
|
||||
Field<U> newGeneratedAlwaysAs,
|
||||
Generator<U> newGeneratedAlwaysAs,
|
||||
GenerationOption newGenerationOption,
|
||||
GenerationLocation newGenerationLocation,
|
||||
Collation newCollation,
|
||||
CharacterSet newCharacterSet,
|
||||
boolean newIdentity,
|
||||
@ -102,8 +102,9 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
|
||||
newLength,
|
||||
newNullability,
|
||||
newReadonly,
|
||||
(Field) newGeneratedAlwaysAs,
|
||||
(Generator) newGeneratedAlwaysAs,
|
||||
newGenerationOption,
|
||||
newGenerationLocation,
|
||||
newCollation,
|
||||
newCharacterSet,
|
||||
newIdentity,
|
||||
@ -209,8 +210,8 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<U> generatedAlwaysAs() {
|
||||
return (Field<U>) delegate.generatedAlwaysAs();
|
||||
public final Generator<U> generatedAlwaysAsGenerator() {
|
||||
return (Generator<U>) delegate.generatedAlwaysAsGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -218,6 +219,11 @@ final class ConvertedDataType<T, U> extends AbstractDataTypeX<U> {
|
||||
return delegate.generationOption();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GenerationLocation generationLocation() {
|
||||
return delegate.generationLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Collation collation() {
|
||||
return delegate.collation();
|
||||
|
||||
@ -45,9 +45,11 @@ import org.jooq.Collation;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
|
||||
/**
|
||||
@ -58,23 +60,25 @@ import org.jooq.impl.QOM.GenerationOption;
|
||||
*/
|
||||
final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
|
||||
private AbstractDataType<T> type;
|
||||
private final Integer overridePrecision;
|
||||
private final Integer overrideScale;
|
||||
private final Integer overrideLength;
|
||||
private final Nullability overrideNullability;
|
||||
private final Boolean overrideReadonly;
|
||||
private final Field<T> overrideGeneratedAlwaysAs;
|
||||
private final GenerationOption overrideGenerationOption;
|
||||
private final Collation overrideCollation;
|
||||
private final CharacterSet overrideCharacterSet;
|
||||
private final Boolean overrideIdentity;
|
||||
private final Field<T> overrideDefaultValue;
|
||||
private AbstractDataType<T> type;
|
||||
private final Integer overridePrecision;
|
||||
private final Integer overrideScale;
|
||||
private final Integer overrideLength;
|
||||
private final Nullability overrideNullability;
|
||||
private final Boolean overrideReadonly;
|
||||
private final Generator<T> overrideGeneratedAlwaysAs;
|
||||
private final GenerationOption overrideGenerationOption;
|
||||
private final GenerationLocation overrideGenerationLocation;
|
||||
private final Collation overrideCollation;
|
||||
private final CharacterSet overrideCharacterSet;
|
||||
private final Boolean overrideIdentity;
|
||||
private final Field<T> overrideDefaultValue;
|
||||
|
||||
DataTypeProxy(AbstractDataType<T> type) {
|
||||
this(type, null, null, null, null, null, null, null, null, null, null, null);
|
||||
this(type, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DataTypeProxy(
|
||||
AbstractDataType<T> type,
|
||||
Integer overridePrecision,
|
||||
@ -82,8 +86,9 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
Integer overrideLength,
|
||||
Nullability overrideNullability,
|
||||
Boolean overrideReadonly,
|
||||
Field<T> overrideGeneratedAlwaysAs,
|
||||
Generator<T> overrideGeneratedAlwaysAs,
|
||||
GenerationOption overrideGenerationOption,
|
||||
GenerationLocation overrideGenerationLocation,
|
||||
Collation overrideCollation,
|
||||
CharacterSet overrideCharacterSet,
|
||||
Boolean overrideIdentity,
|
||||
@ -99,6 +104,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
this.overrideReadonly = overrideReadonly;
|
||||
this.overrideGeneratedAlwaysAs = overrideGeneratedAlwaysAs;
|
||||
this.overrideGenerationOption = overrideGenerationOption;
|
||||
this.overrideGenerationLocation = overrideGenerationLocation;
|
||||
this.overrideCollation = overrideCollation;
|
||||
this.overrideCharacterSet = overrideCharacterSet;
|
||||
this.overrideIdentity = overrideIdentity;
|
||||
@ -159,6 +165,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -182,6 +189,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
r,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -190,12 +198,12 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> generatedAlwaysAs() {
|
||||
return defaultIfNull(overrideGeneratedAlwaysAs, type.generatedAlwaysAs());
|
||||
public final Generator<T> generatedAlwaysAsGenerator() {
|
||||
return defaultIfNull(overrideGeneratedAlwaysAs, type.generatedAlwaysAsGenerator());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DataType<T> generatedAlwaysAs(Field<T> g) {
|
||||
public final DataType<T> generatedAlwaysAs(Generator<T> g) {
|
||||
return new DataTypeProxy<>(
|
||||
this,
|
||||
overridePrecision,
|
||||
@ -205,6 +213,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
g,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -228,6 +237,31 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
g,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
overrideDefaultValue
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GenerationLocation generationLocation() {
|
||||
return defaultIfNull(overrideGenerationLocation, type.generationLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DataType<T> generationLocation(GenerationLocation g) {
|
||||
return new DataTypeProxy<>(
|
||||
this,
|
||||
overridePrecision,
|
||||
overrideScale,
|
||||
overrideLength,
|
||||
overrideNullability,
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
g,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -251,6 +285,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
c,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -274,6 +309,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
c,
|
||||
overrideIdentity,
|
||||
@ -297,6 +333,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
i,
|
||||
@ -320,6 +357,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -373,6 +411,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -396,6 +435,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
@ -419,6 +459,7 @@ final class DataTypeProxy<T> extends AbstractDataType<T> {
|
||||
overrideReadonly,
|
||||
overrideGeneratedAlwaysAs,
|
||||
overrideGenerationOption,
|
||||
overrideGenerationLocation,
|
||||
overrideCollation,
|
||||
overrideCharacterSet,
|
||||
overrideIdentity,
|
||||
|
||||
@ -94,6 +94,7 @@ import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// ...
|
||||
@ -105,6 +106,7 @@ import org.jooq.Converter;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.QualifiedRecord;
|
||||
@ -112,6 +114,7 @@ import org.jooq.SQLDialect;
|
||||
import org.jooq.exception.MappingException;
|
||||
import org.jooq.exception.SQLDialectNotSupportedException;
|
||||
import org.jooq.impl.DefaultBinding.InternalBinding;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
import org.jooq.types.UByte;
|
||||
import org.jooq.types.UInteger;
|
||||
@ -256,8 +259,9 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
|
||||
private final Nullability nullability;
|
||||
private final boolean readonly;
|
||||
private final Field<T> generatedAlwaysAs;
|
||||
private final Generator<T> generatedAlwaysAs;
|
||||
private final GenerationOption generationOption;
|
||||
private final GenerationLocation generationLocation;
|
||||
private final Collation collation;
|
||||
private final CharacterSet characterSet;
|
||||
private final boolean identity;
|
||||
@ -327,10 +331,10 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
}
|
||||
|
||||
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, Field<T> defaultValue) {
|
||||
this(dialect, sqlDataType, type, binding, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, false, null, GenerationOption.DEFAULT, null, null, false, defaultValue);
|
||||
this(dialect, sqlDataType, type, binding, qualifiedTypeName, typeName, castTypeName, precision, scale, length, nullability, false, null, GenerationOption.DEFAULT, GenerationLocation.SERVER, null, null, false, defaultValue);
|
||||
}
|
||||
|
||||
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, boolean readonly, Field<T> generatedAlwaysAs, GenerationOption generationOption, Collation collation, CharacterSet characterSet, boolean identity, Field<T> defaultValue) {
|
||||
DefaultDataType(SQLDialect dialect, DataType<T> sqlDataType, Class<T> type, Binding<?, T> binding, Name qualifiedTypeName, String typeName, String castTypeName, Integer precision, Integer scale, Integer length, Nullability nullability, boolean readonly, Generator<T> generatedAlwaysAs, GenerationOption generationOption, GenerationLocation generationLocation, Collation collation, CharacterSet characterSet, boolean identity, Field<T> defaultValue) {
|
||||
super(qualifiedTypeName, NO_COMMENT);
|
||||
|
||||
// Initialise final instance members
|
||||
@ -352,6 +356,7 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
this.readonly = readonly;
|
||||
this.generatedAlwaysAs = generatedAlwaysAs;
|
||||
this.generationOption = generationOption == null ? GenerationOption.DEFAULT : generationOption;
|
||||
this.generationLocation = generationLocation == null ? GenerationLocation.SERVER : generationLocation;
|
||||
this.collation = collation;
|
||||
this.characterSet = characterSet;
|
||||
this.identity = identity;
|
||||
@ -396,8 +401,9 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
Integer newLength,
|
||||
Nullability newNullability,
|
||||
boolean newReadonly,
|
||||
Field<T> newGeneratedAlwaysAs,
|
||||
Generator<T> newGeneratedAlwaysAs,
|
||||
GenerationOption newGenerationOption,
|
||||
GenerationLocation newGenerationLocation,
|
||||
Collation newCollation,
|
||||
CharacterSet newCharacterSet,
|
||||
boolean newIdentity,
|
||||
@ -412,6 +418,7 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
newReadonly,
|
||||
newGeneratedAlwaysAs,
|
||||
newGenerationOption,
|
||||
newGenerationLocation,
|
||||
newCollation,
|
||||
newCharacterSet,
|
||||
newIdentity,
|
||||
@ -429,8 +436,9 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
Integer length,
|
||||
Nullability nullability,
|
||||
boolean readonly,
|
||||
Field<T> generatedAlwaysAs,
|
||||
Generator<T> generatedAlwaysAs,
|
||||
GenerationOption generationOption,
|
||||
GenerationLocation generationLocation,
|
||||
Collation collation,
|
||||
CharacterSet characterSet,
|
||||
boolean identity,
|
||||
@ -451,6 +459,7 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
this.readonly = readonly;
|
||||
this.generatedAlwaysAs = generatedAlwaysAs;
|
||||
this.generationOption = generationOption;
|
||||
this.generationLocation = generationLocation;
|
||||
this.collation = collation;
|
||||
this.characterSet = characterSet;
|
||||
this.identity = identity;
|
||||
@ -491,7 +500,7 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Field<T> generatedAlwaysAs() {
|
||||
public final Generator<T> generatedAlwaysAsGenerator() {
|
||||
return generatedAlwaysAs;
|
||||
}
|
||||
|
||||
@ -500,6 +509,11 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
return generationOption;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GenerationLocation generationLocation() {
|
||||
return generationLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Collation collation() {
|
||||
return collation;
|
||||
@ -556,7 +570,7 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
|
||||
|
||||
// ... and then, set them back to the original value
|
||||
// [#2710] TODO: Remove this logic along with cached data types
|
||||
return dataType.construct(precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, collation, characterSet, identity, defaultValue);
|
||||
return dataType.construct(precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, generationLocation, collation, characterSet, identity, defaultValue);
|
||||
}
|
||||
|
||||
// If this is already the dialect's specific data type, return this
|
||||
|
||||
@ -65,8 +65,9 @@ final class DomainDataType<T> extends DefaultDataType<T> {
|
||||
baseType.lengthDefined() ? baseType.length() : null,
|
||||
baseType.nullability(),
|
||||
baseType.readonly(),
|
||||
baseType.generatedAlwaysAs(),
|
||||
baseType.generatedAlwaysAsGenerator(),
|
||||
baseType.generationOption(),
|
||||
baseType.generationLocation(),
|
||||
null, // TODO: Collation
|
||||
null, // TODO: CharacterSet (?)
|
||||
false,
|
||||
|
||||
@ -39,6 +39,7 @@ package org.jooq.impl;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.emptySet;
|
||||
import static org.jooq.Clause.FIELD_ROW;
|
||||
import static org.jooq.Clause.INSERT_SELECT;
|
||||
import static org.jooq.Clause.INSERT_VALUES;
|
||||
@ -49,9 +50,11 @@ import static org.jooq.SQLDialect.YUGABYTEDB;
|
||||
import static org.jooq.conf.WriteIfReadonly.IGNORE;
|
||||
import static org.jooq.conf.WriteIfReadonly.THROW;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.Keywords.K_DEFAULT_VALUES;
|
||||
import static org.jooq.impl.Keywords.K_VALUES;
|
||||
import static org.jooq.impl.QueryPartCollectionView.wrap;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.anyMatch;
|
||||
import static org.jooq.impl.Tools.collect;
|
||||
import static org.jooq.impl.Tools.filter;
|
||||
@ -64,10 +67,12 @@ import java.util.AbstractList;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -84,12 +89,15 @@ import org.jooq.Record;
|
||||
import org.jooq.RenderContext.CastMode;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SelectJoinStep;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.conf.WriteIfReadonly;
|
||||
import org.jooq.exception.DataTypeException;
|
||||
import org.jooq.impl.AbstractStoreQuery.UnknownField;
|
||||
import org.jooq.impl.QOM.UNotYetImplemented;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@ -124,6 +132,12 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
.end(INSERT_VALUES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Single record inserts can use the standard syntax in any dialect
|
||||
|
||||
|
||||
@ -171,13 +185,6 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -187,11 +194,7 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
|
||||
|
||||
case FIREBIRD: {
|
||||
ctx.formatSeparator()
|
||||
.start(INSERT_SELECT)
|
||||
.visit(insertSelect(ctx))
|
||||
.end(INSERT_SELECT);
|
||||
|
||||
toSQLInsertSelect(ctx, insertSelect(ctx));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -209,6 +212,38 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
}
|
||||
}
|
||||
|
||||
static final void toSQLInsertSelect(Context<?> ctx, Select<?> select) {
|
||||
ctx.formatSeparator()
|
||||
.start(INSERT_SELECT)
|
||||
.visit(select)
|
||||
.end(INSERT_SELECT);
|
||||
}
|
||||
|
||||
static final Set<Field<?>> keysAndComputedOnClient(Set<Field<?>> keys, Table<?> table) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -521,15 +556,15 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
return rows > 0;
|
||||
}
|
||||
|
||||
final List<Field<?>> toSQLReferenceKeys(Context<?> ctx) {
|
||||
final Set<Field<?>> toSQLReferenceKeys(Context<?> ctx) {
|
||||
|
||||
// [#1506] with DEFAULT VALUES, we might not have any columns to render
|
||||
if (!isExecutable())
|
||||
return emptyList();
|
||||
return emptySet();
|
||||
|
||||
// [#2995] Do not generate empty column lists.
|
||||
if (values.isEmpty())
|
||||
return emptyList();
|
||||
return emptySet();
|
||||
|
||||
// [#4629] Do not generate column lists for unknown columns
|
||||
unknownFields: {
|
||||
@ -537,11 +572,11 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple
|
||||
if (!(field instanceof UnknownField))
|
||||
break unknownFields;
|
||||
|
||||
return emptyList();
|
||||
return emptySet();
|
||||
}
|
||||
|
||||
// [#989] Avoid qualifying fields in INSERT field declaration
|
||||
List<Field<?>> fields = collect(removeReadonly(ctx, flattenCollection(values.keySet(), true, true), e -> e));
|
||||
Set<Field<?>> fields = keysAndComputedOnClient(keysFlattened(ctx), table);
|
||||
|
||||
if (!fields.isEmpty())
|
||||
ctx.sql(" (").visit(wrap(fields).qualify(false)).sql(')');
|
||||
|
||||
@ -67,6 +67,7 @@ import static org.jooq.impl.DSL.row;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.selectFrom;
|
||||
import static org.jooq.impl.DSL.selectOne;
|
||||
import static org.jooq.impl.FieldMapsForInsert.toSQLInsertSelect;
|
||||
import static org.jooq.impl.Keywords.K_DEFAULT;
|
||||
import static org.jooq.impl.Keywords.K_DEFAULT_VALUES;
|
||||
import static org.jooq.impl.Keywords.K_DO_NOTHING;
|
||||
@ -654,7 +655,7 @@ final class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
.sql(' ')
|
||||
.declareTables(true, c -> c.visit(table(c)));
|
||||
|
||||
List<Field<?>> fields = insertMaps.toSQLReferenceKeys(ctx);
|
||||
Set<Field<?>> fields = insertMaps.toSQLReferenceKeys(ctx);
|
||||
ctx.end(INSERT_INSERT_INTO);
|
||||
|
||||
|
||||
@ -691,11 +692,7 @@ final class InsertQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
|
||||
|
||||
// [#8353] TODO: Support overlapping embeddables
|
||||
ctx.formatSeparator()
|
||||
.start(INSERT_SELECT)
|
||||
.visit(s)
|
||||
.end(INSERT_SELECT);
|
||||
|
||||
toSQLInsertSelect(ctx, s);
|
||||
ctx.data().remove(DATA_INSERT_SELECT_WITHOUT_INSERT_COLUMN_LIST);
|
||||
ctx.data().remove(DATA_INSERT_SELECT);
|
||||
}
|
||||
|
||||
@ -49,10 +49,12 @@ import java.util.Map.Entry;
|
||||
import org.jooq.CharacterSet;
|
||||
import org.jooq.Collation;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
|
||||
/**
|
||||
@ -86,14 +88,15 @@ final class MultisetDataType<R extends Record> extends DefaultDataType<Result<R>
|
||||
Integer length,
|
||||
Nullability nullability,
|
||||
boolean readonly,
|
||||
Field<Result<R>> generatedAlwaysAs,
|
||||
Generator<Result<R>> generatedAlwaysAs,
|
||||
GenerationOption generationOption,
|
||||
GenerationLocation generationLocation,
|
||||
Collation collation,
|
||||
CharacterSet characterSet,
|
||||
boolean identity,
|
||||
Field<Result<R>> defaultValue
|
||||
) {
|
||||
super(t, precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, collation, characterSet, identity, defaultValue);
|
||||
super(t, precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, generationLocation, collation, characterSet, identity, defaultValue);
|
||||
|
||||
this.row = row;
|
||||
this.recordType = recordType;
|
||||
@ -107,8 +110,9 @@ final class MultisetDataType<R extends Record> extends DefaultDataType<Result<R>
|
||||
Integer newLength,
|
||||
Nullability newNullability,
|
||||
boolean newReadonly,
|
||||
Field<Result<R>> newGeneratedAlwaysAs,
|
||||
Generator<Result<R>> newGeneratedAlwaysAs,
|
||||
GenerationOption newGenerationOption,
|
||||
GenerationLocation newGenerationLocation,
|
||||
Collation newCollation,
|
||||
CharacterSet newCharacterSet,
|
||||
boolean newIdentity,
|
||||
@ -125,6 +129,7 @@ final class MultisetDataType<R extends Record> extends DefaultDataType<Result<R>
|
||||
newReadonly,
|
||||
newGeneratedAlwaysAs,
|
||||
newGenerationOption,
|
||||
newGenerationLocation,
|
||||
newCollation,
|
||||
newCharacterSet,
|
||||
newIdentity,
|
||||
|
||||
@ -5815,6 +5815,24 @@ public final class QOM {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>GenerationLocation</code> type.
|
||||
* <p>
|
||||
* Specify where a computed column should be computed, i.e. in the client or on the
|
||||
* server.
|
||||
*/
|
||||
public enum GenerationLocation {
|
||||
CLIENT(keyword("client")),
|
||||
SERVER(keyword("server")),
|
||||
;
|
||||
|
||||
final Keyword keyword;
|
||||
|
||||
private GenerationLocation(Keyword keyword) {
|
||||
this.keyword = keyword;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The <code>GenerationOption</code> type.
|
||||
* <p>
|
||||
|
||||
@ -40,7 +40,6 @@ package org.jooq.impl;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.jooq.impl.Tools.CONFIG;
|
||||
import static org.jooq.impl.Tools.CTX;
|
||||
import static org.jooq.impl.Tools.newRecord;
|
||||
import static org.jooq.impl.Tools.recordType;
|
||||
|
||||
@ -51,9 +50,11 @@ import java.util.Map.Entry;
|
||||
import org.jooq.CharacterSet;
|
||||
import org.jooq.Collation;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.Generator;
|
||||
import org.jooq.Nullability;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.Row;
|
||||
import org.jooq.impl.QOM.GenerationLocation;
|
||||
import org.jooq.impl.QOM.GenerationOption;
|
||||
|
||||
/**
|
||||
@ -88,14 +89,15 @@ final class RecordDataType<R extends Record> extends DefaultDataType<R> {
|
||||
Integer length,
|
||||
Nullability nullability,
|
||||
boolean readonly,
|
||||
Field<R> generatedAlwaysAs,
|
||||
Generator<R> generatedAlwaysAs,
|
||||
GenerationOption generationOption,
|
||||
GenerationLocation generationLocation,
|
||||
Collation collation,
|
||||
CharacterSet characterSet,
|
||||
boolean identity,
|
||||
Field<R> defaultValue
|
||||
) {
|
||||
super(t, precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, collation, characterSet, identity, defaultValue);
|
||||
super(t, precision, scale, length, nullability, readonly, generatedAlwaysAs, generationOption, generationLocation, collation, characterSet, identity, defaultValue);
|
||||
|
||||
this.row = row;
|
||||
}
|
||||
@ -108,8 +110,9 @@ final class RecordDataType<R extends Record> extends DefaultDataType<R> {
|
||||
Integer newLength,
|
||||
Nullability newNullability,
|
||||
boolean newReadonly,
|
||||
Field<R> newGeneratedAlwaysAs,
|
||||
Generator<R> newGeneratedAlwaysAs,
|
||||
GenerationOption newGenerationOption,
|
||||
GenerationLocation newGenerationLocation,
|
||||
Collation newCollation,
|
||||
CharacterSet newCharacterSet,
|
||||
boolean newIdentity,
|
||||
@ -125,6 +128,7 @@ final class RecordDataType<R extends Record> extends DefaultDataType<R> {
|
||||
newReadonly,
|
||||
newGeneratedAlwaysAs,
|
||||
newGenerationOption,
|
||||
newGenerationLocation,
|
||||
newCollation,
|
||||
newCharacterSet,
|
||||
newIdentity,
|
||||
|
||||
@ -83,6 +83,7 @@ import static org.jooq.impl.DSL.row;
|
||||
import static org.jooq.impl.DSL.select;
|
||||
import static org.jooq.impl.DSL.trueCondition;
|
||||
import static org.jooq.impl.FieldMapForUpdate.removeReadonly;
|
||||
import static org.jooq.impl.FieldMapsForInsert.keysAndComputedOnClient;
|
||||
import static org.jooq.impl.Keywords.K_FROM;
|
||||
import static org.jooq.impl.Keywords.K_LIMIT;
|
||||
import static org.jooq.impl.Keywords.K_ORDER_BY;
|
||||
@ -90,6 +91,7 @@ import static org.jooq.impl.Keywords.K_ROW;
|
||||
import static org.jooq.impl.Keywords.K_SET;
|
||||
import static org.jooq.impl.Keywords.K_UPDATE;
|
||||
import static org.jooq.impl.Keywords.K_WHERE;
|
||||
import static org.jooq.impl.Tools.EMPTY_FIELD;
|
||||
import static org.jooq.impl.Tools.fieldName;
|
||||
import static org.jooq.impl.Tools.map;
|
||||
import static org.jooq.impl.Tools.unqualified;
|
||||
@ -97,9 +99,11 @@ import static org.jooq.impl.Tools.visitSubquery;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jooq.Clause;
|
||||
import org.jooq.Condition;
|
||||
@ -180,6 +184,8 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static final Set<SQLDialect> SUPPORT_RVE_SET = SQLDialect.supportedBy(H2, HSQLDB, POSTGRES, YUGABYTEDB);
|
||||
private static final Set<SQLDialect> REQUIRE_RVE_ROW_CLAUSE = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB);
|
||||
|
||||
@ -539,13 +545,54 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
return from;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Override
|
||||
final void accept0(Context<?> ctx) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
accept1(ctx);
|
||||
}
|
||||
|
||||
private final UpdateQueryImpl<R> copy(Consumer<? super UpdateQueryImpl<R>> consumer) {
|
||||
UpdateQueryImpl<R> u = new UpdateQueryImpl<>(configuration(), with, table);
|
||||
|
||||
if (!returning.isEmpty())
|
||||
u.setReturning(returning);
|
||||
|
||||
u.updateMap.putAll(updateMap);
|
||||
u.multiRow = multiRow;
|
||||
u.multiSelect = multiSelect;
|
||||
u.multiValue = multiValue;
|
||||
u.from.addAll(from);
|
||||
u.condition.setWhere(condition.getWhere());
|
||||
u.orderBy.addAll(orderBy);
|
||||
u.limit = limit;
|
||||
consumer.accept(u);
|
||||
return u;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final void accept1(Context<?> ctx) {
|
||||
boolean declareTables = ctx.declareTables();
|
||||
ctx.start(UPDATE_UPDATE)
|
||||
.visit(K_UPDATE)
|
||||
@ -589,10 +636,7 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
map.put(k, Tools.field(v, k));
|
||||
}
|
||||
|
||||
ctx.formatIndentStart()
|
||||
.formatSeparator()
|
||||
.visit(map)
|
||||
.formatIndentEnd();
|
||||
toSQLUpdateMap(ctx, map);
|
||||
}
|
||||
|
||||
|
||||
@ -609,9 +653,6 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
else {
|
||||
Row row = removeReadonly(ctx, multiRow);
|
||||
|
||||
@ -658,12 +699,8 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
}
|
||||
|
||||
// A regular (non-multi-row) update was specified
|
||||
else {
|
||||
ctx.formatIndentStart()
|
||||
.formatSeparator()
|
||||
.visit(updateMap)
|
||||
.formatIndentEnd();
|
||||
}
|
||||
else
|
||||
toSQLUpdateMap(ctx, updateMap);
|
||||
|
||||
ctx.end(UPDATE_SET);
|
||||
|
||||
@ -671,19 +708,9 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
|
||||
|
||||
|
||||
switch (ctx.family()) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
default:
|
||||
acceptFrom(ctx);
|
||||
break;
|
||||
}
|
||||
acceptFrom(ctx);
|
||||
|
||||
if (limit != null && NO_SUPPORT_LIMIT.contains(ctx.dialect()) || !orderBy.isEmpty() && NO_SUPPORT_ORDER_BY_LIMIT.contains(ctx.dialect())) {
|
||||
Field<?>[] keyFields =
|
||||
@ -736,6 +763,13 @@ final class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> impl
|
||||
ctx.end(UPDATE_RETURNING);
|
||||
}
|
||||
|
||||
private static final void toSQLUpdateMap(Context<?> ctx, FieldMapForUpdate updateMap) {
|
||||
ctx.formatIndentStart()
|
||||
.formatSeparator()
|
||||
.visit(updateMap)
|
||||
.formatIndentEnd();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user