[Feature]Support array_contains_seq functions like trino contains_sequence and ck hasSubstr function (#33929)

Signed-off-by: leoyy0316 <571684903@qq.com>
This commit is contained in:
leoyy0316 2023-11-08 22:26:44 -08:00 committed by GitHub
parent c0fb87260d
commit 6320dbc17c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 519 additions and 11 deletions

View File

@ -668,7 +668,7 @@ private:
}
};
template <bool Any>
template <bool Any, bool ContainsSeq>
class ArrayHasImpl {
public:
static StatusOr<ColumnPtr> evaluate(const Column& array, const Column& element) {
@ -752,6 +752,76 @@ private:
return true;
}
}
template <bool NullableElement, bool NullableTarget, typename ElementColumn>
static uint8 __process_seq(const ElementColumn& elements, uint32 element_start, uint32 element_end,
const ElementColumn& targets, uint32 target_start, uint32 target_end,
const NullColumn::Container* null_map_elements,
const NullColumn::Container* null_map_targets) {
using ValueType = std::conditional_t<std::is_same_v<ArrayColumn, ElementColumn> ||
std::is_same_v<MapColumn, ElementColumn> ||
std::is_same_v<StructColumn, ElementColumn>,
uint8_t, typename ElementColumn::ValueType>;
[[maybe_unused]] auto is_null = [](const NullColumn::Container* null_map, size_t idx) -> bool {
return (*null_map)[idx] != 0;
};
if (element_end - element_start < target_end - target_start) {
return false;
}
if (target_end == target_start) {
return true;
}
if (element_end == element_start) {
return false;
}
bool found = false;
size_t i = target_start;
size_t j = element_start;
while (j < element_end) {
if (element_end - j < (target_end - target_start)) {
return false;
}
int k = j;
i = target_start;
while (i < target_end) {
bool null_target = false;
if constexpr (NullableTarget) {
null_target = is_null(null_map_targets, i);
}
bool null_element = false;
if constexpr (NullableElement) {
null_element = is_null(null_map_elements, k);
}
if (null_target && null_element) {
found = true;
} else if (null_target || null_element) {
found = false;
} else {
if constexpr (std::is_same_v<ArrayColumn, ElementColumn> ||
std::is_same_v<MapColumn, ElementColumn> ||
std::is_same_v<StructColumn, ElementColumn> ||
std::is_same_v<JsonColumn, ElementColumn>) {
found = (elements.equals(k, targets, i) == 1);
} else {
auto elements_ptr = (const ValueType*)(elements.raw_data());
auto targets_ptr = (const ValueType*)(targets.raw_data());
found = (elements_ptr[k] == targets_ptr[i]);
}
}
if (found) {
i++;
k++;
} else {
break;
}
}
if (i == target_end) {
return true;
}
j++;
}
return false;
}
template <bool NullableElement, bool NullableTarget, bool ConstTarget, typename ElementColumn>
static StatusOr<ColumnPtr> _process(const ElementColumn& elements, const UInt32Column& element_offsets,
const ElementColumn& targets, const UInt32Column& target_offsets,
@ -769,16 +839,23 @@ private:
for (size_t i = 0; i < num_array; i++) {
uint8_t found = 0;
if constexpr (ConstTarget) {
DCHECK_EQ(num_target, 1);
found = __process<NullableElement, NullableTarget, ElementColumn>(
elements, element_offsets_ptr[i], element_offsets_ptr[i + 1], targets, target_offsets_ptr[0],
target_offsets_ptr[1], null_map_elements, null_map_targets);
} else {
if constexpr (ContainsSeq) {
DCHECK_EQ(num_array, num_target);
found = __process<NullableElement, NullableTarget, ElementColumn>(
found = __process_seq<NullableElement, NullableTarget, ElementColumn>(
elements, element_offsets_ptr[i], element_offsets_ptr[i + 1], targets, target_offsets_ptr[i],
target_offsets_ptr[i + 1], null_map_elements, null_map_targets);
} else {
if constexpr (ConstTarget) {
DCHECK_EQ(num_target, 1);
found = __process<NullableElement, NullableTarget, ElementColumn>(
elements, element_offsets_ptr[i], element_offsets_ptr[i + 1], targets,
target_offsets_ptr[0], target_offsets_ptr[1], null_map_elements, null_map_targets);
} else {
DCHECK_EQ(num_array, num_target);
found = __process<NullableElement, NullableTarget, ElementColumn>(
elements, element_offsets_ptr[i], element_offsets_ptr[i + 1], targets,
target_offsets_ptr[i], target_offsets_ptr[i + 1], null_map_elements, null_map_targets);
}
}
result_ptr[i] = found;
}
@ -962,7 +1039,7 @@ StatusOr<ColumnPtr> ArrayFunctions::array_contains_any([[maybe_unused]] Function
const ColumnPtr& arg0 = ColumnHelper::unpack_and_duplicate_const_column(columns[0]->size(), columns[0]); // array
const ColumnPtr& arg1 = ColumnHelper::unpack_and_duplicate_const_column(columns[1]->size(), columns[1]); // element
return ArrayHasImpl<true>::evaluate(*arg0, *arg1);
return ArrayHasImpl<true, false>::evaluate(*arg0, *arg1);
}
StatusOr<ColumnPtr> ArrayFunctions::array_contains_all([[maybe_unused]] FunctionContext* context,
@ -971,7 +1048,16 @@ StatusOr<ColumnPtr> ArrayFunctions::array_contains_all([[maybe_unused]] Function
const ColumnPtr& arg0 = ColumnHelper::unpack_and_duplicate_const_column(columns[0]->size(), columns[0]); // array
const ColumnPtr& arg1 = ColumnHelper::unpack_and_duplicate_const_column(columns[1]->size(), columns[1]); // element
return ArrayHasImpl<false>::evaluate(*arg0, *arg1);
return ArrayHasImpl<false, false>::evaluate(*arg0, *arg1);
}
StatusOr<ColumnPtr> ArrayFunctions::array_contains_seq([[maybe_unused]] FunctionContext* context,
const Columns& columns) {
RETURN_IF_COLUMNS_ONLY_NULL(columns);
const ColumnPtr& arg0 = ColumnHelper::unpack_and_duplicate_const_column(columns[0]->size(), columns[0]); // array
const ColumnPtr& arg1 = ColumnHelper::unpack_and_duplicate_const_column(columns[1]->size(), columns[1]); // element
return ArrayHasImpl<false, true>::evaluate(*arg0, *arg1);
}
// cannot be called anymore

View File

@ -108,6 +108,7 @@ public:
DEFINE_VECTORIZED_FN(array_filter);
DEFINE_VECTORIZED_FN(all_match);
DEFINE_VECTORIZED_FN(any_match);
DEFINE_VECTORIZED_FN(array_contains_seq);
// array function for nested type(Array/Map/Struct)
DEFINE_VECTORIZED_FN(array_distinct_any_type);

View File

@ -5467,4 +5467,116 @@ TEST_F(ArrayFunctionsTest, array_match_only_null) {
ASSERT_TRUE(dest_column->get(0).get_int8());
}
}
// NOLINTNEXTLINE
TEST_F(ArrayFunctionsTest, array_contains_seq) {
// array_contains_seq(["a", "b", "c"], ["c"]) -> 1
// array_contains_seq(NULL, ["c"]) -> NULL
// array_contains_seq(["a", "b", "c"], NULL) -> NULL
// array_contains_seq(["a", "b", NULL], NULL) -> NULL
// array_contains_seq(["a", "b", NULL], ["a", NULL]) -> 0
// array_contains_seq(NULL, ["a", NULL]) -> NULL
// array_contains_seq(["a", "b", NULL], [NULL]) -> 1
// array_contains_seq(["a", "b", "c"], ["d"]) -> 0
// array_contains_seq(["a", "b", "c"], ["a", "d"]) -> 0
// array_contains_all(["a", "b", "c"], ["a", "c"]) -> 0
{
auto array = ColumnHelper::create_column(TYPE_ARRAY_VARCHAR, true);
array->append_datum(DatumArray{"a", "b", "c"});
array->append_datum(Datum());
array->append_datum(DatumArray{"a", "b", "c"});
array->append_datum(DatumArray{"a", "b", Datum()});
array->append_datum(DatumArray{"a", "b", Datum()});
array->append_datum(Datum());
array->append_datum(DatumArray{"a", "b", Datum()});
array->append_datum(DatumArray{"a", "b", "c"});
array->append_datum(DatumArray{"a", "b", "c"});
array->append_datum(DatumArray{"a", "b", "c"});
auto target = ColumnHelper::create_column(TYPE_ARRAY_VARCHAR, true);
target->append_datum(DatumArray{"c"});
target->append_datum(DatumArray{"c"});
target->append_datum(Datum());
target->append_datum(Datum());
target->append_datum(DatumArray{"a", Datum()});
target->append_datum(DatumArray{"a", Datum()});
target->append_datum(DatumArray{Datum()});
target->append_datum(DatumArray{"d"});
target->append_datum(DatumArray{"a", "d"});
target->append_datum(DatumArray{"a", "c"});
auto result = ArrayFunctions::array_contains_seq(nullptr, {array, target}).value();
EXPECT_EQ(10, result->size());
EXPECT_EQ(1, result->get(0).get_int8());
EXPECT_TRUE(result->get(1).is_null());
EXPECT_TRUE(result->get(2).is_null());
EXPECT_TRUE(result->get(3).is_null());
EXPECT_EQ(0, result->get(4).get_int8());
EXPECT_TRUE(result->get(5).is_null());
EXPECT_EQ(1, result->get(6).get_int8());
EXPECT_EQ(0, result->get(7).get_int8());
EXPECT_EQ(0, result->get(8).get_int8());
EXPECT_EQ(0, result->get(9).get_int8());
}
// array_contains_seq([["a"], ["b"]], [["c"]])
// array_contains_seq(["a","c"], [["c"]])
// array_contains_seq([["a", "b"], ["c"]], [["a", "b"]])
{
auto array = ColumnHelper::create_column(TYPE_ARRAY_ARRAY_VARCHAR, false);
array->append_datum(DatumArray{Datum(DatumArray{"a"}), Datum(DatumArray{"b"})});
array->append_datum(DatumArray{Datum(DatumArray{"a", "c"})});
array->append_datum(DatumArray{Datum(DatumArray{"a", "b"}), Datum(DatumArray{"c"})});
auto target = ColumnHelper::create_column(TYPE_ARRAY_ARRAY_VARCHAR, false);
target->append_datum(DatumArray{Datum(DatumArray{"c"})});
target->append_datum(DatumArray{Datum(DatumArray{"c"})});
target->append_datum(DatumArray{Datum(DatumArray{"a", "b"})});
auto result = ArrayFunctions::array_contains_seq(nullptr, {array, target}).value();
EXPECT_EQ(3, result->size());
EXPECT_EQ(0, result->get(0).get_int8());
EXPECT_EQ(0, result->get(1).get_int8());
EXPECT_EQ(1, result->get(2).get_int8());
}
// array_contains_seq([["a"], ["b"], [NULL]], [["c"]])
// array_contains_seq([["a","d","c"]], [["e"]])
// array_contains_seq([["a", "b"], ["c"]], [["a", "b"]])
{
auto array = ColumnHelper::create_column(TYPE_ARRAY_ARRAY_VARCHAR, true);
array->append_datum(DatumArray{Datum(DatumArray{"a"}), Datum(DatumArray{"b"}), Datum()});
array->append_datum(DatumArray{Datum(DatumArray{"a", "d", "c"})});
array->append_datum(DatumArray{Datum(DatumArray{"a", "b"}), Datum(DatumArray{"c"})});
auto target = ColumnHelper::create_column(TYPE_ARRAY_ARRAY_VARCHAR, false);
target->append_datum(DatumArray{Datum(DatumArray{"c"})});
target->append_datum(DatumArray{Datum(DatumArray{"e"})});
target->append_datum(DatumArray{Datum(DatumArray{"a", "b"})});
auto result = ArrayFunctions::array_contains_seq(nullptr, {array, target}).value();
EXPECT_EQ(3, result->size());
EXPECT_EQ(0, result->get(0).get_int8());
EXPECT_EQ(0, result->get(1).get_int8());
EXPECT_EQ(1, result->get(2).get_int8());
}
// array_contains_seq([["a"], ["b"]], [["c"], [NULL]])
// array_contains_seq([["a","d","c"]], [["e", NULL]])
// array_contains_seq([["a", "b"], ["c"]], [["a", "b"]])
{
auto array = ColumnHelper::create_column(TYPE_ARRAY_ARRAY_VARCHAR, false);
array->append_datum(DatumArray{Datum(DatumArray{"a"}), Datum(DatumArray{"b"})});
array->append_datum(DatumArray{Datum(DatumArray{"a", "d", "c"})});
array->append_datum(DatumArray{Datum(DatumArray{"a", "b"}), Datum(DatumArray{"c"})});
auto target = ColumnHelper::create_column(TYPE_ARRAY_ARRAY_VARCHAR, true);
target->append_datum(DatumArray{Datum(DatumArray{"c"}), Datum()});
target->append_datum(DatumArray{Datum(DatumArray{"e"}), Datum()});
target->append_datum(DatumArray{Datum(DatumArray{"a", "b"})});
auto result = ArrayFunctions::array_contains_seq(nullptr, {array, target}).value();
EXPECT_EQ(3, result->size());
EXPECT_EQ(0, result->get(0).get_int8());
EXPECT_EQ(0, result->get(1).get_int8());
EXPECT_EQ(1, result->get(2).get_int8());
}
}
} // namespace starrocks

View File

@ -421,6 +421,7 @@
+ [array_concat](./sql-reference/sql-functions/array-functions/array_concat.md)
+ [array_contains](./sql-reference/sql-functions/array-functions/array_contains.md)
+ [array_contains_all](./sql-reference/sql-functions/array-functions/array_contains_all.md)
+ [array_contains_seq](./sql-reference/sql-functions/array-functions/array_contains_seq.md)
+ [array_cum_sum](./sql-reference/sql-functions/array-functions/array_cum_sum.md)
+ [array_difference](./sql-reference/sql-functions/array-functions/array_difference.md)
+ [array_distinct](./sql-reference/sql-functions/array-functions/array_distinct.md)

View File

@ -0,0 +1,77 @@
# array_contains_seq
## Description
Checks whether all the elements of array2 appear in array1 in the same exact order. Therefore, the function will return 1, if and only if array1 = prefix + array2 + suffix.
## Syntax
~~~Haskell
BOOLEAN array_contains_all(arr1, arr2)
~~~
## Parameters
`arr`: the two arrays to compare. This syntax checks whether `arr2` is a subset of `arr1` and in the same exact order.
The data types of elements in the two arrays must be the same. For the data types of array elements supported by StarRocks, see [ARRAY](../../../sql-reference/sql-statements/data-types/Array.md).
## Return value
Returns a value of the BOOLEAN type.
1 is returned if `arr2` is a subset of `arr1`. Otherwise, 0 is returned.
Null processed as a value. In other words array_contains_seq([1, 2, NULL, 3, 4], [2,3]) will return 0. However, array_contains_seq([1, 2, NULL, 3, 4], [2,NULL,3]) will return 1
Order of values in both of arrays does matter
## Examples
Returns a value of the BOOLEAN type.
```Plaintext
MySQL [(none)]> select array_contains_seq([1,2,3,4], [1,2,3]);
+---------------------------------------------+
| array_contains_seq([1, 2, 3, 4], [1, 2, 3]) |
+---------------------------------------------+
| 1 |
+---------------------------------------------+
```
```Plaintext
MySQL [(none)]> select array_contains_seq([1,2,3,4], [3,2]);
+------------------------------------------+
| array_contains_seq([1, 2, 3, 4], [3, 2]) |
+------------------------------------------+
| 0 |
+------------------------------------------+
1 row in set (0.18 sec)
```
```Plaintext
MySQL [(none)]> select array_contains_all([1, 2, NULL, 3, 4], ['a']);
+-----------------------------------------------+
| array_contains_all([1, 2, NULL, 3, 4], ['a']) |
+-----------------------------------------------+
| 0 |
+-----------------------------------------------+
1 row in set (0.18 sec)
```
```Plaintext
MySQL [(none)]> select array_contains([1, 2, NULL, 3, 4], 'a');
+-----------------------------------------+
| array_contains([1, 2, NULL, 3, 4], 'a') |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
1 row in set (0.18 sec)
```
```Plaintext
MySQL [(none)]> SELECT array_contains([1, 2,3,4,null], null);
+------------------------------------------+
| array_contains([1, 2, 3, 4, NULL], NULL) |
+------------------------------------------+
| 1 |
+------------------------------------------+
1 row in set (0.18 sec)
```

View File

@ -967,7 +967,7 @@ vectorized_functions = [
# reserve 150281
[150282, 'array_contains_all', 'BOOLEAN', ['ANY_ARRAY', 'ANY_ARRAY'], 'ArrayFunctions::array_contains_all'],
[150283, 'array_contains_seq', 'BOOLEAN', ['ANY_ARRAY', 'ANY_ARRAY'], 'ArrayFunctions::array_contains_seq'],
[150300, 'array_filter', 'ANY_ARRAY', ['ANY_ARRAY', 'ARRAY_BOOLEAN'], 'ArrayFunctions::array_filter'],
[150301, 'all_match', 'BOOLEAN', ['ARRAY_BOOLEAN'], 'ArrayFunctions::all_match'],
[150302, 'any_match', 'BOOLEAN', ['ARRAY_BOOLEAN'], 'ArrayFunctions::any_match'],

View File

@ -4394,4 +4394,183 @@ select array_filter([row(1,2,3), row(3,4,5), row(4,5,6)], [0,1,0]);
select cardinality([row(1,2,3), row(3,4,5)]);
-- result:
2
-- !result
select array_contains_seq([1,2,3,4], [2,3]);
-- result:
1
-- !result
select array_contains_seq([1,2,3,4], [3,2]);
-- result:
0
-- !result
select array_contains_seq([1,2,3,4], [1,2,3]);
-- result:
1
-- !result
select array_contains_seq([1,2,3,4], [1,2,4]);
-- result:
0
-- !result
select array_contains_seq([], []);
-- result:
1
-- !result
select array_contains_seq([1,null], [null]);
-- result:
1
-- !result
select array_contains_seq([1.0,2,3,4], [1]);
-- result:
1
-- !result
select array_contains_seq([cast(1.0 as decimal),2,3,4], [cast(1 as int)]);
-- result:
1
-- !result
select array_contains_seq(['a','b','c'], ['a','b']);
-- result:
1
-- !result
select array_contains_seq(['a','b','c'], ['a','c']);
-- result:
0
-- !result
select array_contains_seq([[1, 2], [3, 4], [5, 6]], [[1, 2], [3, 4]]);
-- result:
1
-- !result
select array_contains_seq([json_keys('{"a":1,"b":2}')], [json_keys('{"a":1}')]);
-- result:
0
-- !result
select array_contains_seq([json_keys('{"a":1,"b":2}')], [json_keys('{"a":1,"b":2}')]);
-- result:
1
-- !result
select array_contains_seq([map([1,2,5],[2,4,5])], [map([1,2,5],[2,4,5])]);
-- result:
1
-- !result
select array_contains_seq([map([1,2,5],[2,4,5])], [map([1,2],[2,4])]);
-- result:
0
-- !result
select array_contains_seq([1, 2, NULL, 3, 4], ['a']);
-- result:
0
-- !result
select array_contains_seq([1, 2, NULL, 3, 4], [2,3]);
-- result:
0
-- !result
select array_contains_seq([1, 2, NULL, 3, 4], null);
-- result:
None
-- !result
select array_contains_seq(null, [2,3]);
-- result:
None
-- !result
select array_contains_seq([1, 2, NULL, 3, 4], [null,null]);
-- result:
0
-- !result
select array_contains_seq([1, 2, NULL], [null,2]);
-- result:
0
-- !result
select array_contains_seq(null, null);
-- result:
None
-- !result
select array_contains_seq([1, 1, 2, NULL], [1,2]);
-- result:
1
-- !result
CREATE TABLE array_test_01 (
pk bigint not null ,
i_0 Array<BigInt>,
i_1 Array<BigInt>,
ai_0 Array<Array<BigInt>>,
ai_1 Array<Array<BigInt>>
) ENGINE=OLAP
DUPLICATE KEY(`pk`)
DISTRIBUTED BY HASH(`pk`) BUCKETS 3
PROPERTIES (
"replication_num" = "1",
"in_memory" = "false"
);
-- result:
-- !result
insert into array_test_01 values
(1,[null,1],[null],[null],[[]]),
(2,[null],[1,3,4,5,1,2],[[null,1],null],[[1,null]]),
(3,[],[],[[],null,[1,1]],[[1,1]]),
(4,null,[],[[1,1]],[[1,1],null]),
(5,[4,4,4],[4,null],[null],[null]),
(6,[1,1,2,1,1,2,3,3],[1,2,3],[[1]],[[1],[2],null,[null]]);
-- result:
-- !result
select array_contains_seq(i_0,i_1) from array_test_01 order by pk;
-- result:
1
0
1
None
0
1
-- !result
select array_contains_seq(i_0,i_0) from array_test_01 order by pk;
-- result:
1
1
1
None
1
1
-- !result
select array_contains_seq(i_1,i_0) from array_test_01 order by pk;
-- result:
0
0
1
None
0
0
-- !result
select array_contains_seq(ai_0, ai_1) from array_test_01 order by pk;
-- result:
0
0
1
0
1
0
-- !result
select array_contains_seq(ai_1, ai_1) from array_test_01 order by pk;
-- result:
1
1
1
1
1
1
-- !result
select array_contains_seq(ai_1, ai_0) from array_test_01 order by pk;
-- result:
0
0
0
1
1
1
-- !result
select array_contains_seq(ai_0,null) from array_test_01 order by pk;
-- result:
None
None
None
None
None
None
-- !result

View File

@ -825,3 +825,55 @@ select array_intersect([row(1,2,3), row(3,4,5)], [row(3,4,5)]);
select array_contains_all([row(1,2,3), row(3,4,5)], [row(3,4,5)]);
select array_filter([row(1,2,3), row(3,4,5), row(4,5,6)], [0,1,0]);
select cardinality([row(1,2,3), row(3,4,5)]);
select array_contains_seq([1,2,3,4], [2,3]);
select array_contains_seq([1,2,3,4], [3,2]);
select array_contains_seq([1,2,3,4], [1,2,3]);
select array_contains_seq([1,2,3,4], [1,2,4]);
select array_contains_seq([], []);
select array_contains_seq([1,null], [null]);
select array_contains_seq([1.0,2,3,4], [1]);
select array_contains_seq([cast(1.0 as decimal),2,3,4], [cast(1 as int)]);
select array_contains_seq(['a','b','c'], ['a','b']);
select array_contains_seq(['a','b','c'], ['a','c']);
select array_contains_seq([[1, 2], [3, 4], [5, 6]], [[1, 2], [3, 4]]);
select array_contains_seq([json_keys('{"a":1,"b":2}')], [json_keys('{"a":1}')]);
select array_contains_seq([json_keys('{"a":1,"b":2}')], [json_keys('{"a":1,"b":2}')]);
select array_contains_seq([map([1,2,5],[2,4,5])], [map([1,2,5],[2,4,5])]);
select array_contains_seq([map([1,2,5],[2,4,5])], [map([1,2],[2,4])]);
select array_contains_seq([1, 2, NULL, 3, 4], ['a']);
select array_contains_seq([1, 2, NULL, 3, 4], [2,3]);
select array_contains_seq([1, 2, NULL, 3, 4], null);
select array_contains_seq(null, [2,3]);
select array_contains_seq([1, 2, NULL, 3, 4], [null,null]);
select array_contains_seq([1, 2, NULL], [null,2]);
select array_contains_seq(null, null);
select array_contains_seq([1, 1, 2, NULL], [1,2]);
CREATE TABLE array_test_01 (
pk bigint not null ,
i_0 Array<BigInt>,
i_1 Array<BigInt>,
ai_0 Array<Array<BigInt>>,
ai_1 Array<Array<BigInt>>
) ENGINE=OLAP
DUPLICATE KEY(`pk`)
DISTRIBUTED BY HASH(`pk`) BUCKETS 3
PROPERTIES (
"replication_num" = "1",
"in_memory" = "false"
);
insert into array_test_01 values
(1,[null,1],[null],[null],[[]]),
(2,[null],[1,3,4,5,1,2],[[null,1],null],[[1,null]]),
(3,[],[],[[],null,[1,1]],[[1,1]]),
(4,null,[],[[1,1]],[[1,1],null]),
(5,[4,4,4],[4,null],[null],[null]),
(6,[1,1,2,1,1,2,3,3],[1,2,3],[[1]],[[1],[2],null,[null]]);
select array_contains_seq(i_0,i_1) from array_test_01 order by pk;
select array_contains_seq(i_0,i_0) from array_test_01 order by pk;
select array_contains_seq(i_1,i_0) from array_test_01 order by pk;
select array_contains_seq(ai_0, ai_1) from array_test_01 order by pk;
select array_contains_seq(ai_1, ai_1) from array_test_01 order by pk;
select array_contains_seq(ai_1, ai_0) from array_test_01 order by pk;
select array_contains_seq(ai_0,null) from array_test_01 order by pk;