From dfcaa4c3aa36af7940842aaa3d1e9278ef4262ad Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 26 Feb 2024 13:33:21 +0100 Subject: [PATCH] [jOOQ/jOOQ#579] Auto alias unnamed field expressions in derived tables --- .../main/java/org/jooq/codegen/Constants.java | 3 +- .../main/java/org/jooq/meta/Constants.java | 2 +- jOOQ/src/main/java/org/jooq/Constants.java | 2 +- .../org/jooq/conf/AutoAliasExpressions.java | 39 ++++++++++++++ .../java/org/jooq/conf/ObjectFactory.java | 4 +- .../src/main/java/org/jooq/conf/Settings.java | 45 ++++++++++++++++ .../main/java/org/jooq/conf/package-info.java | 2 +- jOOQ/src/main/java/org/jooq/impl/Alias.java | 17 +++++- .../main/java/org/jooq/impl/FieldAlias.java | 10 +++- jOOQ/src/main/java/org/jooq/impl/Level.java | 1 + .../main/java/org/jooq/impl/NamedField.java | 53 +++++++++++++++++++ jOOQ/src/main/java/org/jooq/impl/Rownum.java | 1 + .../main/java/org/jooq/impl/SQLCondition.java | 8 ++- .../src/main/java/org/jooq/impl/SQLField.java | 9 +++- .../java/org/jooq/impl/SelectQueryImpl.java | 23 +++++--- .../java/org/jooq/impl/TableFieldImpl.java | 1 + jOOQ/src/main/java/org/jooq/impl/Tools.java | 7 +++ .../java/org/jooq/impl/UDTPathFieldImpl.java | 1 + ...ime-3.19.0.xsd => jooq-runtime-3.20.0.xsd} | 24 ++++++++- 19 files changed, 232 insertions(+), 20 deletions(-) create mode 100644 jOOQ/src/main/java/org/jooq/conf/AutoAliasExpressions.java create mode 100644 jOOQ/src/main/java/org/jooq/impl/NamedField.java rename jOOQ/src/main/resources/org/jooq/xsd/{jooq-runtime-3.19.0.xsd => jooq-runtime-3.20.0.xsd} (99%) diff --git a/jOOQ-codegen/src/main/java/org/jooq/codegen/Constants.java b/jOOQ-codegen/src/main/java/org/jooq/codegen/Constants.java index fc2d3b7a7e..4cf3f784fc 100644 --- a/jOOQ-codegen/src/main/java/org/jooq/codegen/Constants.java +++ b/jOOQ-codegen/src/main/java/org/jooq/codegen/Constants.java @@ -79,7 +79,8 @@ public final class Constants { /** * The current jooq-runtime XSD file name. */ - public static final String XSD_RUNTIME = "jooq-runtime-3.19.0.xsd"; + public static final String XSD_RUNTIME = "jooq-runtime-3.20.0.xsd"; + /** * The current jooq-runtime XML namespace. diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/Constants.java b/jOOQ-meta/src/main/java/org/jooq/meta/Constants.java index 8766a412bf..55b7a395d3 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/Constants.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/Constants.java @@ -79,7 +79,7 @@ public final class Constants { /** * The current jooq-runtime XSD file name. */ - public static final String XSD_RUNTIME = "jooq-runtime-3.19.0.xsd"; + public static final String XSD_RUNTIME = "jooq-runtime-3.20.0.xsd"; /** * The current jooq-runtime XML namespace. diff --git a/jOOQ/src/main/java/org/jooq/Constants.java b/jOOQ/src/main/java/org/jooq/Constants.java index a7e997ed1a..ae99562a35 100644 --- a/jOOQ/src/main/java/org/jooq/Constants.java +++ b/jOOQ/src/main/java/org/jooq/Constants.java @@ -79,7 +79,7 @@ public final class Constants { /** * The current jooq-runtime XSD file name. */ - public static final String XSD_RUNTIME = "jooq-runtime-3.19.0.xsd"; + public static final String XSD_RUNTIME = "jooq-runtime-3.20.0.xsd"; /** * The current jooq-runtime XML namespace. diff --git a/jOOQ/src/main/java/org/jooq/conf/AutoAliasExpressions.java b/jOOQ/src/main/java/org/jooq/conf/AutoAliasExpressions.java new file mode 100644 index 0000000000..8f8b118dca --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/conf/AutoAliasExpressions.java @@ -0,0 +1,39 @@ + +package org.jooq.conf; + +import jakarta.xml.bind.annotation.XmlEnum; +import jakarta.xml.bind.annotation.XmlType; + + +/** + *

Java class for AutoAliasExpressions. + * + *

The following schema fragment specifies the expected content contained within this class. + *

+ * <simpleType name="AutoAliasExpressions">
+ *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
+ *     <enumeration value="NEVER"/>
+ *     <enumeration value="UNNAMED"/>
+ *     <enumeration value="ALWAYS"/>
+ *   </restriction>
+ * </simpleType>
+ * 
+ * + */ +@XmlType(name = "AutoAliasExpressions") +@XmlEnum +public enum AutoAliasExpressions { + + NEVER, + UNNAMED, + ALWAYS; + + public String value() { + return name(); + } + + public static AutoAliasExpressions fromValue(String v) { + return valueOf(v); + } + +} diff --git a/jOOQ/src/main/java/org/jooq/conf/ObjectFactory.java b/jOOQ/src/main/java/org/jooq/conf/ObjectFactory.java index e00fdf23c4..f1340d05cf 100644 --- a/jOOQ/src/main/java/org/jooq/conf/ObjectFactory.java +++ b/jOOQ/src/main/java/org/jooq/conf/ObjectFactory.java @@ -24,7 +24,7 @@ import javax.xml.namespace.QName; @XmlRegistry public class ObjectFactory { - private final static QName _Settings_QNAME = new QName("http://www.jooq.org/xsd/jooq-runtime-3.19.0.xsd", "settings"); + private final static QName _Settings_QNAME = new QName("http://www.jooq.org/xsd/jooq-runtime-3.20.0.xsd", "settings"); /** * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.jooq.conf @@ -121,7 +121,7 @@ public class ObjectFactory { * @return * the new instance of {@link JAXBElement }{@code <}{@link Settings }{@code >} */ - @XmlElementDecl(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.19.0.xsd", name = "settings") + @XmlElementDecl(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.20.0.xsd", name = "settings") public JAXBElement createSettings(Settings value) { return new JAXBElement(_Settings_QNAME, Settings.class, null, value); } diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 115ff14eda..4eed197f70 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -70,6 +70,9 @@ public class Settings @XmlElement(defaultValue = "false") protected Boolean renderFormatted = false; protected RenderFormatting renderFormatting; + @XmlElement(defaultValue = "NEVER") + @XmlSchemaType(name = "string") + protected AutoAliasExpressions renderAutoAliasedDerivedTableExpressions = AutoAliasExpressions.NEVER; @XmlElement(defaultValue = "DEFAULT") @XmlSchemaType(name = "string") protected RenderOptionalKeyword renderOptionalAssociativityParentheses = RenderOptionalKeyword.DEFAULT; @@ -894,6 +897,26 @@ public class Settings this.renderFormatting = value; } + /** + * Whether to auto-alias expressions in derived tables. + *

+ * This feature is available in the commercial distribution only. + * + */ + public AutoAliasExpressions getRenderAutoAliasedDerivedTableExpressions() { + return renderAutoAliasedDerivedTableExpressions; + } + + /** + * Whether to auto-alias expressions in derived tables. + *

+ * This feature is available in the commercial distribution only. + * + */ + public void setRenderAutoAliasedDerivedTableExpressions(AutoAliasExpressions value) { + this.renderAutoAliasedDerivedTableExpressions = value; + } + /** * Whether to render optional parentheses to make associativity explicit, e.g. ((a + b) + c) instead of (a + b + c). * @@ -6817,6 +6840,17 @@ public class Settings return this; } + /** + * Whether to auto-alias expressions in derived tables. + *

+ * This feature is available in the commercial distribution only. + * + */ + public Settings withRenderAutoAliasedDerivedTableExpressions(AutoAliasExpressions value) { + setRenderAutoAliasedDerivedTableExpressions(value); + return this; + } + /** * Whether to render optional parentheses to make associativity explicit, e.g. ((a + b) + c) instead of (a + b + c). * @@ -9421,6 +9455,7 @@ public class Settings builder.append("renderLocale", renderLocale); builder.append("renderFormatted", renderFormatted); builder.append("renderFormatting", renderFormatting); + builder.append("renderAutoAliasedDerivedTableExpressions", renderAutoAliasedDerivedTableExpressions); builder.append("renderOptionalAssociativityParentheses", renderOptionalAssociativityParentheses); builder.append("renderOptionalAsKeywordForTableAliases", renderOptionalAsKeywordForTableAliases); builder.append("renderOptionalAsKeywordForFieldAliases", renderOptionalAsKeywordForFieldAliases); @@ -9778,6 +9813,15 @@ public class Settings return false; } } + if (renderAutoAliasedDerivedTableExpressions == null) { + if (other.renderAutoAliasedDerivedTableExpressions!= null) { + return false; + } + } else { + if (!renderAutoAliasedDerivedTableExpressions.equals(other.renderAutoAliasedDerivedTableExpressions)) { + return false; + } + } if (renderOptionalAssociativityParentheses == null) { if (other.renderOptionalAssociativityParentheses!= null) { return false; @@ -11689,6 +11733,7 @@ public class Settings result = ((prime*result)+((renderLocale == null)? 0 :renderLocale.hashCode())); result = ((prime*result)+((renderFormatted == null)? 0 :renderFormatted.hashCode())); result = ((prime*result)+((renderFormatting == null)? 0 :renderFormatting.hashCode())); + result = ((prime*result)+((renderAutoAliasedDerivedTableExpressions == null)? 0 :renderAutoAliasedDerivedTableExpressions.hashCode())); result = ((prime*result)+((renderOptionalAssociativityParentheses == null)? 0 :renderOptionalAssociativityParentheses.hashCode())); result = ((prime*result)+((renderOptionalAsKeywordForTableAliases == null)? 0 :renderOptionalAsKeywordForTableAliases.hashCode())); result = ((prime*result)+((renderOptionalAsKeywordForFieldAliases == null)? 0 :renderOptionalAsKeywordForFieldAliases.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/conf/package-info.java b/jOOQ/src/main/java/org/jooq/conf/package-info.java index 76d3e7e338..f8df3971f8 100644 --- a/jOOQ/src/main/java/org/jooq/conf/package-info.java +++ b/jOOQ/src/main/java/org/jooq/conf/package-info.java @@ -1,2 +1,2 @@ -@jakarta.xml.bind.annotation.XmlSchema(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.19.0.xsd", elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED) +@jakarta.xml.bind.annotation.XmlSchema(namespace = "http://www.jooq.org/xsd/jooq-runtime-3.20.0.xsd", elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED) package org.jooq.conf; diff --git a/jOOQ/src/main/java/org/jooq/impl/Alias.java b/jOOQ/src/main/java/org/jooq/impl/Alias.java index 46f48e59b4..0c6c872963 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Alias.java +++ b/jOOQ/src/main/java/org/jooq/impl/Alias.java @@ -113,6 +113,7 @@ import org.jooq.Select; import org.jooq.Table; import org.jooq.conf.RenderOptionalKeyword; import org.jooq.impl.QOM.UEmpty; +import org.jooq.impl.Tools.BooleanDataKey; /** * @author Lukas Eder @@ -421,8 +422,22 @@ final class Alias extends AbstractQueryPart implements UEmp else ctx.sql('('); - if (nestedJoinTable && NO_SUPPORT_ALIASED_JOIN_TABLES.contains(ctx.dialect())) + if (nestedJoinTable && NO_SUPPORT_ALIASED_JOIN_TABLES.contains(ctx.dialect())) { ctx.visit(select(asterisk()).from((Table) wrapped)); + } + + + + + + + + + + + + + else ctx.visit(wrapped); diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java b/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java index 8cc402489d..3f8d4453f7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java @@ -44,7 +44,6 @@ import org.jooq.Field; import org.jooq.Name; import org.jooq.QueryPart; // ... -import org.jooq.Table; // ... import org.jetbrains.annotations.NotNull; @@ -52,7 +51,14 @@ import org.jetbrains.annotations.NotNull; /** * @author Lukas Eder */ -final class FieldAlias extends AbstractField implements QOM.FieldAlias, SimpleCheckQueryPart { +final class FieldAlias +extends + AbstractField +implements + QOM.FieldAlias, + SimpleCheckQueryPart, + NamedField +{ private final Alias> alias; diff --git a/jOOQ/src/main/java/org/jooq/impl/Level.java b/jOOQ/src/main/java/org/jooq/impl/Level.java index d68c0b71d7..bfb73caad1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Level.java +++ b/jOOQ/src/main/java/org/jooq/impl/Level.java @@ -125,5 +125,6 @@ package org.jooq.impl; + diff --git a/jOOQ/src/main/java/org/jooq/impl/NamedField.java b/jOOQ/src/main/java/org/jooq/impl/NamedField.java new file mode 100644 index 0000000000..3e52fdec57 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/NamedField.java @@ -0,0 +1,53 @@ +/* + * 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 + * + * https://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: https://www.jooq.org/legal/licensing + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import org.jooq.Field; + +/** + * A marker interface for fields whose name is defined. + *

+ * While all {@link Field} implementations are {@link Named}, not all of them + * produce a name known to the underlying dialect's SQL engine. E.g. + * 'a' || 'b' has a name called "concat", but this may not be the + * name the SQL engine uses for this expression. In some cases, jOOQ needs to + * explicitly produce the name for unnamed fields. + * + * @author Lukas Eder + */ +interface NamedField extends Field {} diff --git a/jOOQ/src/main/java/org/jooq/impl/Rownum.java b/jOOQ/src/main/java/org/jooq/impl/Rownum.java index 53ebc9ac16..88d1f2ef92 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Rownum.java +++ b/jOOQ/src/main/java/org/jooq/impl/Rownum.java @@ -129,5 +129,6 @@ package org.jooq.impl; + diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java b/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java index 9c620a10fe..ba17fa94ba 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java @@ -44,7 +44,13 @@ import org.jooq.SQL; import org.jooq.impl.QOM.UEmpty; import org.jooq.impl.QOM.UEmptyCondition; -final class SQLCondition extends AbstractCondition implements UEmptyCondition { +final class SQLCondition +extends + AbstractCondition +implements + UEmptyCondition, + NamedField +{ private final SQL delegate; diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLField.java b/jOOQ/src/main/java/org/jooq/impl/SQLField.java index 71b5cbb507..48f77e7841 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SQLField.java +++ b/jOOQ/src/main/java/org/jooq/impl/SQLField.java @@ -43,7 +43,14 @@ import org.jooq.QueryPart; import org.jooq.SQL; import org.jooq.impl.QOM.UEmptyField; -final class SQLField extends AbstractField implements UEmptyField, TypedReference { +final class SQLField +extends + AbstractField +implements + UEmptyField, + TypedReference, + NamedField +{ final SQLImpl delegate; diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 28ad6128cd..f203bc30c5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -103,7 +103,6 @@ import static org.jooq.SQLDialect.MYSQL; // ... // ... // ... -// ... import static org.jooq.SQLDialect.POSTGRES; // ... // ... @@ -229,7 +228,6 @@ import static org.jooq.impl.Tools.BooleanDataKey.DATA_INSERT_SELECT_WITHOUT_INSE import static org.jooq.impl.Tools.BooleanDataKey.DATA_MULTISET_CONTENT; import static org.jooq.impl.Tools.BooleanDataKey.DATA_NESTED_SET_OPERATIONS; import static org.jooq.impl.Tools.BooleanDataKey.DATA_OMIT_INTO_CLAUSE; -import static org.jooq.impl.Tools.BooleanDataKey.DATA_RENDER_IMPLICIT_JOIN; import static org.jooq.impl.Tools.BooleanDataKey.DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE; import static org.jooq.impl.Tools.BooleanDataKey.DATA_UNALIAS_ALIASED_EXPRESSIONS; import static org.jooq.impl.Tools.BooleanDataKey.DATA_WRAP_DERIVED_TABLES_IN_PARENTHESES; @@ -248,7 +246,6 @@ import static org.jooq.impl.Transformations.transformGroupByColumnIndex; import static org.jooq.impl.Transformations.transformInlineCTE; import static org.jooq.impl.Transformations.transformQualify; import static org.jooq.impl.Transformations.transformRownum; -import static org.jooq.tools.StringUtils.defaultIfNull; import java.sql.ResultSetMetaData; import java.sql.SQLException; @@ -269,8 +266,6 @@ import java.util.Set; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; import org.jooq.Asterisk; import org.jooq.Clause; @@ -324,8 +319,8 @@ import org.jooq.TableRecord; // ... import org.jooq.WindowDefinition; import org.jooq.XML; +import org.jooq.conf.AutoAliasExpressions; import org.jooq.exception.DataAccessException; -import org.jooq.impl.AbstractContext.JoinNode; import org.jooq.impl.ForLock.ForLockMode; import org.jooq.impl.ForLock.ForLockWaitMode; import org.jooq.impl.QOM.CompareCondition; @@ -1746,14 +1741,28 @@ final class SelectQueryImpl extends AbstractResultQuery imp Object renderTrailingLimit = context.data(DATA_RENDER_TRAILING_LIMIT_IF_APPLICABLE); Name[] selectAliases = (Name[]) context.data(DATA_SELECT_ALIASES); + + + + + + + + + + try { List> originalFields = null; List> alternativeFields = null; if (selectAliases != null) { context.data().remove(DATA_SELECT_ALIASES); + + + + Name[] a = selectAliases; alternativeFields = map(originalFields = getSelect(), - (f, i) -> i < selectAliases.length ? f.as(selectAliases[i]) : f + (f, i) -> i < a.length && a[i] != null ? f.as(a[i]) : f ); } diff --git a/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java index 3bcd25af08..8d296f1ce9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java @@ -89,6 +89,7 @@ implements TableField, SimpleQueryPart, TypedReference, + NamedField, ScopeMappable, UEmpty { diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index aa4ea5f368..37834368b1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -527,6 +527,13 @@ final class Tools { + + + + + + + /** diff --git a/jOOQ/src/main/java/org/jooq/impl/UDTPathFieldImpl.java b/jOOQ/src/main/java/org/jooq/impl/UDTPathFieldImpl.java index 82e3719cf5..16356be789 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UDTPathFieldImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/UDTPathFieldImpl.java @@ -89,6 +89,7 @@ implements UDTPathField, SimpleQueryPart, TypedReference, + NamedField, ScopeMappable, UEmpty { diff --git a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd similarity index 99% rename from jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd rename to jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd index bd8b26a17f..addd321fd1 100644 --- a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.19.0.xsd +++ b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.20.0.xsd @@ -1,10 +1,10 @@ @@ -129,6 +129,12 @@ providing a name to parameters, resulting in :1 or @1 + + + +This feature is available in the commercial distribution only.]]> + ((a + b) + c) instead of (a + b + c).]]> @@ -2454,4 +2460,18 @@ Either <input/> or <inputExpression/> must be provided]]> + + + + + + + + + + + + + + \ No newline at end of file