Skip to content

HHH-17355 Smoothen rough edges with array functions #7480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ed59810
HHH-17355 Skip ArraySliceTest on CockroachDB as slicing is not yet im…
beikov Oct 26, 2023
e60fd0c
HHH-17355 Rename array_contains_any to array_overlaps
beikov Oct 26, 2023
93cf0ef
HHH-17355 Unify array_contains and array_contains_all as well as depr…
beikov Oct 26, 2023
a61d9ea
HHH-17355 Small Return type resolver method cleanup and fix firstNonN…
beikov Oct 26, 2023
a5b5b27
HHH-17355 Support binding single element value for basic plural param…
beikov Oct 26, 2023
827abae
HHH-17355 Support double-pipe operator for array concatenation
beikov Oct 26, 2023
18a552f
HHH-17355 Add array functions to NodeBuilder
beikov Oct 26, 2023
d3de36a
HHH-17355 Add array functions for collection types to NodeBuilder
beikov Oct 26, 2023
1c0a821
HHH-17355 Add array_agg documentation and add it to NodeBuilder
beikov Oct 27, 2023
92b3b0c
HHH-17355 Add array_trim function
beikov Oct 27, 2023
ff975b0
HHH-17355 Add array_trim functions to NodeBuilder
beikov Oct 27, 2023
a90d02d
HHH-17355 Add array_fill function
beikov Oct 30, 2023
1297bb3
HHH-17355 Add array_fill function to NodeBuilder
beikov Oct 30, 2023
103eb0e
HHH-17355 Add array_positions and array_positions_list functions
beikov Oct 30, 2023
e8cb07b
HHH-17355 Add array_positions and array_positions_list to NodeBuilder
beikov Oct 30, 2023
357bfa8
HHH-17355 Add array_to_string function
beikov Oct 30, 2023
8478bc1
HHH-17355 Add array_to_string to NodeBuilder
beikov Oct 30, 2023
886b63e
HHH-17355 Test array functions with NodeBuilder
beikov Oct 31, 2023
7f6306d
HHH-17355 Smoothen some rough edges with parameter typing and PG12 su…
beikov Nov 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1118,27 +1118,36 @@ 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_list()` | Like `array`, but returns the result as `List<?>`
| `array_agg()` | Aggregates row values into an array
| `array_position()` | Determines the position of an element in an array
| `array_positions()` | Determines all positions of an element in an array
| `array_positions_list()` | Like `array_positions`, but returns the result as `List<Integer>`
| `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
| `array_remove_index()` | Creates array copy with the element at the given index removed
| `array_slice()` | Creates a sub-array of the based on lower and upper index
| `array_replace()` | Creates array copy replacing a given element with another
| `array_trim()` | Creates array copy trimming the last _N_ elements
| `array_fill()` | Creates array filled with the same element _N_ times
| `array_fill_list()` | Like `array_fill`, but returns the result as `List<?>`
| `array_to_string()` | String representation of non-null array elements
|===

===== `array()`
[[hql-array-constructor-functions]]
===== `array()` and `array_list()`

Creates an array based on the passed arguments, and infers the array type from the context if possible.
To retrieve the result as `List<?>`, use the `array_list()` function.

[[hql-array-constructor-example]]
====
Expand All @@ -1148,22 +1157,16 @@ include::{array-example-dir-hql}/ArrayConstructorTest.java[tags=hql-array-exampl
----
====

[[hql-array-contains-functions]]
===== `array_contains()` and `array_contains_null()`
[[hql-array-aggregate-functions]]
===== `array_agg()`

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.
An <<hql-aggregate-functions-orderedset,ordered set aggregate function>> that aggregates values to an array.

[[hql-array-contains-example]]
[[hql-array-agg-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]
include::{array-example-dir-hql}/ArrayAggregateTest.java[tags=hql-array-agg-example]
----
====

Expand All @@ -1180,6 +1183,20 @@ include::{array-example-dir-hql}/ArrayPositionTest.java[tags=hql-array-position-
----
====

[[hql-array-positions-functions]]
===== `array_positions()` and `array_positions_list()`

Returns an `int[]` of 1-based positions of matching elements in the array. Returns an empty array if the element is not found and `null` if the array is `null`.
To retrieve the result as `List<Integer>`, use the `array_positions_list()` function.

[[hql-array-positions-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayPositionsTest.java[tags=hql-array-positions-example]
----
====

[[hql-array-length-functions]]
===== `array_length()`

Expand All @@ -1194,7 +1211,7 @@ include::{array-example-dir-hql}/ArrayLengthTest.java[tags=hql-array-length-exam
====

[[hql-array-concat-functions]]
===== `array_concat()`
===== `array_concat()` or `||`

Concatenates arrays with each other in order. Returns `null` if one of the arguments is `null`.

Expand All @@ -1206,6 +1223,26 @@ include::{array-example-dir-hql}/ArrayConcatTest.java[tags=hql-array-concat-exam
----
====

Arrays can also be concatenated with the `||` (double-pipe) operator.

[[hql-array-concat-pipe-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayConcatTest.java[tags=hql-array-concat-pipe-example]
----
====

In addition, the `||` (double-pipe) operator also support concatenating single elements to arrays.

[[hql-array-concat-pipe-element-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayConcatTest.java[tags=hql-array-concat-pipe-element-example]
----
====

[[hql-array-prepend-functions]]
===== `array_prepend()`

Expand All @@ -1232,49 +1269,63 @@ 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}/ArrayContainsAllTest.java[tags=hql-array-contains-all-example]
include::{array-example-dir-hql}/ArrayContainsTest.java[tags=hql-array-contains-example]
----
====

[[hql-array-contains-any-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]
----
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-example]
----
====

To search for `null` elements, the `array_contains_nullable` function must be used with an array argument.

[[hql-array-contains-array-nullable-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsAnyTest.java[tags=hql-array-contains-any-example]
include::{array-example-dir-hql}/ArrayContainsArrayTest.java[tags=hql-array-contains-array-nullable-example]
----
====

[[hql-array-contains-quantified-functions]]
===== `array_contains_all_nullable()` & `array_contains_any_nullable()`
[[hql-array-overlaps-functions]]
===== `array_overlaps()` and `array_overlaps_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.
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-contains-all-nullable-example]]
[[hql-array-overlaps-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayContainsAllTest.java[tags=hql-array-contains-all-nullable-example]
include::{array-example-dir-hql}/ArrayOverlapsTest.java[tags=hql-array-overlaps-example]
----
====

[[hql-array-contains-any-nullable-example]]
[[hql-array-overlaps-nullable-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-nullable-example]
----
====

Expand Down Expand Up @@ -1358,6 +1409,49 @@ include::{array-example-dir-hql}/ArrayReplaceTest.java[tags=hql-array-replace-ex
----
====

[[hql-array-trim-functions]]
===== `array_trim()`

Returns an array copy without the last _N_ elements, specified by the second argument.
It is an error if any array has a length smaller than the second argument.

[[hql-array-trim-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayTrimTest.java[tags=hql-array-trim-example]
----
====

[[hql-array-fill-functions]]
===== `array_fill()` and `array_fill_list()`

Creates an array filled with the same element _N_ times as specified by the arguments.
It is an error to supply an array length smaller than 0.
To retrieve the result as `List<?>`, use the `array_fill_list()` function.

[[hql-array-fill-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayFillTest.java[tags=hql-array-fill-example]
----
====

[[hql-array-to-string-functions]]
===== `array_to_string()`

Concatenates the non-null array elements with a separator, as specified by the arguments.
Returns `null` if the first argument is `null`.

[[hql-array-to-string-example]]
====
[source, JAVA, indent=0]
----
include::{array-example-dir-hql}/ArrayToStringTest.java[tags=hql-array-to-string-example]
----
====

[[hql-user-defined-functions]]
==== Native and user-defined functions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,25 +461,25 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
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.arrayPositions_postgresql();
functionFactory.arrayLength_cardinality();
functionFactory.arrayConcat_postgresql();
functionFactory.arrayPrepend_postgresql();
functionFactory.arrayAppend_postgresql();
functionFactory.arrayContainsAll_operator();
functionFactory.arrayContainsAny_operator();
functionFactory.arrayContainsAllNullable_operator();
functionFactory.arrayContainsAnyNullable_operator();
functionFactory.arrayContains_postgresql();
functionFactory.arrayOverlaps_postgresql();
functionFactory.arrayGet_bracket();
functionFactory.arraySet_unnest();
functionFactory.arrayRemove();
functionFactory.arrayRemoveIndex_unnest( true );
functionFactory.arraySlice_operator();
functionFactory.arrayReplace();
functionFactory.arrayTrim_unnest();
functionFactory.arrayFill_cockroachdb();
functionFactory.arrayToString_postgresql();

functionContributions.getFunctionRegistry().register(
"trunc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,22 +372,23 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.listagg( null );
functionFactory.array();
functionFactory.arrayAggregate();
functionFactory.arrayContains();
functionFactory.arrayContainsNull();
functionFactory.arrayPosition_h2( getMaximumArraySize() );
functionFactory.arrayPositions_h2( getMaximumArraySize() );
functionFactory.arrayLength_cardinality();
functionFactory.arrayConcat_operator();
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContainsAll_h2();
functionFactory.arrayContainsAny_h2();
functionFactory.arrayContainsAllNullable_h2();
functionFactory.arrayContainsAnyNullable_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() );
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_h2();
functionFactory.arrayToString_h2( getMaximumArraySize() );
}
else {
// Use group_concat until 2.x as listagg was buggy
Expand All @@ -399,6 +400,16 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
}
}

/**
* 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 ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,25 +247,25 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
functionFactory.rownum();
}
functionFactory.listagg_groupConcat();
functionFactory.array();
functionFactory.array_hsql();
functionFactory.arrayAggregate();
functionFactory.arrayContains_hsql();
functionFactory.arrayContainsNull_hsql();
functionFactory.arrayPosition_hsql();
functionFactory.arrayPositions_hsql();
functionFactory.arrayLength_cardinality();
functionFactory.arrayConcat_operator();
functionFactory.arrayPrepend_operator();
functionFactory.arrayAppend_operator();
functionFactory.arrayContainsAll_hsql();
functionFactory.arrayContainsAny_hsql();
functionFactory.arrayContainsAllNullable_hsql();
functionFactory.arrayContainsAnyNullable_hsql();
functionFactory.arrayContains_hsql();
functionFactory.arrayOverlaps_hsql();
functionFactory.arrayGet_unnest();
functionFactory.arraySet_hsql();
functionFactory.arrayRemove_hsql();
functionFactory.arrayRemoveIndex_unnest( false );
functionFactory.arraySlice_unnest();
functionFactory.arrayReplace_unnest();
functionFactory.arrayTrim_trim_array();
functionFactory.arrayFill_hsql();
functionFactory.arrayToString_hsql();
}

@Override
Expand Down
Loading