HHH-17355 Rename array_contains_any to array_overlaps

This commit is contained in:
Christian Beikov 2023-10-26 09:45:46 +02:00
parent 3e0feab155
commit 5506714611
15 changed files with 107 additions and 124 deletions

View File

@ -1118,17 +1118,15 @@ The following functions deal with SQL array types, which are not supported on ev
| Function | Purpose
| `array()` | Creates an array based on the passed arguments
| `array_contains()` | Whether an array contains an element
| `array_contains_null()` | Whether an array contains a null
| `array_position()` | Determines the position of an element in an array
| `array_length()` | Determines the length of an array
| `array_concat()` | Concatenates array with each other in order
| `array_prepend()` | Prepends element to array
| `array_append()` | Appends element to array
| `array_contains_all()` | Determines if one array holds all elements of another array
| `array_contains_all_nullable()` | Determines if one array holds all elements of another array, supporting null elements
| `array_contains_any()` | Determines if one array holds at least one element of another array
| `array_contains_any_nullable()` | Determines if one array holds at least one element of another array, supporting null elements
| `array_contains()` | Whether an array contains element(s)
| `array_contains_nullable()` | Whether an array contains element(s), supporting `null` elements
| `array_overlaps()` | Whether an array holds at least one element of another array
| `array_overlaps_nullable()` | Whether an array holds at least one element of another array, supporting `null` elements
| `array_get()` | Accesses the element of an array by index
| `array_set()` | Creates array copy with given element at given index
| `array_remove()` | Creates array copy with given element removed
@ -1148,25 +1146,6 @@ include::{array-example-dir-hql}/ArrayConstructorTest.java[tags=hql-array-exampl
----
====
[[hql-array-contains-functions]]
===== `array_contains()` and `array_contains_null()`
Both functions return `null` if the first argument, the array, is null, yet the result of the `array_contains` function
is undefined when the second argument, the element to search, is `null`.
The `array_contains_null` function only takes a single argument, the array, and will return whether the array contains a `null` element.
[[hql-array-contains-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-example]
----
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-null-example]
----
====
[[hql-array-position-functions]]
===== `array_position()`
@ -1232,14 +1211,25 @@ include::{array-example-dir-hql}/ArrayAppendTest.java[tags=hql-array-append-exam
----
====
[[hql-array-contains-quantified-functions]]
===== `array_contains_all()` and `array_contains_any()`
[[hql-array-contains-functions]]
===== `array_contains()` and `array_contains_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`. The result of the functions
is undefined when the second array argument contains a `null`.
Checks if the first array argument contains the element(s) of the second argument.
Returns `null` if the first argument is `null`. The result of the `array_contains` function
is undefined when the second argument, the element to search, is `null`.
[[hql-array-contains-all-example]]
[[hql-array-contains-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-example]
----
====
The second argument may be an array of the same type as the first argument.
The result of `array_contains` is undefined when the second argument is an array that contains a `null` element.
[[hql-array-contains-array-example]]
====
[source, JAVA, indent=0]
----
@ -1247,22 +1237,9 @@ include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contai
----
====
[[hql-array-contains-any-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsAnyTest.java[tags=hql-array-contains-any-example]
----
====
To search for `null` elements, the `array_contains_nullable` function must be used with an array argument.
[[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]]
[[hql-array-contains-array-nullable-example]]
====
[source, JAVA, indent=0]
----
@ -1270,11 +1247,27 @@ include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contai
----
====
[[hql-array-contains-any-nullable-example]]
[[hql-array-overlaps-functions]]
===== `array_overlaps()` and `array_overlaps_nullable()`
Checks if the first array argument any of the elements of the second array argument.
Returns `null` if either of the arguments is `null`. The result of `array_overlaps`
is undefined when the second array argument contains a `null` array element.
Only `array_overlaps_nullable` is guaranteed to produce correct results for `null` array elements.
[[hql-array-overlaps-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsAnyTest.java[tags=hql-array-contains-any-nullable-example]
include::{array-example-dir-hql}/ArrayOverlapsTest.java[tags=hql-array-overlaps-example]
----
====
[[hql-array-overlaps-nullable-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayOverlapsTest.java[tags=hql-array-overlaps-nullable-example]
----
====

View File

@ -471,9 +471,9 @@ public class CockroachLegacyDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContainsAll_operator();
functionFactory.arrayContainsAny_operator();
functionFactory.arrayOverlaps_operator();
functionFactory.arrayContainsAllNullable_operator();
functionFactory.arrayContainsAnyNullable_operator();
functionFactory.arrayOverlapsNullable_unnest();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -379,9 +379,9 @@ public class H2LegacyDialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContainsAll_h2();
functionFactory.arrayContainsAny_h2();
functionFactory.arrayOverlaps_h2();
functionFactory.arrayContainsAllNullable_h2();
functionFactory.arrayContainsAnyNullable_h2();
functionFactory.arrayOverlapsNullable_h2();
functionFactory.arrayGet_h2();
functionFactory.arraySet_h2();
functionFactory.arrayRemove_h2();

View File

@ -257,9 +257,9 @@ public class HSQLLegacyDialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContainsAll_hsql();
functionFactory.arrayContainsAny_hsql();
functionFactory.arrayOverlaps_hsql();
functionFactory.arrayContainsAllNullable_hsql();
functionFactory.arrayContainsAnyNullable_hsql();
functionFactory.arrayOverlapsNullable_unnest();
functionFactory.arrayGet_unnest();
functionFactory.arraySet_hsql();
functionFactory.arrayRemove_hsql();

View File

@ -293,9 +293,9 @@ public class OracleLegacyDialect extends Dialect {
functionFactory.arrayPrepend_oracle();
functionFactory.arrayAppend_oracle();
functionFactory.arrayContainsAll_oracle();
functionFactory.arrayContainsAny_oracle();
functionFactory.arrayOverlaps_oracle();
functionFactory.arrayContainsAllNullable_oracle();
functionFactory.arrayContainsAnyNullable_oracle();
functionFactory.arrayOverlapsNullable_oracle();
functionFactory.arrayGet_oracle();
functionFactory.arraySet_oracle();
functionFactory.arrayRemove_oracle();

View File

@ -591,9 +591,9 @@ public class PostgreSQLLegacyDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContainsAll_operator();
functionFactory.arrayContainsAny_operator();
functionFactory.arrayOverlaps_operator();
functionFactory.arrayContainsAllNullable_operator();
functionFactory.arrayContainsAnyNullable_operator();
functionFactory.arrayOverlapsNullable_unnest();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -458,9 +458,9 @@ public class CockroachDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContainsAll_operator();
functionFactory.arrayContainsAny_operator();
functionFactory.arrayOverlaps_operator();
functionFactory.arrayContainsAllNullable_operator();
functionFactory.arrayContainsAnyNullable_operator();
functionFactory.arrayOverlapsNullable_unnest();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -318,9 +318,9 @@ public class H2Dialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContainsAll_h2();
functionFactory.arrayContainsAny_h2();
functionFactory.arrayOverlaps_h2();
functionFactory.arrayContainsAllNullable_h2();
functionFactory.arrayContainsAnyNullable_h2();
functionFactory.arrayOverlapsNullable_h2();
functionFactory.arrayGet_h2();
functionFactory.arraySet_h2();
functionFactory.arrayRemove_h2();

View File

@ -197,9 +197,9 @@ public class HSQLDialect extends Dialect {
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContainsAll_hsql();
functionFactory.arrayContainsAny_hsql();
functionFactory.arrayOverlaps_hsql();
functionFactory.arrayContainsAllNullable_hsql();
functionFactory.arrayContainsAnyNullable_hsql();
functionFactory.arrayOverlapsNullable_unnest();
functionFactory.arrayGet_unnest();
functionFactory.arraySet_hsql();
functionFactory.arrayRemove_hsql();

View File

@ -307,10 +307,10 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
);
database.addAuxiliaryDatabaseObject(
new NamedAuxiliaryDatabaseObject(
arrayTypeName + "_contains_any",
arrayTypeName + "_overlaps",
database.getDefaultNamespace(),
new String[]{
"create or replace function " + arrayTypeName + "_contains_any(haystack in " + arrayTypeName +
"create or replace function " + arrayTypeName + "_overlaps(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; " +
@ -322,7 +322,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType {
"return 0; " +
"end;"
},
new String[] { "drop function " + arrayTypeName + "_contains_any" },
new String[] { "drop function " + arrayTypeName + "_overlaps" },
emptySet(),
false
)

View File

@ -322,9 +322,9 @@ public class OracleDialect extends Dialect {
functionFactory.arrayPrepend_oracle();
functionFactory.arrayAppend_oracle();
functionFactory.arrayContainsAll_oracle();
functionFactory.arrayContainsAny_oracle();
functionFactory.arrayOverlaps_oracle();
functionFactory.arrayContainsAllNullable_oracle();
functionFactory.arrayContainsAnyNullable_oracle();
functionFactory.arrayOverlapsNullable_oracle();
functionFactory.arrayGet_oracle();
functionFactory.arraySet_oracle();
functionFactory.arrayRemove_oracle();

View File

@ -639,9 +639,9 @@ public class PostgreSQLDialect extends Dialect {
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContainsAll_operator();
functionFactory.arrayContainsAny_operator();
functionFactory.arrayOverlaps_operator();
functionFactory.arrayContainsAllNullable_operator();
functionFactory.arrayContainsAnyNullable_operator();
functionFactory.arrayOverlapsNullable_unnest();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();

View File

@ -40,7 +40,7 @@ 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.OracleArrayContainsAnyFunction;
import org.hibernate.dialect.function.array.OracleArrayOverlapsFunction;
import org.hibernate.dialect.function.array.OracleArrayGetFunction;
import org.hibernate.dialect.function.array.OracleArrayLengthFunction;
import org.hibernate.dialect.function.array.OracleArrayPositionFunction;
@ -2768,39 +2768,39 @@ public class CommonFunctionFactory {
}
/**
* H2 array_contains_any() function
* H2 array_overlaps() function
*/
public void arrayContainsAny_h2() {
public void arrayOverlaps_h2() {
functionRegistry.register(
"array_contains_any",
"array_overlaps",
new H2ArrayContainsQuantifiedEmulation( typeConfiguration, false, false )
);
}
/**
* HSQL array_contains_any() function
* HSQL array_overlaps() function
*/
public void arrayContainsAny_hsql() {
public void arrayOverlaps_hsql() {
functionRegistry.register(
"array_contains_any",
"array_overlaps",
new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, false, false )
);
}
/**
* CockroachDB and PostgreSQL array contains any operator
* CockroachDB and PostgreSQL array overlaps operator
*/
public void arrayContainsAny_operator() {
functionRegistry.register( "array_contains_any", new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, false, false ) );
public void arrayOverlaps_operator() {
functionRegistry.register( "array_overlaps", new ArrayContainsQuantifiedOperatorFunction( typeConfiguration, false, false ) );
}
/**
* Oracle array_contains_any() function
* Oracle array_overlaps() function
*/
public void arrayContainsAny_oracle() {
public void arrayOverlaps_oracle() {
functionRegistry.register(
"array_contains_any",
new OracleArrayContainsAnyFunction( typeConfiguration, false )
"array_overlaps",
new OracleArrayOverlapsFunction( typeConfiguration, false )
);
}
@ -2845,42 +2845,32 @@ public class CommonFunctionFactory {
}
/**
* H2 array_contains_any_nullable() function
* H2 array_overlaps_nullable() function
*/
public void arrayContainsAnyNullable_h2() {
public void arrayOverlapsNullable_h2() {
functionRegistry.register(
"array_contains_any_nullable",
"array_overlaps_nullable",
new H2ArrayContainsQuantifiedEmulation( typeConfiguration, false, true )
);
}
/**
* HSQL array_contains_any_nullable() function
* HSQL, CockroachDB and PostgreSQL array_overlaps_nullable() function
*/
public void arrayContainsAnyNullable_hsql() {
public void arrayOverlapsNullable_unnest() {
functionRegistry.register(
"array_contains_any_nullable",
"array_overlaps_nullable",
new ArrayContainsQuantifiedUnnestFunction( typeConfiguration, false, true )
);
}
/**
* CockroachDB and PostgreSQL array contains any nullable operator
* Oracle array_overlaps_nullable() function
*/
public void arrayContainsAnyNullable_operator() {
public void arrayOverlapsNullable_oracle() {
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 )
"array_overlaps_nullable",
new OracleArrayOverlapsFunction( typeConfiguration, true )
);
}

View File

@ -14,12 +14,12 @@ 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 {
public class OracleArrayOverlapsFunction extends AbstractArrayContainsQuantifiedFunction {
private final boolean nullable;
public OracleArrayContainsAnyFunction(TypeConfiguration typeConfiguration, boolean nullable) {
super( "array_contains_any", typeConfiguration );
public OracleArrayOverlapsFunction(TypeConfiguration typeConfiguration, boolean nullable) {
super( "array_overlaps", typeConfiguration );
this.nullable = nullable;
}
@ -31,7 +31,7 @@ public class OracleArrayContainsAnyFunction extends AbstractArrayContainsQuantif
final Expression haystackExpression = (Expression) sqlAstArguments.get( 0 );
final String arrayTypeName = DdlTypeHelper.getTypeName( haystackExpression.getExpressionType(), walker );
sqlAppender.appendSql( arrayTypeName );
sqlAppender.append( "_contains_any(" );
sqlAppender.append( "_overlaps(" );
haystackExpression.accept( walker );
sqlAppender.append( ',' );
sqlAstArguments.get( 1 ).accept( walker );

View File

@ -35,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
// otherwise we might run into ORA-21700: object does not exist or is marked for delete
// because the JDBC connection or database session caches something that should have been invalidated
@ServiceRegistry(settings = @Setting(name = AvailableSettings.CONNECTION_PROVIDER, value = ""))
public class ArrayContainsAnyTest {
public class ArrayOverlapsTest {
@BeforeEach
public void prepareData(SessionFactoryScope scope) {
@ -54,30 +54,30 @@ public class ArrayContainsAnyTest {
}
@Test
public void testContainsAny(SessionFactoryScope scope) {
public void testOverlapsFully(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 )
//tag::hql-array-overlaps-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('abc', 'def'))", EntityWithArrays.class )
.getResultList();
//end::hql-array-contains-any-example[]
//end::hql-array-overlaps-example[]
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
} );
}
@Test
public void testDoesNotContain(SessionFactoryScope scope) {
public void testDoesNotOverlap(SessionFactoryScope scope) {
scope.inSession( em -> {
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any(e.theArray, array('xyz'))", EntityWithArrays.class )
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('xyz'))", EntityWithArrays.class )
.getResultList();
assertEquals( 0, results.size() );
} );
}
@Test
public void testContainsPartly(SessionFactoryScope scope) {
public void testOverlaps(SessionFactoryScope scope) {
scope.inSession( em -> {
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps(e.theArray, array('abc','xyz'))", EntityWithArrays.class )
.getResultList();
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
@ -86,9 +86,9 @@ public class ArrayContainsAnyTest {
@Test
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "Type inference isn't smart enough to figure out the type for the `null`")
public void testContainsNull(SessionFactoryScope scope) {
public void testOverlapsNullFully(SessionFactoryScope scope) {
scope.inSession( em -> {
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_contains_any_nullable(e.theArray, array(null))", EntityWithArrays.class )
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array(null))", EntityWithArrays.class )
.getResultList();
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
@ -96,12 +96,12 @@ public class ArrayContainsAnyTest {
}
@Test
public void testContainsNullPartly(SessionFactoryScope scope) {
public void testOverlapsNull(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 )
//tag::hql-array-overlaps-nullable-example[]
List<EntityWithArrays> results = em.createQuery( "from EntityWithArrays e where array_overlaps_nullable(e.theArray, array('xyz',null))", EntityWithArrays.class )
.getResultList();
//end::hql-array-contains-any-nullable-example[]
//end::hql-array-overlaps-nullable-example[]
assertEquals( 1, results.size() );
assertEquals( 2L, results.get( 0 ).getId() );
} );