HHH-17355 Unify array_contains and array_contains_all as well as deprecate FunctionRenderingSupport in favor of new FunctionRenderer contract

This commit is contained in:
Christian Beikov 2023-10-26 16:40:07 +02:00
parent 5506714611
commit bfb9fcc0f6
144 changed files with 1617 additions and 1241 deletions

View File

@ -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]
----
====

View File

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

View File

@ -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<String> tableTypesList) {
if ( getVersion().isSameOrAfter( 2 ) ) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -479,7 +479,7 @@ public class SpannerDialect extends Dialect {
functionFactory.listagg_stringAgg( "string" );
functionFactory.inverseDistributionOrderedSetAggregates();
functionFactory.hypotheticalOrderedSetAggregates();
functionFactory.array_withoutKeyword();
functionFactory.array_spanner();
}
@Override

View File

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

View File

@ -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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, null, walker );
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, null, returnType, walker );
}
@Override
@ -71,6 +76,7 @@ public class AvgFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
SqlAppender sqlAppender,
List<? extends SqlAstNode> 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 );

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final int numberOfArguments = arguments.size();
if ( numberOfArguments > 1 ) {

View File

@ -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<? extends SqlAstNode> arguments, SqlAstTranslator<?> walker) {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression source = (Expression) arguments.get( 0 );
final JdbcMapping sourceMapping = source.getExpressionType().getSingleJdbcMapping();
final CastType sourceType = getCastType( sourceMapping );

View File

@ -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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> 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.

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
@SuppressWarnings("unchecked")
final QueryLiteral<Number> literal = (QueryLiteral<Number>) arguments.get( 0 );

View File

@ -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 ) );
}
/**

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
String separator = "(";
for ( int i = 0; i < sqlAstArguments.size(); i++ ) {

View File

@ -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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, null, walker );
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, null, returnType, walker );
}
@Override
@ -142,6 +147,7 @@ public class CountFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
SqlAppender sqlAppender,
List<? extends SqlAstNode> 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 );

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql( sql );
}

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression datetime = (Expression) arguments.get( 0 );
sqlAppender.appendSql( "varchar_format(" );

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final int argumentCount = arguments.size();
sqlAppender.appendSql( "position(" );

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final int argumentCount = arguments.size();
sqlAppender.appendSql( "substring(" );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql( toDateFunction );
sqlAppender.append( '(' );

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final SqlAstNode string = arguments.get( 0 );
final SqlAstNode length = arguments.get( 1 );

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final SqlAstNode string = arguments.get( 0 );
final SqlAstNode length = arguments.get( 1 );

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
this.render( sqlAppender, sqlAstArguments, null, walker );
SqlAppender sqlAppender, List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
this.render( sqlAppender, sqlAstArguments, null, returnType, walker );
}
}

View File

@ -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<? extends SqlAstNode> 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,

View File

@ -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<? extends SqlAstNode> 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<? extends SqmTypedNode<?>> arguments,
ReturnableType<T> 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<SqlAstNode> 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

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
if ( filter != null && !translator.supportsFilterClause() ) {
throw new IllegalArgumentException( "Can't emulate filter clause for inverse distribution function [" + getName() + "]" );

View File

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

View File

@ -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<? extends SqlAstNode> 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 );
}
}

View File

@ -75,8 +75,9 @@ public class InverseDistributionFunction extends AbstractSqmSelfRenderingFunctio
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
if ( filter != null && !translator.supportsFilterClause() ) {
throw new IllegalArgumentException( "Can't emulate filter clause for inverse distribution function [" + getName() + "]" );

View File

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

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression expression = (Expression) sqlAstArguments.get( 0 );
final JdbcType jdbcType = expression.getExpressionType().getSingleJdbcMapping().getJdbcType();

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !translator.supportsFilterClause();
sqlAppender.appendSql( "listagg(" );

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !translator.supportsFilterClause();
sqlAppender.appendSql( "group_concat(" );

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !translator.supportsFilterClause();
sqlAppender.appendSql( functionName );

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
this.render( sqlAppender, sqlAstArguments, null, walker );
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
this.render( sqlAppender, sqlAstArguments, null, returnType, walker );
}
}

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !translator.supportsFilterClause();
sqlAppender.appendSql( "stats_mode(" );

View File

@ -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<T> impliedResultType,
QueryEngine queryEngine) {
final List<SqmTypedNode<?>> 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,

View File

@ -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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, null, walker );
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
render( sqlAppender, sqlAstArguments, null, returnType, walker );
}
@Override
@ -55,6 +60,7 @@ public class PostgreSQLMinMaxFunction extends AbstractSqmSelfRenderingFunctionDe
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !translator.supportsFilterClause();
sqlAppender.appendSql( getName() );

View File

@ -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 <a href="https://www.postgresql.org/docs/current/functions-math.html">PostgreSQL documentation</a>
*/
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<? extends SqlAstNode> arguments, SqlAstTranslator<?> walker) {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final int numberOfArguments = arguments.size();
final Expression firstArg = (Expression) arguments.get( 0 );
final JdbcType jdbcType = firstArg.getExpressionType().getSingleJdbcMapping().getJdbcType();

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final int numberOfArguments = arguments.size();
if ( numberOfArguments > 1 ) {

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
this.render( sqlAppender, sqlAstArguments, null, walker );
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
this.render( sqlAppender, sqlAstArguments, null, (ReturnableType<?>) null, walker );
}
}

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression datetime = (Expression) arguments.get(0);

View File

@ -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<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final QueryLiteral<String> sqlFragmentLiteral = (QueryLiteral<String>) arguments.get( 0 );
final String sqlFragment = sqlFragmentLiteral.getLiteralValue();

View File

@ -79,6 +79,7 @@ public class SqlServerConvertTruncFunction extends TruncFunction {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql( toDateFunction );
sqlAppender.append( '(' );

View File

@ -87,6 +87,7 @@ public class SybaseTruncFunction extends TruncFunction {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql( toDateFunction );
sqlAppender.append( '(' );

View File

@ -65,6 +65,7 @@ public class TimestampaddFunction
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final DurationUnit field = (DurationUnit) arguments.get( 0 );

View File

@ -74,6 +74,7 @@ public class TimestampdiffFunction
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final DurationUnit field = (DurationUnit) arguments.get( 0 );

View File

@ -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<? extends SqlAstNode> arguments, SqlAstTranslator<?> walker) {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.appendSql( "str(" );
arguments.get( 0 ).accept( walker );
for ( int i = 1; i < arguments.size(); i++ ) {

View File

@ -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<? extends SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> 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 );

View File

@ -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<SqmTypedNode<?>> 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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final PatternRenderer pattern;
if ( twoArgTruncPattern != null && sqlAstArguments.size() == 2 ) {

View File

@ -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)";
}
}

View File

@ -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)";
}
}

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && ( !supportsFilter || !translator.supportsFilterClause() );
sqlAppender.appendSql( functionName );

View File

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

View File

@ -44,7 +44,7 @@ public class ArrayArgumentValidator implements ArgumentsValidator {
return getElementType( arrayIndex, arguments, functionName, typeConfiguration );
}
protected BasicType<?> getElementType(
protected BasicPluralType<?, ?> getPluralType(
int arrayIndex,
List<? extends SqmTypedNode<?>> 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<? extends SqmTypedNode<?>> arguments,
String functionName,
TypeConfiguration typeConfiguration) {
return getPluralType( arrayIndex, arguments, functionName, typeConfiguration ).getElementType();
}
}

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final SqlAstNode firstArgument = sqlAstArguments.get( 0 );
final SqlAstNode secondArgument = sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
sqlAppender.append( prefix );
sqlAstArguments.get( 0 ).accept( walker );

View File

@ -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<? extends SqlAstNode> arguments, SqlAstTranslator<?> walker) {
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> arguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
if ( withKeyword ) {
sqlAppender.append( "array" );
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<? extends SqmTypedNode<?>> 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()
)
);
}
}
}

View File

@ -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<? extends SqlAstNode> 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)";
}
}

View File

@ -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<? extends SqlAstNode> 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( ")" );
}
}
}

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression indexExpression = (Expression) sqlAstArguments.get( 1 );

View File

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

View File

@ -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<? extends SqlAstNode> 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 );
}
}

View File

@ -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<? extends SqlAstNode> 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( ")))" );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression indexExpression = (Expression) sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression oldExpression = (Expression) sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression indexExpression = (Expression) sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression startIndexExpression = (Expression) sqlAstArguments.get( 1 );

View File

@ -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 <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
List<? extends SqmTypedNode<?>> arguments,
ReturnableType<T> impliedResultType,
QueryEngine queryEngine) {
return new ArrayConstructorSqmFunction<>(
this,
this,
arguments,
impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(),
getName()
);
}
protected static class ArrayConstructorSqmFunction<T> extends SelfRenderingSqmFunction<T> {
public ArrayConstructorSqmFunction(
CastingArrayConstructorFunction descriptor,
FunctionRenderingSupport renderingSupport,
List<? extends SqmTypedNode<?>> arguments,
ReturnableType<T> 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<SqlAstNode> 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( ')' );
}
}
};
}
}
}

View File

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

View File

@ -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<? extends SqlAstNode> 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( ')' );
}
}
}

View File

@ -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<? extends SqlAstNode> 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;
}
}

View File

@ -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<? extends SqlAstNode> 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;
}
}

View File

@ -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<? extends SqlAstNode> 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;
}
}

View File

@ -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<? extends SqlAstNode> 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;
}
}

View File

@ -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<? extends SqlAstNode> 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;
}
}

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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();
}
}

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression elementExpression = (Expression) sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final Expression elementExpression = (Expression) sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> 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;
}
}

View File

@ -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<? extends SqlAstNode> 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<? extends SqlAstNode> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
sqlAppender.appendSql( "json_arrayagg" );
sqlAppender.appendSql( '(' );
@ -154,7 +155,7 @@ public class OracleArrayAggEmulation extends AbstractSqmSelfRenderingFunctionDes
protected static class OracleArrayAggSqmFunction<T> extends SelfRenderingSqmOrderedSetAggregateFunction<T> {
public OracleArrayAggSqmFunction(
OracleArrayAggEmulation descriptor,
FunctionRenderingSupport renderingSupport,
FunctionRenderer renderingSupport,
List<? extends SqmTypedNode<?>> 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<? extends SqlAstNode> sqlAstArguments,
Predicate filter,
List<SortSpecification> withinGroup,

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression firstArgument = (Expression) sqlAstArguments.get( 0 );
final Expression secondArgument = (Expression) sqlAstArguments.get( 1 );

View File

@ -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<? extends SqlAstNode> 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 );
}
}

View File

@ -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 <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
List<? extends SqmTypedNode<?>> arguments,
ReturnableType<T> impliedResultType,
QueryEngine queryEngine) {
return new ArrayConstructorSqmFunction<>(
this,
this,
arguments,
impliedResultType,
getArgumentsValidator(),
getReturnTypeResolver(),
queryEngine.getCriteriaBuilder(),
getName()
);
}
protected static class ArrayConstructorSqmFunction<T> extends SelfRenderingSqmFunction<T> {
public ArrayConstructorSqmFunction(
OracleArrayConstructorFunction descriptor,
FunctionRenderingSupport renderingSupport,
List<? extends SqmTypedNode<?>> arguments,
ReturnableType<T> impliedResultType,
ArgumentsValidator argumentsValidator,
FunctionReturnTypeResolver returnTypeResolver,
NodeBuilder nodeBuilder,
String name) {
super(
descriptor,
renderingSupport,
arguments,
impliedResultType,
argumentsValidator,
returnTypeResolver,
nodeBuilder,
name
public void render(
SqlAppender sqlAppender,
List<? extends SqlAstNode> 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<SqlAstNode> 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<? extends SqlAstNode> 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( ')' );
}
}

View File

@ -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<? extends SqlAstNode> 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" );
}
}

View File

@ -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<? extends SqlAstNode> 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" );
}
}
}

View File

@ -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<? extends SqlAstNode> 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)";
}
}

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final String arrayTypeName = DdlTypeHelper.getTypeName(
( (Expression) sqlAstArguments.get( 0 ) ).getExpressionType(),

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker );

View File

@ -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<? extends SqlAstNode> sqlAstArguments,
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
final String arrayTypeName = DdlTypeHelper.getTypeName( arrayExpression.getExpressionType(), walker );

Some files were not shown because too many files have changed in this diff Show More