From bfb9fcc0f6e2e273447af61818126e9816d4b50f Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 26 Oct 2023 16:40:07 +0200 Subject: [PATCH] HHH-17355 Unify array_contains and array_contains_all as well as deprecate FunctionRenderingSupport in favor of new FunctionRenderer contract --- .../chapters/query/hql/QueryLanguage.adoc | 4 +- .../dialect/CockroachLegacyDialect.java | 10 +- .../community/dialect/H2LegacyDialect.java | 26 +- .../community/dialect/HSQLLegacyDialect.java | 8 +- .../dialect/OracleLegacyDialect.java | 6 +- .../dialect/PostgreSQLLegacyDialect.java | 10 +- .../hibernate/dialect/CockroachDialect.java | 10 +- .../java/org/hibernate/dialect/H2Dialect.java | 26 +- .../org/hibernate/dialect/HSQLDialect.java | 8 +- .../dialect/OracleArrayJdbcType.java | 6 +- .../org/hibernate/dialect/OracleDialect.java | 6 +- .../hibernate/dialect/PostgreSQLDialect.java | 10 +- .../org/hibernate/dialect/SpannerDialect.java | 2 +- ...regateWindowEmulationQueryTransformer.java | 2 +- .../dialect/function/AvgFunction.java | 17 +- .../function/CaseLeastGreatestEmulation.java | 2 + .../dialect/function/CastFunction.java | 7 +- .../function/CastingConcatFunction.java | 7 +- .../dialect/function/ChrLiteralEmulation.java | 2 + .../function/CommonFunctionFactory.java | 270 ++++-------------- .../dialect/function/ConcatPipeFunction.java | 2 + .../dialect/function/CountFunction.java | 20 +- .../dialect/function/CurrentFunction.java | 2 + .../dialect/function/DB2FormatEmulation.java | 10 +- .../dialect/function/DB2PositionFunction.java | 2 + .../function/DB2SubstringFunction.java | 2 + .../dialect/function/DateTruncEmulation.java | 5 +- .../dialect/function/DerbyLpadEmulation.java | 2 + .../dialect/function/DerbyRpadEmulation.java | 2 + .../dialect/function/EveryAnyEmulation.java | 8 +- .../dialect/function/ExtractFunction.java | 8 +- .../dialect/function/FormatFunction.java | 37 ++- .../function/HypotheticalSetFunction.java | 8 +- .../HypotheticalSetWindowEmulation.java | 2 +- .../IntegralTimestampaddFunction.java | 4 +- .../function/InverseDistributionFunction.java | 7 +- .../InverseDistributionWindowEmulation.java | 2 +- .../dialect/function/LengthFunction.java | 2 + .../dialect/function/ListaggFunction.java | 8 +- .../function/ListaggGroupConcatEmulation.java | 8 +- .../function/ListaggStringAggEmulation.java | 8 +- .../function/MinMaxCaseEveryAnyEmulation.java | 9 +- .../function/ModeStatsModeEmulation.java | 2 + .../dialect/function/OracleTruncFunction.java | 9 +- .../function/PostgreSQLMinMaxFunction.java | 10 +- .../PostgreSQLTruncRoundFunction.java | 9 +- .../QuantifiedLeastGreatestEmulation.java | 2 + .../function/SQLServerEveryAnyEmulation.java | 9 +- .../function/SQLServerFormatEmulation.java | 2 + .../dialect/function/SqlFunction.java | 2 + .../SqlServerConvertTruncFunction.java | 1 + .../dialect/function/SybaseTruncFunction.java | 1 + .../function/TimestampaddFunction.java | 1 + .../function/TimestampdiffFunction.java | 1 + .../function/TransactSQLStrFunction.java | 9 +- .../dialect/function/TrimFunction.java | 7 +- .../dialect/function/TruncFunction.java | 7 +- .../array/AbstractArrayContainsFunction.java | 39 +++ ...ava => AbstractArrayOverlapsFunction.java} | 18 +- .../function/array/ArrayAggFunction.java | 8 +- .../ArrayAndElementArgumentTypeResolver.java | 31 +- .../array/ArrayArgumentValidator.java | 12 +- .../array/ArrayConcatElementFunction.java | 2 + .../function/array/ArrayConcatFunction.java | 2 + .../array/ArrayConstructorFunction.java | 7 +- .../ArrayContainsArgumentTypeResolver.java | 60 ++++ .../array/ArrayContainsArgumentValidator.java | 48 ++++ .../array/ArrayContainsOperatorFunction.java | 79 ++--- .../array/ArrayContainsUnnestFunction.java | 77 +++++ .../array/ArrayGetUnnestFunction.java | 2 + .../dialect/function/array/ArrayHelper.java | 21 ++ ...ava => ArrayOverlapsOperatorFunction.java} | 20 +- ....java => ArrayOverlapsUnnestFunction.java} | 37 +-- .../array/ArrayRemoveIndexUnnestFunction.java | 2 + .../array/ArrayReplaceUnnestFunction.java | 2 + .../array/ArraySetUnnestFunction.java | 2 + .../array/ArraySliceUnnestFunction.java | 2 + .../CastingArrayConstructorFunction.java | 128 --------- .../dialect/function/array/DdlTypeHelper.java | 7 +- .../array/H2ArrayContainsFunction.java | 87 ++++++ ...tion.java => H2ArrayOverlapsFunction.java} | 44 ++- .../function/array/H2ArrayRemoveFunction.java | 17 +- .../array/H2ArrayRemoveIndexFunction.java | 17 +- .../array/H2ArrayReplaceFunction.java | 18 +- .../function/array/H2ArraySetFunction.java | 18 +- .../array/HSQLArrayConstructorFunction.java | 77 +++++ .../array/HSQLArrayPositionFunction.java | 2 + .../array/HSQLArrayRemoveFunction.java | 2 + .../function/array/HSQLArraySetFunction.java | 6 +- .../array/OracleArrayAggEmulation.java | 17 +- .../OracleArrayConcatElementFunction.java | 2 + .../array/OracleArrayConcatFunction.java | 15 +- .../array/OracleArrayConstructorFunction.java | 135 ++------- .../array/OracleArrayContainsAllFunction.java | 43 --- .../array/OracleArrayContainsFunction.java | 55 ++-- .../OracleArrayContainsNullFunction.java | 51 ---- .../array/OracleArrayGetFunction.java | 2 + .../array/OracleArrayLengthFunction.java | 2 + .../array/OracleArrayOverlapsFunction.java | 9 +- .../array/OracleArrayPositionFunction.java | 2 + .../array/OracleArrayRemoveFunction.java | 2 + .../array/OracleArrayRemoveIndexFunction.java | 2 + .../array/OracleArrayReplaceFunction.java | 2 + .../array/OracleArraySetFunction.java | 2 + .../array/OracleArraySliceFunction.java | 2 + .../array/OracleCollectArrayAggEmulation.java | 217 -------------- .../PostgreSQLArrayConcatElementFunction.java | 2 + .../array/PostgreSQLArrayConcatFunction.java | 4 +- .../PostgreSQLArrayConstructorFunction.java | 59 ++++ .../PostgreSQLArrayPositionFunction.java | 2 + .../ordering/ast/FunctionExpression.java | 11 +- ...actSqmSelfRenderingFunctionDescriptor.java | 4 +- .../query/sqm/function/FunctionRenderer.java | 81 ++++++ .../function/FunctionRenderingSupport.java | 69 +++++ .../JdbcEscapeFunctionDescriptor.java | 6 +- .../function/NamedSqmFunctionDescriptor.java | 5 + .../PatternBasedSqmFunctionDescriptor.java | 5 + ...ringAggregateFunctionSqlAstExpression.java | 17 +- ...SelfRenderingFunctionSqlAstExpression.java | 34 ++- ...dSetAggregateFunctionSqlAstExpression.java | 18 +- .../SelfRenderingSqmAggregateFunction.java | 22 +- .../function/SelfRenderingSqmFunction.java | 35 ++- ...nderingSqmOrderedSetAggregateFunction.java | 33 ++- .../SelfRenderingSqmWindowFunction.java | 26 +- ...nderingWindowFunctionSqlAstExpression.java | 21 +- .../internal/SqmInsertStrategyHelper.java | 4 +- .../sqm/sql/BaseSqmToSqlAstConverter.java | 20 +- .../sql/ast/spi/AbstractSqlAstTranslator.java | 71 +---- .../org/hibernate/type/BasicTypeRegistry.java | 7 +- .../AnsiTrimEmulationFunctionTest.java | 4 +- ...lTest.java => ArrayContainsArrayTest.java} | 66 +++-- .../function/array/ArrayContainsTest.java | 12 - .../function/array/ArrayOverlapsTest.java | 1 - .../orm/test/subquery/SubqueryTest.java | 6 +- .../function/OrderByFragmentFunction.java | 7 +- .../dialect/oracle/OracleSpatialFunction.java | 8 +- .../oracle/OracleSpatialSQLMMFunction.java | 2 + .../dialect/oracle/SDOGetGeometryType.java | 7 +- .../dialect/oracle/SDOMethodDescriptor.java | 9 +- .../dialect/oracle/SDORelateFunction.java | 7 +- .../dialect/oracle/STRelateFunction.java | 7 +- .../PostgisSqmFunctionDescriptors.java | 2 + .../SqlServerSqmFunctionDescriptors.java | 11 +- migration-guide.adoc | 30 +- 144 files changed, 1617 insertions(+), 1241 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsFunction.java rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{AbstractArrayContainsQuantifiedFunction.java => AbstractArrayOverlapsFunction.java} (65%) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentValidator.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsUnnestFunction.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayHelper.java rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{ArrayContainsQuantifiedOperatorFunction.java => ArrayOverlapsOperatorFunction.java} (64%) rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{ArrayContainsQuantifiedUnnestFunction.java => ArrayOverlapsUnnestFunction.java} (62%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/CastingArrayConstructorFunction.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsFunction.java rename hibernate-core/src/main/java/org/hibernate/dialect/function/array/{H2ArrayContainsQuantifiedEmulation.java => H2ArrayOverlapsFunction.java} (67%) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayConstructorFunction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsAllFunction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsNullFunction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleCollectArrayAggEmulation.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConstructorFunction.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderer.java rename hibernate-core/src/test/java/org/hibernate/orm/test/function/array/{ArrayContainsAllTest.java => ArrayContainsArrayTest.java} (57%) diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc index cfe250e9a0..6cdeb0849e 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc @@ -1233,7 +1233,7 @@ The result of `array_contains` is undefined when the second argument is an array ==== [source, JAVA, indent=0] ---- -include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contains-all-example] +include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-example] ---- ==== @@ -1243,7 +1243,7 @@ To search for `null` elements, the `array_contains_nullable` function must be us ==== [source, JAVA, indent=0] ---- -include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contains-all-nullable-example] +include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-nullable-example] ---- ==== diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index 683c6890b1..f286a0dcf2 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -461,19 +461,15 @@ public class CockroachLegacyDialect extends Dialect { functionFactory.listagg_stringAgg( "string" ); functionFactory.inverseDistributionOrderedSetAggregates(); functionFactory.hypotheticalOrderedSetAggregates_windowEmulation(); - functionFactory.array_casting(); + functionFactory.array_postgresql(); functionFactory.arrayAggregate(); - functionFactory.arrayContains_operator(); - functionFactory.arrayContainsNull_array_position(); functionFactory.arrayPosition_postgresql(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_postgresql(); functionFactory.arrayPrepend_postgresql(); functionFactory.arrayAppend_postgresql(); - functionFactory.arrayContainsAll_operator(); - functionFactory.arrayOverlaps_operator(); - functionFactory.arrayContainsAllNullable_operator(); - functionFactory.arrayOverlapsNullable_unnest(); + functionFactory.arrayContains_postgresql(); + functionFactory.arrayOverlaps_postgresql(); functionFactory.arrayGet_bracket(); functionFactory.arraySet_unnest(); functionFactory.arrayRemove(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java index 0c4eb620f8..080066cf82 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java @@ -372,22 +372,18 @@ public class H2LegacyDialect extends Dialect { functionFactory.listagg( null ); functionFactory.array(); functionFactory.arrayAggregate(); - functionFactory.arrayContains(); - functionFactory.arrayContainsNull(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_operator(); functionFactory.arrayPrepend_operator(); functionFactory.arrayAppend_operator(); - functionFactory.arrayContainsAll_h2(); - functionFactory.arrayOverlaps_h2(); - functionFactory.arrayContainsAllNullable_h2(); - functionFactory.arrayOverlapsNullable_h2(); + functionFactory.arrayContains_h2( getMaximumArraySize() ); + functionFactory.arrayOverlaps_h2( getMaximumArraySize() ); functionFactory.arrayGet_h2(); - functionFactory.arraySet_h2(); - functionFactory.arrayRemove_h2(); - functionFactory.arrayRemoveIndex_h2(); + functionFactory.arraySet_h2( getMaximumArraySize() ); + functionFactory.arrayRemove_h2( getMaximumArraySize() ); + functionFactory.arrayRemoveIndex_h2( getMaximumArraySize() ); functionFactory.arraySlice(); - functionFactory.arrayReplace_h2(); + functionFactory.arrayReplace_h2( getMaximumArraySize() ); } else { // Use group_concat until 2.x as listagg was buggy @@ -399,6 +395,16 @@ public class H2LegacyDialect extends Dialect { } } + /** + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same, + * but requires that {@code system_range} is fed with a "maximum array size". + */ + protected int getMaximumArraySize() { + return 1000; + } + @Override public void augmentPhysicalTableTypes(List tableTypesList) { if ( getVersion().isSameOrAfter( 2 ) ) { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java index 63b7a3f3dd..7991cc2754 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java @@ -247,19 +247,15 @@ public class HSQLLegacyDialect extends Dialect { functionFactory.rownum(); } functionFactory.listagg_groupConcat(); - functionFactory.array(); + functionFactory.array_hsql(); functionFactory.arrayAggregate(); - functionFactory.arrayContains_hsql(); - functionFactory.arrayContainsNull_hsql(); functionFactory.arrayPosition_hsql(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_operator(); functionFactory.arrayPrepend_operator(); functionFactory.arrayAppend_operator(); - functionFactory.arrayContainsAll_hsql(); + functionFactory.arrayContains_hsql(); functionFactory.arrayOverlaps_hsql(); - functionFactory.arrayContainsAllNullable_hsql(); - functionFactory.arrayOverlapsNullable_unnest(); functionFactory.arrayGet_unnest(); functionFactory.arraySet_hsql(); functionFactory.arrayRemove_hsql(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 121c33995d..c2b2ac4f3d 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -285,17 +285,13 @@ public class OracleLegacyDialect extends Dialect { functionFactory.array_oracle(); functionFactory.arrayAggregate_jsonArrayagg(); - functionFactory.arrayContains_oracle(); - functionFactory.arrayContainsNull_oracle(); functionFactory.arrayPosition_oracle(); functionFactory.arrayLength_oracle(); functionFactory.arrayConcat_oracle(); functionFactory.arrayPrepend_oracle(); functionFactory.arrayAppend_oracle(); - functionFactory.arrayContainsAll_oracle(); + functionFactory.arrayContains_oracle(); functionFactory.arrayOverlaps_oracle(); - functionFactory.arrayContainsAllNullable_oracle(); - functionFactory.arrayOverlapsNullable_oracle(); functionFactory.arrayGet_oracle(); functionFactory.arraySet_oracle(); functionFactory.arrayRemove_oracle(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java index f885c2bc28..7ea466ad65 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java @@ -581,19 +581,15 @@ public class PostgreSQLLegacyDialect extends Dialect { functionFactory.locate_positionSubstring(); functionFactory.windowFunctions(); functionFactory.listagg_stringAgg( "varchar" ); - functionFactory.array_casting(); + functionFactory.array_postgresql(); functionFactory.arrayAggregate(); - functionFactory.arrayContains_operator(); - functionFactory.arrayContainsNull_array_position(); functionFactory.arrayPosition_postgresql(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_postgresql(); functionFactory.arrayPrepend_postgresql(); functionFactory.arrayAppend_postgresql(); - functionFactory.arrayContainsAll_operator(); - functionFactory.arrayOverlaps_operator(); - functionFactory.arrayContainsAllNullable_operator(); - functionFactory.arrayOverlapsNullable_unnest(); + functionFactory.arrayContains_postgresql(); + functionFactory.arrayOverlaps_postgresql(); functionFactory.arrayGet_bracket(); functionFactory.arraySet_unnest(); functionFactory.arrayRemove(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index 717cecc926..2dfedb0eaf 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -448,19 +448,15 @@ public class CockroachDialect extends Dialect { functionFactory.listagg_stringAgg( "string" ); functionFactory.inverseDistributionOrderedSetAggregates(); functionFactory.hypotheticalOrderedSetAggregates_windowEmulation(); - functionFactory.array_casting(); + functionFactory.array_postgresql(); functionFactory.arrayAggregate(); - functionFactory.arrayContains_operator(); - functionFactory.arrayContainsNull_array_position(); functionFactory.arrayPosition_postgresql(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_postgresql(); functionFactory.arrayPrepend_postgresql(); functionFactory.arrayAppend_postgresql(); - functionFactory.arrayContainsAll_operator(); - functionFactory.arrayOverlaps_operator(); - functionFactory.arrayContainsAllNullable_operator(); - functionFactory.arrayOverlapsNullable_unnest(); + functionFactory.arrayContains_postgresql(); + functionFactory.arrayOverlaps_postgresql(); functionFactory.arrayGet_bracket(); functionFactory.arraySet_unnest(); functionFactory.arrayRemove(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index d75ca4d31a..05791ef64e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -311,22 +311,28 @@ public class H2Dialect extends Dialect { functionFactory.hypotheticalOrderedSetAggregates(); functionFactory.array(); functionFactory.arrayAggregate(); - functionFactory.arrayContains(); - functionFactory.arrayContainsNull(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_operator(); functionFactory.arrayPrepend_operator(); functionFactory.arrayAppend_operator(); - functionFactory.arrayContainsAll_h2(); - functionFactory.arrayOverlaps_h2(); - functionFactory.arrayContainsAllNullable_h2(); - functionFactory.arrayOverlapsNullable_h2(); + functionFactory.arrayContains_h2( getMaximumArraySize() ); + functionFactory.arrayOverlaps_h2( getMaximumArraySize() ); functionFactory.arrayGet_h2(); - functionFactory.arraySet_h2(); - functionFactory.arrayRemove_h2(); - functionFactory.arrayRemoveIndex_h2(); + functionFactory.arraySet_h2( getMaximumArraySize() ); + functionFactory.arrayRemove_h2( getMaximumArraySize() ); + functionFactory.arrayRemoveIndex_h2( getMaximumArraySize() ); functionFactory.arraySlice(); - functionFactory.arrayReplace_h2(); + functionFactory.arrayReplace_h2( getMaximumArraySize() ); + } + + /** + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same, + * but requires that {@code system_range} is fed with a "maximum array size". + */ + protected int getMaximumArraySize() { + return 1000; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index 4c5a0d5f4b..93971acb8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -187,19 +187,15 @@ public class HSQLDialect extends Dialect { // from v. 2.2.0 ROWNUM() is supported in all modes as the equivalent of Oracle ROWNUM functionFactory.rownum(); functionFactory.listagg_groupConcat(); - functionFactory.array(); + functionFactory.array_hsql(); functionFactory.arrayAggregate(); - functionFactory.arrayContains_hsql(); - functionFactory.arrayContainsNull_hsql(); functionFactory.arrayPosition_hsql(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_operator(); functionFactory.arrayPrepend_operator(); functionFactory.arrayAppend_operator(); - functionFactory.arrayContainsAll_hsql(); + functionFactory.arrayContains_hsql(); functionFactory.arrayOverlaps_hsql(); - functionFactory.arrayContainsAllNullable_hsql(); - functionFactory.arrayOverlapsNullable_unnest(); functionFactory.arrayGet_unnest(); functionFactory.arraySet_hsql(); functionFactory.arrayRemove_hsql(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java index ef29cf0dde..33364dc849 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java @@ -284,10 +284,10 @@ public class OracleArrayJdbcType extends ArrayJdbcType { ); database.addAuxiliaryDatabaseObject( new NamedAuxiliaryDatabaseObject( - arrayTypeName + "_contains_all", + arrayTypeName + "_contains", database.getDefaultNamespace(), new String[]{ - "create or replace function " + arrayTypeName + "_contains_all(haystack in " + arrayTypeName + + "create or replace function " + arrayTypeName + "_contains(haystack in " + arrayTypeName + ", needle in " + arrayTypeName + ", nullable in number) return number deterministic is found number(1,0); begin " + "if haystack is null or needle is null then return null; end if; " + "for i in 1 .. needle.count loop " + @@ -300,7 +300,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType { "return 1; " + "end;" }, - new String[] { "drop function " + arrayTypeName + "_contains_all" }, + new String[] { "drop function " + arrayTypeName + "_contains" }, emptySet(), false ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 231579f342..d63617a2ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -314,17 +314,13 @@ public class OracleDialect extends Dialect { functionFactory.array_oracle(); functionFactory.arrayAggregate_jsonArrayagg(); - functionFactory.arrayContains_oracle(); - functionFactory.arrayContainsNull_oracle(); functionFactory.arrayPosition_oracle(); functionFactory.arrayLength_oracle(); functionFactory.arrayConcat_oracle(); functionFactory.arrayPrepend_oracle(); functionFactory.arrayAppend_oracle(); - functionFactory.arrayContainsAll_oracle(); + functionFactory.arrayContains_oracle(); functionFactory.arrayOverlaps_oracle(); - functionFactory.arrayContainsAllNullable_oracle(); - functionFactory.arrayOverlapsNullable_oracle(); functionFactory.arrayGet_oracle(); functionFactory.arraySet_oracle(); functionFactory.arrayRemove_oracle(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index c5820869b5..060b2d7b03 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -629,19 +629,15 @@ public class PostgreSQLDialect extends Dialect { functionFactory.locate_positionSubstring(); functionFactory.windowFunctions(); functionFactory.listagg_stringAgg( "varchar" ); - functionFactory.array_casting(); + functionFactory.array_postgresql(); functionFactory.arrayAggregate(); - functionFactory.arrayContains_operator(); - functionFactory.arrayContainsNull_array_position(); functionFactory.arrayPosition_postgresql(); functionFactory.arrayLength_cardinality(); functionFactory.arrayConcat_postgresql(); functionFactory.arrayPrepend_postgresql(); functionFactory.arrayAppend_postgresql(); - functionFactory.arrayContainsAll_operator(); - functionFactory.arrayOverlaps_operator(); - functionFactory.arrayContainsAllNullable_operator(); - functionFactory.arrayOverlapsNullable_unnest(); + functionFactory.arrayContains_postgresql(); + functionFactory.arrayOverlaps_postgresql(); functionFactory.arrayGet_bracket(); functionFactory.arraySet_unnest(); functionFactory.arrayRemove(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java index f0d5fa2ab2..24734e7844 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java @@ -479,7 +479,7 @@ public class SpannerDialect extends Dialect { functionFactory.listagg_stringAgg( "string" ); functionFactory.inverseDistributionOrderedSetAggregates(); functionFactory.hypotheticalOrderedSetAggregates(); - functionFactory.array_withoutKeyword(); + functionFactory.array_spanner(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/AggregateWindowEmulationQueryTransformer.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/AggregateWindowEmulationQueryTransformer.java index 6e81043466..d3d653ee40 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/AggregateWindowEmulationQueryTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/AggregateWindowEmulationQueryTransformer.java @@ -129,7 +129,7 @@ public class AggregateWindowEmulationQueryTransformer implements QueryTransforme if ( expression == windowFunction ) { finalExpression = new SelfRenderingAggregateFunctionSqlAstExpression( "min", - (sqlAppender, sqlAstArguments, walker1) -> { + (sqlAppender, sqlAstArguments, returnType, walker1) -> { sqlAppender.appendSql( "min(" ); sqlAstArguments.get( 0 ).accept( walker1 ); sqlAppender.append( ')' ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java index 065b51205c..179ff6dae8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/AvgFunction.java @@ -11,6 +11,7 @@ import java.util.List; import org.hibernate.dialect.Dialect; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -62,8 +63,12 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor { } @Override - public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, walker ); + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + render( sqlAppender, sqlAstArguments, null, returnType, walker ); } @Override @@ -71,6 +76,7 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor { SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( "avg(" ); @@ -108,7 +114,12 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor { final JdbcMapping sourceMapping = realArg.getExpressionType().getSingleJdbcMapping(); // Only cast to float/double if this is an integer if ( sourceMapping.getJdbcType().isInteger() ) { - castFunction.render( sqlAppender, Arrays.asList( realArg, new CastTarget(doubleType) ), translator ); + castFunction.render( + sqlAppender, + Arrays.asList( realArg, new CastTarget( doubleType ) ), + doubleType, + translator + ); } else { translator.render( realArg, defaultArgumentRenderingMode ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CaseLeastGreatestEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CaseLeastGreatestEmulation.java index e1dcbec45d..2f2d3a2b44 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CaseLeastGreatestEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CaseLeastGreatestEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -44,6 +45,7 @@ public class CaseLeastGreatestEmulation public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final int numberOfArguments = arguments.size(); if ( numberOfArguments > 1 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CastFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CastFunction.java index 79ac4a3a52..60eddadd26 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CastFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CastFunction.java @@ -11,6 +11,7 @@ import java.util.List; import org.hibernate.dialect.Dialect; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -57,7 +58,11 @@ public class CastFunction extends AbstractSqmSelfRenderingFunctionDescriptor { } @Override - public void render(SqlAppender sqlAppender, List arguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List arguments, + ReturnableType returnType, + SqlAstTranslator walker) { final Expression source = (Expression) arguments.get( 0 ); final JdbcMapping sourceMapping = source.getExpressionType().getSingleJdbcMapping(); final CastType sourceType = getCastType( sourceMapping ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java index 4acb013d2c..d0bb1c1f2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CastingConcatFunction.java @@ -12,6 +12,7 @@ import java.util.List; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.Size; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -64,7 +65,11 @@ public class CastingConcatFunction extends AbstractSqmSelfRenderingFunctionDescr } @Override - public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { // Apache Derby and DB2 add up the sizes of operands for concat operations and has a limit of 4000/32k until // it changes the data type to long varchar, at which point problems start arising, because a long varchar // can't be compared with a regular varchar for some reason. diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ChrLiteralEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ChrLiteralEmulation.java index 90e9edb86f..9abcda5513 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ChrLiteralEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ChrLiteralEmulation.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Locale; import org.hibernate.QueryException; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; @@ -68,6 +69,7 @@ public class ChrLiteralEmulation extends AbstractSqmSelfRenderingFunctionDescrip public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { @SuppressWarnings("unchecked") final QueryLiteral literal = (QueryLiteral) arguments.get( 0 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java index c6cd26ea45..785d18863a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java @@ -19,9 +19,10 @@ import org.hibernate.dialect.function.array.ArrayArgumentValidator; import org.hibernate.dialect.function.array.ArrayConcatElementFunction; import org.hibernate.dialect.function.array.ArrayConcatFunction; import org.hibernate.dialect.function.array.ArrayConstructorFunction; -import org.hibernate.dialect.function.array.ArrayContainsQuantifiedOperatorFunction; import org.hibernate.dialect.function.array.ArrayContainsOperatorFunction; -import org.hibernate.dialect.function.array.ArrayContainsQuantifiedUnnestFunction; +import org.hibernate.dialect.function.array.ArrayContainsUnnestFunction; +import org.hibernate.dialect.function.array.ArrayOverlapsOperatorFunction; +import org.hibernate.dialect.function.array.ArrayOverlapsUnnestFunction; import org.hibernate.dialect.function.array.ArrayGetUnnestFunction; import org.hibernate.dialect.function.array.ArrayRemoveIndexUnnestFunction; import org.hibernate.dialect.function.array.ArrayReplaceUnnestFunction; @@ -29,17 +30,18 @@ import org.hibernate.dialect.function.array.ArraySetUnnestFunction; import org.hibernate.dialect.function.array.ArraySliceUnnestFunction; import org.hibernate.dialect.function.array.ArrayViaArgumentReturnTypeResolver; import org.hibernate.dialect.function.array.ElementViaArrayArgumentReturnTypeResolver; -import org.hibernate.dialect.function.array.H2ArrayContainsQuantifiedEmulation; +import org.hibernate.dialect.function.array.H2ArrayContainsFunction; +import org.hibernate.dialect.function.array.H2ArrayOverlapsFunction; import org.hibernate.dialect.function.array.H2ArrayRemoveFunction; import org.hibernate.dialect.function.array.H2ArrayRemoveIndexFunction; import org.hibernate.dialect.function.array.H2ArrayReplaceFunction; import org.hibernate.dialect.function.array.H2ArraySetFunction; +import org.hibernate.dialect.function.array.HSQLArrayConstructorFunction; import org.hibernate.dialect.function.array.HSQLArrayPositionFunction; import org.hibernate.dialect.function.array.HSQLArrayRemoveFunction; import org.hibernate.dialect.function.array.HSQLArraySetFunction; import org.hibernate.dialect.function.array.OracleArrayConcatElementFunction; import org.hibernate.dialect.function.array.OracleArrayConcatFunction; -import org.hibernate.dialect.function.array.OracleArrayContainsAllFunction; import org.hibernate.dialect.function.array.OracleArrayOverlapsFunction; import org.hibernate.dialect.function.array.OracleArrayGetFunction; import org.hibernate.dialect.function.array.OracleArrayLengthFunction; @@ -52,11 +54,10 @@ import org.hibernate.dialect.function.array.OracleArraySliceFunction; import org.hibernate.dialect.function.array.PostgreSQLArrayConcatElementFunction; import org.hibernate.dialect.function.array.PostgreSQLArrayConcatFunction; import org.hibernate.dialect.function.array.PostgreSQLArrayPositionFunction; -import org.hibernate.dialect.function.array.CastingArrayConstructorFunction; +import org.hibernate.dialect.function.array.PostgreSQLArrayConstructorFunction; import org.hibernate.dialect.function.array.OracleArrayAggEmulation; import org.hibernate.dialect.function.array.OracleArrayConstructorFunction; import org.hibernate.dialect.function.array.OracleArrayContainsFunction; -import org.hibernate.dialect.function.array.OracleArrayContainsNullFunction; import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -2589,17 +2590,24 @@ public class CommonFunctionFactory { functionRegistry.register( "array", new ArrayConstructorFunction( true ) ); } + /** + * H2, HSQL array() constructor function + */ + public void array_hsql() { + functionRegistry.register( "array", new HSQLArrayConstructorFunction() ); + } + /** * CockroachDB and PostgreSQL array() constructor function */ - public void array_casting() { - functionRegistry.register( "array", new CastingArrayConstructorFunction() ); + public void array_postgresql() { + functionRegistry.register( "array", new PostgreSQLArrayConstructorFunction() ); } /** * Google Spanner array() constructor function */ - public void array_withoutKeyword() { + public void array_spanner() { functionRegistry.register( "array", new ArrayConstructorFunction( false ) ); } @@ -2627,153 +2635,58 @@ public class CommonFunctionFactory { /** * H2 array_contains() function */ - public void arrayContains() { - functionRegistry.namedDescriptorBuilder( "array_contains" ) - .setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) ) - .setArgumentsValidator( - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 2 ), - ArrayAndElementArgumentValidator.DEFAULT_INSTANCE - ) - ) - .setArgumentTypeResolver( ArrayAndElementArgumentTypeResolver.DEFAULT_INSTANCE ) - .setArgumentListSignature( "(ARRAY array, OBJECT element)" ) - .register(); + public void arrayContains_h2(int maximumArraySize) { + functionRegistry.register( + "array_contains", + new H2ArrayContainsFunction( false, maximumArraySize, typeConfiguration ) + ); + functionRegistry.register( + "array_contains_nullable", + new H2ArrayContainsFunction( true, maximumArraySize, typeConfiguration ) + ); } /** * HSQL array_contains() function */ public void arrayContains_hsql() { - functionRegistry.patternDescriptorBuilder( "array_contains", "position_array(?2 in ?1)>0" ) - .setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) ) - .setArgumentsValidator( - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 2 ), - ArrayAndElementArgumentValidator.DEFAULT_INSTANCE - ) - ) - .setArgumentTypeResolver( ArrayAndElementArgumentTypeResolver.DEFAULT_INSTANCE ) - .setArgumentListSignature( "(ARRAY array, OBJECT element)" ) - .register(); + functionRegistry.register( + "array_contains", + new ArrayContainsUnnestFunction( false, typeConfiguration ) + ); + functionRegistry.register( + "array_contains_nullable", + new ArrayContainsUnnestFunction( true, typeConfiguration ) + ); } /** * CockroachDB and PostgreSQL array contains operator */ - public void arrayContains_operator() { - functionRegistry.register( "array_contains", new ArrayContainsOperatorFunction( typeConfiguration ) ); + public void arrayContains_postgresql() { + functionRegistry.register( "array_contains", new ArrayContainsOperatorFunction( false, typeConfiguration ) ); + functionRegistry.register( "array_contains_nullable", new ArrayContainsOperatorFunction( true, typeConfiguration ) ); } /** * Oracle array_contains() function */ public void arrayContains_oracle() { - functionRegistry.register( "array_contains", new OracleArrayContainsFunction( typeConfiguration ) ); - } - - /** - * H2, HSQL array_contains_null() function - */ - public void arrayContainsNull() { - functionRegistry.patternDescriptorBuilder( "array_contains_null", "array_contains(?1,null)" ) - .setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) ) - .setArgumentsValidator( - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 1 ), - ArrayArgumentValidator.DEFAULT_INSTANCE - ) - ) - .setArgumentListSignature( "(ARRAY array)" ) - .register(); - } - - /** - * CockroachDB and PostgreSQL array contains null emulation - */ - public void arrayContainsNull_array_position() { - functionRegistry.patternDescriptorBuilder( "array_contains_null", "array_position(?1,null) is not null" ) - .setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) ) - .setArgumentsValidator( - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 1 ), - ArrayArgumentValidator.DEFAULT_INSTANCE - ) - ) - .setArgumentListSignature( "(ARRAY array)" ) - .register(); - } - - /** - * Oracle array_contains() function - */ - public void arrayContainsNull_oracle() { - functionRegistry.register( "array_contains_null", new OracleArrayContainsNullFunction( typeConfiguration ) ); - } - - /** - * CockroachDB and PostgreSQL array contains null emulation - */ - public void arrayContainsNull_hsql() { - functionRegistry.patternDescriptorBuilder( "array_contains_null", "exists(select 1 from unnest(?1) t(i) where t.i is null)" ) - .setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) ) - .setArgumentsValidator( - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 1 ), - ArrayArgumentValidator.DEFAULT_INSTANCE - ) - ) - .setArgumentListSignature( "(ARRAY array)" ) - .register(); - } - - /** - * H2 array_contains_all() function - */ - public void arrayContainsAll_h2() { - functionRegistry.register( - "array_contains_all", - new H2ArrayContainsQuantifiedEmulation( typeConfiguration, true, false ) - ); - } - - /** - * HSQL array_contains_all() function - */ - public void arrayContainsAll_hsql() { - functionRegistry.register( - "array_contains_all", - new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, true, false ) - ); - } - - /** - * CockroachDB and PostgreSQL array contains all operator - */ - public void arrayContainsAll_operator() { - functionRegistry.register( - "array_contains_all", - new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, true, false ) - ); - } - - /** - * Oracle array_contains_all() function - */ - public void arrayContainsAll_oracle() { - functionRegistry.register( - "array_contains_all", - new OracleArrayContainsAllFunction( typeConfiguration, false ) - ); + functionRegistry.register( "array_contains", new OracleArrayContainsFunction( false, typeConfiguration ) ); + functionRegistry.register( "array_contains_nullable", new OracleArrayContainsFunction( true, typeConfiguration ) ); } /** * H2 array_overlaps() function */ - public void arrayOverlaps_h2() { + public void arrayOverlaps_h2(int maximumArraySize) { functionRegistry.register( "array_overlaps", - new H2ArrayContainsQuantifiedEmulation( typeConfiguration, false, false ) + new H2ArrayOverlapsFunction( false, maximumArraySize, typeConfiguration ) + ); + functionRegistry.register( + "array_overlaps_nullable", + new H2ArrayOverlapsFunction( true, maximumArraySize, typeConfiguration ) ); } @@ -2783,15 +2696,20 @@ public class CommonFunctionFactory { public void arrayOverlaps_hsql() { functionRegistry.register( "array_overlaps", - new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, false, false ) + new ArrayOverlapsUnnestFunction( false, typeConfiguration ) + ); + functionRegistry.register( + "array_overlaps_nullable", + new ArrayOverlapsUnnestFunction( true, typeConfiguration ) ); } /** * CockroachDB and PostgreSQL array overlaps operator */ - public void arrayOverlaps_operator() { - functionRegistry.register( "array_overlaps", new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, false, false ) ); + public void arrayOverlaps_postgresql() { + functionRegistry.register( "array_overlaps", new ArrayOverlapsOperatorFunction( false, typeConfiguration ) ); + functionRegistry.register( "array_overlaps_nullable", new ArrayOverlapsOperatorFunction( true, typeConfiguration ) ); } /** @@ -2802,72 +2720,6 @@ public class CommonFunctionFactory { "array_overlaps", new OracleArrayOverlapsFunction( typeConfiguration, false ) ); - } - - /** - * H2 array_contains_all_nullable() function - */ - public void arrayContainsAllNullable_h2() { - functionRegistry.register( - "array_contains_all_nullable", - new H2ArrayContainsQuantifiedEmulation( typeConfiguration, true, true ) - ); - } - - /** - * HSQL array_contains_all_nullable() function - */ - public void arrayContainsAllNullable_hsql() { - functionRegistry.register( - "array_contains_all_nullable", - new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, true, true ) - ); - } - - /** - * CockroachDB and PostgreSQL array contains all nullable operator - */ - public void arrayContainsAllNullable_operator() { - functionRegistry.register( - "array_contains_all_nullable", - new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, true, true ) - ); - } - - /** - * Oracle array_contains_all_nullable() function - */ - public void arrayContainsAllNullable_oracle() { - functionRegistry.register( - "array_contains_all_nullable", - new OracleArrayContainsAllFunction( typeConfiguration, true ) - ); - } - - /** - * H2 array_overlaps_nullable() function - */ - public void arrayOverlapsNullable_h2() { - functionRegistry.register( - "array_overlaps_nullable", - new H2ArrayContainsQuantifiedEmulation( typeConfiguration, false, true ) - ); - } - - /** - * HSQL, CockroachDB and PostgreSQL array_overlaps_nullable() function - */ - public void arrayOverlapsNullable_unnest() { - functionRegistry.register( - "array_overlaps_nullable", - new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, false, true ) - ); - } - - /** - * Oracle array_overlaps_nullable() function - */ - public void arrayOverlapsNullable_oracle() { functionRegistry.register( "array_overlaps_nullable", new OracleArrayOverlapsFunction( typeConfiguration, true ) @@ -3031,8 +2883,8 @@ public class CommonFunctionFactory { /** * H2 array_set() function */ - public void arraySet_h2() { - functionRegistry.register( "array_set", new H2ArraySetFunction() ); + public void arraySet_h2(int maximumArraySize) { + functionRegistry.register( "array_set", new H2ArraySetFunction( maximumArraySize ) ); } /** @@ -3075,8 +2927,8 @@ public class CommonFunctionFactory { /** * H2 array_remove() function */ - public void arrayRemove_h2() { - functionRegistry.register( "array_remove", new H2ArrayRemoveFunction() ); + public void arrayRemove_h2(int maximumArraySize) { + functionRegistry.register( "array_remove", new H2ArrayRemoveFunction( maximumArraySize ) ); } /** @@ -3096,8 +2948,8 @@ public class CommonFunctionFactory { /** * H2 array_remove_index() function */ - public void arrayRemoveIndex_h2() { - functionRegistry.register( "array_remove_index", new H2ArrayRemoveIndexFunction() ); + public void arrayRemoveIndex_h2(int maximumArraySize) { + functionRegistry.register( "array_remove_index", new H2ArrayRemoveIndexFunction( maximumArraySize ) ); } /** @@ -3175,8 +3027,8 @@ public class CommonFunctionFactory { /** * H2 array_replace() function */ - public void arrayReplace_h2() { - functionRegistry.register( "array_replace", new H2ArrayReplaceFunction() ); + public void arrayReplace_h2(int maximumArraySize) { + functionRegistry.register( "array_replace", new H2ArrayReplaceFunction( maximumArraySize ) ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ConcatPipeFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ConcatPipeFunction.java index 1276ee0c24..f74f2f4f23 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ConcatPipeFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ConcatPipeFunction.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function; import java.util.Collections; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers; @@ -48,6 +49,7 @@ public class ConcatPipeFunction extends AbstractSqmSelfRenderingFunctionDescript public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { String separator = "("; for ( int i = 0; i < sqlAstArguments.size(); i++ ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CountFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CountFunction.java index bf8616c216..4df09c17a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CountFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CountFunction.java @@ -13,6 +13,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; @@ -133,8 +134,12 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor { } @Override - public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, walker ); + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + render( sqlAppender, sqlAstArguments, null, returnType, walker ); } @Override @@ -142,6 +147,7 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor { SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); final SqlAstNode arg = sqlAstArguments.get( 0 ); @@ -207,15 +213,15 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor { sqlAppender.appendSql( "''" ); } sqlAppender.appendSql( SqlAppender.COMMA_SEPARATOR_CHAR ); - chr.render( sqlAppender, chrArguments, translator ); + chr.render( sqlAppender, chrArguments, returnType, translator ); sqlAppender.appendSql( "),'')," ); - chr.render( sqlAppender, chrArguments, translator ); + chr.render( sqlAppender, chrArguments, returnType, translator ); sqlAppender.appendSql( concatOperator ); sqlAppender.appendSql( "'" ); sqlAppender.appendSql( argumentNumber ); sqlAppender.appendSql( "')" ); sqlAppender.appendSql( concatOperator ); - chr.render( sqlAppender, chrArguments, translator ); + chr.render( sqlAppender, chrArguments, returnType, translator ); sqlAppender.appendSql( concatOperator ); sqlAppender.appendSql( "coalesce(nullif(coalesce(" ); needsConcat = renderCastedArgument( sqlAppender, translator, expressions.get( i ) ); @@ -226,9 +232,9 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor { sqlAppender.appendSql( "''" ); } sqlAppender.appendSql( SqlAppender.COMMA_SEPARATOR_CHAR ); - chr.render( sqlAppender, chrArguments, translator ); + chr.render( sqlAppender, chrArguments, returnType, translator ); sqlAppender.appendSql( "),'')," ); - chr.render( sqlAppender, chrArguments, translator ); + chr.render( sqlAppender, chrArguments, returnType, translator ); sqlAppender.appendSql( concatOperator ); sqlAppender.appendSql( "'" ); sqlAppender.appendSql( argumentNumber ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java index 4a613a80ad..703d556505 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CurrentFunction.java @@ -6,6 +6,7 @@ */ package org.hibernate.dialect.function; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; @@ -41,6 +42,7 @@ public class CurrentFunction public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.appendSql( sql ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java index dea34f3d22..1e8537cf6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2FormatEmulation.java @@ -8,20 +8,11 @@ package org.hibernate.dialect.function; import java.util.List; -import org.hibernate.dialect.OracleDialect; import org.hibernate.query.ReturnableType; -import org.hibernate.query.spi.QueryEngine; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; -import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; -import org.hibernate.query.sqm.function.SqmFunctionDescriptor; -import org.hibernate.query.sqm.produce.function.ArgumentsValidator; -import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; -import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.sql.ast.tree.expression.Format; import org.hibernate.type.spi.TypeConfiguration; import jakarta.persistence.TemporalType; @@ -49,6 +40,7 @@ public class DB2FormatEmulation extends FormatFunction { public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression datetime = (Expression) arguments.get( 0 ); sqlAppender.appendSql( "varchar_format(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2PositionFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2PositionFunction.java index 3347b2d3ba..16d5a7b2f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2PositionFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2PositionFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -41,6 +42,7 @@ public class DB2PositionFunction extends AbstractSqmSelfRenderingFunctionDescrip public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final int argumentCount = arguments.size(); sqlAppender.appendSql( "position(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java index 029c7b0d6b..977a55aea1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.FunctionParameterType; @@ -43,6 +44,7 @@ public class DB2SubstringFunction extends AbstractSqmSelfRenderingFunctionDescri public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final int argumentCount = arguments.size(); sqlAppender.appendSql( "substring(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java index a416215db6..f2f3ca3a67 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java @@ -13,7 +13,7 @@ import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -39,7 +39,7 @@ import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEM * * @author Marco Belladelli */ -public class DateTruncEmulation extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { +public class DateTruncEmulation extends AbstractSqmFunctionDescriptor implements FunctionRenderer { protected final String toDateFunction; private final SqmFormat sqmFormat; @@ -58,6 +58,7 @@ public class DateTruncEmulation extends AbstractSqmFunctionDescriptor implements public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.appendSql( toDateFunction ); sqlAppender.append( '(' ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java index c8165e33c9..21dc09b98f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyLpadEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -46,6 +47,7 @@ public class DerbyLpadEmulation public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final SqlAstNode string = arguments.get( 0 ); final SqlAstNode length = arguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java index 30b4a01136..b37d71b5e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyRpadEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -46,6 +47,7 @@ public class DerbyRpadEmulation public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final SqlAstNode string = arguments.get( 0 ); final SqlAstNode length = arguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java index fc8cc1c26f..73e703a7be 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/EveryAnyEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -70,6 +71,7 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { if ( trueLiteral != null ) { sqlAppender.appendSql( "case when " ); @@ -108,7 +110,9 @@ public class EveryAnyEmulation extends AbstractSqmSelfRenderingFunctionDescripto @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - this.render( sqlAppender, sqlAstArguments, null, walker ); + SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + this.render( sqlAppender, sqlAstArguments, null, returnType, walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java index 0390e69bf3..34204e4fd6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ExtractFunction.java @@ -13,7 +13,7 @@ import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -48,8 +48,7 @@ import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEM * * @author Gavin King */ -public class ExtractFunction - extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { +public class ExtractFunction extends AbstractSqmFunctionDescriptor implements FunctionRenderer { private final Dialect dialect; @@ -70,6 +69,7 @@ public class ExtractFunction public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final ExtractUnit field = (ExtractUnit) sqlAstArguments.get( 0 ); final TemporalUnit unit = field.getUnit(); @@ -100,7 +100,7 @@ public class ExtractFunction ); return new SelfRenderingSqmFunction<>( this, - (sqlAppender, sqlAstArguments, walker) -> sqlAstArguments.get( 0 ).accept( walker ), + (sqlAppender, sqlAstArguments, returnType, walker) -> sqlAstArguments.get( 0 ).accept( walker ), Collections.singletonList( offsetPath ), null, null, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/FormatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/FormatFunction.java index 58c3b543cf..b88037560b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/FormatFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/FormatFunction.java @@ -20,6 +20,7 @@ import org.hibernate.query.sqm.ComparisonOperator; import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.FunctionRenderingSupport; import org.hibernate.query.sqm.function.MultipatternSqmFunctionDescriptor; import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; @@ -61,7 +62,7 @@ import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEM * * @author Christian Beikov */ -public class FormatFunction extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { +public class FormatFunction extends AbstractSqmFunctionDescriptor implements FunctionRenderer { private final String nativeFunctionName; private final boolean reversedArguments; @@ -103,6 +104,7 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.appendSql( nativeFunctionName ); sqlAppender.append( '(' ); @@ -171,6 +173,10 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun private final boolean supportsPatternLiterals; private final TypeConfiguration typeConfiguration; + /** + * @deprecated Use {@link #FormatSqmFunction(SqmFunctionDescriptor, FunctionRenderer, List, ReturnableType, ArgumentsValidator, FunctionReturnTypeResolver, boolean, QueryEngine)} instead + */ + @Deprecated(forRemoval = true) public FormatSqmFunction( SqmFunctionDescriptor descriptor, FunctionRenderingSupport renderingSupport, @@ -194,6 +200,29 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun this.typeConfiguration = queryEngine.getTypeConfiguration(); } + public FormatSqmFunction( + SqmFunctionDescriptor descriptor, + FunctionRenderer renderer, + List> arguments, + ReturnableType impliedResultType, + ArgumentsValidator argumentsValidator, + FunctionReturnTypeResolver returnTypeResolver, + boolean supportsPatternLiterals, + QueryEngine queryEngine) { + super( + descriptor, + renderer, + arguments, + impliedResultType, + argumentsValidator, + returnTypeResolver, + queryEngine.getCriteriaBuilder(), + "format" + ); + this.supportsPatternLiterals = supportsPatternLiterals; + this.typeConfiguration = queryEngine.getTypeConfiguration(); + } + @Override public Expression convertToSqlAst(SqmToSqlAstConverter walker) { final List arguments = resolveSqlAstArguments( getArguments(), walker ); @@ -293,7 +322,7 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun formatExpression, new SelfRenderingFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), List.of( arguments.get( 0 ), new QueryLiteral<>( formatPart, stringType ) @@ -419,7 +448,7 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun formatExpression, new SelfRenderingFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), List.of( arguments.get( 0 ), new Format( chunks[i] ) ), resultType, mappingModelExpressible @@ -440,7 +469,7 @@ public class FormatFunction extends AbstractSqmFunctionDescriptor implements Fun } return new SelfRenderingFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, resultType, mappingModelExpressible diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetFunction.java index 2a5c299a06..8cb3ad0f96 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetFunction.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function; import java.util.Collections; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; @@ -42,8 +43,9 @@ public class HypotheticalSetFunction extends AbstractSqmSelfRenderingFunctionDes public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -51,8 +53,9 @@ public class HypotheticalSetFunction extends AbstractSqmSelfRenderingFunctionDes SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -61,6 +64,7 @@ public class HypotheticalSetFunction extends AbstractSqmSelfRenderingFunctionDes List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { if ( filter != null && !translator.supportsFilterClause() ) { throw new IllegalArgumentException( "Can't emulate filter clause for inverse distribution function [" + getName() + "]" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetWindowEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetWindowEmulation.java index 6b1d44cbe4..691fbdd62c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetWindowEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/HypotheticalSetWindowEmulation.java @@ -101,7 +101,7 @@ public class HypotheticalSetWindowEmulation extends HypotheticalSetFunction { } final SelfRenderingFunctionSqlAstExpression function = new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), Collections.emptyList(), getFilter() == null ? null : (Predicate) getFilter().accept( walker ), Collections.emptyList(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/IntegralTimestampaddFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/IntegralTimestampaddFunction.java index 7304ce1900..b9988deac6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/IntegralTimestampaddFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/IntegralTimestampaddFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import org.hibernate.dialect.Dialect; import org.hibernate.metamodel.mapping.BasicValuedMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.BinaryArithmeticOperator; import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; @@ -53,6 +54,7 @@ public class IntegralTimestampaddFunction public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final DurationUnit field = (DurationUnit) arguments.get( 0 ); @@ -64,7 +66,7 @@ public class IntegralTimestampaddFunction renderWithUnitConversion( sqlAppender, magnitude, to, walker, field, unit ); } else { - super.render( sqlAppender, arguments, walker ); + super.render( sqlAppender, arguments, returnType, walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionFunction.java index 8f073d2598..732f72bb52 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionFunction.java @@ -75,8 +75,9 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -84,8 +85,9 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -94,6 +96,7 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { if ( filter != null && !translator.supportsFilterClause() ) { throw new IllegalArgumentException( "Can't emulate filter clause for inverse distribution function [" + getName() + "]" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionWindowEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionWindowEmulation.java index 3447e48ca3..d480adabcd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionWindowEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/InverseDistributionWindowEmulation.java @@ -96,7 +96,7 @@ public class InverseDistributionWindowEmulation extends InverseDistributionFunct } final SelfRenderingFunctionSqlAstExpression function = new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, getFilter() == null ? null : (Predicate) getFilter().accept( walker ), withinGroup, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/LengthFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/LengthFunction.java index 9bcbdf5ad4..3c8b653820 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/LengthFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/LengthFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.FunctionParameterType; @@ -54,6 +55,7 @@ public class LengthFunction extends AbstractSqmSelfRenderingFunctionDescriptor { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression expression = (Expression) sqlAstArguments.get( 0 ); final JdbcType jdbcType = expression.getExpressionType().getSingleJdbcMapping().getJdbcType(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggFunction.java index adb3a9b4f9..e248974b58 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggFunction.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function; import java.util.Collections; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -52,8 +53,9 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -61,8 +63,9 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -71,6 +74,7 @@ public class ListaggFunction extends AbstractSqmSelfRenderingFunctionDescriptor List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( "listagg(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggGroupConcatEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggGroupConcatEmulation.java index 81e00901cc..ca1698f76e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggGroupConcatEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggGroupConcatEmulation.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function; import java.util.Collections; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -52,8 +53,9 @@ public class ListaggGroupConcatEmulation extends AbstractSqmSelfRenderingFunctio public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -61,8 +63,9 @@ public class ListaggGroupConcatEmulation extends AbstractSqmSelfRenderingFunctio SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -71,6 +74,7 @@ public class ListaggGroupConcatEmulation extends AbstractSqmSelfRenderingFunctio List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( "group_concat(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggStringAggEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggStringAggEmulation.java index 888b0fa11a..158e5a3424 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggStringAggEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ListaggStringAggEmulation.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.List; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; @@ -65,8 +66,9 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -74,8 +76,9 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -84,6 +87,7 @@ public class ListaggStringAggEmulation extends AbstractSqmSelfRenderingFunctionD List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( functionName ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/MinMaxCaseEveryAnyEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/MinMaxCaseEveryAnyEmulation.java index 01dcf20a38..fa8ca2e234 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/MinMaxCaseEveryAnyEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/MinMaxCaseEveryAnyEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -54,6 +55,7 @@ public class MinMaxCaseEveryAnyEmulation extends AbstractSqmSelfRenderingFunctio SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { if ( every ) { sqlAppender.appendSql( "min(case when " ); @@ -77,7 +79,10 @@ public class MinMaxCaseEveryAnyEmulation extends AbstractSqmSelfRenderingFunctio @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - this.render( sqlAppender, sqlAstArguments, null, walker ); + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + this.render( sqlAppender, sqlAstArguments, null, returnType, walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/ModeStatsModeEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/ModeStatsModeEmulation.java index 97c0bdefa0..ce8ef0f1b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/ModeStatsModeEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/ModeStatsModeEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; @@ -37,6 +38,7 @@ public class ModeStatsModeEmulation extends InverseDistributionFunction { List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( "stats_mode(" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/OracleTruncFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/OracleTruncFunction.java index 2b3c74a982..74c430aefd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/OracleTruncFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/OracleTruncFunction.java @@ -12,6 +12,7 @@ import java.util.List; import org.hibernate.query.ReturnableType; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.TemporalUnit; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.FunctionRenderingSupport; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; @@ -45,11 +46,11 @@ public class OracleTruncFunction extends TruncFunction { ReturnableType impliedResultType, QueryEngine queryEngine) { final List> args = new ArrayList<>( arguments ); - final FunctionRenderingSupport renderingSupport; + final FunctionRenderer renderer; final ArgumentsValidator argumentsValidator; if ( arguments.size() == 2 && arguments.get( 1 ) instanceof SqmExtractUnit ) { // datetime truncation - renderingSupport = datetimeRenderingSupport; + renderer = datetimeRenderingSupport; argumentsValidator = TruncArgumentsValidator.DATETIME_VALIDATOR; // the trunc() function requires translating the temporal_unit to a format string final TemporalUnit temporalUnit = ( (SqmExtractUnit) arguments.get( 1 ) ).getUnit(); @@ -92,13 +93,13 @@ public class OracleTruncFunction extends TruncFunction { } else { // numeric truncation - renderingSupport = numericRenderingSupport; + renderer = numericRenderingSupport; argumentsValidator = TruncArgumentsValidator.NUMERIC_VALIDATOR; } return new SelfRenderingSqmFunction<>( this, - renderingSupport, + renderer, args, impliedResultType, argumentsValidator, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLMinMaxFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLMinMaxFunction.java index fb4d1bb400..4937b23cd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLMinMaxFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLMinMaxFunction.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function; import java.util.List; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -46,8 +47,12 @@ public class PostgreSQLMinMaxFunction extends AbstractSqmSelfRenderingFunctionDe } @Override - public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, walker ); + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + render( sqlAppender, sqlAstArguments, null, returnType, walker ); } @Override @@ -55,6 +60,7 @@ public class PostgreSQLMinMaxFunction extends AbstractSqmSelfRenderingFunctionDe SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( getName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLTruncRoundFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLTruncRoundFunction.java index ece88e3bef..74b1221266 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLTruncRoundFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/PostgreSQLTruncRoundFunction.java @@ -11,6 +11,7 @@ import java.util.List; import org.hibernate.query.ReturnableType; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.FunctionRenderingSupport; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -46,7 +47,7 @@ import static org.hibernate.query.sqm.produce.function.FunctionParameterType.NUM * @author Marco Belladelli * @see PostgreSQL documentation */ -public class PostgreSQLTruncRoundFunction extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { +public class PostgreSQLTruncRoundFunction extends AbstractSqmFunctionDescriptor implements FunctionRenderer { private final boolean supportsTwoArguments; public PostgreSQLTruncRoundFunction(String name, boolean supportsTwoArguments) { @@ -60,7 +61,11 @@ public class PostgreSQLTruncRoundFunction extends AbstractSqmFunctionDescriptor } @Override - public void render(SqlAppender sqlAppender, List arguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List arguments, + ReturnableType returnType, + SqlAstTranslator walker) { final int numberOfArguments = arguments.size(); final Expression firstArg = (Expression) arguments.get( 0 ); final JdbcType jdbcType = firstArg.getExpressionType().getSingleJdbcMapping().getJdbcType(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java index 3d166c1394..e9f98adbed 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -43,6 +44,7 @@ public class QuantifiedLeastGreatestEmulation public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final int numberOfArguments = arguments.size(); if ( numberOfArguments > 1 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java index 3b1d2cc1a4..9e3aca2f8e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerEveryAnyEmulation.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -56,6 +57,7 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { if ( every ) { sqlAppender.appendSql( "min(iif(" ); @@ -79,7 +81,10 @@ public class SQLServerEveryAnyEmulation extends AbstractSqmSelfRenderingFunction @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - this.render( sqlAppender, sqlAstArguments, null, walker ); + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + this.render( sqlAppender, sqlAstArguments, null, (ReturnableType) null, walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerFormatEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerFormatEmulation.java index 22baed0cb0..8374b8284c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerFormatEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/SQLServerFormatEmulation.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function; import java.util.List; import jakarta.persistence.TemporalType; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -31,6 +32,7 @@ public class SQLServerFormatEmulation extends FormatFunction { public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression datetime = (Expression) arguments.get(0); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlFunction.java index ca8d4e25f9..f2454a15c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; @@ -38,6 +39,7 @@ public class SqlFunction public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final QueryLiteral sqlFragmentLiteral = (QueryLiteral) arguments.get( 0 ); final String sqlFragment = sqlFragmentLiteral.getLiteralValue(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlServerConvertTruncFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlServerConvertTruncFunction.java index 197f8c3a1b..a14a9c1092 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlServerConvertTruncFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/SqlServerConvertTruncFunction.java @@ -79,6 +79,7 @@ public class SqlServerConvertTruncFunction extends TruncFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.appendSql( toDateFunction ); sqlAppender.append( '(' ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/SybaseTruncFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/SybaseTruncFunction.java index 79929c5ca2..05fcd1e159 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/SybaseTruncFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/SybaseTruncFunction.java @@ -87,6 +87,7 @@ public class SybaseTruncFunction extends TruncFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.appendSql( toDateFunction ); sqlAppender.append( '(' ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java index 05c159a53e..f8513def73 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java @@ -65,6 +65,7 @@ public class TimestampaddFunction public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final DurationUnit field = (DurationUnit) arguments.get( 0 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java index ec338f98fb..0acdb948de 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java @@ -74,6 +74,7 @@ public class TimestampdiffFunction public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final DurationUnit field = (DurationUnit) arguments.get( 0 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java index f4fd857511..343c71800c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java @@ -10,6 +10,7 @@ import java.util.List; import org.hibernate.query.ReturnableType; import org.hibernate.query.spi.QueryEngine; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.FunctionRenderingSupport; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -28,7 +29,7 @@ import org.hibernate.type.spi.TypeConfiguration; * * @author Christian Beikov */ -public class TransactSQLStrFunction extends CastStrEmulation implements FunctionRenderingSupport { +public class TransactSQLStrFunction extends CastStrEmulation implements FunctionRenderer { public TransactSQLStrFunction(TypeConfiguration typeConfiguration) { super( @@ -66,7 +67,11 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function } @Override - public void render(SqlAppender sqlAppender, List arguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List arguments, + ReturnableType returnType, + SqlAstTranslator walker) { sqlAppender.appendSql( "str(" ); arguments.get( 0 ).accept( walker ); for ( int i = 1; i < arguments.size(); i++ ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java index 0577f0aed5..fa44b7ba69 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java @@ -7,6 +7,7 @@ package org.hibernate.dialect.function; import org.hibernate.dialect.Dialect; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.TrimSpec; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; @@ -58,7 +59,11 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor { } @Override - public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { final TrimSpec specification = ( (TrimSpecification) sqlAstArguments.get( 0 ) ).getSpecification(); final Object trimCharacter = ( (Literal) sqlAstArguments.get( 1 ) ).getLiteralValue(); final Expression sourceExpr = (Expression) sqlAstArguments.get( 2 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TruncFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TruncFunction.java index a2d825ea67..837e590258 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TruncFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TruncFunction.java @@ -14,7 +14,7 @@ import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.TemporalUnit; import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; @@ -100,7 +100,7 @@ public class TruncFunction extends AbstractSqmFunctionDescriptor { QueryEngine queryEngine) { final NodeBuilder nodeBuilder = queryEngine.getCriteriaBuilder(); final List> args = new ArrayList<>( arguments ); - final FunctionRenderingSupport renderingSupport; + final FunctionRenderer renderingSupport; final ArgumentsValidator argumentsValidator; if ( arguments.size() == 2 && arguments.get( 1 ) instanceof SqmExtractUnit ) { // datetime truncation @@ -171,7 +171,7 @@ public class TruncFunction extends AbstractSqmFunctionDescriptor { ); } - private static class TruncRenderingSupport implements FunctionRenderingSupport { + protected static class TruncRenderingSupport implements FunctionRenderer { private final PatternRenderer truncPattern; private final PatternRenderer twoArgTruncPattern; @@ -184,6 +184,7 @@ public class TruncFunction extends AbstractSqmFunctionDescriptor { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final PatternRenderer pattern; if ( twoArgTruncPattern != null && sqlAstArguments.size() == 2 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsFunction.java new file mode 100644 index 0000000000..314dbd5c42 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsFunction.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.dialect.function.array; + +import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; +import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; +import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * Encapsulates the validator, return type and argument type resolvers for the array_contains function. + * Subclasses only have to implement the rendering. + */ +public abstract class AbstractArrayContainsFunction extends AbstractSqmSelfRenderingFunctionDescriptor { + + protected final boolean nullable; + + public AbstractArrayContainsFunction(boolean nullable, TypeConfiguration typeConfiguration) { + super( + "array_contains" + ( nullable ? "_nullable" : "" ), + StandardArgumentsValidators.composite( + StandardArgumentsValidators.exactly( 2 ), + ArrayContainsArgumentValidator.INSTANCE + ), + StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ), + ArrayContainsArgumentTypeResolver.INSTANCE + ); + this.nullable = nullable; + } + + @Override + public String getArgumentListSignature() { + return "(ARRAY haystackArray, OBJECT needleElementOrArray)"; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsQuantifiedFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayOverlapsFunction.java similarity index 65% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsQuantifiedFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayOverlapsFunction.java index 924ee815dd..eb38aa14ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayContainsQuantifiedFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/AbstractArrayOverlapsFunction.java @@ -13,25 +13,31 @@ import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolv import org.hibernate.type.spi.TypeConfiguration; /** - * Encapsulates the validator, return type and argument type resolvers for the quantified array_contains functions. + * Encapsulates the validator, return type and argument type resolvers for the array_overlaps function. * Subclasses only have to implement the rendering. */ -public abstract class AbstractArrayContainsQuantifiedFunction extends AbstractSqmSelfRenderingFunctionDescriptor { +public abstract class AbstractArrayOverlapsFunction extends AbstractSqmSelfRenderingFunctionDescriptor { - public AbstractArrayContainsQuantifiedFunction(String functionName, TypeConfiguration typeConfiguration) { + protected final boolean nullable; + + public AbstractArrayOverlapsFunction(boolean nullable, TypeConfiguration typeConfiguration) { super( - functionName, + "array_overlaps" + ( nullable ? "_nullable" : "" ), StandardArgumentsValidators.composite( StandardArgumentsValidators.exactly( 2 ), ArraysOfSameTypeArgumentValidator.INSTANCE ), StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ), - StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE + StandardFunctionArgumentTypeResolvers.byArgument( + StandardFunctionArgumentTypeResolvers.argumentsOrImplied( 1 ), + StandardFunctionArgumentTypeResolvers.argumentsOrImplied( 0 ) + ) ); + this.nullable = nullable; } @Override public String getArgumentListSignature() { - return "(ARRAY haystackArray, ARRAY needleArray)"; + return "(ARRAY array0, OBJECT array1)"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAggFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAggFunction.java index 88d46a03f3..68202cd13d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAggFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAggFunction.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function.array; import java.util.Collections; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -50,8 +51,9 @@ public class ArrayAggFunction extends AbstractSqmSelfRenderingFunctionDescriptor public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -59,8 +61,9 @@ public class ArrayAggFunction extends AbstractSqmSelfRenderingFunctionDescriptor SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -69,6 +72,7 @@ public class ArrayAggFunction extends AbstractSqmSelfRenderingFunctionDescriptor List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { final boolean caseWrapper = filter != null && ( !supportsFilter || !translator.supportsFilterClause() ); sqlAppender.appendSql( functionName ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAndElementArgumentTypeResolver.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAndElementArgumentTypeResolver.java index 8dffe03c4f..3dd759167a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAndElementArgumentTypeResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayAndElementArgumentTypeResolver.java @@ -9,11 +9,10 @@ package org.hibernate.dialect.function.array; import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.metamodel.mapping.MappingModelExpressible; import org.hibernate.metamodel.model.domain.DomainType; -import org.hibernate.query.ReturnableType; -import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.type.BasicPluralType; @@ -40,21 +39,27 @@ public class ArrayAndElementArgumentTypeResolver implements FunctionArgumentType SqmToSqlAstConverter converter) { if ( argumentIndex == arrayIndex ) { for ( int elementIndex : elementIndexes ) { - final SqmTypedNode argument = function.getArguments().get( elementIndex ); - final DomainType sqmType = argument.getExpressible().getSqmType(); - if ( sqmType instanceof ReturnableType ) { - return DdlTypeHelper.resolveArrayType( - sqmType, - converter.getCreationContext().getSessionFactory().getTypeConfiguration() - ); + final SqmTypedNode node = function.getArguments().get( elementIndex ); + if ( node instanceof SqmExpression ) { + final MappingModelExpressible expressible = converter.determineValueMapping( (SqmExpression) node ); + if ( expressible != null ) { + return DdlTypeHelper.resolveArrayType( + (DomainType) expressible.getSingleJdbcMapping(), + converter.getCreationContext().getSessionFactory().getTypeConfiguration() + ); + } } } } else if ( ArrayHelper.contains( elementIndexes, argumentIndex ) ) { - final SqmTypedNode argument = function.getArguments().get( arrayIndex ); - final SqmExpressible sqmType = argument.getNodeType(); - if ( sqmType instanceof BasicPluralType ) { - return ( (BasicPluralType) sqmType ).getElementType(); + final SqmTypedNode node = function.getArguments().get( arrayIndex ); + if ( node instanceof SqmExpression ) { + final MappingModelExpressible expressible = converter.determineValueMapping( (SqmExpression) node ); + if ( expressible != null ) { + if ( expressible.getSingleJdbcMapping() instanceof BasicPluralType ) { + return ( (BasicPluralType) expressible.getSingleJdbcMapping() ).getElementType(); + } + } } } return null; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayArgumentValidator.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayArgumentValidator.java index c4c5144d9f..040537b948 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayArgumentValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayArgumentValidator.java @@ -44,7 +44,7 @@ public class ArrayArgumentValidator implements ArgumentsValidator { return getElementType( arrayIndex, arguments, functionName, typeConfiguration ); } - protected BasicType getElementType( + protected BasicPluralType getPluralType( int arrayIndex, List> arguments, String functionName, @@ -64,6 +64,14 @@ public class ArrayArgumentValidator implements ArgumentsValidator { ) ); } - return ( (BasicPluralType) arrayType ).getElementType(); + return (BasicPluralType) arrayType; + } + + protected BasicType getElementType( + int arrayIndex, + List> arguments, + String functionName, + TypeConfiguration typeConfiguration) { + return getPluralType( arrayIndex, arguments, functionName, typeConfiguration ).getElementType(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatElementFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatElementFunction.java index bd08bacf8e..a9cfc0f61c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatElementFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatElementFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.sql.ast.SqlAstTranslator; @@ -47,6 +48,7 @@ public class ArrayConcatElementFunction extends AbstractSqmSelfRenderingFunction public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final SqlAstNode firstArgument = sqlAstArguments.get( 0 ); final SqlAstNode secondArgument = sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatFunction.java index 0ee3c9f291..60c8cf3dfe 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConcatFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers; @@ -44,6 +45,7 @@ public class ArrayConcatFunction extends AbstractSqmSelfRenderingFunctionDescrip public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.append( prefix ); sqlAstArguments.get( 0 ).accept( walker ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java index 26db64df14..c7f306c629 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayConstructorFunction.java @@ -10,6 +10,7 @@ import java.util.List; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.internal.TypecheckUtil; @@ -39,7 +40,11 @@ public class ArrayConstructorFunction extends AbstractSqmSelfRenderingFunctionDe } @Override - public void render(SqlAppender sqlAppender, List arguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List arguments, + ReturnableType returnType, + SqlAstTranslator walker) { if ( withKeyword ) { sqlAppender.append( "array" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java new file mode 100644 index 0000000000..af076cb3aa --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentTypeResolver.java @@ -0,0 +1,60 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect.function.array; + +import org.hibernate.metamodel.mapping.MappingModelExpressible; +import org.hibernate.metamodel.model.domain.DomainType; +import org.hibernate.query.ReturnableType; +import org.hibernate.query.sqm.SqmExpressible; +import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver; +import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; +import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.expression.SqmExpression; +import org.hibernate.query.sqm.tree.expression.SqmFunction; +import org.hibernate.type.BasicPluralType; + +/** + * A {@link FunctionArgumentTypeResolver} that resolves the argument types for the {@code array_contains} function. + */ +public class ArrayContainsArgumentTypeResolver implements FunctionArgumentTypeResolver { + + public static final FunctionArgumentTypeResolver INSTANCE = new ArrayContainsArgumentTypeResolver(); + + @Override + public MappingModelExpressible resolveFunctionArgumentType( + SqmFunction function, + int argumentIndex, + SqmToSqlAstConverter converter) { + if ( argumentIndex == 0 ) { + final SqmTypedNode node = function.getArguments().get( 1 ); + if ( node instanceof SqmExpression ) { + final MappingModelExpressible expressible = converter.determineValueMapping( (SqmExpression) node ); + if ( expressible != null ) { + if ( expressible.getSingleJdbcMapping() instanceof BasicPluralType ) { + return expressible; + } + else { + return DdlTypeHelper.resolveArrayType( + (DomainType) expressible.getSingleJdbcMapping(), + converter.getCreationContext().getSessionFactory().getTypeConfiguration() + ); + } + } + } + } + else if ( argumentIndex == 1 ) { + final SqmTypedNode node = function.getArguments().get( 0 ); + if ( node instanceof SqmExpression ) { + final MappingModelExpressible expressible = converter.determineValueMapping( (SqmExpression) node ); + if ( expressible != null ) { + return expressible; + } + } + } + return null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentValidator.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentValidator.java new file mode 100644 index 0000000000..921c469645 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsArgumentValidator.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect.function.array; + +import java.util.List; + +import org.hibernate.query.sqm.SqmExpressible; +import org.hibernate.query.sqm.produce.function.ArgumentsValidator; +import org.hibernate.query.sqm.produce.function.FunctionArgumentException; +import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.type.BasicPluralType; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * A {@link ArgumentsValidator} that validates the arguments for the {@code array_contains} function. + */ +public class ArrayContainsArgumentValidator extends ArrayArgumentValidator { + + public static final ArgumentsValidator INSTANCE = new ArrayContainsArgumentValidator(); + + protected ArrayContainsArgumentValidator() { + super( 0 ); + } + + @Override + public void validate( + List> arguments, + String functionName, + TypeConfiguration typeConfiguration) { + final BasicPluralType haystackType = getPluralType( 0, arguments, functionName, typeConfiguration ); + final SqmExpressible expressible = arguments.get( 1 ).getExpressible(); + final SqmExpressible needleType = expressible == null ? null : expressible.getSqmType(); + if ( needleType != null && !haystackType.equals( needleType ) && !haystackType.getElementType().equals( needleType ) ) { + throw new FunctionArgumentException( + String.format( + "Parameter 1 of function '%s()' has type %s, but argument is of type '%s'", + functionName, + haystackType.getJavaTypeDescriptor().getTypeName(), + needleType.getTypeName() + ) + ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsOperatorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsOperatorFunction.java index 3b792fd51f..524cf323ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsOperatorFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsOperatorFunction.java @@ -8,53 +8,73 @@ package org.hibernate.dialect.function.array; import java.util.List; -import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; -import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; -import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.type.BasicPluralType; import org.hibernate.type.spi.TypeConfiguration; /** * Special array contains function that also applies a cast to the element argument. PostgreSQL needs this, * because by default it assumes a {@code text[]}, which is not compatible with {@code varchar[]}. */ -public class ArrayContainsOperatorFunction extends AbstractSqmSelfRenderingFunctionDescriptor { +public class ArrayContainsOperatorFunction extends ArrayContainsUnnestFunction { - public ArrayContainsOperatorFunction(TypeConfiguration typeConfiguration) { - super( - "array_contains", - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 2 ), - ArrayAndElementArgumentValidator.DEFAULT_INSTANCE - ), - StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ), - ArrayAndElementArgumentTypeResolver.DEFAULT_INSTANCE - ); + public ArrayContainsOperatorFunction(boolean nullable, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); - final Expression elementExpression = (Expression) sqlAstArguments.get( 1 ); - arrayExpression.accept( walker ); - sqlAppender.append( "@>" ); - if ( needsArrayCasting( elementExpression ) ) { - sqlAppender.append( "cast(array[" ); - elementExpression.accept( walker ); - sqlAppender.append( "] as " ); - sqlAppender.append( DdlTypeHelper.getCastTypeName( arrayExpression.getExpressionType(), walker ) ); - sqlAppender.append( ')' ); + final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); + final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); + final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType(); + final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping(); + if ( needleType == null || needleType instanceof BasicPluralType ) { + if ( nullable ) { + super.render( sqlAppender, sqlAstArguments, returnType, walker ); + } + else { + haystackExpression.accept( walker ); + sqlAppender.append( "@>" ); + needleExpression.accept( walker ); + } } else { - sqlAppender.append( "array[" ); - elementExpression.accept( walker ); - sqlAppender.append( ']' ); + if ( nullable ) { + sqlAppender.append( "array_position(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + needleExpression.accept( walker ); + sqlAppender.append( ") is not null" ); + } + else { + haystackExpression.accept( walker ); + sqlAppender.append( "@>" ); + if ( needsArrayCasting( needleExpression ) ) { + sqlAppender.append( "cast(array[" ); + needleExpression.accept( walker ); + sqlAppender.append( "] as " ); + sqlAppender.append( DdlTypeHelper.getCastTypeName( + haystackExpression.getExpressionType(), + walker + ) ); + sqlAppender.append( ')' ); + } + else { + sqlAppender.append( "array[" ); + needleExpression.accept( walker ); + sqlAppender.append( ']' ); + } + } } } @@ -62,9 +82,4 @@ public class ArrayContainsOperatorFunction extends AbstractSqmSelfRenderingFunct // PostgreSQL doesn't do implicit conversion between text[] and varchar[], so we need casting return elementExpression.getExpressionType().getSingleJdbcMapping().getJdbcType().isString(); } - - @Override - public String getArgumentListSignature() { - return "(ARRAY array, OBJECT element)"; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsUnnestFunction.java new file mode 100644 index 0000000000..a6b425df63 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsUnnestFunction.java @@ -0,0 +1,77 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.dialect.function.array; + +import java.util.List; + +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.type.BasicPluralType; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * Implement the array contains function by using {@code unnest}. + */ +public class ArrayContainsUnnestFunction extends AbstractArrayContainsFunction { + + public ArrayContainsUnnestFunction(boolean nullable, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); + } + + @Override + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); + final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); + final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType(); + final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping(); + if ( needleType == null || needleType instanceof BasicPluralType ) { + sqlAppender.append( '(' ); + if ( ArrayHelper.isNullable( haystackExpression ) ) { + walker.render( haystackExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( " is not null and " ); + } + if ( ArrayHelper.isNullable( needleExpression ) ) { + walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( " is not null and " ); + } + if ( !nullable ) { + sqlAppender.append( "not exists(select 1 from unnest(" ); + walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( ") t(i) where t.i is null) and " ); + } + sqlAppender.append( "not exists(select * from unnest(" ); + walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( ") except select * from unnest(" ); + walker.render( haystackExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( ")))" ); + } + else { + sqlAppender.append( "exists(select 1 from unnest(" ); + walker.render( haystackExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( ") t(i) where t.i" ); + if ( nullable ) { + sqlAppender.append( " is not distinct from " ); + } + else { + sqlAppender.append( '=' ); + } + walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( ")" ); + } + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayGetUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayGetUnnestFunction.java index 1cc412b164..0211709efe 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayGetUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayGetUnnestFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -41,6 +42,7 @@ public class ArrayGetUnnestFunction extends AbstractSqmSelfRenderingFunctionDesc public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression indexExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayHelper.java new file mode 100644 index 0000000000..96a993990a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayHelper.java @@ -0,0 +1,21 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.dialect.function.array; + +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.ast.tree.expression.FunctionExpression; + +public class ArrayHelper { + public static boolean isNullable(Expression expression) { + if ( expression instanceof FunctionExpression ) { + final FunctionExpression functionExpression = (FunctionExpression) expression; + // An array function literal is never null + return !"array".equals( functionExpression.getFunctionName() ); + } + return true; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsQuantifiedOperatorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsOperatorFunction.java similarity index 64% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsQuantifiedOperatorFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsOperatorFunction.java index ab9ea40f33..23969f9d30 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsQuantifiedOperatorFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsOperatorFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -15,32 +16,27 @@ import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.type.spi.TypeConfiguration; /** - * Array contains all function that uses the PostgreSQL {@code @>} operator. + * Array overlaps function that uses the PostgreSQL {@code &&} operator. */ -public class ArrayContainsQuantifiedOperatorFunction extends ArrayContainsQuantifiedUnnestFunction { +public class ArrayOverlapsOperatorFunction extends ArrayOverlapsUnnestFunction { - public ArrayContainsQuantifiedOperatorFunction(TypeConfiguration typeConfiguration, boolean all, boolean nullable) { - super( typeConfiguration, all, nullable ); + public ArrayOverlapsOperatorFunction(boolean nullable, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, - SqlAstTranslator walker) { + ReturnableType returnType, SqlAstTranslator walker) { if ( nullable ) { - super.render( sqlAppender, sqlAstArguments, walker ); + super.render( sqlAppender, sqlAstArguments, returnType, walker ); } else { final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); haystackExpression.accept( walker ); - if ( all ) { - sqlAppender.append( "@>" ); - } - else { - sqlAppender.append( "&&" ); - } + sqlAppender.append( "&&" ); needleExpression.accept( walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsQuantifiedUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsUnnestFunction.java similarity index 62% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsQuantifiedUnnestFunction.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsUnnestFunction.java index 26a712b8d2..0c58665c8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayContainsQuantifiedUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayOverlapsUnnestFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -15,48 +16,40 @@ import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.type.spi.TypeConfiguration; /** - * Implement the contains all function by using {@code unnest}. + * Implement the overlaps function by using {@code unnest}. */ -public class ArrayContainsQuantifiedUnnestFunction extends AbstractArrayContainsQuantifiedFunction { +public class ArrayOverlapsUnnestFunction extends AbstractArrayOverlapsFunction { - protected final boolean all; - protected final boolean nullable; - - public ArrayContainsQuantifiedUnnestFunction(TypeConfiguration typeConfiguration, boolean all, boolean nullable) { - super( "array_contains_" + ( all ? "all" : "any" ), typeConfiguration ); - this.all = all; - this.nullable = nullable; + public ArrayOverlapsUnnestFunction(boolean nullable, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); sqlAppender.append( '(' ); - haystackExpression.accept( walker ); - sqlAppender.append( " is not null and " ); - needleExpression.accept( walker ); - sqlAppender.append( " is not null and " ); + if ( ArrayHelper.isNullable( haystackExpression ) ) { + haystackExpression.accept( walker ); + sqlAppender.append( " is not null and " ); + } + if ( ArrayHelper.isNullable( needleExpression ) ) { + needleExpression.accept( walker ); + sqlAppender.append( " is not null and " ); + } if ( !nullable ) { sqlAppender.append( "not exists(select 1 from unnest(" ); needleExpression.accept( walker ); sqlAppender.append( ") t(i) where t.i is null) and " ); } - if ( all ) { - sqlAppender.append( "not " ); - } sqlAppender.append( "exists(select * from unnest(" ); needleExpression.accept( walker ); sqlAppender.append( ")" ); - if ( all ) { - sqlAppender.append( " except " ); - } - else { - sqlAppender.append( " intersect " ); - } + sqlAppender.append( " intersect " ); sqlAppender.append( "select * from unnest(" ); haystackExpression.accept( walker ); sqlAppender.append( ")))" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayRemoveIndexUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayRemoveIndexUnnestFunction.java index 410601906b..194d667f43 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayRemoveIndexUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayRemoveIndexUnnestFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -47,6 +48,7 @@ public class ArrayRemoveIndexUnnestFunction extends AbstractSqmSelfRenderingFunc public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression indexExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayReplaceUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayReplaceUnnestFunction.java index 6a08ec312d..3a66a99ac3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayReplaceUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArrayReplaceUnnestFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.sql.ast.SqlAstTranslator; @@ -36,6 +37,7 @@ public class ArrayReplaceUnnestFunction extends AbstractSqmSelfRenderingFunction public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression oldExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySetUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySetUnnestFunction.java index dcbf4b2726..f9bf22e6fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySetUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySetUnnestFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -45,6 +46,7 @@ public class ArraySetUnnestFunction extends AbstractSqmSelfRenderingFunctionDesc public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression indexExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySliceUnnestFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySliceUnnestFunction.java index a2faabf410..9fb58b46c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySliceUnnestFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/ArraySliceUnnestFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; @@ -47,6 +48,7 @@ public class ArraySliceUnnestFunction extends AbstractSqmSelfRenderingFunctionDe public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression startIndexExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/CastingArrayConstructorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/CastingArrayConstructorFunction.java deleted file mode 100644 index ea4b017a47..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/CastingArrayConstructorFunction.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.dialect.function.array; - -import java.util.List; - -import org.hibernate.engine.jdbc.Size; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.model.domain.DomainType; -import org.hibernate.query.ReturnableType; -import org.hibernate.query.spi.QueryEngine; -import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; -import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; -import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; -import org.hibernate.query.sqm.produce.function.ArgumentsValidator; -import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; -import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; -import org.hibernate.query.sqm.tree.SqmTypedNode; -import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.spi.SqlAppender; -import org.hibernate.sql.ast.tree.SqlAstNode; -import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.type.BasicPluralType; -import org.hibernate.type.BasicType; -import org.hibernate.type.descriptor.sql.DdlType; -import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; -import org.hibernate.type.spi.TypeConfiguration; - -/** - * Special array constructor function that also applies a cast to the array literal, - * based on the inferred result type. PostgreSQL needs this, - * because by default it assumes a {@code text[]}, which is not compatible with {@code varchar[]}. - */ -public class CastingArrayConstructorFunction extends ArrayConstructorFunction { - - public CastingArrayConstructorFunction() { - super( true ); - } - - @Override - protected SelfRenderingSqmFunction generateSqmFunctionExpression( - List> arguments, - ReturnableType impliedResultType, - QueryEngine queryEngine) { - return new ArrayConstructorSqmFunction<>( - this, - this, - arguments, - impliedResultType, - getArgumentsValidator(), - getReturnTypeResolver(), - queryEngine.getCriteriaBuilder(), - getName() - ); - } - - protected static class ArrayConstructorSqmFunction extends SelfRenderingSqmFunction { - public ArrayConstructorSqmFunction( - CastingArrayConstructorFunction descriptor, - FunctionRenderingSupport renderingSupport, - List> arguments, - ReturnableType impliedResultType, - ArgumentsValidator argumentsValidator, - FunctionReturnTypeResolver returnTypeResolver, - NodeBuilder nodeBuilder, - String name) { - super( - descriptor, - renderingSupport, - arguments, - impliedResultType, - argumentsValidator, - returnTypeResolver, - nodeBuilder, - name - ); - } - - @Override - public Expression convertToSqlAst(SqmToSqlAstConverter walker) { - final ReturnableType resultType = resolveResultType( walker ); - - List arguments = resolveSqlAstArguments( getArguments(), walker ); - if ( getArgumentsValidator() != null ) { - getArgumentsValidator().validateSqlTypes( arguments, getFunctionName() ); - } - return new SelfRenderingFunctionSqlAstExpression( - getFunctionName(), - getRenderingSupport(), - arguments, - resultType, - resultType == null ? null : getMappingModelExpressible( walker, resultType, arguments ) - ) { - @Override - public void renderToSql( - SqlAppender sqlAppender, - SqlAstTranslator walker, - SessionFactoryImplementor sessionFactory) { - String arrayTypeName = null; - if ( resultType != null ) { - final DomainType type = resultType.getSqmType(); - if ( type instanceof BasicPluralType ) { - final BasicPluralType pluralType = (BasicPluralType) type; - final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration(); - final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry(); - final DdlType ddlType = ddlTypeRegistry.getDescriptor( - pluralType.getJdbcType().getDdlTypeCode() - ); - arrayTypeName = ddlType.getCastTypeName( Size.nil(), pluralType, ddlTypeRegistry ); - sqlAppender.append( "cast(" ); - } - } - super.renderToSql( sqlAppender, walker, sessionFactory ); - if ( arrayTypeName != null ) { - sqlAppender.appendSql( " as " ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.appendSql( ')' ); - } - } - }; - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/DdlTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/DdlTypeHelper.java index 4f35d41a79..9a021a01d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/DdlTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/DdlTypeHelper.java @@ -13,6 +13,7 @@ import org.hibernate.engine.jdbc.Size; import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.SqlTypedMapping; import org.hibernate.metamodel.model.domain.DomainType; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.type.BasicPluralType; @@ -59,13 +60,13 @@ public class DdlTypeHelper { return AbstractSqlAstTranslator.getCastTypeName( (SqlTypedMapping) type, walker.getSessionFactory() ); } else { - final BasicType jdbcMapping = (BasicType) type.getSingleJdbcMapping(); + final BasicType basicType = (BasicType) type.getSingleJdbcMapping(); final TypeConfiguration typeConfiguration = walker.getSessionFactory().getTypeConfiguration(); final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry(); final DdlType ddlType = ddlTypeRegistry.getDescriptor( - jdbcMapping.getJdbcType().getDdlTypeCode() + basicType.getJdbcType().getDdlTypeCode() ); - return ddlType.getCastTypeName( Size.nil(), jdbcMapping, ddlTypeRegistry ); + return ddlType.getCastTypeName( Size.nil(), basicType, ddlTypeRegistry ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsFunction.java new file mode 100644 index 0000000000..9880fedc0a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsFunction.java @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.dialect.function.array; + +import java.util.List; + +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.type.BasicPluralType; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same. + */ +public class H2ArrayContainsFunction extends AbstractArrayContainsFunction { + + private final int maximumArraySize; + + public H2ArrayContainsFunction(boolean nullable, int maximumArraySize, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); + this.maximumArraySize = maximumArraySize; + } + + @Override + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); + final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); + final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType(); + final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping(); + if ( needleType == null || needleType instanceof BasicPluralType ) { + sqlAppender.append( '(' ); + if ( ArrayHelper.isNullable( haystackExpression ) ) { + haystackExpression.accept( walker ); + sqlAppender.append( " is not null and " ); + } + if ( ArrayHelper.isNullable( needleExpression ) ) { + needleExpression.accept( walker ); + sqlAppender.append( " is not null and " ); + } + if ( !nullable ) { + sqlAppender.append( "not array_contains(" ); + needleExpression.accept( walker ); + sqlAppender.append( ",null) and " ); + } + sqlAppender.append( "not " ); + sqlAppender.append( "exists(select array_get(" ); + walker.render( needleExpression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + sqlAppender.append( ",t.i) from system_range(1," ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); + sqlAppender.append( ") t(i) where array_length(" ); + needleExpression.accept( walker ); + sqlAppender.append( ")>=t.i" ); + sqlAppender.append( " except " ); + sqlAppender.append( "select array_get(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ",t.i) from system_range(1," ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); + sqlAppender.append( ") t(i) where array_length(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ")>=t.i))" ); + } + else { + sqlAppender.append( "array_contains(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + needleExpression.accept( walker ); + sqlAppender.append( ')' ); + } + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsQuantifiedEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayOverlapsFunction.java similarity index 67% rename from hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsQuantifiedEmulation.java rename to hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayOverlapsFunction.java index 8276cd3b5b..43992511d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayContainsQuantifiedEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayOverlapsFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -19,61 +20,52 @@ import org.hibernate.type.spi.TypeConfiguration; * due to https://github.com/h2database/h2database/issues/1815. * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same. */ -public class H2ArrayContainsQuantifiedEmulation extends AbstractArrayContainsQuantifiedFunction { +public class H2ArrayOverlapsFunction extends AbstractArrayOverlapsFunction { - private final boolean all; - private final boolean nullable; + private final int maximumArraySize; - public H2ArrayContainsQuantifiedEmulation(TypeConfiguration typeConfiguration, boolean all, boolean nullable) { - super( "array_contains_" + ( all ? "all" : "any" ), typeConfiguration ); - this.all = all; - this.nullable = nullable; + public H2ArrayOverlapsFunction(boolean nullable, int maximumArraySize, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); + this.maximumArraySize = maximumArraySize; } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); sqlAppender.append( '(' ); - haystackExpression.accept( walker ); - sqlAppender.append( " is not null and " ); - needleExpression.accept( walker ); - sqlAppender.append( " is not null and " ); + if ( ArrayHelper.isNullable( haystackExpression ) ) { + haystackExpression.accept( walker ); + sqlAppender.append( " is not null and " ); + } + if ( ArrayHelper.isNullable( needleExpression ) ) { + needleExpression.accept( walker ); + sqlAppender.append( " is not null and " ); + } if ( !nullable ) { sqlAppender.append( "not array_contains(" ); needleExpression.accept( walker ); sqlAppender.append( ",null) and " ); } - if ( all ) { - sqlAppender.append( "not " ); - } sqlAppender.append( "exists(select array_get(" ); needleExpression.accept( walker ); sqlAppender.append( ",t.i) from system_range(1," ); - sqlAppender.append( Integer.toString( getMaximumArraySize() ) ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); sqlAppender.append( ") t(i) where array_length(" ); needleExpression.accept( walker ); sqlAppender.append( ")>=t.i" ); - if ( all ) { - sqlAppender.append( " except " ); - } - else { - sqlAppender.append( " intersect " ); - } + sqlAppender.append( " intersect " ); sqlAppender.append( "select array_get(" ); haystackExpression.accept( walker ); sqlAppender.append( ",t.i) from system_range(1," ); - sqlAppender.append( Integer.toString( getMaximumArraySize() ) ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); sqlAppender.append( ") t(i) where array_length(" ); haystackExpression.accept( walker ); sqlAppender.append( ")>=t.i))" ); } - protected int getMaximumArraySize() { - return 1000; - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveFunction.java index 0250bb1db4..c936776a67 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveFunction.java @@ -8,23 +8,30 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; /** - * H2 array_remove function. + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same. */ public class H2ArrayRemoveFunction extends AbstractArrayRemoveFunction { - public H2ArrayRemoveFunction() { + private final int maximumArraySize; + + public H2ArrayRemoveFunction(int maximumArraySize) { + this.maximumArraySize = maximumArraySize; } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression elementExpression = (Expression) sqlAstArguments.get( 1 ); @@ -33,7 +40,7 @@ public class H2ArrayRemoveFunction extends AbstractArrayRemoveFunction { sqlAppender.append( " is null then null else coalesce((select array_agg(array_get("); arrayExpression.accept( walker ); sqlAppender.append(",i.idx)) from system_range(1," ); - sqlAppender.append( Integer.toString( getMaximumArraySize() ) ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); sqlAppender.append( ") i(idx) where i.idx<=coalesce(cardinality("); arrayExpression.accept( walker ); sqlAppender.append("),0) and array_get("); @@ -42,8 +49,4 @@ public class H2ArrayRemoveFunction extends AbstractArrayRemoveFunction { elementExpression.accept( walker ); sqlAppender.append( "),array[]) end" ); } - - protected int getMaximumArraySize() { - return 1000; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveIndexFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveIndexFunction.java index 966f899bc3..9d85e911a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveIndexFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayRemoveIndexFunction.java @@ -8,24 +8,31 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; /** - * H2 array_remove_index function. + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same. */ public class H2ArrayRemoveIndexFunction extends ArrayRemoveIndexUnnestFunction { - public H2ArrayRemoveIndexFunction() { + private final int maximumArraySize; + + public H2ArrayRemoveIndexFunction(int maximumArraySize) { super( false ); + this.maximumArraySize = maximumArraySize; } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression indexExpression = (Expression) sqlAstArguments.get( 1 ); @@ -34,15 +41,11 @@ public class H2ArrayRemoveIndexFunction extends ArrayRemoveIndexUnnestFunction { sqlAppender.append( " is null then null else coalesce((select array_agg(array_get("); arrayExpression.accept( walker ); sqlAppender.append(",i.idx)) from system_range(1," ); - sqlAppender.append( Integer.toString( getMaximumArraySize() ) ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); sqlAppender.append( ") i(idx) where i.idx<=coalesce(cardinality("); arrayExpression.accept( walker ); sqlAppender.append("),0) and i.idx is distinct from " ); indexExpression.accept( walker ); sqlAppender.append( "),array[]) end" ); } - - protected int getMaximumArraySize() { - return 1000; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayReplaceFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayReplaceFunction.java index 947c2e8987..44f1c0a996 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayReplaceFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArrayReplaceFunction.java @@ -8,20 +8,30 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; /** - * H2 array_replace function. + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same. */ public class H2ArrayReplaceFunction extends ArrayReplaceUnnestFunction { + private final int maximumArraySize; + + public H2ArrayReplaceFunction(int maximumArraySize) { + this.maximumArraySize = maximumArraySize; + } + @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression oldExpression = (Expression) sqlAstArguments.get( 1 ); @@ -37,13 +47,9 @@ public class H2ArrayReplaceFunction extends ArrayReplaceUnnestFunction { sqlAppender.append( " else array_get(" ); arrayExpression.accept( walker ); sqlAppender.append(",i.idx) end) from system_range(1," ); - sqlAppender.append( Integer.toString( getMaximumArraySize() ) ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); sqlAppender.append( ") i(idx) where i.idx<=coalesce(cardinality("); arrayExpression.accept( walker ); sqlAppender.append("),0)),array[]) end" ); } - - protected int getMaximumArraySize() { - return 1000; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArraySetFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArraySetFunction.java index b481cc919f..5c570afcec 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArraySetFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/H2ArraySetFunction.java @@ -8,24 +8,30 @@ package org.hibernate.dialect.function.array; import java.util.List; -import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; /** - * H2 array_set function. + * H2 requires a very special emulation, because {@code unnest} is pretty much useless, + * due to https://github.com/h2database/h2database/issues/1815. + * This emulation uses {@code array_get}, {@code array_length} and {@code system_range} functions to roughly achieve the same. */ public class H2ArraySetFunction extends ArraySetUnnestFunction { - public H2ArraySetFunction() { + private final int maximumArraySize; + + public H2ArraySetFunction(int maximumArraySize) { + this.maximumArraySize = maximumArraySize; } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression indexExpression = (Expression) sqlAstArguments.get( 1 ); @@ -41,7 +47,7 @@ public class H2ArraySetFunction extends ArraySetUnnestFunction { sqlAppender.append(") then array_get("); arrayExpression.accept( walker ); sqlAppender.append(",i.idx) end) from system_range(1," ); - sqlAppender.append( Integer.toString( getMaximumArraySize() ) ); + sqlAppender.append( Integer.toString( maximumArraySize ) ); sqlAppender.append( ") i(idx) where i.idx<=greatest(case when "); arrayExpression.accept( walker ); sqlAppender.append(" is not null then cardinality(" ); @@ -50,8 +56,4 @@ public class H2ArraySetFunction extends ArraySetUnnestFunction { indexExpression.accept( walker ); sqlAppender.append( "))" ); } - - protected int getMaximumArraySize() { - return 1000; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayConstructorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayConstructorFunction.java new file mode 100644 index 0000000000..6142998a0b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayConstructorFunction.java @@ -0,0 +1,77 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.dialect.function.array; + +import java.util.List; + +import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.metamodel.mapping.SqlTypedMapping; +import org.hibernate.query.ReturnableType; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.type.BottomType; + +public class HSQLArrayConstructorFunction extends ArrayConstructorFunction { + + public HSQLArrayConstructorFunction() { + super( true ); + } + + @Override + public void render( + SqlAppender sqlAppender, + List arguments, + ReturnableType returnType, + SqlAstTranslator walker) { + final String castTypeName; + if ( returnType != null && hasOnlyBottomArguments( arguments ) ) { + if ( returnType instanceof SqlTypedMapping ) { + castTypeName = AbstractSqlAstTranslator.getCastTypeName( (SqlTypedMapping) returnType, walker.getSessionFactory() ); + } + else { + castTypeName = DdlTypeHelper.getCastTypeName( (JdbcMappingContainer) returnType, walker ); + } + sqlAppender.append( "cast(" ); + } + else { + castTypeName = null; + } + sqlAppender.append( "array" ); + final int size = arguments.size(); + if ( size == 0 ) { + sqlAppender.append( '[' ); + } + else { + char separator = '['; + for ( int i = 0; i < size; i++ ) { + SqlAstNode argument = arguments.get( i ); + sqlAppender.append( separator ); + argument.accept( walker ); + separator = ','; + } + } + sqlAppender.append( ']' ); + if ( castTypeName != null ) { + sqlAppender.append( " as " ); + sqlAppender.append( castTypeName ); + sqlAppender.append( ')' ); + } + } + + private boolean hasOnlyBottomArguments(List arguments) { + for ( int i = 0; i < arguments.size(); i++ ) { + final Expression argument = (Expression) arguments.get( i ); + if ( !( argument.getExpressionType().getSingleJdbcMapping() instanceof BottomType ) ) { + return false; + } + } + return !arguments.isEmpty(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayPositionFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayPositionFunction.java index 1c56e399c4..ed38287f2c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayPositionFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayPositionFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -27,6 +28,7 @@ public class HSQLArrayPositionFunction extends AbstractArrayPositionFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression elementExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayRemoveFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayRemoveFunction.java index 635772f9a2..32e8d70d30 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayRemoveFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArrayRemoveFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -25,6 +26,7 @@ public class HSQLArrayRemoveFunction extends AbstractArrayRemoveFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression elementExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArraySetFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArraySetFunction.java index 14094e5dd9..0fff4d508b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArraySetFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/HSQLArraySetFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -25,6 +26,7 @@ public class HSQLArraySetFunction extends ArraySetUnnestFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression indexExpression = (Expression) sqlAstArguments.get( 1 ); @@ -41,8 +43,4 @@ public class HSQLArraySetFunction extends ArraySetUnnestFunction { arrayExpression.accept( walker ); sqlAppender.append( ") with ordinality t(val, idx) on i.idx=t.idx)" ); } - - protected int getMaximumArraySize() { - return 1000; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayAggEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayAggEmulation.java index f2011fa176..472177be46 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayAggEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayAggEmulation.java @@ -18,10 +18,9 @@ import org.hibernate.query.ReturnableType; import org.hibernate.query.SemanticException; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.FunctionKind; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.SelfRenderingOrderedSetAggregateFunctionSqlAstExpression; import org.hibernate.query.sqm.function.SelfRenderingSqmOrderedSetAggregateFunction; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; @@ -38,7 +37,6 @@ import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.cte.CteContainer; -import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.cte.SelfRenderingCteObject; import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Expression; @@ -73,8 +71,9 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), returnType, walker ); } @Override @@ -82,8 +81,9 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { - render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), walker ); + render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), returnType, walker ); } @Override @@ -92,6 +92,7 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { sqlAppender.appendSql( "json_arrayagg" ); sqlAppender.appendSql( '(' ); @@ -154,7 +155,7 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes protected static class OracleArrayAggSqmFunction extends SelfRenderingSqmOrderedSetAggregateFunction { public OracleArrayAggSqmFunction( OracleArrayAggEmulation descriptor, - FunctionRenderingSupport renderingSupport, + FunctionRenderer renderingSupport, List> arguments, SqmPredicate filter, SqmOrderByClause withinGroupClause, @@ -241,7 +242,7 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes } final OracleArrayAggEmulationSqlAstExpression expression = new OracleArrayAggEmulationSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, getFilter() == null ? null : walker.visitNestedTopLevelPredicate( getFilter() ), withinGroup, @@ -261,7 +262,7 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes public OracleArrayAggEmulationSqlAstExpression( String functionName, - FunctionRenderingSupport renderer, + FunctionRenderer renderer, List sqlAstArguments, Predicate filter, List withinGroup, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatElementFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatElementFunction.java index bb000737ea..e052291721 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatElementFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatElementFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -26,6 +27,7 @@ public class OracleArrayConcatElementFunction extends ArrayConcatElementFunction public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression firstArgument = (Expression) sqlAstArguments.get( 0 ); final Expression secondArgument = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatFunction.java index 8e0f978592..cab164f383 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConcatFunction.java @@ -9,10 +9,10 @@ package org.hibernate.dialect.function.array; import java.util.List; import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; -import org.hibernate.sql.ast.tree.expression.Expression; /** * Oracle concatenation function for arrays. @@ -27,18 +27,11 @@ public class OracleArrayConcatFunction extends ArrayConcatFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - JdbcMappingContainer expressionType = null; - for ( SqlAstNode sqlAstArgument : sqlAstArguments ) { - expressionType = ( (Expression) sqlAstArgument ).getExpressionType(); - if ( expressionType != null ) { - break; - } - } - - final String arrayTypeName = DdlTypeHelper.getTypeName( expressionType, walker ); + final String arrayTypeName = DdlTypeHelper.getTypeName( (JdbcMappingContainer) returnType, walker ); sqlAppender.append( arrayTypeName ); sqlAppender.append( "_concat" ); - super.render( sqlAppender, sqlAstArguments, walker ); + super.render( sqlAppender, sqlAstArguments, returnType, walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConstructorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConstructorFunction.java index 551f94d027..2807d60653 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConstructorFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayConstructorFunction.java @@ -8,28 +8,13 @@ package org.hibernate.dialect.function.array; import java.util.List; -import org.hibernate.engine.jdbc.Size; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.query.ReturnableType; import org.hibernate.query.SemanticException; -import org.hibernate.query.spi.QueryEngine; -import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; -import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; -import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; -import org.hibernate.query.sqm.produce.function.ArgumentsValidator; -import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; -import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; -import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; -import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.type.BasicPluralType; -import org.hibernate.type.descriptor.sql.DdlType; -import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; -import org.hibernate.type.spi.TypeConfiguration; public class OracleArrayConstructorFunction extends ArrayConstructorFunction { @@ -38,100 +23,38 @@ public class OracleArrayConstructorFunction extends ArrayConstructorFunction { } @Override - protected SelfRenderingSqmFunction generateSqmFunctionExpression( - List> arguments, - ReturnableType impliedResultType, - QueryEngine queryEngine) { - return new ArrayConstructorSqmFunction<>( - this, - this, - arguments, - impliedResultType, - getArgumentsValidator(), - getReturnTypeResolver(), - queryEngine.getCriteriaBuilder(), - getName() - ); - } - - protected static class ArrayConstructorSqmFunction extends SelfRenderingSqmFunction { - public ArrayConstructorSqmFunction( - OracleArrayConstructorFunction descriptor, - FunctionRenderingSupport renderingSupport, - List> arguments, - ReturnableType impliedResultType, - ArgumentsValidator argumentsValidator, - FunctionReturnTypeResolver returnTypeResolver, - NodeBuilder nodeBuilder, - String name) { - super( - descriptor, - renderingSupport, - arguments, - impliedResultType, - argumentsValidator, - returnTypeResolver, - nodeBuilder, - name + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + if ( returnType == null ) { + throw new SemanticException( + "Oracle array constructor emulation requires knowledge about the return type, but resolved return type could not be determined" ); } - - @Override - public Expression convertToSqlAst(SqmToSqlAstConverter walker) { - final ReturnableType resultType = resolveResultType( walker ); - - List arguments = resolveSqlAstArguments( getArguments(), walker ); - if ( getArgumentsValidator() != null ) { - getArgumentsValidator().validateSqlTypes( arguments, getFunctionName() ); - } - if ( resultType == null ) { - throw new SemanticException( - "Oracle array constructor emulation requires knowledge about the return type, but resolved return type could not be determined" - ); - } - final DomainType type = resultType.getSqmType(); - if ( !( type instanceof BasicPluralType ) ) { - throw new SemanticException( - "Oracle array constructor emulation requires a basic plural return type, but resolved return type was: " + type - ); - } - final BasicPluralType pluralType = (BasicPluralType) type; - final TypeConfiguration typeConfiguration = walker.getCreationContext().getSessionFactory().getTypeConfiguration(); - final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry(); - final DdlType ddlType = ddlTypeRegistry.getDescriptor( - pluralType.getJdbcType().getDdlTypeCode() + final DomainType type = returnType.getSqmType(); + if ( !( type instanceof BasicPluralType ) ) { + throw new SemanticException( + "Oracle array constructor emulation requires a basic plural return type, but resolved return type was: " + type ); - final String arrayTypeName = ddlType.getCastTypeName( Size.nil(), pluralType, ddlTypeRegistry ); - return new SelfRenderingFunctionSqlAstExpression( - getFunctionName(), - getRenderingSupport(), - arguments, - resultType, - getMappingModelExpressible( walker, resultType, arguments ) - ) { - @Override - public void renderToSql( - SqlAppender sqlAppender, - SqlAstTranslator walker, - SessionFactoryImplementor sessionFactory) { - sqlAppender.appendSql( arrayTypeName ); - final List arguments = getArguments(); - final int size = arguments.size(); - if ( size == 0 ) { - sqlAppender.append( '(' ); - } - else { - char separator = '('; - for ( int i = 0; i < size; i++ ) { - SqlAstNode argument = arguments.get( i ); - sqlAppender.append( separator ); - argument.accept( walker ); - separator = ','; - } - } - sqlAppender.append( ')' ); - } - }; } + final BasicPluralType pluralType = (BasicPluralType) type; + final String arrayTypeName = DdlTypeHelper.getCastTypeName( pluralType, walker ); + sqlAppender.appendSql( arrayTypeName ); + final int size = sqlAstArguments.size(); + if ( size == 0 ) { + sqlAppender.append( '(' ); + } + else { + char separator = '('; + for ( int i = 0; i < size; i++ ) { + SqlAstNode argument = sqlAstArguments.get( i ); + sqlAppender.append( separator ); + argument.accept( walker ); + separator = ','; + } + } + sqlAppender.append( ')' ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsAllFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsAllFunction.java deleted file mode 100644 index 05f5f66a5c..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsAllFunction.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.dialect.function.array; - -import java.util.List; - -import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.spi.SqlAppender; -import org.hibernate.sql.ast.tree.SqlAstNode; -import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.type.spi.TypeConfiguration; - -public class OracleArrayContainsAllFunction extends AbstractArrayContainsQuantifiedFunction { - - private final boolean nullable; - - public OracleArrayContainsAllFunction(TypeConfiguration typeConfiguration, boolean nullable) { - super( "array_contains_all", typeConfiguration ); - this.nullable = nullable; - } - - @Override - public void render( - SqlAppender sqlAppender, - List sqlAstArguments, - SqlAstTranslator walker) { - final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); - final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.append( "_contains_all(" ); - haystackExpression.accept( walker ); - sqlAppender.append( ',' ); - sqlAstArguments.get( 1 ).accept( walker ); - sqlAppender.append( ',' ); - sqlAppender.append( nullable ? "1" : "0" ); - sqlAppender.append( ")>0" ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java index 3d64c91dbd..715446d88b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsFunction.java @@ -8,46 +8,49 @@ package org.hibernate.dialect.function.array; import java.util.List; -import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; -import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; -import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.type.BasicPluralType; import org.hibernate.type.spi.TypeConfiguration; -public class OracleArrayContainsFunction extends AbstractSqmSelfRenderingFunctionDescriptor { +public class OracleArrayContainsFunction extends AbstractArrayContainsFunction { - public OracleArrayContainsFunction(TypeConfiguration typeConfiguration) { - super( - "array_contains", - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 2 ), - ArrayAndElementArgumentValidator.DEFAULT_INSTANCE - ), - StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ), - ArrayAndElementArgumentTypeResolver.DEFAULT_INSTANCE - ); + public OracleArrayContainsFunction(boolean nullable, TypeConfiguration typeConfiguration) { + super( nullable, typeConfiguration ); } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { - final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); - final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker ); + final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); + final Expression needleExpression = (Expression) sqlAstArguments.get( 1 ); + final JdbcMappingContainer needleTypeContainer = needleExpression.getExpressionType(); + final JdbcMapping needleType = needleTypeContainer == null ? null : needleTypeContainer.getSingleJdbcMapping(); + final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker ); sqlAppender.appendSql( arrayTypeName ); - sqlAppender.append( "_position(" ); - arrayExpression.accept( walker ); - sqlAppender.append( ',' ); - sqlAstArguments.get( 1 ).accept( walker ); - sqlAppender.append( ")>0" ); - } - - @Override - public String getArgumentListSignature() { - return "(ARRAY array, OBJECT element)"; + if ( needleType == null || needleType instanceof BasicPluralType ) { + sqlAppender.append( "_contains(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ',' ); + sqlAppender.append( nullable ? "1" : "0" ); + sqlAppender.append( ")>0" ); + } + else { + sqlAppender.append( "_position(" ); + haystackExpression.accept( walker ); + sqlAppender.append( ',' ); + needleExpression.accept( walker ); + sqlAppender.append( ")>0" ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsNullFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsNullFunction.java deleted file mode 100644 index d2c6f454ae..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayContainsNullFunction.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.dialect.function.array; - -import java.util.List; - -import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; -import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; -import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; -import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.spi.SqlAppender; -import org.hibernate.sql.ast.tree.SqlAstNode; -import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.type.spi.TypeConfiguration; - -public class OracleArrayContainsNullFunction extends AbstractSqmSelfRenderingFunctionDescriptor { - - public OracleArrayContainsNullFunction(TypeConfiguration typeConfiguration) { - super( - "array_contains_null", - StandardArgumentsValidators.composite( - StandardArgumentsValidators.exactly( 1 ), - ArrayArgumentValidator.DEFAULT_INSTANCE - ), - StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ), - null - ); - } - - @Override - public void render( - SqlAppender sqlAppender, - List sqlAstArguments, - SqlAstTranslator walker) { - final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); - final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.append( "_position(" ); - arrayExpression.accept( walker ); - sqlAppender.append( ",null)>0" ); - } - - @Override - public String getArgumentListSignature() { - return "(ARRAY array)"; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayGetFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayGetFunction.java index 8ccc35bd03..9f1ddf41f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayGetFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayGetFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -25,6 +26,7 @@ public class OracleArrayGetFunction extends ArrayGetUnnestFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final String arrayTypeName = DdlTypeHelper.getTypeName( ( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayLengthFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayLengthFunction.java index 11b1c8cca5..1ad5e38798 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayLengthFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayLengthFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; @@ -35,6 +36,7 @@ public class OracleArrayLengthFunction extends AbstractSqmSelfRenderingFunctionD public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java index 6aa23d9847..0e8e5c01a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayOverlapsFunction.java @@ -8,25 +8,24 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.type.spi.TypeConfiguration; -public class OracleArrayOverlapsFunction extends AbstractArrayContainsQuantifiedFunction { - - private final boolean nullable; +public class OracleArrayOverlapsFunction extends AbstractArrayOverlapsFunction { public OracleArrayOverlapsFunction(TypeConfiguration typeConfiguration, boolean nullable) { - super( "array_overlaps", typeConfiguration ); - this.nullable = nullable; + super( nullable, typeConfiguration ); } @Override public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 ); final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayPositionFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayPositionFunction.java index 6ad4fdac80..9e18ab0f2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayPositionFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayPositionFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -24,6 +25,7 @@ public class OracleArrayPositionFunction extends AbstractArrayPositionFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveFunction.java index b2241c10db..3f35efd2b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -25,6 +26,7 @@ public class OracleArrayRemoveFunction extends AbstractArrayRemoveFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final String arrayTypeName = DdlTypeHelper.getTypeName( ( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveIndexFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveIndexFunction.java index 682f783006..410cadc78b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveIndexFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayRemoveIndexFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -26,6 +27,7 @@ public class OracleArrayRemoveIndexFunction extends ArrayRemoveIndexUnnestFuncti public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final String arrayTypeName = DdlTypeHelper.getTypeName( ( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayReplaceFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayReplaceFunction.java index 6f7acd11b0..edaee54d9e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayReplaceFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArrayReplaceFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -22,6 +23,7 @@ public class OracleArrayReplaceFunction extends ArrayReplaceUnnestFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final String arrayTypeName = DdlTypeHelper.getTypeName( ( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySetFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySetFunction.java index c7041ee0a9..16d9930a4c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySetFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySetFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -25,6 +26,7 @@ public class OracleArraySetFunction extends ArraySetUnnestFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final String arrayTypeName = DdlTypeHelper.getTypeName( ( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySliceFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySliceFunction.java index 0600794a8d..7414336710 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySliceFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleArraySliceFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -26,6 +27,7 @@ public class OracleArraySliceFunction extends ArraySliceUnnestFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final String arrayTypeName = DdlTypeHelper.getTypeName( ( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleCollectArrayAggEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleCollectArrayAggEmulation.java deleted file mode 100644 index 94d6c3dcff..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/OracleCollectArrayAggEmulation.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.dialect.function.array; - -import java.util.List; - -import org.hibernate.engine.jdbc.Size; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.model.domain.DomainType; -import org.hibernate.query.ReturnableType; -import org.hibernate.query.SemanticException; -import org.hibernate.query.spi.QueryEngine; -import org.hibernate.query.sqm.NodeBuilder; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; -import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; -import org.hibernate.query.sqm.function.SelfRenderingSqmOrderedSetAggregateFunction; -import org.hibernate.query.sqm.produce.function.ArgumentsValidator; -import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; -import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; -import org.hibernate.query.sqm.tree.SqmTypedNode; -import org.hibernate.query.sqm.tree.expression.SqmDistinct; -import org.hibernate.query.sqm.tree.predicate.SqmPredicate; -import org.hibernate.query.sqm.tree.select.SqmOrderByClause; -import org.hibernate.sql.ast.Clause; -import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.spi.SqlAppender; -import org.hibernate.sql.ast.tree.SqlAstNode; -import org.hibernate.sql.ast.tree.expression.Distinct; -import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.sql.ast.tree.predicate.Predicate; -import org.hibernate.sql.ast.tree.select.SortSpecification; -import org.hibernate.type.BasicPluralType; -import org.hibernate.type.descriptor.sql.DdlType; -import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; -import org.hibernate.type.spi.TypeConfiguration; - -/** - * @author Christian Beikov - */ -public class OracleCollectArrayAggEmulation extends ArrayAggFunction { - - public OracleCollectArrayAggEmulation() { - super( "collect", false, false ); - } - @Override - public SelfRenderingSqmOrderedSetAggregateFunction generateSqmOrderedSetAggregateFunctionExpression( - List> arguments, - SqmPredicate filter, - SqmOrderByClause withinGroupClause, - ReturnableType impliedResultType, - QueryEngine queryEngine) { - if ( arguments.get( 0 ) instanceof SqmDistinct ) { - throw new SemanticException( "Can't emulate distinct clause for Oracle array_agg emulation" ); - } - if ( filter != null ) { - throw new SemanticException( "Can't emulate filter clause for Oracle array_agg emulation" ); - } - return super.generateSqmOrderedSetAggregateFunctionExpression( - arguments, - filter, - withinGroupClause, - impliedResultType, - queryEngine - ); - } - - @Override - public void render( - SqlAppender sqlAppender, - List sqlAstArguments, - Predicate filter, - List withinGroup, - SqlAstTranslator translator) { - sqlAppender.appendSql( "json_arrayagg" ); - sqlAppender.appendSql( '(' ); - final SqlAstNode firstArg = sqlAstArguments.get( 0 ); - final Expression arg; - if ( firstArg instanceof Distinct ) { - sqlAppender.appendSql( "distinct " ); - arg = ( (Distinct) firstArg ).getExpression(); - } - else { - arg = (Expression) firstArg; - } - arg.accept( translator ); - if ( withinGroup != null && !withinGroup.isEmpty() ) { - translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP ); - sqlAppender.appendSql( " order by " ); - withinGroup.get( 0 ).accept( translator ); - for ( int i = 1; i < withinGroup.size(); i++ ) { - sqlAppender.appendSql( ',' ); - withinGroup.get( i ).accept( translator ); - } - translator.getCurrentClauseStack().pop(); - } - sqlAppender.appendSql( " null on null returning clob" ); - sqlAppender.appendSql( ')' ); - if ( filter != null ) { - translator.getCurrentClauseStack().push( Clause.WHERE ); - sqlAppender.appendSql( " filter (where " ); - filter.accept( translator ); - sqlAppender.appendSql( ')' ); - translator.getCurrentClauseStack().pop(); - } - } - -// @Override -// public SelfRenderingSqmOrderedSetAggregateFunction generateSqmOrderedSetAggregateFunctionExpression( -// List> arguments, -// SqmPredicate filter, -// SqmOrderByClause withinGroupClause, -// ReturnableType impliedResultType, -// QueryEngine queryEngine) { -// return new OracleArrayAggSqmFunction<>( -// this, -// this, -// arguments, -// filter, -// withinGroupClause, -// impliedResultType, -// getArgumentsValidator(), -// getReturnTypeResolver(), -// queryEngine.getCriteriaBuilder(), -// getName() -// ); -// } - - protected static class OracleArrayAggSqmFunction extends SelfRenderingSqmOrderedSetAggregateFunction { - public OracleArrayAggSqmFunction( - OracleCollectArrayAggEmulation descriptor, - FunctionRenderingSupport renderingSupport, - List> arguments, - SqmPredicate filter, - SqmOrderByClause withinGroupClause, - ReturnableType impliedResultType, - ArgumentsValidator argumentsValidator, - FunctionReturnTypeResolver returnTypeResolver, - NodeBuilder nodeBuilder, - String name) { - super( - descriptor, - renderingSupport, - arguments, - filter, - withinGroupClause, - impliedResultType, - argumentsValidator, - returnTypeResolver, - nodeBuilder, - name - ); - } - - @Override - public Expression convertToSqlAst(SqmToSqlAstConverter walker) { - final ReturnableType resultType = resolveResultType( walker ); - - List arguments = resolveSqlAstArguments( getArguments(), walker ); - if ( getArgumentsValidator() != null ) { - getArgumentsValidator().validateSqlTypes( arguments, getFunctionName() ); - } - if ( resultType == null ) { - throw new SemanticException( - "Oracle array_agg emulation requires knowledge about the return type, but resolved return type could not be determined" - ); - } - final DomainType type = resultType.getSqmType(); - if ( !( type instanceof BasicPluralType ) ) { - throw new SemanticException( - "Oracle array_agg emulation requires a basic plural return type, but resolved return type was: " + type - ); - } - final BasicPluralType pluralType = (BasicPluralType) type; - final TypeConfiguration typeConfiguration = walker.getCreationContext().getSessionFactory().getTypeConfiguration(); - final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry(); - final DdlType ddlType = ddlTypeRegistry.getDescriptor( - pluralType.getJdbcType().getDdlTypeCode() - ); - final String arrayTypeName = ddlType.getCastTypeName( Size.nil(), pluralType, ddlTypeRegistry ); - return new SelfRenderingFunctionSqlAstExpression( - getFunctionName(), - getRenderingSupport(), - arguments, - resultType, - getMappingModelExpressible( walker, resultType, arguments ) - ) { - @Override - public void renderToSql( - SqlAppender sqlAppender, - SqlAstTranslator walker, - SessionFactoryImplementor sessionFactory) { - // Oracle doesn't have an array_agg function, so we must use the collect function, - // which requires that we cast the result to the array type. - // On empty results, we require that array_agg returns null, - // but Oracle rather returns an empty collection, so we have to handle that. - // Unfortunately, nullif doesn't work with collection types, - // so we have to render a case when expression instead - sqlAppender.append( "case when cast(" ); - super.renderToSql( sqlAppender, walker, sessionFactory ); - sqlAppender.appendSql( " as " ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.appendSql( ")=" ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.appendSql( "() then null else cast(" ); - super.renderToSql( sqlAppender, walker, sessionFactory ); - sqlAppender.appendSql( " as " ); - sqlAppender.appendSql( arrayTypeName ); - sqlAppender.appendSql( ") end" ); - } - }; - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatElementFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatElementFunction.java index 1997f14ce7..52d5544626 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatElementFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatElementFunction.java @@ -9,6 +9,7 @@ package org.hibernate.dialect.function.array; import java.util.List; import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -30,6 +31,7 @@ public class PostgreSQLArrayConcatElementFunction extends ArrayConcatElementFunc public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression firstArgument = (Expression) sqlAstArguments.get( 0 ); final Expression secondArgument = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatFunction.java index 10e095ad53..e3beb3d2c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConcatFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -25,6 +26,7 @@ public class PostgreSQLArrayConcatFunction extends ArrayConcatFunction { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.append( "case when " ); String separator = ""; @@ -36,7 +38,7 @@ public class PostgreSQLArrayConcatFunction extends ArrayConcatFunction { } sqlAppender.append( " then " ); - super.render( sqlAppender, sqlAstArguments, walker ); + super.render( sqlAppender, sqlAstArguments, returnType, walker ); sqlAppender.append( " end" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConstructorFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConstructorFunction.java new file mode 100644 index 0000000000..68a63c5151 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayConstructorFunction.java @@ -0,0 +1,59 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.dialect.function.array; + +import java.util.List; + +import org.hibernate.metamodel.model.domain.DomainType; +import org.hibernate.query.ReturnableType; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.type.BasicPluralType; +import org.hibernate.type.BasicType; + +/** + * Special array constructor function that also applies a cast to the array literal, + * based on the inferred result type. PostgreSQL needs this, + * because by default it assumes a {@code text[]}, which is not compatible with {@code varchar[]}. + */ +public class PostgreSQLArrayConstructorFunction extends ArrayConstructorFunction { + + public PostgreSQLArrayConstructorFunction() { + super( true ); + } + + @Override + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + String arrayTypeName = null; + if ( returnType != null ) { + final DomainType type = returnType.getSqmType(); + if ( type instanceof BasicPluralType ) { + final BasicPluralType pluralType = (BasicPluralType) type; + if ( needsArrayCasting( pluralType.getElementType() ) ) { + arrayTypeName = DdlTypeHelper.getCastTypeName( pluralType, walker ); + sqlAppender.append( "cast(" ); + } + } + } + super.render( sqlAppender, sqlAstArguments, returnType, walker ); + if ( arrayTypeName != null ) { + sqlAppender.appendSql( " as " ); + sqlAppender.appendSql( arrayTypeName ); + sqlAppender.appendSql( ')' ); + } + } + + private static boolean needsArrayCasting(BasicType elementType) { + // PostgreSQL doesn't do implicit conversion between text[] and varchar[], so we need casting + return elementType.getJdbcType().isString(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayPositionFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayPositionFunction.java index 3d56e8f71c..9189acbbca 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayPositionFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/array/PostgreSQLArrayPositionFunction.java @@ -8,6 +8,7 @@ package org.hibernate.dialect.function.array; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -27,6 +28,7 @@ public class PostgreSQLArrayPositionFunction extends AbstractArrayPositionFuncti public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 ); final Expression elementExpression = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ordering/ast/FunctionExpression.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ordering/ast/FunctionExpression.java index 95779d038c..2ce45c1863 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ordering/ast/FunctionExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ordering/ast/FunctionExpression.java @@ -13,8 +13,9 @@ import java.util.List; import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.internal.AbstractDomainPath; import org.hibernate.query.NullPrecedence; +import org.hibernate.query.ReturnableType; import org.hibernate.query.SortDirection; -import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; @@ -30,7 +31,7 @@ import org.hibernate.sql.ast.tree.select.SortSpecification; * * @author Steve Ebersole */ -public class FunctionExpression implements OrderingExpression, FunctionRenderingSupport { +public class FunctionExpression implements OrderingExpression, FunctionRenderer { private final String name; private final List arguments; @@ -108,7 +109,11 @@ public class FunctionExpression implements OrderingExpression, FunctionRendering } @Override - public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { sqlAppender.appendSql( name ); sqlAppender.appendSql( '(' ); if ( !sqlAstArguments.isEmpty() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java index fea4ee4325..c999e26643 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java @@ -21,7 +21,7 @@ import java.util.List; * @author Gavin King */ public abstract class AbstractSqmSelfRenderingFunctionDescriptor - extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { + extends AbstractSqmFunctionDescriptor implements FunctionRenderer { private final FunctionKind functionKind; @@ -82,7 +82,7 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor default: return new SelfRenderingSqmFunction<>( this, - (sqlAppender, sqlAstArguments, walker) -> render(sqlAppender, sqlAstArguments, walker), + this, arguments, impliedResultType, getArgumentsValidator(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderer.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderer.java new file mode 100644 index 0000000000..177691824e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderer.java @@ -0,0 +1,81 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query.sqm.function; + +import java.util.List; + +import org.hibernate.query.ReturnableType; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.predicate.Predicate; +import org.hibernate.sql.ast.tree.select.SortSpecification; + +/** + * Support for {@link SqmFunctionDescriptor}s that ultimately want + * to perform SQL rendering themselves. This is a protocol passed + * from the {@link AbstractSqmSelfRenderingFunctionDescriptor} + * along to its {@link SelfRenderingSqmFunction} and ultimately to + * the {@link SelfRenderingFunctionSqlAstExpression} which calls it + * to finally render SQL. + * + * @author Steve Ebersole + * @since 6.4 + */ +@FunctionalInterface +public interface FunctionRenderer extends FunctionRenderingSupport { + /** + * @deprecated Use {@link #render(SqlAppender, List, ReturnableType, SqlAstTranslator)} instead + */ + @Deprecated(forRemoval = true) + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + SqlAstTranslator walker) { + render( sqlAppender, sqlAstArguments, (ReturnableType) null, walker ); + } + + void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker); + + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, returnType, walker ); + } + + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + List withinGroup, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, returnType, walker ); + } + + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + Boolean respectNulls, + Boolean fromFirst, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, returnType, walker ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java index e73b3663ed..523b41f0fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.function; +import org.hibernate.query.ReturnableType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; @@ -23,7 +24,9 @@ import java.util.List; * to finally render SQL. * * @author Steve Ebersole + * @deprecated Use {@link FunctionRenderer} instead */ +@Deprecated(forRemoval = true) @FunctionalInterface public interface FunctionRenderingSupport { void render( @@ -31,6 +34,10 @@ public interface FunctionRenderingSupport { List sqlAstArguments, SqlAstTranslator walker); + /** + * @deprecated Use {@link #render(SqlAppender, List, Predicate, ReturnableType, SqlAstTranslator)} instead + */ + @Deprecated(forRemoval = true) default void render( SqlAppender sqlAppender, List sqlAstArguments, @@ -40,6 +47,10 @@ public interface FunctionRenderingSupport { render( sqlAppender, sqlAstArguments, walker ); } + /** + * @deprecated Use {@link #render(SqlAppender, List, Predicate, List, ReturnableType, SqlAstTranslator)} instead + */ + @Deprecated(forRemoval = true) default void render( SqlAppender sqlAppender, List sqlAstArguments, @@ -50,6 +61,10 @@ public interface FunctionRenderingSupport { render( sqlAppender, sqlAstArguments, walker ); } + /** + * @deprecated Use {@link #render(SqlAppender, List, Predicate, Boolean, Boolean, ReturnableType, SqlAstTranslator)} instead + */ + @Deprecated(forRemoval = true) default void render( SqlAppender sqlAppender, List sqlAstArguments, @@ -60,4 +75,58 @@ public interface FunctionRenderingSupport { // Ignore the filter by default. Subclasses will override this render( sqlAppender, sqlAstArguments, walker ); } + + /** + * @since 6.4 + */ + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the return type by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, walker ); + } + + /** + * @since 6.4 + */ + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, returnType, walker ); + } + + /** + * @since 6.4 + */ + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + List withinGroup, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, returnType, walker ); + } + + /** + * @since 6.4 + */ + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + Boolean respectNulls, + Boolean fromFirst, + ReturnableType returnType, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, returnType, walker ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java index cde831c73d..ae228aa5d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/JdbcEscapeFunctionDescriptor.java @@ -44,10 +44,10 @@ public class JdbcEscapeFunctionDescriptor return new SelfRenderingSqmFunction<>( JdbcEscapeFunctionDescriptor.this, - (sqlAppender, sqlAstArguments, walker) -> { + (sqlAppender, sqlAstArguments, returnType, walker) -> { sqlAppender.appendSql("{fn "); - delegate.getRenderingSupport() - .render(sqlAppender, sqlAstArguments, walker); + delegate.getFunctionRenderer() + .render( sqlAppender, sqlAstArguments, returnType, walker); sqlAppender.appendSql("}"); }, arguments, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java index bba145bc3a..888d64cc6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.function; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; @@ -117,6 +118,7 @@ public class NamedSqmFunctionDescriptor public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator translator) { render( sqlAppender, sqlAstArguments, null, Collections.emptyList(), null, null, translator ); } @@ -126,6 +128,7 @@ public class NamedSqmFunctionDescriptor SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator translator) { render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), null, null, translator ); } @@ -136,6 +139,7 @@ public class NamedSqmFunctionDescriptor List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator translator) { render( sqlAppender, sqlAstArguments, filter, withinGroup, null, null, translator ); } @@ -147,6 +151,7 @@ public class NamedSqmFunctionDescriptor Predicate filter, Boolean respectNulls, Boolean fromFirst, + ReturnableType returnType, SqlAstTranslator walker) { render( sqlAppender, sqlAstArguments, filter, Collections.emptyList(), respectNulls, fromFirst, walker ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java index 42dda026ea..3b26527977 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.function; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.FunctionArgumentTypeResolver; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; @@ -76,6 +77,7 @@ public class PatternBasedSqmFunctionDescriptor public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { renderer.render( sqlAppender, sqlAstArguments, null, walker ); } @@ -85,6 +87,7 @@ public class PatternBasedSqmFunctionDescriptor SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, + ReturnableType returnType, SqlAstTranslator walker) { renderer.render( sqlAppender, sqlAstArguments, filter, walker ); } @@ -95,6 +98,7 @@ public class PatternBasedSqmFunctionDescriptor List sqlAstArguments, Predicate filter, List withinGroup, + ReturnableType returnType, SqlAstTranslator walker) { renderer.render( sqlAppender, sqlAstArguments, filter, withinGroup, walker ); } @@ -106,6 +110,7 @@ public class PatternBasedSqmFunctionDescriptor Predicate filter, Boolean respectNulls, Boolean fromFirst, + ReturnableType returnType, SqlAstTranslator walker) { renderer.render( sqlAppender, sqlAstArguments, filter, respectNulls, fromFirst, walker ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java index 649d020451..021db6a32d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java @@ -28,6 +28,10 @@ public class SelfRenderingAggregateFunctionSqlAstExpression extends SelfRenderin private final Predicate filter; + /** + * @deprecated Use {@link #SelfRenderingAggregateFunctionSqlAstExpression(String, FunctionRenderer, List, Predicate, ReturnableType, JdbcMappingContainer)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingAggregateFunctionSqlAstExpression( String functionName, FunctionRenderingSupport renderer, @@ -39,6 +43,17 @@ public class SelfRenderingAggregateFunctionSqlAstExpression extends SelfRenderin this.filter = filter; } + public SelfRenderingAggregateFunctionSqlAstExpression( + String functionName, + FunctionRenderer renderer, + List sqlAstArguments, + Predicate filter, + ReturnableType type, + JdbcMappingContainer expressible) { + super( functionName, renderer, sqlAstArguments, type, expressible ); + this.filter = filter; + } + @Override public Predicate getFilter() { return filter; @@ -49,6 +64,6 @@ public class SelfRenderingAggregateFunctionSqlAstExpression extends SelfRenderin SqlAppender sqlAppender, SqlAstTranslator walker, SessionFactoryImplementor sessionFactory) { - getRenderer().render( sqlAppender, getArguments(), filter, walker ); + getFunctionRenderer().render( sqlAppender, getArguments(), filter, getType(), walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java index 3065d0cb0a..6b316eb7d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java @@ -42,11 +42,15 @@ import org.hibernate.type.spi.TypeConfiguration; public class SelfRenderingFunctionSqlAstExpression implements SelfRenderingExpression, Selectable, SqlExpressible, DomainResultProducer, FunctionExpression { private final String functionName; - private final FunctionRenderingSupport renderer; + private final FunctionRenderer renderer; private final List sqlAstArguments; private final ReturnableType type; private final JdbcMappingContainer expressible; + /** + * @deprecated Use {@link #SelfRenderingFunctionSqlAstExpression(String, FunctionRenderer, List, ReturnableType, JdbcMappingContainer)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingFunctionSqlAstExpression( String functionName, FunctionRenderingSupport renderer, @@ -54,6 +58,20 @@ public class SelfRenderingFunctionSqlAstExpression ReturnableType type, JdbcMappingContainer expressible) { this.functionName = functionName; + this.renderer = renderer::render; + this.sqlAstArguments = sqlAstArguments; + this.type = type; + //might be null due to code in SelfRenderingFunctionSqlAstExpression + this.expressible = expressible; + } + + public SelfRenderingFunctionSqlAstExpression( + String functionName, + FunctionRenderer renderer, + List sqlAstArguments, + ReturnableType type, + JdbcMappingContainer expressible) { + this.functionName = functionName; this.renderer = renderer; this.sqlAstArguments = sqlAstArguments; this.type = type; @@ -78,10 +96,22 @@ public class SelfRenderingFunctionSqlAstExpression : expressible; } + /** + * @deprecated Use {@link #getFunctionRenderer()} instead + */ + @Deprecated(forRemoval = true) protected FunctionRenderingSupport getRenderer() { return renderer; } + protected FunctionRenderer getFunctionRenderer() { + return renderer; + } + + protected ReturnableType getType() { + return type; + } + @Override public SqlSelection createSqlSelection( int jdbcPosition, @@ -151,7 +181,7 @@ public class SelfRenderingFunctionSqlAstExpression SqlAppender sqlAppender, SqlAstTranslator walker, SessionFactoryImplementor sessionFactory) { - renderer.render( sqlAppender, sqlAstArguments, walker ); + renderer.render( sqlAppender, sqlAstArguments, type, walker ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingOrderedSetAggregateFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingOrderedSetAggregateFunctionSqlAstExpression.java index bf80b999b4..c5556daa54 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingOrderedSetAggregateFunctionSqlAstExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingOrderedSetAggregateFunctionSqlAstExpression.java @@ -29,6 +29,10 @@ public class SelfRenderingOrderedSetAggregateFunctionSqlAstExpression extends Se private final List withinGroup; + /** + * @deprecated Use {@link #SelfRenderingOrderedSetAggregateFunctionSqlAstExpression(String, FunctionRenderer, List, Predicate, List, ReturnableType, JdbcMappingContainer)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingOrderedSetAggregateFunctionSqlAstExpression( String functionName, FunctionRenderingSupport renderer, @@ -41,6 +45,18 @@ public class SelfRenderingOrderedSetAggregateFunctionSqlAstExpression extends Se this.withinGroup = withinGroup; } + public SelfRenderingOrderedSetAggregateFunctionSqlAstExpression( + String functionName, + FunctionRenderer renderer, + List sqlAstArguments, + Predicate filter, + List withinGroup, + ReturnableType type, + JdbcMappingContainer expressible) { + super( functionName, renderer, sqlAstArguments, filter, type, expressible ); + this.withinGroup = withinGroup; + } + @Override public List getWithinGroup() { return withinGroup; @@ -51,6 +67,6 @@ public class SelfRenderingOrderedSetAggregateFunctionSqlAstExpression extends Se SqlAppender sqlAppender, SqlAstTranslator walker, SessionFactoryImplementor sessionFactory) { - getRenderer().render( sqlAppender, getArguments(), getFilter(), withinGroup, walker ); + getFunctionRenderer().render( sqlAppender, getArguments(), getFilter(), withinGroup, getType(), walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java index 3f74238240..e60c930cc3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java @@ -30,6 +30,10 @@ public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFuncti private final SqmPredicate filter; + /** + * @deprecated Use {@link #SelfRenderingSqmAggregateFunction(SqmFunctionDescriptor, FunctionRenderer, List, SqmPredicate, ReturnableType, ArgumentsValidator, FunctionReturnTypeResolver, NodeBuilder, String)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingSqmAggregateFunction( SqmFunctionDescriptor descriptor, FunctionRenderingSupport renderingSupport, @@ -44,6 +48,20 @@ public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFuncti this.filter = filter; } + public SelfRenderingSqmAggregateFunction( + SqmFunctionDescriptor descriptor, + FunctionRenderer renderer, + List> arguments, + SqmPredicate filter, + ReturnableType impliedResultType, + ArgumentsValidator argumentsValidator, + FunctionReturnTypeResolver returnTypeResolver, + NodeBuilder nodeBuilder, + String name) { + super( descriptor, renderer, arguments, impliedResultType, argumentsValidator, returnTypeResolver, nodeBuilder, name ); + this.filter = filter; + } + @Override public SelfRenderingSqmAggregateFunction copy(SqmCopyContext context) { final SelfRenderingSqmAggregateFunction existing = context.getCopy( this ); @@ -58,7 +76,7 @@ public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFuncti this, new SelfRenderingSqmAggregateFunction<>( getFunctionDescriptor(), - getRenderingSupport(), + getFunctionRenderer(), arguments, filter == null ? null : filter.copy( context ), getImpliedResultType(), @@ -83,7 +101,7 @@ public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFuncti } return new SelfRenderingAggregateFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, filter == null ? null : walker.visitNestedTopLevelPredicate( filter ), resultType, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java index 7495cfab01..b48df6d8b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java @@ -37,8 +37,13 @@ public class SelfRenderingSqmFunction extends SqmFunction { private final ArgumentsValidator argumentsValidator; private final FunctionReturnTypeResolver returnTypeResolver; private final FunctionRenderingSupport renderingSupport; + private final FunctionRenderer renderer; private ReturnableType resultType; + /** + * @deprecated Use {@link #SelfRenderingSqmFunction(SqmFunctionDescriptor, FunctionRenderer, List, ReturnableType, ArgumentsValidator, FunctionReturnTypeResolver, NodeBuilder, String)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingSqmFunction( SqmFunctionDescriptor descriptor, FunctionRenderingSupport renderingSupport, @@ -50,6 +55,24 @@ public class SelfRenderingSqmFunction extends SqmFunction { String name) { super( name, descriptor, impliedResultType, arguments, nodeBuilder ); this.renderingSupport = renderingSupport; + this.renderer = renderingSupport::render; + this.impliedResultType = impliedResultType; + this.argumentsValidator = argumentsValidator; + this.returnTypeResolver = returnTypeResolver; + } + + public SelfRenderingSqmFunction( + SqmFunctionDescriptor descriptor, + FunctionRenderer renderer, + List> arguments, + ReturnableType impliedResultType, + ArgumentsValidator argumentsValidator, + FunctionReturnTypeResolver returnTypeResolver, + NodeBuilder nodeBuilder, + String name) { + super( name, descriptor, impliedResultType, arguments, nodeBuilder ); + this.renderingSupport = renderer; + this.renderer = renderer; this.impliedResultType = impliedResultType; this.argumentsValidator = argumentsValidator; this.returnTypeResolver = returnTypeResolver; @@ -69,7 +92,7 @@ public class SelfRenderingSqmFunction extends SqmFunction { this, new SelfRenderingSqmFunction<>( getFunctionDescriptor(), - getRenderingSupport(), + getFunctionRenderer(), arguments, getImpliedResultType(), getArgumentsValidator(), @@ -82,10 +105,18 @@ public class SelfRenderingSqmFunction extends SqmFunction { return expression; } + /** + * @deprecated Use {@link #getFunctionRenderer()} instead + */ + @Deprecated(forRemoval = true) public FunctionRenderingSupport getRenderingSupport() { return renderingSupport; } + public FunctionRenderer getFunctionRenderer() { + return renderer; + } + protected ReturnableType getImpliedResultType() { return impliedResultType; } @@ -144,7 +175,7 @@ public class SelfRenderingSqmFunction extends SqmFunction { } return new SelfRenderingFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, resultType, resultType == null ? null : getMappingModelExpressible( walker, resultType, arguments ) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java index 93bc3c4062..6a23fcf5c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java @@ -35,6 +35,10 @@ public class SelfRenderingSqmOrderedSetAggregateFunction extends SelfRenderin private final SqmOrderByClause withinGroup; + /** + * @deprecated Use {@link #SelfRenderingSqmOrderedSetAggregateFunction(SqmFunctionDescriptor, FunctionRenderer, List, SqmPredicate, SqmOrderByClause, ReturnableType, ArgumentsValidator, FunctionReturnTypeResolver, NodeBuilder, String)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingSqmOrderedSetAggregateFunction( SqmFunctionDescriptor descriptor, FunctionRenderingSupport renderingSupport, @@ -60,6 +64,31 @@ public class SelfRenderingSqmOrderedSetAggregateFunction extends SelfRenderin this.withinGroup = withinGroupClause; } + public SelfRenderingSqmOrderedSetAggregateFunction( + SqmFunctionDescriptor descriptor, + FunctionRenderer renderer, + List> arguments, + SqmPredicate filter, + SqmOrderByClause withinGroupClause, + ReturnableType impliedResultType, + ArgumentsValidator argumentsValidator, + FunctionReturnTypeResolver returnTypeResolver, + NodeBuilder nodeBuilder, + String name) { + super( + descriptor, + renderer, + arguments, + filter, + impliedResultType, + argumentsValidator, + returnTypeResolver, + nodeBuilder, + name + ); + this.withinGroup = withinGroupClause; + } + @Override public SelfRenderingSqmOrderedSetAggregateFunction copy(SqmCopyContext context) { final SelfRenderingSqmOrderedSetAggregateFunction existing = context.getCopy( this ); @@ -74,7 +103,7 @@ public class SelfRenderingSqmOrderedSetAggregateFunction extends SelfRenderin this, new SelfRenderingSqmOrderedSetAggregateFunction<>( getFunctionDescriptor(), - getRenderingSupport(), + getFunctionRenderer(), arguments, getFilter() == null ? null : getFilter().copy( context ), withinGroup == null ? null : withinGroup.copy( context ), @@ -120,7 +149,7 @@ public class SelfRenderingSqmOrderedSetAggregateFunction extends SelfRenderin } return new SelfRenderingOrderedSetAggregateFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, getFilter() == null ? null : walker.visitNestedTopLevelPredicate( getFilter() ), withinGroup, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmWindowFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmWindowFunction.java index 8117db29f3..fd0287bdae 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmWindowFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmWindowFunction.java @@ -32,6 +32,10 @@ public class SelfRenderingSqmWindowFunction extends SelfRenderingSqmFunction< private final Boolean respectNulls; private final Boolean fromFirst; + /** + * @deprecated Use {@link #SelfRenderingSqmWindowFunction(SqmFunctionDescriptor, FunctionRenderer, List, SqmPredicate, Boolean, Boolean, ReturnableType, ArgumentsValidator, FunctionReturnTypeResolver, NodeBuilder, String)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingSqmWindowFunction( SqmFunctionDescriptor descriptor, FunctionRenderingSupport renderingSupport, @@ -50,6 +54,24 @@ public class SelfRenderingSqmWindowFunction extends SelfRenderingSqmFunction< this.fromFirst = fromFirst; } + public SelfRenderingSqmWindowFunction( + SqmFunctionDescriptor descriptor, + FunctionRenderer renderer, + List> arguments, + SqmPredicate filter, + Boolean respectNulls, + Boolean fromFirst, + ReturnableType impliedResultType, + ArgumentsValidator argumentsValidator, + FunctionReturnTypeResolver returnTypeResolver, + NodeBuilder nodeBuilder, + String name) { + super( descriptor, renderer, arguments, impliedResultType, argumentsValidator, returnTypeResolver, nodeBuilder, name ); + this.filter = filter; + this.respectNulls = respectNulls; + this.fromFirst = fromFirst; + } + @Override public SelfRenderingSqmWindowFunction copy(SqmCopyContext context) { final SelfRenderingSqmWindowFunction existing = context.getCopy( this ); @@ -64,7 +86,7 @@ public class SelfRenderingSqmWindowFunction extends SelfRenderingSqmFunction< this, new SelfRenderingSqmWindowFunction<>( getFunctionDescriptor(), - getRenderingSupport(), + getFunctionRenderer(), arguments, filter == null ? null : filter.copy( context ), respectNulls, @@ -91,7 +113,7 @@ public class SelfRenderingSqmWindowFunction extends SelfRenderingSqmFunction< } return new SelfRenderingWindowFunctionSqlAstExpression( getFunctionName(), - getRenderingSupport(), + getFunctionRenderer(), arguments, filter == null ? null : walker.visitNestedTopLevelPredicate( filter ), respectNulls, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingWindowFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingWindowFunctionSqlAstExpression.java index e7990f5d03..2f233fef5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingWindowFunctionSqlAstExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingWindowFunctionSqlAstExpression.java @@ -30,6 +30,10 @@ public class SelfRenderingWindowFunctionSqlAstExpression extends SelfRenderingFu private final Boolean respectNulls; private final Boolean fromFirst; + /** + * @deprecated Use {@link #SelfRenderingWindowFunctionSqlAstExpression(String, FunctionRenderer, List, Predicate, Boolean, Boolean, ReturnableType, JdbcMappingContainer)} instead + */ + @Deprecated(forRemoval = true) public SelfRenderingWindowFunctionSqlAstExpression( String functionName, FunctionRenderingSupport renderer, @@ -45,6 +49,21 @@ public class SelfRenderingWindowFunctionSqlAstExpression extends SelfRenderingFu this.fromFirst = fromFirst; } + public SelfRenderingWindowFunctionSqlAstExpression( + String functionName, + FunctionRenderer renderer, + List sqlAstArguments, + Predicate filter, + Boolean respectNulls, + Boolean fromFirst, + ReturnableType type, + JdbcMappingContainer expressible) { + super( functionName, renderer, sqlAstArguments, type, expressible ); + this.filter = filter; + this.respectNulls = respectNulls; + this.fromFirst = fromFirst; + } + @Override public Predicate getFilter() { return filter; @@ -65,6 +84,6 @@ public class SelfRenderingWindowFunctionSqlAstExpression extends SelfRenderingFu SqlAppender sqlAppender, SqlAstTranslator walker, SessionFactoryImplementor sessionFactory) { - getRenderer().render( sqlAppender, getArguments(), filter, respectNulls, fromFirst, walker ); + getFunctionRenderer().render( sqlAppender, getArguments(), filter, respectNulls, fromFirst, getType(), walker ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SqmInsertStrategyHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SqmInsertStrategyHelper.java index 5a2f1b021d..5aab9a0c56 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SqmInsertStrategyHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/SqmInsertStrategyHelper.java @@ -44,7 +44,7 @@ public final class SqmInsertStrategyHelper { functionExpression = new SelfRenderingWindowFunctionSqlAstExpression( "dense_rank", - (appender, args, walker) -> appender.appendSql( "dense_rank()" ), + (appender, args, returnType, walker) -> appender.appendSql( "dense_rank()" ), Collections.emptyList(), null, null, @@ -71,7 +71,7 @@ public final class SqmInsertStrategyHelper { else { functionExpression = new SelfRenderingWindowFunctionSqlAstExpression( "row_number", - (appender, args, walker) -> appender.appendSql( "row_number()" ), + (appender, args, returnType, walker) -> appender.appendSql( "row_number()" ), Collections.emptyList(), null, null, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index bb1fc8b809..3753491c22 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -333,7 +333,6 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer; import org.hibernate.sql.ast.tree.from.TableReference; -import org.hibernate.sql.ast.tree.from.VirtualTableGroup; import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.insert.Values; @@ -4286,15 +4285,16 @@ public abstract class BaseSqmToSqlAstConverter extends Base private Expression extractEpoch(Expression intervalExpression) { final BasicType intType = getTypeConfiguration().getBasicTypeForJavaType( Integer.class ); + final PatternRenderer patternRenderer = new PatternRenderer( + creationContext.getSessionFactory() + .getJdbcServices() + .getDialect() + .extractPattern( EPOCH ) + ); return new SelfRenderingFunctionSqlAstExpression( "extract", - (sqlAppender, sqlAstArguments, walker) -> - new PatternRenderer( - creationContext.getSessionFactory() - .getJdbcServices() - .getDialect() - .extractPattern( EPOCH ) - ).render( sqlAppender, sqlAstArguments, walker ), + (sqlAppender, sqlAstArguments, returnType, walker) -> + patternRenderer.render( sqlAppender, sqlAstArguments, walker ), Arrays.asList( new ExtractUnit( EPOCH, intType ), intervalExpression ), intType, intType @@ -4968,7 +4968,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base if ( jdbcTypeCount == 1 ) { return new SelfRenderingFunctionSqlAstExpression( pathName, - (sqlAppender, sqlAstArguments, walker) -> sqlAstArguments.get( 0 ).accept( walker ), + (sqlAppender, sqlAstArguments, returnType, walker) -> sqlAstArguments.get( 0 ).accept( walker ), resultColumnReferences, (ReturnableType) resultColumnReferences.get( 0 ).getJdbcMapping(), resultColumnReferences.get( 0 ).getJdbcMapping() @@ -4990,7 +4990,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base .getSqlSelections(); return new SelfRenderingFunctionSqlAstExpression( pathName, - (sqlAppender, sqlAstArguments, walker) -> sqlAstArguments.get( 0 ).accept( walker ), + (sqlAppender, sqlAstArguments, returnType, walker) -> sqlAstArguments.get( 0 ).accept( walker ), singletonList( new ColumnReference( identifierVariable, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java index bb80c75f26..19b73d806e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java @@ -55,7 +55,6 @@ import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.metamodel.mapping.SqlExpressible; import org.hibernate.metamodel.mapping.SqlTypedMapping; import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.Loadable; @@ -210,12 +209,10 @@ import org.hibernate.sql.model.internal.TableUpdateStandard; import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducerProvider; -import org.hibernate.type.BasicPluralType; import org.hibernate.type.BasicType; import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.BasicPluralJavaType; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcType; @@ -2313,7 +2310,7 @@ public abstract class AbstractSqlAstTranslator implemen ); arguments.add( nullSeparator ); } - concat.render( this, arguments, this ); + concat.render( this, arguments, stringType, this ); } else { arguments.add( @@ -2352,7 +2349,7 @@ public abstract class AbstractSqlAstTranslator implemen arguments.add( nullSeparator ); } arguments.add( nullSeparator ); - concat.render( this, arguments, this ); + concat.render( this, arguments, stringType, this ); } } else { @@ -2644,7 +2641,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( "case when " ); visitColumnReference( cyclePathColumnReference ); appendSql( " like " ); - concat.render( this, arguments, this ); + concat.render( this, arguments, stringType, this ); appendSql( " then " ); currentCteStatement.getCycleValue().accept( this ); appendSql( " else " ); @@ -2657,7 +2654,7 @@ public abstract class AbstractSqlAstTranslator implemen arguments.remove( arguments.size() - 1 ); arguments.set( 0, cyclePathColumnReference ); // Cycle path - concat.render( this, arguments, this ); + concat.render( this, arguments, stringType, this ); } else { if ( !supportsRecursiveCycleClause() ) { @@ -5194,23 +5191,23 @@ public abstract class AbstractSqlAstTranslator implemen } final List arguments = new ArrayList<>( 2 ); arguments.add( expression ); + final CastTarget castTarget; if ( expression instanceof SqlTypedMappingJdbcParameter ) { final SqlTypedMappingJdbcParameter parameter = (SqlTypedMappingJdbcParameter) expression; final SqlTypedMapping sqlTypedMapping = parameter.getSqlTypedMapping(); - arguments.add( - new CastTarget( - parameter.getJdbcMapping(), - sqlTypedMapping.getColumnDefinition(), - sqlTypedMapping.getLength(), - sqlTypedMapping.getPrecision(), - sqlTypedMapping.getScale() - ) + castTarget = new CastTarget( + parameter.getJdbcMapping(), + sqlTypedMapping.getColumnDefinition(), + sqlTypedMapping.getLength(), + sqlTypedMapping.getPrecision(), + sqlTypedMapping.getScale() ); } else { - arguments.add( new CastTarget( expression.getExpressionType().getSingleJdbcMapping() ) ); + castTarget = new CastTarget( expression.getExpressionType().getSingleJdbcMapping() ); } - castFunction().render( this, arguments, this ); + arguments.add( castTarget ); + castFunction().render( this, arguments, (ReturnableType) castTarget.getJdbcMapping(), this ); } @SuppressWarnings("unchecked") @@ -5917,7 +5914,7 @@ public abstract class AbstractSqlAstTranslator implemen 0, new SelfRenderingAggregateFunctionSqlAstExpression( "count", - (sqlAppender, sqlAstArguments, walker) -> sqlAppender.append( "count(*)" ), + (sqlAppender, sqlAstArguments, returnType, walker) -> sqlAppender.append( "count(*)" ), List.of( Star.INSTANCE ), null, getIntegerType(), @@ -6274,25 +6271,6 @@ public abstract class AbstractSqlAstTranslator implemen final Size castTargetSize = castTarget.toSize(); final DdlTypeRegistry ddlTypeRegistry = factory.getTypeConfiguration().getDdlTypeRegistry(); final BasicType expressionType = (BasicType) castTarget.getJdbcMapping(); - if ( expressionType instanceof BasicPluralType ) { - final BasicPluralType containerType = (BasicPluralType) expressionType; - final BasicPluralJavaType javaTypeDescriptor = (BasicPluralJavaType) containerType.getJavaTypeDescriptor(); - final BasicType elementType = containerType.getElementType(); - final String elementTypeName = ddlTypeRegistry.getDescriptor( elementType.getJdbcType().getDdlTypeCode() ) - .getCastTypeName( - castTargetSize, - elementType, - ddlTypeRegistry - ); - final String arrayTypeName = factory.getJdbcServices().getDialect().getArrayTypeName( - javaTypeDescriptor.getElementJavaType().getJavaTypeClass().getSimpleName(), - elementTypeName, - null - ); - if ( arrayTypeName != null ) { - return arrayTypeName; - } - } DdlType ddlType = ddlTypeRegistry.getDescriptor( expressionType.getJdbcType().getDdlTypeCode() ); if ( ddlType == null ) { // this may happen when selecting a null value like `SELECT null from ...` @@ -6312,25 +6290,6 @@ public abstract class AbstractSqlAstTranslator implemen final Size castTargetSize = castTarget.toSize(); final DdlTypeRegistry ddlTypeRegistry = factory.getTypeConfiguration().getDdlTypeRegistry(); final BasicType expressionType = (BasicType) castTarget.getJdbcMapping(); - if ( expressionType instanceof BasicPluralType ) { - final BasicPluralType containerType = (BasicPluralType) expressionType; - final BasicPluralJavaType javaTypeDescriptor = (BasicPluralJavaType) containerType.getJavaTypeDescriptor(); - final BasicType elementType = containerType.getElementType(); - final String elementTypeName = ddlTypeRegistry.getDescriptor( elementType.getJdbcType().getDdlTypeCode() ) - .getCastTypeName( - castTargetSize, - elementType, - ddlTypeRegistry - ); - final String arrayTypeName = factory.getJdbcServices().getDialect().getArrayTypeName( - javaTypeDescriptor.getElementJavaType().getJavaTypeClass().getSimpleName(), - elementTypeName, - null - ); - if ( arrayTypeName != null ) { - return arrayTypeName; - } - } DdlType ddlType = ddlTypeRegistry.getDescriptor( expressionType.getJdbcType().getDdlTypeCode() ); if ( ddlType == null ) { // this may happen when selecting a null value like `SELECT null from ...` diff --git a/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java index 2a272c40d2..3a814f8559 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java @@ -122,16 +122,11 @@ public class BasicTypeRegistry implements Serializable { } public BasicType getRegisteredType(java.lang.reflect.Type javaType) { - if ( javaType instanceof Class ) { - // using `javaType.getTypeName()` causes problems with arrays - //noinspection unchecked - return getRegisteredType( (Class) javaType ); - } return getRegisteredType( javaType.getTypeName() ); } public BasicType getRegisteredType(Class javaType) { - return getRegisteredType( javaType.getName() ); + return getRegisteredType( javaType.getTypeName() ); } public BasicType resolve(BasicTypeReference basicTypeReference) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/function/AnsiTrimEmulationFunctionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/function/AnsiTrimEmulationFunctionTest.java index 50ffeb4a94..eec8198aec 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/function/AnsiTrimEmulationFunctionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/function/AnsiTrimEmulationFunctionTest.java @@ -17,6 +17,7 @@ import org.hibernate.dialect.function.TrimFunction; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.TrimSpec; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; @@ -33,7 +34,6 @@ import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.testing.orm.junit.ServiceRegistryScope; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -148,7 +148,7 @@ public class AnsiTrimEmulationFunctionTest { return null; } } ); - function.render( walker, sqlAstArguments, walker ); + function.render( walker, sqlAstArguments, (ReturnableType) null, walker ); return walker.getSql(); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsAllTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java similarity index 57% rename from hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsAllTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java index 62cdef25f6..e87f062ca2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsAllTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsArrayTest.java @@ -35,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; // otherwise we might run into ORA-21700: object does not exist or is marked for delete // because the JDBC connection or database session caches something that should have been invalidated @ServiceRegistry(settings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER, value = "")) -public class ArrayContainsAllTest { +public class ArrayContainsArrayTest { @BeforeEach public void prepareData(SessionFactoryScope scope) { @@ -54,40 +54,39 @@ public class ArrayContainsAllTest { } @Test - public void testContainsAll(SessionFactoryScope scope) { + public void testContainsArray(SessionFactoryScope scope) { scope.inSession( em -> { - //tag::hql-array-contains-all-example[] - List results = em.createQuery( "from EntityWithArrays e where array_contains_all(e.theArray, array('abc', 'def'))", EntityWithArrays.class ) + //tag::hql-array-contains-array-example[] + List results = em.createQuery( "from EntityWithArrays e where array_contains(e.theArray, array('abc', 'def'))", EntityWithArrays.class ) .getResultList(); - //end::hql-array-contains-all-example[] + //end::hql-array-contains-array-example[] assertEquals( 1, results.size() ); assertEquals( 2L, results.get( 0 ).getId() ); } ); } @Test - public void testDoesNotContain(SessionFactoryScope scope) { + public void testDoesNotContainArray(SessionFactoryScope scope) { scope.inSession( em -> { - List results = em.createQuery( "from EntityWithArrays e where array_contains_all(e.theArray, array('xyz'))", EntityWithArrays.class ) + List results = em.createQuery( "from EntityWithArrays e where array_contains(e.theArray, array('xyz'))", EntityWithArrays.class ) .getResultList(); assertEquals( 0, results.size() ); } ); } @Test - public void testContainsPartly(SessionFactoryScope scope) { + public void testContainsArrayPartly(SessionFactoryScope scope) { scope.inSession( em -> { - List results = em.createQuery( "from EntityWithArrays e where array_contains_all(e.theArray, array('abc','xyz'))", EntityWithArrays.class ) + List results = em.createQuery( "from EntityWithArrays e where array_contains(e.theArray, array('abc','xyz'))", EntityWithArrays.class ) .getResultList(); assertEquals( 0, results.size() ); } ); } @Test - @SkipForDialect(dialectClass = HSQLDialect.class, reason = "Type inference isn't smart enough to figure out the type for the `null`") - public void testContainsNull(SessionFactoryScope scope) { + public void testContainsArrayWithNullElementOnly(SessionFactoryScope scope) { scope.inSession( em -> { - List results = em.createQuery( "from EntityWithArrays e where array_contains_all_nullable(e.theArray, array(null))", EntityWithArrays.class ) + List results = em.createQuery( "from EntityWithArrays e where array_contains_nullable(e.theArray, array(null))", EntityWithArrays.class ) .getResultList(); assertEquals( 1, results.size() ); assertEquals( 2L, results.get( 0 ).getId() ); @@ -95,15 +94,50 @@ public class ArrayContainsAllTest { } @Test - public void testContainsWithNull(SessionFactoryScope scope) { + public void testContainsArrayWithNullElement(SessionFactoryScope scope) { scope.inSession( em -> { - //tag::hql-array-contains-all-nullable-example[] - List results = em.createQuery( "from EntityWithArrays e where array_contains_all_nullable(e.theArray, array('abc',null))", EntityWithArrays.class ) + //tag::hql-array-contains-array-nullable-example[] + List results = em.createQuery( "from EntityWithArrays e where array_contains_nullable(e.theArray, array('abc',null))", EntityWithArrays.class ) .getResultList(); - //end::hql-array-contains-all-nullable-example[] + //end::hql-array-contains-array-nullable-example[] assertEquals( 1, results.size() ); assertEquals( 2L, results.get( 0 ).getId() ); } ); } + @Test + public void testContainsElementParameter(SessionFactoryScope scope) { + scope.inSession( em -> { + List results = em.createQuery( + "from EntityWithArrays e where array_contains_nullable(e.theArray, :param)", + EntityWithArrays.class + ).setParameter( "param", "abc" ).getResultList(); + assertEquals( 1, results.size() ); + assertEquals( 2L, results.get( 0 ).getId() ); + } ); + } + + @Test + public void testContainsArrayParameter(SessionFactoryScope scope) { + scope.inSession( em -> { + List results = em.createQuery( + "from EntityWithArrays e where array_contains_nullable(e.theArray, :param)", + EntityWithArrays.class + ).setParameter( "param", new String[]{ "abc", null } ).getResultList(); + assertEquals( 1, results.size() ); + assertEquals( 2L, results.get( 0 ).getId() ); + } ); + } + + @Test + public void testContainsNullParameter(SessionFactoryScope scope) { + scope.inSession( em -> { + List results = em.createQuery( + "from EntityWithArrays e where array_contains_nullable(e.theArray, :param)", + EntityWithArrays.class + ).setParameter( "param", null ).getResultList(); + assertEquals( 0, results.size() ); + } ); + } + } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java index 1e5a50874c..3d6c18b147 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayContainsTest.java @@ -72,16 +72,4 @@ public class ArrayContainsTest { } ); } - @Test - public void testContainsNull(SessionFactoryScope scope) { - scope.inSession( em -> { - //tag::hql-array-contains-null-example[] - List results = em.createQuery( "from EntityWithArrays e where array_contains_null(e.theArray)", EntityWithArrays.class ) - .getResultList(); - //end::hql-array-contains-null-example[] - assertEquals( 1, results.size() ); - assertEquals( 2L, results.get( 0 ).getId() ); - } ); - } - } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java index 5f286a54d7..504aa2d804 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/function/array/ArrayOverlapsTest.java @@ -85,7 +85,6 @@ public class ArrayOverlapsTest { } @Test - @SkipForDialect(dialectClass = HSQLDialect.class, reason = "Type inference isn't smart enough to figure out the type for the `null`") public void testOverlapsNullFully(SessionFactoryScope scope) { scope.inSession( em -> { List results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array(null))", EntityWithArrays.class ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/subquery/SubqueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/subquery/SubqueryTest.java index 8c053f6448..731b47d2f6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/subquery/SubqueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/subquery/SubqueryTest.java @@ -13,6 +13,7 @@ import java.util.List; import org.hibernate.boot.MetadataBuilder; import org.hibernate.dialect.H2Dialect; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; @@ -59,7 +60,10 @@ public class SubqueryTest extends BaseSessionFactoryFunctionalTest { @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { sqlAstArguments.get( 0 ).accept( walker ); sqlAppender.appendSql( " limit " + ( (UnparsedNumericLiteral) sqlAstArguments.get( 1 ) ).getUnparsedLiteralValue() ); } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java b/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java index 6599f70727..e105f4fc5e 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/function/OrderByFragmentFunction.java @@ -16,6 +16,7 @@ import org.hibernate.metamodel.mapping.ordering.OrderByFragment; import org.hibernate.query.ReturnableType; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.Joinable; +import org.hibernate.query.sqm.function.FunctionRenderer; import org.hibernate.spi.NavigablePath; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.NodeBuilder; @@ -149,7 +150,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor { private OrderByFragmentSelfRenderingSqmFunction( SqmFunctionDescriptor descriptor, - FunctionRenderingSupport renderingSupport, + FunctionRenderer renderer, List> arguments, ReturnableType impliedResultType, ArgumentsValidator argumentsValidator, @@ -158,7 +159,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor { String name) { super( descriptor, - renderingSupport, + renderer, arguments, impliedResultType, argumentsValidator, @@ -182,7 +183,7 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor { this, new OrderByFragmentSelfRenderingSqmFunction<>( getFunctionDescriptor(), - getRenderingSupport(), + getFunctionRenderer(), arguments, getImpliedResultType(), getArgumentsValidator(), diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialFunction.java index d13e4103c2..f048118dca 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialFunction.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialFunction.java @@ -9,6 +9,7 @@ package org.hibernate.spatial.dialect.oracle; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; @@ -24,7 +25,10 @@ public class OracleSpatialFunction extends NamedSqmFunctionDescriptor { @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - super.render( sqlAppender, sqlAstArguments, walker ); + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { + super.render( sqlAppender, sqlAstArguments, returnType, walker ); } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialSQLMMFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialSQLMMFunction.java index b5815ab9a5..3a1500ec46 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialSQLMMFunction.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSpatialSQLMMFunction.java @@ -9,6 +9,7 @@ package org.hibernate.spatial.dialect.oracle; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.sql.ast.SqlAstNodeRenderingMode; @@ -57,6 +58,7 @@ public class OracleSpatialSQLMMFunction extends OracleSpatialFunction { public void render( SqlAppender sqlAppender, List arguments, + ReturnableType returnType, SqlAstTranslator walker) { final Expression geometry = (Expression) arguments.get( 0 ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGetGeometryType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGetGeometryType.java index 9211b18cd8..0de0cea1f9 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGetGeometryType.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOGetGeometryType.java @@ -9,6 +9,7 @@ package org.hibernate.spatial.dialect.oracle; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.sql.ast.SqlAstTranslator; @@ -27,10 +28,12 @@ public class SDOGetGeometryType extends OracleSpatialFunction { StandardFunctionReturnTypeResolvers.invariant( typeRegistry.resolve( StandardBasicTypes.STRING ) ) ); } - @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { sqlAppender.appendSql( "CASE " ); ( (Expression) sqlAstArguments.get( 0 ) ).accept( walker ); sqlAppender.appendSql( ".Get_GType() " ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOMethodDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOMethodDescriptor.java index 4d5db25631..26811b97a5 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOMethodDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDOMethodDescriptor.java @@ -9,6 +9,7 @@ package org.hibernate.spatial.dialect.oracle; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.sql.ast.SqlAstTranslator; @@ -32,12 +33,12 @@ public class SDOMethodDescriptor extends OracleSpatialFunction { this( name, true, argValidator, returnTypeResolver ); } - - - @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { sqlAstArguments.get(0).accept( walker ); sqlAppender.appendSql( "." ); sqlAppender.appendSql( getName() ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDORelateFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDORelateFunction.java index f4423d6e32..5b243aaaff 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDORelateFunction.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/SDORelateFunction.java @@ -9,7 +9,7 @@ package org.hibernate.spatial.dialect.oracle; import java.util.List; -import org.hibernate.dialect.OracleSqlAstTranslator; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.sql.ast.SqlAstNodeRenderingMode; @@ -37,7 +37,10 @@ public class SDORelateFunction extends OracleSpatialFunction { @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { Expression geom1 = (Expression) sqlAstArguments.get( 0 ); Expression geom2 = (Expression) sqlAstArguments.get( 1 ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/STRelateFunction.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/STRelateFunction.java index 1cdbf72127..679f44ead1 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/STRelateFunction.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/STRelateFunction.java @@ -9,6 +9,7 @@ package org.hibernate.spatial.dialect.oracle; import java.util.List; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.sql.ast.SqlAstNodeRenderingMode; @@ -31,7 +32,11 @@ public class STRelateFunction extends OracleSpatialFunction { } @Override - public void render(SqlAppender sqlAppender, List arguments, SqlAstTranslator walker) { + public void render( + SqlAppender sqlAppender, + List arguments, + ReturnableType returnType, + SqlAstTranslator walker) { final Expression geom1 = (Expression) arguments.get( 0 ); final Expression geom2 = (Expression) arguments.get( 1 ); sqlAppender.appendSql( "ST_GEOMETRY(" ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSqmFunctionDescriptors.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSqmFunctionDescriptors.java index 2edb1add4f..072ddc53cf 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSqmFunctionDescriptors.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSqmFunctionDescriptors.java @@ -10,6 +10,7 @@ package org.hibernate.spatial.dialect.postgis; import java.util.List; import org.hibernate.boot.model.FunctionContributions; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; @@ -73,6 +74,7 @@ public class PostgisSqmFunctionDescriptors extends BaseSqmFunctionDescriptors { public void render( SqlAppender sqlAppender, List sqlAstArguments, + ReturnableType returnType, SqlAstTranslator walker) { sqlAppender.appendSql( '(' ); final Expression arg1 = (Expression) sqlAstArguments.get( 0 ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerSqmFunctionDescriptors.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerSqmFunctionDescriptors.java index fd77c711a8..f559c9a379 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerSqmFunctionDescriptors.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerSqmFunctionDescriptors.java @@ -10,6 +10,7 @@ package org.hibernate.spatial.dialect.sqlserver; import java.util.List; import org.hibernate.boot.model.FunctionContributions; +import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.function.NamedSqmFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; @@ -169,7 +170,10 @@ class Property extends NamedSqmFunctionDescriptor { @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { final Expression arg1 = (Expression) sqlAstArguments.get( 0 ); walker.render( arg1, SqlAstNodeRenderingMode.DEFAULT ); @@ -187,7 +191,10 @@ class Method extends NamedSqmFunctionDescriptor { @Override public void render( - SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + SqlAppender sqlAppender, + List sqlAstArguments, + ReturnableType returnType, + SqlAstTranslator walker) { final Expression arg1 = (Expression) sqlAstArguments.get( 0 ); walker.render( arg1, SqlAstNodeRenderingMode.DEFAULT ); diff --git a/migration-guide.adoc b/migration-guide.adoc index db09f132ca..82ce63493d 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -41,4 +41,32 @@ or one of the `MultiTenantConnectionProvider` subtypes. [[IdGeneratorStrategyInterpreter]] == Removed IdGeneratorStrategyInterpreter -`IdGeneratorStrategyInterpreter` has been deprecated since 6.0 and has been removed to simplify id generator internals. \ No newline at end of file +`IdGeneratorStrategyInterpreter` has been deprecated since 6.0 and has been removed to simplify id generator internals. + +[[function-rendering-support-deprecation]] +== Deprecation of `FunctionRenderingSupport` + +The `FunctionRenderingSupport` interface was deprecated for removal in favor of the new `FunctionRenderer` interface. +`FunctionRenderer` extends `FunctionRenderingSupport`, so switching to the new type should not be a big deal. +Classes the previously implemented the `FunctionRenderingSupport` interface should switch to implement `FunctionRenderer` +and the signature of the implemented `render(SqlAppender, List, SqlAstTranslator)` method has to be changed to +`render(SqlAppender, List, ReturnableType, SqlAstTranslator)` i.e. add `ReturnableType` as second last argument. + +The newly passed `ReturnableType` argument allows the rendering process to consider the resolved function result type +during rendering, which is common for certain array specific functions, especially for Oracle. + +Note that the deprecation also affects some methods/constructors of the `SelfRenderingSqlAstExpression` type hierarchy, +which were previously accepting/returning a `FunctionRenderingSupport`. Constructors that accept a `FunctionRenderer` +have been added to: + +* `SelfRenderingSqmFunction` +* `SelfRenderingSqmWindowFunction` +* `SelfRenderingSqmAggregateFunction` +* `SelfRenderingSqmOrderedSetAggregateFunction` +* `SelfRenderingFunctionSqlAstExpression` +* `SelfRenderingWindowFunctionSqlAstExpression` +* `SelfRenderingAggregateFunctionSqlAstExpression` +* `SelfRenderingOrderedSetAggregateFunctionSqlAstExpression` + +In addition, the `SelfRenderingSqmFunction.getRenderingSupport()` method was deprecated in favor of the new `SelfRenderingSqmFunction.getFunctionRenderer()` method. +Finally, the `SelfRenderingFunctionSqlAstExpression.getRenderer()` method was deprecated in favor of the new `SelfRenderingFunctionSqlAstExpression.getFunctionRenderer()` method.