HHH-17335 Add array_contains quantified functions
This commit is contained in:
parent
d46fcf1abe
commit
d5404fdd49
|
@ -1195,6 +1195,52 @@ include::{array-example-dir-hql}/ArrayConcatTest.java[tags=hql-array-concat-exam
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[hql-array-contains-quantified-functions]]
|
||||||
|
===== `array_contains_all()` and `array_contains_any()`
|
||||||
|
|
||||||
|
Checks if the first array argument contains all or any of the elements of the second array argument.
|
||||||
|
Returns `null` if either of the arguments is `null`. The result of the functions
|
||||||
|
is undefined when the second array argument contains a `null`.
|
||||||
|
|
||||||
|
[[hql-array-contains-all-example]]
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contains-all-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
[[hql-array-contains-any-example]]
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{array-example-dir-hql}/ArrayContainsAnyTest.java[tags=hql-array-contains-any-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
[[hql-array-contains-quantified-functions]]
|
||||||
|
===== `array_contains_all_nullable()` & `array_contains_any_nullable()`
|
||||||
|
|
||||||
|
Checks if the first array argument contains all or any of the elements of the second array argument.
|
||||||
|
Returns `null` if either of the arguments is `null`. Contrary to `array_contains_all()` and `array_contains_any()`,
|
||||||
|
these functions use the `distinct from` operator to also support searching for `null` elements.
|
||||||
|
|
||||||
|
[[hql-array-contains-all-nullable-example]]
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contains-all-nullable-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
[[hql-array-contains-any-nullable-example]]
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{array-example-dir-hql}/ArrayContainsAnyTest.java[tags=hql-array-contains-any-nullable-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
[[hql-user-defined-functions]]
|
[[hql-user-defined-functions]]
|
||||||
==== Native and user-defined functions
|
==== Native and user-defined functions
|
||||||
|
|
||||||
|
|
|
@ -468,6 +468,10 @@ public class CockroachLegacyDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_postgresql();
|
functionFactory.arrayPosition_postgresql();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_postgresql();
|
functionFactory.arrayConcat_postgresql();
|
||||||
|
functionFactory.arrayContainsAll_operator();
|
||||||
|
functionFactory.arrayContainsAny_operator();
|
||||||
|
functionFactory.arrayContainsAllNullable_operator();
|
||||||
|
functionFactory.arrayContainsAnyNullable_operator();
|
||||||
|
|
||||||
functionContributions.getFunctionRegistry().register(
|
functionContributions.getFunctionRegistry().register(
|
||||||
"trunc",
|
"trunc",
|
||||||
|
|
|
@ -376,6 +376,10 @@ public class H2LegacyDialect extends Dialect {
|
||||||
functionFactory.arrayContainsNull();
|
functionFactory.arrayContainsNull();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_operator();
|
functionFactory.arrayConcat_operator();
|
||||||
|
functionFactory.arrayContainsAll_h2();
|
||||||
|
functionFactory.arrayContainsAny_h2();
|
||||||
|
functionFactory.arrayContainsAllNullable_h2();
|
||||||
|
functionFactory.arrayContainsAnyNullable_h2();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Use group_concat until 2.x as listagg was buggy
|
// Use group_concat until 2.x as listagg was buggy
|
||||||
|
|
|
@ -254,6 +254,10 @@ public class HSQLLegacyDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_hsql();
|
functionFactory.arrayPosition_hsql();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_operator();
|
functionFactory.arrayConcat_operator();
|
||||||
|
functionFactory.arrayContainsAll_hsql();
|
||||||
|
functionFactory.arrayContainsAny_hsql();
|
||||||
|
functionFactory.arrayContainsAllNullable_hsql();
|
||||||
|
functionFactory.arrayContainsAnyNullable_hsql();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -290,6 +290,10 @@ public class OracleLegacyDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_oracle();
|
functionFactory.arrayPosition_oracle();
|
||||||
functionFactory.arrayLength_oracle();
|
functionFactory.arrayLength_oracle();
|
||||||
functionFactory.arrayConcat_oracle();
|
functionFactory.arrayConcat_oracle();
|
||||||
|
functionFactory.arrayContainsAll_oracle();
|
||||||
|
functionFactory.arrayContainsAny_oracle();
|
||||||
|
functionFactory.arrayContainsAllNullable_oracle();
|
||||||
|
functionFactory.arrayContainsAnyNullable_oracle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -588,6 +588,10 @@ public class PostgreSQLLegacyDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_postgresql();
|
functionFactory.arrayPosition_postgresql();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_postgresql();
|
functionFactory.arrayConcat_postgresql();
|
||||||
|
functionFactory.arrayContainsAll_operator();
|
||||||
|
functionFactory.arrayContainsAny_operator();
|
||||||
|
functionFactory.arrayContainsAllNullable_operator();
|
||||||
|
functionFactory.arrayContainsAnyNullable_operator();
|
||||||
|
|
||||||
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
|
||||||
functionFactory.makeDateTimeTimestamp();
|
functionFactory.makeDateTimeTimestamp();
|
||||||
|
|
|
@ -455,6 +455,10 @@ public class CockroachDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_postgresql();
|
functionFactory.arrayPosition_postgresql();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_postgresql();
|
functionFactory.arrayConcat_postgresql();
|
||||||
|
functionFactory.arrayContainsAll_operator();
|
||||||
|
functionFactory.arrayContainsAny_operator();
|
||||||
|
functionFactory.arrayContainsAllNullable_operator();
|
||||||
|
functionFactory.arrayContainsAnyNullable_operator();
|
||||||
|
|
||||||
functionContributions.getFunctionRegistry().register(
|
functionContributions.getFunctionRegistry().register(
|
||||||
"trunc",
|
"trunc",
|
||||||
|
|
|
@ -316,6 +316,10 @@ public class H2Dialect extends Dialect {
|
||||||
functionFactory.arrayContainsNull();
|
functionFactory.arrayContainsNull();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_operator();
|
functionFactory.arrayConcat_operator();
|
||||||
|
functionFactory.arrayContainsAll_h2();
|
||||||
|
functionFactory.arrayContainsAny_h2();
|
||||||
|
functionFactory.arrayContainsAllNullable_h2();
|
||||||
|
functionFactory.arrayContainsAnyNullable_h2();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -194,6 +194,10 @@ public class HSQLDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_hsql();
|
functionFactory.arrayPosition_hsql();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_operator();
|
functionFactory.arrayConcat_operator();
|
||||||
|
functionFactory.arrayContainsAll_hsql();
|
||||||
|
functionFactory.arrayContainsAny_hsql();
|
||||||
|
functionFactory.arrayContainsAllNullable_hsql();
|
||||||
|
functionFactory.arrayContainsAnyNullable_hsql();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -282,6 +282,51 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
database.addAuxiliaryDatabaseObject(
|
||||||
|
new NamedAuxiliaryDatabaseObject(
|
||||||
|
arrayTypeName + "_contains_all",
|
||||||
|
database.getDefaultNamespace(),
|
||||||
|
new String[]{
|
||||||
|
"create or replace function " + arrayTypeName + "_contains_all(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 " +
|
||||||
|
"found := 0; " +
|
||||||
|
"for j in 1 .. haystack.count loop " +
|
||||||
|
"if nullable = 1 and needle(i) is null and haystack(j) is null or needle(i)=haystack(j) then found := 1; exit; end if; " +
|
||||||
|
"end loop; " +
|
||||||
|
"if found = 0 then return 0; end if;" +
|
||||||
|
"end loop; " +
|
||||||
|
"return 1; " +
|
||||||
|
"end;"
|
||||||
|
},
|
||||||
|
new String[] { "drop function " + arrayTypeName + "_contains_all" },
|
||||||
|
emptySet(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
database.addAuxiliaryDatabaseObject(
|
||||||
|
new NamedAuxiliaryDatabaseObject(
|
||||||
|
arrayTypeName + "_contains_any",
|
||||||
|
database.getDefaultNamespace(),
|
||||||
|
new String[]{
|
||||||
|
"create or replace function " + arrayTypeName + "_contains_any(haystack in " + arrayTypeName +
|
||||||
|
", needle in " + arrayTypeName + ", nullable in number) return number deterministic is begin " +
|
||||||
|
"if haystack is null or needle is null then return null; end if; " +
|
||||||
|
"if needle.count = 0 then return 1; end if; " +
|
||||||
|
"for i in 1 .. needle.count loop " +
|
||||||
|
"for j in 1 .. haystack.count loop " +
|
||||||
|
"if nullable = 1 and needle(i) is null and haystack(j) is null or needle(i)=haystack(j) then return 1; end if; " +
|
||||||
|
"end loop; " +
|
||||||
|
"end loop; " +
|
||||||
|
"return 0; " +
|
||||||
|
"end;"
|
||||||
|
},
|
||||||
|
new String[] { "drop function " + arrayTypeName + "_contains_any" },
|
||||||
|
emptySet(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String createOrReplaceConcatFunction(String arrayTypeName) {
|
protected String createOrReplaceConcatFunction(String arrayTypeName) {
|
||||||
|
|
|
@ -319,6 +319,10 @@ public class OracleDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_oracle();
|
functionFactory.arrayPosition_oracle();
|
||||||
functionFactory.arrayLength_oracle();
|
functionFactory.arrayLength_oracle();
|
||||||
functionFactory.arrayConcat_oracle();
|
functionFactory.arrayConcat_oracle();
|
||||||
|
functionFactory.arrayContainsAll_oracle();
|
||||||
|
functionFactory.arrayContainsAny_oracle();
|
||||||
|
functionFactory.arrayContainsAllNullable_oracle();
|
||||||
|
functionFactory.arrayContainsAnyNullable_oracle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -636,6 +636,10 @@ public class PostgreSQLDialect extends Dialect {
|
||||||
functionFactory.arrayPosition_postgresql();
|
functionFactory.arrayPosition_postgresql();
|
||||||
functionFactory.arrayLength_cardinality();
|
functionFactory.arrayLength_cardinality();
|
||||||
functionFactory.arrayConcat_postgresql();
|
functionFactory.arrayConcat_postgresql();
|
||||||
|
functionFactory.arrayContainsAll_operator();
|
||||||
|
functionFactory.arrayContainsAny_operator();
|
||||||
|
functionFactory.arrayContainsAllNullable_operator();
|
||||||
|
functionFactory.arrayContainsAnyNullable_operator();
|
||||||
|
|
||||||
functionFactory.makeDateTimeTimestamp();
|
functionFactory.makeDateTimeTimestamp();
|
||||||
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions
|
// Note that PostgreSQL doesn't support the OVER clause for ordered set-aggregate functions
|
||||||
|
|
|
@ -16,12 +16,16 @@ import org.hibernate.dialect.function.array.ArrayAggFunction;
|
||||||
import org.hibernate.dialect.function.array.ArrayAndElementArgumentTypeResolver;
|
import org.hibernate.dialect.function.array.ArrayAndElementArgumentTypeResolver;
|
||||||
import org.hibernate.dialect.function.array.ArrayAndElementArgumentValidator;
|
import org.hibernate.dialect.function.array.ArrayAndElementArgumentValidator;
|
||||||
import org.hibernate.dialect.function.array.ArrayArgumentValidator;
|
import org.hibernate.dialect.function.array.ArrayArgumentValidator;
|
||||||
import org.hibernate.dialect.function.array.ArrayConcatArgumentValidator;
|
|
||||||
import org.hibernate.dialect.function.array.ArrayConcatFunction;
|
import org.hibernate.dialect.function.array.ArrayConcatFunction;
|
||||||
import org.hibernate.dialect.function.array.ArrayConstructorFunction;
|
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.ArrayContainsOperatorFunction;
|
||||||
|
import org.hibernate.dialect.function.array.ArrayContainsQuantifiedUnnestFunction;
|
||||||
|
import org.hibernate.dialect.function.array.H2ArrayContainsQuantifiedEmulation;
|
||||||
import org.hibernate.dialect.function.array.HSQLArrayPositionFunction;
|
import org.hibernate.dialect.function.array.HSQLArrayPositionFunction;
|
||||||
import org.hibernate.dialect.function.array.OracleArrayConcatFunction;
|
import org.hibernate.dialect.function.array.OracleArrayConcatFunction;
|
||||||
|
import org.hibernate.dialect.function.array.OracleArrayContainsAllFunction;
|
||||||
|
import org.hibernate.dialect.function.array.OracleArrayContainsAnyFunction;
|
||||||
import org.hibernate.dialect.function.array.OracleArrayLengthFunction;
|
import org.hibernate.dialect.function.array.OracleArrayLengthFunction;
|
||||||
import org.hibernate.dialect.function.array.OracleArrayPositionFunction;
|
import org.hibernate.dialect.function.array.OracleArrayPositionFunction;
|
||||||
import org.hibernate.dialect.function.array.PostgreSQLArrayConcatFunction;
|
import org.hibernate.dialect.function.array.PostgreSQLArrayConcatFunction;
|
||||||
|
@ -2688,7 +2692,7 @@ public class CommonFunctionFactory {
|
||||||
* CockroachDB and PostgreSQL array contains null emulation
|
* CockroachDB and PostgreSQL array contains null emulation
|
||||||
*/
|
*/
|
||||||
public void arrayContainsNull_hsql() {
|
public void arrayContainsNull_hsql() {
|
||||||
functionRegistry.patternDescriptorBuilder( "array_contains_null", "position_array(null in ?1)>0" )
|
functionRegistry.patternDescriptorBuilder( "array_contains_null", "exists(select 1 from unnest(?1) t(i) where t.i is null)" )
|
||||||
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) )
|
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.invariant( booleanType ) )
|
||||||
.setArgumentsValidator(
|
.setArgumentsValidator(
|
||||||
StandardArgumentsValidators.composite(
|
StandardArgumentsValidators.composite(
|
||||||
|
@ -2700,6 +2704,163 @@ public class CommonFunctionFactory {
|
||||||
.register();
|
.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 )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H2 array_contains_any() function
|
||||||
|
*/
|
||||||
|
public void arrayContainsAny_h2() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any",
|
||||||
|
new H2ArrayContainsQuantifiedEmulation( typeConfiguration, false, false )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HSQL array_contains_any() function
|
||||||
|
*/
|
||||||
|
public void arrayContainsAny_hsql() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any",
|
||||||
|
new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, false, false )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CockroachDB and PostgreSQL array contains any operator
|
||||||
|
*/
|
||||||
|
public void arrayContainsAny_operator() {
|
||||||
|
functionRegistry.register( "array_contains_any", new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, false, false ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Oracle array_contains_any() function
|
||||||
|
*/
|
||||||
|
public void arrayContainsAny_oracle() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any",
|
||||||
|
new OracleArrayContainsAnyFunction( 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_contains_any_nullable() function
|
||||||
|
*/
|
||||||
|
public void arrayContainsAnyNullable_h2() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any_nullable",
|
||||||
|
new H2ArrayContainsQuantifiedEmulation( typeConfiguration, false, true )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HSQL array_contains_any_nullable() function
|
||||||
|
*/
|
||||||
|
public void arrayContainsAnyNullable_hsql() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any_nullable",
|
||||||
|
new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, false, true )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CockroachDB and PostgreSQL array contains any nullable operator
|
||||||
|
*/
|
||||||
|
public void arrayContainsAnyNullable_operator() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any_nullable",
|
||||||
|
new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, false, true )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Oracle array_contains_any_nullable() function
|
||||||
|
*/
|
||||||
|
public void arrayContainsAnyNullable_oracle() {
|
||||||
|
functionRegistry.register(
|
||||||
|
"array_contains_any_nullable",
|
||||||
|
new OracleArrayContainsAnyFunction( typeConfiguration, true )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CockroachDB and PostgreSQL array_position() function
|
* CockroachDB and PostgreSQL array_position() function
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.StandardFunctionArgumentTypeResolvers;
|
||||||
|
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 quantified array_contains functions.
|
||||||
|
* Subclasses only have to implement the rendering.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractArrayContainsQuantifiedFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
|
||||||
|
|
||||||
|
public AbstractArrayContainsQuantifiedFunction(String functionName, TypeConfiguration typeConfiguration) {
|
||||||
|
super(
|
||||||
|
functionName,
|
||||||
|
StandardArgumentsValidators.composite(
|
||||||
|
StandardArgumentsValidators.exactly( 2 ),
|
||||||
|
ArraysOfSameTypeArgumentValidator.INSTANCE
|
||||||
|
),
|
||||||
|
StandardFunctionReturnTypeResolvers.invariant( typeConfiguration.standardBasicTypeForJavaType( Boolean.class ) ),
|
||||||
|
StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getArgumentListSignature() {
|
||||||
|
return "(ARRAY haystackArray, ARRAY needleArray)";
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ public class ArrayConcatFunction extends AbstractSqmSelfRenderingFunctionDescrip
|
||||||
"array_concat",
|
"array_concat",
|
||||||
StandardArgumentsValidators.composite(
|
StandardArgumentsValidators.composite(
|
||||||
StandardArgumentsValidators.min( 2 ),
|
StandardArgumentsValidators.min( 2 ),
|
||||||
ArrayConcatArgumentValidator.INSTANCE
|
ArraysOfSameTypeArgumentValidator.INSTANCE
|
||||||
),
|
),
|
||||||
StandardFunctionReturnTypeResolvers.useFirstNonNull(),
|
StandardFunctionReturnTypeResolvers.useFirstNonNull(),
|
||||||
StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE
|
StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array contains all function that uses the PostgreSQL {@code @>} operator.
|
||||||
|
*/
|
||||||
|
public class ArrayContainsQuantifiedOperatorFunction extends ArrayContainsQuantifiedUnnestFunction {
|
||||||
|
|
||||||
|
public ArrayContainsQuantifiedOperatorFunction(TypeConfiguration typeConfiguration, boolean all, boolean nullable) {
|
||||||
|
super( typeConfiguration, all, nullable );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
if ( nullable ) {
|
||||||
|
super.render( sqlAppender, sqlAstArguments, 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( "&&" );
|
||||||
|
}
|
||||||
|
needleExpression.accept( walker );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement the contains all function by using {@code unnest}.
|
||||||
|
*/
|
||||||
|
public class ArrayContainsQuantifiedUnnestFunction extends AbstractArrayContainsQuantifiedFunction {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
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 ( !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( "select * from unnest(" );
|
||||||
|
haystackExpression.accept( walker );
|
||||||
|
sqlAppender.append( ")))" );
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ package org.hibernate.dialect.function.array;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.DomainType;
|
import org.hibernate.metamodel.model.domain.DomainType;
|
||||||
|
import org.hibernate.query.sqm.SqmExpressible;
|
||||||
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
|
||||||
import org.hibernate.query.sqm.produce.function.FunctionArgumentException;
|
import org.hibernate.query.sqm.produce.function.FunctionArgumentException;
|
||||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||||
|
@ -18,9 +19,9 @@ import org.hibernate.type.spi.TypeConfiguration;
|
||||||
/**
|
/**
|
||||||
* A {@link ArgumentsValidator} that validates all arguments are of the same array type.
|
* A {@link ArgumentsValidator} that validates all arguments are of the same array type.
|
||||||
*/
|
*/
|
||||||
public class ArrayConcatArgumentValidator implements ArgumentsValidator {
|
public class ArraysOfSameTypeArgumentValidator implements ArgumentsValidator {
|
||||||
|
|
||||||
public static final ArgumentsValidator INSTANCE = new ArrayConcatArgumentValidator();
|
public static final ArgumentsValidator INSTANCE = new ArraysOfSameTypeArgumentValidator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(
|
public void validate(
|
||||||
|
@ -29,8 +30,9 @@ public class ArrayConcatArgumentValidator implements ArgumentsValidator {
|
||||||
TypeConfiguration typeConfiguration) {
|
TypeConfiguration typeConfiguration) {
|
||||||
BasicPluralType<?, ?> arrayType = null;
|
BasicPluralType<?, ?> arrayType = null;
|
||||||
for ( int i = 0; i < arguments.size(); i++ ) {
|
for ( int i = 0; i < arguments.size(); i++ ) {
|
||||||
final DomainType<?> sqmType = arguments.get( i ).getExpressible().getSqmType();
|
final SqmExpressible<?> expressible = arguments.get( i ).getExpressible();
|
||||||
if ( sqmType != null ) {
|
final DomainType<?> sqmType;
|
||||||
|
if ( expressible != null && ( sqmType = expressible.getSqmType() ) != null ) {
|
||||||
if ( arrayType == null ) {
|
if ( arrayType == null ) {
|
||||||
if ( !( sqmType instanceof BasicPluralType<?, ?> ) ) {
|
if ( !( sqmType instanceof BasicPluralType<?, ?> ) ) {
|
||||||
throw new FunctionArgumentException(
|
throw new FunctionArgumentException(
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 H2ArrayContainsQuantifiedEmulation extends AbstractArrayContainsQuantifiedFunction {
|
||||||
|
|
||||||
|
private final boolean all;
|
||||||
|
private final boolean nullable;
|
||||||
|
|
||||||
|
public H2ArrayContainsQuantifiedEmulation(TypeConfiguration typeConfiguration, boolean all, boolean nullable) {
|
||||||
|
super( "array_contains_" + ( all ? "all" : "any" ), typeConfiguration );
|
||||||
|
this.all = all;
|
||||||
|
this.nullable = nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
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 ( !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( ") t(i) where array_length(" );
|
||||||
|
needleExpression.accept( walker );
|
||||||
|
sqlAppender.append( ")>=t.i" );
|
||||||
|
if ( all ) {
|
||||||
|
sqlAppender.append( " except " );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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( ") t(i) where array_length(" );
|
||||||
|
haystackExpression.accept( walker );
|
||||||
|
sqlAppender.append( ")>=t.i))" );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getMaximumArraySize() {
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -30,14 +30,16 @@ public class HSQLArrayPositionFunction extends AbstractArrayPositionFunction {
|
||||||
SqlAstTranslator<?> walker) {
|
SqlAstTranslator<?> walker) {
|
||||||
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
|
final Expression arrayExpression = (Expression) sqlAstArguments.get( 0 );
|
||||||
final Expression elementExpression = (Expression) sqlAstArguments.get( 1 );
|
final Expression elementExpression = (Expression) sqlAstArguments.get( 1 );
|
||||||
sqlAppender.append( "position_array(" );
|
sqlAppender.append( "case when " );
|
||||||
elementExpression.accept( walker );
|
|
||||||
sqlAppender.append( " in " );
|
|
||||||
arrayExpression.accept( walker );
|
arrayExpression.accept( walker );
|
||||||
|
sqlAppender.append( " is not null then coalesce((select t.idx from unnest(");
|
||||||
|
arrayExpression.accept( walker );
|
||||||
|
sqlAppender.append(") with ordinality t(val,idx) where t.val is not distinct from " );
|
||||||
|
elementExpression.accept( walker );
|
||||||
if ( sqlAstArguments.size() > 2 ) {
|
if ( sqlAstArguments.size() > 2 ) {
|
||||||
sqlAppender.append( " from " );
|
sqlAppender.append( " and t.idx>=" );
|
||||||
sqlAstArguments.get( 2 ).accept( walker );
|
sqlAstArguments.get( 2 ).accept( walker );
|
||||||
}
|
}
|
||||||
sqlAppender.append( ')' );
|
sqlAppender.append( "),0) end" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 = ArrayTypeHelper.getArrayTypeName( 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" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 OracleArrayContainsAnyFunction extends AbstractArrayContainsQuantifiedFunction {
|
||||||
|
|
||||||
|
private final boolean nullable;
|
||||||
|
|
||||||
|
public OracleArrayContainsAnyFunction(TypeConfiguration typeConfiguration, boolean nullable) {
|
||||||
|
super( "array_contains_any", 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 = ArrayTypeHelper.getArrayTypeName( haystackExpression.getExpressionType(), walker );
|
||||||
|
sqlAppender.appendSql( arrayTypeName );
|
||||||
|
sqlAppender.append( "_contains_any(" );
|
||||||
|
haystackExpression.accept( walker );
|
||||||
|
sqlAppender.append( ',' );
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
sqlAppender.append( ',' );
|
||||||
|
sqlAppender.append( nullable ? "1" : "0" );
|
||||||
|
sqlAppender.append( ")>0" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.function.array;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Beikov
|
||||||
|
*/
|
||||||
|
@DomainModel(annotatedClasses = EntityWithArrays.class)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||||
|
// Make sure this stuff runs on a dedicated connection pool,
|
||||||
|
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
// because the JDBC connection or database session caches something that should have been invalidated
|
||||||
|
@ServiceRegistry(settings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER, value = ""))
|
||||||
|
public class ArrayContainsAllTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void prepareData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( em -> {
|
||||||
|
em.persist( new EntityWithArrays( 1L, new String[]{} ) );
|
||||||
|
em.persist( new EntityWithArrays( 2L, new String[]{ "abc", null, "def" } ) );
|
||||||
|
em.persist( new EntityWithArrays( 3L, null ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanup(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( em -> {
|
||||||
|
em.createMutationQuery( "delete from EntityWithArrays" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsAll(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-array-contains-all-example[]
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_all(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
//end::hql-array-contains-all-example[]
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotContain(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_all(e.theArray, array('xyz'))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 0, results.size() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsPartly(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_all(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 0, results.size() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "Type inference isn't smart enough to figure out the type for the `null`")
|
||||||
|
public void testContainsNull(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_all_nullable(e.theArray, array(null))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsWithNull(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-array-contains-all-nullable-example[]
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_all_nullable(e.theArray, array('abc',null))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
//end::hql-array-contains-all-nullable-example[]
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.function.array;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Christian Beikov
|
||||||
|
*/
|
||||||
|
@DomainModel(annotatedClasses = EntityWithArrays.class)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialectFeature( feature = DialectFeatureChecks.SupportsStructuralArrays.class)
|
||||||
|
// Make sure this stuff runs on a dedicated connection pool,
|
||||||
|
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
|
||||||
|
// because the JDBC connection or database session caches something that should have been invalidated
|
||||||
|
@ServiceRegistry(settings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER, value = ""))
|
||||||
|
public class ArrayContainsAnyTest {
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void prepareData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( em -> {
|
||||||
|
em.persist( new EntityWithArrays( 1L, new String[]{} ) );
|
||||||
|
em.persist( new EntityWithArrays( 2L, new String[]{ "abc", null, "def" } ) );
|
||||||
|
em.persist( new EntityWithArrays( 3L, null ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanup(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( em -> {
|
||||||
|
em.createMutationQuery( "delete from EntityWithArrays" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsAny(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-array-contains-any-example[]
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
//end::hql-array-contains-any-example[]
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDoesNotContain(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any(e.theArray, array('xyz'))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 0, results.size() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsPartly(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "Type inference isn't smart enough to figure out the type for the `null`")
|
||||||
|
public void testContainsNull(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any_nullable(e.theArray, array(null))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContainsNullPartly(SessionFactoryScope scope) {
|
||||||
|
scope.inSession( em -> {
|
||||||
|
//tag::hql-array-contains-any-nullable-example[]
|
||||||
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any_nullable(e.theArray, array('xyz',null))", EntityWithArrays.class )
|
||||||
|
.getResultList();
|
||||||
|
//end::hql-array-contains-any-nullable-example[]
|
||||||
|
assertEquals( 1, results.size() );
|
||||||
|
assertEquals( 2L, results.get( 0 ).getId() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ package org.hibernate.orm.test.function.array;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
@ -18,7 +17,6 @@ import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -75,7 +73,6 @@ public class ArrayContainsTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "See https://sourceforge.net/p/hsqldb/bugs/1692/")
|
|
||||||
public void testContainsNull(SessionFactoryScope scope) {
|
public void testContainsNull(SessionFactoryScope scope) {
|
||||||
scope.inSession( em -> {
|
scope.inSession( em -> {
|
||||||
//tag::hql-array-contains-null-example[]
|
//tag::hql-array-contains-null-example[]
|
||||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.orm.test.function.array;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
@ -18,7 +17,6 @@ import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -76,7 +74,6 @@ public class ArrayLengthTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "See https://sourceforge.net/p/hsqldb/bugs/1692/")
|
|
||||||
public void testLengthNull(SessionFactoryScope scope) {
|
public void testLengthNull(SessionFactoryScope scope) {
|
||||||
scope.inSession( em -> {
|
scope.inSession( em -> {
|
||||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_length(e.theArray) is null", EntityWithArrays.class )
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_length(e.theArray) is null", EntityWithArrays.class )
|
||||||
|
|
|
@ -10,7 +10,6 @@ import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.dialect.H2Dialect;
|
import org.hibernate.dialect.H2Dialect;
|
||||||
import org.hibernate.dialect.HSQLDialect;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
@ -77,7 +76,6 @@ public class ArrayPositionTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "See https://sourceforge.net/p/hsqldb/bugs/1692/")
|
|
||||||
public void testPositionNull(SessionFactoryScope scope) {
|
public void testPositionNull(SessionFactoryScope scope) {
|
||||||
scope.inSession( em -> {
|
scope.inSession( em -> {
|
||||||
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_position(e.theArray, null) = 2", EntityWithArrays.class )
|
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_position(e.theArray, null) = 2", EntityWithArrays.class )
|
||||||
|
|
Loading…
Reference in New Issue