This is an automated email from the ASF dual-hosted git repository.
jacktengg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new c9c85e75539 [fix](fe) Accept UUID elements in array function
validation (#68704)
c9c85e75539 is described below
commit c9c85e75539b31a3bae8d2e97bd0d16fcbfc98fa
Author: TengJianPing <[email protected]>
AuthorDate: Thu Oct 8 10:17:03 2026 +0800
[fix](fe) Accept UUID elements in array function validation (#68704)
### What problem does this PR solve?
Issue Number: None
Related PR: None
Problem Summary: The UUID array matrix fails during analysis because
ARRAY_DISTINCT rejects UUID elements. The shared array set/equality and
min/max type checks omit UUID even though the corresponding BE
implementations already support its native column type. Add UUID to
these checks so distinct, set, equality, enumerate-uniq and min/max
functions reach their existing implementations. Add a unit test covering
15 call forms with nullable and non-nullable inputs and preserving UUID
result types.
### Release note
UUID arrays no longer produce incorrect unsupported-element-type errors
in array set/equality functions and ARRAY_MIN/ARRAY_MAX.
### Check List (For Author)
- Test: Unit Test / Regression test
- FE unit tests: UuidFunctionsTest and VarBinaryCollectionLegalityTest
(13 passed); new test fails before the fix
- Regression tests: test_uuid_array_matrix,
test_uuid_array_element_matrix and array_function_invalid_argument (3
passed against existing expected outputs)
- Build: build.sh --fe, including Checkstyle (0 violations)
- Behavior changed: Yes; array function validation accepts UUID elements
supported by BE
- Does this need documentation: No; restores existing UUID array
function support
### What problem does this PR solve?
Issue Number: close #xxx
Related PR: #xxx
Problem Summary:
### Release note
None
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [ ] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [ ] Yes. <!-- Explain the behavior change -->
- Does this need documentation?
- [ ] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
---
be/src/exec/common/hash_table/hash.h | 5 +
.../function/array/function_array_except_all.cpp | 3 +-
be/src/exprs/function/array/function_array_hash.h | 31 ++++++
be/src/exprs/function/array/function_array_map.h | 3 +-
be/src/exprs/function/array/function_array_set.h | 3 +-
.../exec/common/hash_table/default_hash_test.cpp | 108 +++++++++++++++++++++
.../functions/ComputeSignatureHelper.java | 4 +
.../functions/scalar/ArrayFunctionUtils.java | 4 +-
.../functions/scalar/UuidFunctionsTest.java | 68 ++++++++++++-
.../uuid/test_uuid_array_validation_and_hash.out | 13 +++
.../test_uuid_array_validation_and_hash.groovy | 73 ++++++++++++++
.../sql-functions/doc_array_functions_test.groovy | 4 +-
12 files changed, 310 insertions(+), 9 deletions(-)
diff --git a/be/src/exec/common/hash_table/hash.h
b/be/src/exec/common/hash_table/hash.h
index ea598fd7fc3..29829d70ebd 100644
--- a/be/src/exec/common/hash_table/hash.h
+++ b/be/src/exec/common/hash_table/hash.h
@@ -93,6 +93,11 @@ struct DefaultHash<T> {
size_t operator()(T key) const { return default_hash64<T>(key); }
};
+template <>
+struct DefaultHash<unsigned __int128> {
+ size_t operator()(unsigned __int128 key) const { return
doris::UInt128HashCRC32()(key); }
+};
+
template <>
struct DefaultHash<doris::VecDateTimeValue> {
size_t operator()(doris::VecDateTimeValue key) const { return
int_hash64(*(int64_t*)&key); }
diff --git a/be/src/exprs/function/array/function_array_except_all.cpp
b/be/src/exprs/function/array/function_array_except_all.cpp
index cc6823a0062..ee9ca72e283 100644
--- a/be/src/exprs/function/array/function_array_except_all.cpp
+++ b/be/src/exprs/function/array/function_array_except_all.cpp
@@ -29,6 +29,7 @@
#include "core/data_type/primitive_type.h"
#include "core/string_ref.h"
#include "exec/common/hash_table/phmap_fwd_decl.h"
+#include "exprs/function/array/function_array_hash.h"
#include "exprs/function/function.h"
#include "exprs/function/simple_function_factory.h"
@@ -38,7 +39,7 @@ template <PrimitiveType PType>
struct ArrayExceptAllCountMap {
using ElementType = typename ColumnElementView<PType>::ElementType;
using KeyType = typename NativeType<ElementType>::Type;
- using Type = doris::flat_hash_map<KeyType, size_t>;
+ using Type = doris::flat_hash_map<KeyType, size_t, ArraySetHash<KeyType>>;
};
template <>
diff --git a/be/src/exprs/function/array/function_array_hash.h
b/be/src/exprs/function/array/function_array_hash.h
new file mode 100644
index 00000000000..767b3797680
--- /dev/null
+++ b/be/src/exprs/function/array/function_array_hash.h
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <type_traits>
+
+#include "exec/common/hash_table/hash.h"
+
+namespace doris {
+
+// std::hash<unsigned __int128> can discard high64. Preserve phmap's hash for
other keys.
+template <typename T>
+using ArraySetHash =
+ std::conditional_t<std::is_same_v<T, UUIDValueType>, DefaultHash<T>,
phmap::Hash<T>>;
+
+} // namespace doris
diff --git a/be/src/exprs/function/array/function_array_map.h
b/be/src/exprs/function/array/function_array_map.h
index 9f6cf94bd9c..4fe05b73293 100644
--- a/be/src/exprs/function/array/function_array_map.h
+++ b/be/src/exprs/function/array/function_array_map.h
@@ -24,6 +24,7 @@
#include "core/column/column_string.h"
#include "core/data_type/data_type_array.h"
#include "core/data_type/primitive_type.h"
+#include "exprs/function/array/function_array_hash.h"
#include "exprs/function/array/function_array_utils.h"
#include "exprs/function/function_helpers.h"
@@ -54,7 +55,7 @@ template <MapOperation operation, typename ColumnType>
struct OpenMapImpl {
using Element = typename ColumnType::value_type;
using ElementNativeType = typename NativeType<Element>::Type;
- using Map = phmap::flat_hash_map<ElementNativeType, size_t>;
+ using Map = phmap::flat_hash_map<ElementNativeType, size_t,
ArraySetHash<ElementNativeType>>;
using Action = typename MapActionImpl<Map, ColumnType, operation>::Action;
Action action;
diff --git a/be/src/exprs/function/array/function_array_set.h
b/be/src/exprs/function/array/function_array_set.h
index d0e04981118..cce5c043639 100644
--- a/be/src/exprs/function/array/function_array_set.h
+++ b/be/src/exprs/function/array/function_array_set.h
@@ -24,6 +24,7 @@
#include "core/column/column_string.h"
#include "core/data_type/data_type_array.h"
#include "core/data_type/primitive_type.h"
+#include "exprs/function/array/function_array_hash.h"
#include "exprs/function/array/function_array_utils.h"
#include "exprs/function/function_helpers.h"
@@ -49,7 +50,7 @@ template <SetOperation operation, typename ColumnType>
struct OpenSetImpl {
using Element = typename ColumnType::value_type;
using ElementNativeType = typename NativeType<Element>::Type;
- using Set = phmap::flat_hash_set<ElementNativeType>;
+ using Set = phmap::flat_hash_set<ElementNativeType,
ArraySetHash<ElementNativeType>>;
using Action = typename ActionImpl<Set, Element, operation>::Action;
Action action;
Set set;
diff --git a/be/test/exec/common/hash_table/default_hash_test.cpp
b/be/test/exec/common/hash_table/default_hash_test.cpp
new file mode 100644
index 00000000000..2d19df84c0b
--- /dev/null
+++ b/be/test/exec/common/hash_table/default_hash_test.cpp
@@ -0,0 +1,108 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <gtest/gtest.h>
+
+#include "exec/common/hash_table/hash.h"
+#include "exprs/function/array/function_array_hash.h"
+#include "parallel_hashmap/phmap.h"
+
+namespace doris {
+
+TEST(DefaultHashTest, UuidUsesBothHalves) {
+ const DefaultHash<UUIDValueType> hasher;
+ const UUIDValueType key = (UUIDValueType {0x123456789abcdef0ULL} << 64) |
0x9234001122334455ULL;
+ for (int bit = 0; bit < 128; ++bit) {
+ EXPECT_NE(hasher(key), hasher(key ^ (UUIDValueType {1} << bit))) <<
"bit " << bit;
+ }
+}
+
+struct CountingUuidEqual {
+ size_t* comparisons;
+
+ bool operator()(UUIDValueType lhs, UUIDValueType rhs) const {
+ ++*comparisons;
+ return lhs == rhs;
+ }
+};
+
+template <typename Hash>
+void check_uuid_set_probe_growth(size_t count) {
+ size_t comparisons = 0;
+ phmap::flat_hash_set<UUIDValueType, Hash, CountingUuidEqual> set(
+ 0, Hash {}, CountingUuidEqual {&comparisons});
+ const auto key = [](size_t high) {
+ return (static_cast<UUIDValueType>(high) << 64) |
0x9234001122334455ULL;
+ };
+ // Exercise the contains/insert pattern in array_distinct, including table
growth.
+ for (size_t i = 1; i <= count; ++i) {
+ ASSERT_FALSE(set.contains(key(i)));
+ ASSERT_TRUE(set.insert(key(i)).second);
+ }
+ EXPECT_EQ(count, set.size());
+ // Exercise matching and disjoint inputs as in arrays_overlap.
+ for (size_t i = 1; i <= count; ++i) {
+ ASSERT_TRUE(set.contains(key(i)));
+ ASSERT_FALSE(set.contains(key(i + count)));
+ }
+ EXPECT_LT(comparisons, 64 * count);
+}
+
+TEST(DefaultHashTest, UuidSameLowBitsHaveLinearProbeGrowth) {
+ for (const size_t count : {1024, 4096, 16384}) {
+ check_uuid_set_probe_growth<DefaultHash<UUIDValueType>>(count);
+ }
+}
+
+TEST(ArraySetHashTest, UuidSetHasLinearProbeGrowth) {
+ for (const size_t count : {1024, 4096, 16384}) {
+ check_uuid_set_probe_growth<ArraySetHash<UUIDValueType>>(count);
+ }
+}
+
+TEST(ArraySetHashTest, UuidMapHasLinearProbeGrowth) {
+ for (const size_t count : {1024, 4096, 16384}) {
+ size_t comparisons = 0;
+ phmap::flat_hash_map<UUIDValueType, size_t,
ArraySetHash<UUIDValueType>, CountingUuidEqual>
+ map(0, ArraySetHash<UUIDValueType> {}, CountingUuidEqual
{&comparisons});
+ const auto key = [](size_t high) {
+ return (static_cast<UUIDValueType>(high) << 64) |
0x9234001122334455ULL;
+ };
+ // Exercise union/intersect insertion and except_all counting,
including duplicates.
+ for (size_t i = 1; i <= count; ++i) {
+ ++map[key(i)];
+ ++map[key(i)];
+ }
+ EXPECT_EQ(count, map.size());
+ for (size_t i = 1; i <= count; ++i) {
+ const auto entry = map.find(key(i));
+ ASSERT_NE(entry, map.end());
+ EXPECT_EQ(2, entry->second);
+ --entry->second;
+ EXPECT_EQ(map.end(), map.find(key(i + count)));
+ }
+ EXPECT_LT(comparisons, 64 * count);
+ }
+}
+
+TEST(ArraySetHashTest, PreserveOtherKeyHashers) {
+ static_assert(std::is_same_v<ArraySetHash<Int64>, phmap::Hash<Int64>>);
+ static_assert(std::is_same_v<ArraySetHash<Int128>, phmap::Hash<Int128>>);
+ static_assert(std::is_same_v<ArraySetHash<Float64>, phmap::Hash<Float64>>);
+}
+
+} // namespace doris
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java
index 45e529f9ce3..7d61eb6367b 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignatureHelper.java
@@ -378,6 +378,10 @@ public class ComputeSignatureHelper {
} else {
dataType =
TypeCoercionUtils.findWiderCommonTypeForComparison(dataTypes.getValue());
}
+ if (!dataType.isPresent()) {
+ throw new AnalysisException("Cannot find a common type for
indexed ANY arguments: "
+ + dataTypes.getValue());
+ }
// TODO: should we use tinyint when all any data type's expression
is null type?
// if (dataType.isPresent() && dataType.get() instanceof NullType)
{
// dataType = Optional.of(TinyIntType.INSTANCE);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java
index 8598e4ae03f..a3e2c66d8dc 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayFunctionUtils.java
@@ -60,7 +60,7 @@ final class ArrayFunctionUtils {
/** Whether the element type is supported by hash-based array set
functions. */
static boolean isSupportedByArraySetFunctions(DataType dataType) {
return dataType.isNumericType() || dataType.isBooleanType() ||
dataType.isStringLikeType()
- || dataType.isDateLikeType() || dataType.isIPType() ||
dataType.isNullType();
+ || dataType.isDateLikeType() || dataType.isIPType() ||
dataType.isUuidType() || dataType.isNullType();
}
/** Whether the element type is supported by array equality and hash
functions. */
@@ -96,6 +96,6 @@ final class ArrayFunctionUtils {
|| dataType.isBooleanType() || dataType.isStringLikeType()
|| dataType.isDateV2Type() || dataType.isDateTimeV2Type()
|| dataType.isTimeStampNsType() || dataType.isTimeStampTzType()
- || dataType.isIPType() || dataType.isNullType();
+ || dataType.isIPType() || dataType.isUuidType() ||
dataType.isNullType();
}
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidFunctionsTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidFunctionsTest.java
index af53ebdc19b..1de80242c02 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidFunctionsTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidFunctionsTest.java
@@ -17,7 +17,10 @@
package org.apache.doris.nereids.trees.expressions.functions.scalar;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.rules.expression.ExpressionRewriteTestHelper;
import org.apache.doris.nereids.rules.expression.check.CheckCast;
+import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.ExpressionEvaluator;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import
org.apache.doris.nereids.trees.expressions.functions.executable.UuidArithmetic;
@@ -26,10 +29,14 @@ import
org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
import org.apache.doris.nereids.trees.expressions.literal.UuidLiteral;
import org.apache.doris.nereids.types.ArrayType;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.IntegerType;
import org.apache.doris.nereids.types.LargeIntType;
+import org.apache.doris.nereids.types.NullType;
import org.apache.doris.nereids.types.StringType;
import org.apache.doris.nereids.types.UuidType;
import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.GlobalVariable;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
@@ -123,13 +130,70 @@ class UuidFunctionsTest {
@Test
void rejectsImplicitNumericFunctions() {
-
Assertions.assertThrows(org.apache.doris.nereids.exceptions.AnalysisException.class,
+ Assertions.assertThrows(AnalysisException.class,
() -> new Abs(NORMAL).getSignature());
}
+ @Test
+ void arrayFunctionsAcceptUuidElements() {
+ for (boolean nullable : List.of(false, true)) {
+ SlotReference array = new SlotReference("items",
ArrayType.of(UuidType.INSTANCE), nullable);
+ SlotReference value = new SlotReference("value",
UuidType.INSTANCE, nullable);
+ List<ScalarFunction> functions = List.of(
+ new ArrayDistinct(array), new ArrayUnion(array, array),
new ArrayIntersect(array, array),
+ new ArrayExcept(array, array), new ArrayExceptAll(array,
array),
+ new ArraysOverlap(array, array), new
ArrayContainsAll(array, array),
+ new ArrayEnumerateUniq(array), new
ArrayEnumerateUniq(array, array),
+ new ArrayContains(array, value), new ArrayPosition(array,
value),
+ new ArrayRemove(array, value), new CountEqual(array,
value),
+ new ArrayMin(array), new ArrayMax(array));
+ Assertions.assertAll(functions.stream().map(function -> () -> {
+
Assertions.assertDoesNotThrow(function::checkLegalityBeforeTypeCoercion,
function.getName());
+ Assertions.assertDoesNotThrow(function::getSignature,
function.getName());
+ }));
+ Assertions.assertEquals(array.getDataType(), new
ArrayDistinct(array).getDataType());
+ Assertions.assertEquals(UuidType.INSTANCE, new
ArrayMin(array).getDataType());
+ Assertions.assertEquals(UuidType.INSTANCE, new
ArrayMax(array).getDataType());
+ }
+ }
+
+ @Test
+ void arraysOverlapRejectsIncompatibleUuidArrays() {
+ boolean originalBehavior =
GlobalVariable.enableNewTypeCoercionBehavior;
+ try {
+ GlobalVariable.enableNewTypeCoercionBehavior = true;
+ SlotReference uuids = new SlotReference("uuids",
ArrayType.of(UuidType.INSTANCE));
+ SlotReference integers = new SlotReference("integers",
ArrayType.of(IntegerType.INSTANCE));
+ for (ArraysOverlap function : List.of(new ArraysOverlap(uuids,
integers),
+ new ArraysOverlap(integers, uuids))) {
+ AnalysisException exception =
Assertions.assertThrows(AnalysisException.class,
+ () ->
ExpressionRewriteTestHelper.typeCoercion(function));
+ Assertions.assertTrue(exception.getMessage().contains(
+ "Cannot find a common type for indexed ANY
arguments"), exception::getMessage);
+ }
+ } finally {
+ GlobalVariable.enableNewTypeCoercionBehavior = originalBehavior;
+ }
+ }
+
+ @Test
+ void arraysOverlapCoercesCompatibleUuidArrays() {
+ SlotReference uuids = new SlotReference("uuids",
ArrayType.of(UuidType.INSTANCE));
+ for (DataType itemType : List.of(UuidType.INSTANCE, NullType.INSTANCE,
StringType.INSTANCE)) {
+ SlotReference other = new SlotReference("other",
ArrayType.of(itemType));
+ DataType commonType = itemType.isStringLikeType() ?
other.getDataType() : uuids.getDataType();
+ for (ArraysOverlap function : List.of(new ArraysOverlap(uuids,
other), new ArraysOverlap(other, uuids))) {
+ Expression coerced =
ExpressionRewriteTestHelper.typeCoercion(function);
+ Assertions.assertEquals(commonType,
coerced.child(0).getDataType());
+ Assertions.assertEquals(commonType,
coerced.child(1).getDataType());
+
Assertions.assertDoesNotThrow(coerced::checkLegalityAfterRewrite);
+ }
+ }
+ }
+
@Test
void decoderRequiresConstantTimezone() {
-
Assertions.assertThrows(org.apache.doris.nereids.exceptions.AnalysisException.class,
+ Assertions.assertThrows(AnalysisException.class,
() -> new UuidV7ToDateTime(NORMAL, new SlotReference("tz",
StringType.INSTANCE))
.checkLegalityBeforeTypeCoercion());
}
diff --git
a/regression-test/data/datatype_p0/uuid/test_uuid_array_validation_and_hash.out
b/regression-test/data/datatype_p0/uuid/test_uuid_array_validation_and_hash.out
new file mode 100644
index 00000000000..b386561647b
--- /dev/null
+++
b/regression-test/data/datatype_p0/uuid/test_uuid_array_validation_and_hash.out
@@ -0,0 +1,13 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !compatible_arrays --
+1 true false false true true
+2 false false false false false
+3 true true true true true
+4 \N \N \N \N \N
+
+-- !same_low_bits --
+1 16384 16385 false true
+
+-- !same_low_bits_set_functions --
+1 16384 32768 16384 0 0 16384 0 16384 16384
+
diff --git
a/regression-test/suites/datatype_p0/uuid/test_uuid_array_validation_and_hash.groovy
b/regression-test/suites/datatype_p0/uuid/test_uuid_array_validation_and_hash.groovy
new file mode 100644
index 00000000000..52350844754
--- /dev/null
+++
b/regression-test/suites/datatype_p0/uuid/test_uuid_array_validation_and_hash.groovy
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_uuid_array_validation_and_hash", "p0") {
+ sql "DROP TABLE IF EXISTS uuid_array_mixed_types"
+ sql """CREATE TABLE uuid_array_mixed_types (
+ id INT, uuids ARRAY<UUID>, integers ARRAY<INT>, strings
ARRAY<STRING>
+ ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES('replication_num' = '1')"""
+ sql """INSERT INTO uuid_array_mixed_types VALUES
+ (1, ARRAY(CAST('00112233-4455-6677-8899-aabbccddeeff' AS
UUID)), ARRAY(1),
+ ARRAY('00112233-4455-6677-8899-aabbccddeeff')),
+ (2, [], [], []),
+ (3, [NULL], [NULL], [NULL]),
+ (4, NULL, NULL, NULL)"""
+
+ test {
+ sql "SELECT arrays_overlap(uuids, integers) FROM
uuid_array_mixed_types"
+ exception "Cannot find a common type for indexed ANY arguments"
+ }
+ test {
+ sql "SELECT arrays_overlap(integers, uuids) FROM
uuid_array_mixed_types"
+ exception "Cannot find a common type for indexed ANY arguments"
+ }
+
+ order_qt_compatible_arrays """SELECT id,
+ arrays_overlap(uuids, uuids), arrays_overlap(uuids,
ARRAY(NULL)),
+ arrays_overlap(ARRAY(NULL), uuids), arrays_overlap(uuids,
strings),
+ arrays_overlap(strings, uuids)
+ FROM uuid_array_mixed_types"""
+
+ sql "DROP TABLE IF EXISTS uuid_array_same_low_bits"
+ sql """CREATE TABLE uuid_array_same_low_bits (
+ id INT, uuids ARRAY<UUID>, disjoint ARRAY<UUID>
+ ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES('replication_num' = '1')"""
+ // All 16,384 distinct UUIDs in each array share the same low 64 bits.
+ sql """INSERT INTO uuid_array_same_low_bits
+ SELECT 1,
+ array_agg(CAST(CONCAT(LPAD(HEX(number + 1), 8, '0'),
+ '-1234-1234-9234-001122334455') AS UUID)),
+ array_agg(CAST(CONCAT(LPAD(HEX(number + 16385), 8, '0'),
+ '-1234-1234-9234-001122334455') AS UUID))
+ FROM numbers('number' = '16384')"""
+
+ order_qt_same_low_bits """SELECT id, size(array_distinct(uuids)),
+ size(array_distinct(array_concat(uuids, uuids,
+ ARRAY(CAST(NULL AS UUID), CAST(NULL AS UUID))))),
+ arrays_overlap(uuids, disjoint), arrays_overlap(uuids, uuids)
+ FROM uuid_array_same_low_bits"""
+
+ order_qt_same_low_bits_set_functions """SELECT id,
+ size(array_union(uuids, uuids)), size(array_union(uuids,
disjoint)),
+ size(array_intersect(uuids, uuids)),
size(array_intersect(uuids, disjoint)),
+ size(array_except(uuids, uuids)), size(array_except(uuids,
disjoint)),
+ size(array_except_all(uuids, uuids)),
size(array_except_all(uuids, disjoint)),
+ size(array_except_all(array_concat(uuids, uuids), uuids))
+ FROM uuid_array_same_low_bits"""
+}
diff --git
a/regression-test/suites/doc/sql-manual/sql-functions/doc_array_functions_test.groovy
b/regression-test/suites/doc/sql-manual/sql-functions/doc_array_functions_test.groovy
index 8641f929668..672860bb4da 100644
---
a/regression-test/suites/doc/sql-manual/sql-functions/doc_array_functions_test.groovy
+++
b/regression-test/suites/doc/sql-manual/sql-functions/doc_array_functions_test.groovy
@@ -79,7 +79,7 @@ suite("doc_array_functions_test") {
test {
sql ''' SELECT array_concat([[1,2]], [{'k':1}]); '''
- exception "can not cast"
+ exception "Cannot find"
}
qt_array_concat_map '''
@@ -98,7 +98,7 @@ suite("doc_array_functions_test") {
test {
sql ''' SELECT
array_concat(array(named_struct('name','Alice','age',20)),
array(named_struct('id',1,'score',95.5,'age',10))); '''
- exception "can not cast"
+ exception "Cannot find"
}
test {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]