This is an automated email from the ASF dual-hosted git repository. morrysnow 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 e9848066c95 [FIX](type) fix matchExactType for complex type (#28233) e9848066c95 is described below commit e9848066c953d97aae9248b2ac22794ccd242d3c Author: amory <wangqian...@selectdb.com> AuthorDate: Thu Dec 21 11:49:05 2023 +0800 [FIX](type) fix matchExactType for complex type (#28233) fe matchExactType function should call type.matchTypes for its own logic, do not switch case to do special logic otherwise we may meet core in be like this. ``` F20231208 18:54:39.359673 680131 block.h:535] Check failed: _data_types[i]->is_nullable() target type: Struct(l_info:Nullable(Array(Nullable(String)))) src type: Struct(col:Nullable(Array(Nullable(UInt8)))) *** Check failure stack trace: *** @ 0x5584e952b926 google::LogMessage::SendToLog() @ 0x5584e9527ef0 google::LogMessage::Flush() @ 0x5584e952c169 google::LogMessageFatal::~LogMessageFatal() @ 0x5584cf17201e doris::vectorized::MutableBlock::merge_impl<>() @ 0x5584ceac4b1d doris::vectorized::MutableBlock::merge<>() @ 0x5584d4dd7de3 doris::vectorized::VUnionNode::get_next_const() @ 0x5584d4dd9a45 doris::vectorized::VUnionNode::get_next() @ 0x5584bce469bd std::__invoke_impl<>() @ 0x5584bce466d0 std::__invoke<>() @ 0x5584bce465c7 _ZNSt5_BindIFMN5doris8ExecNodeEFNS0_6StatusEPNS0_12RuntimeStateEPNS0_10vectorized5BlockEPbEPS1_St12_PlaceholderILi1EESC_ILi2EESC_ILi3EEEE6__callIS2_JOS4_OS7_OS8_EJLm0ELm1ELm2ELm3EEEET_OSt5tupleIJDpT0_EESt12_Index_tupleIJXspT1_EEE @ 0x5584bce46358 std::_Bind<>::operator()<>() @ 0x5584bce46208 std::__invoke_impl<>() @ 0x5584bce46178 _ZSt10__invoke_rIN5doris6StatusERSt5_BindIFMNS0_8ExecNodeEFS1_PNS0_12RuntimeStateEPNS0_10vectorized5BlockEPbEPS3_St12_PlaceholderILi1EESD_ILi2EESD_ILi3EEEEJS5_S8_S9_EENSt9enable_ifIX16is_invocable_r_vIT_T0_DpT1_EESL_E4typeEOSM_DpOSN_ @ 0x5584bce45c18 std::_Function_handler<>::_M_invoke() @ 0x5584bce6412f std::function<>::operator()() @ 0x5584bce56382 doris::ExecNode::get_next_after_projects() @ 0x5584bce26218 doris::PlanFragmentExecutor::get_vectorized_internal() @ 0x5584bce2431b doris::PlanFragmentExecutor::open_vectorized_internal() @ 0x5584bce22a96 doris::PlanFragmentExecutor::open() @ 0x5584bce27c9d doris::PlanFragmentExecutor::execute() @ 0x5584bcbdb3f8 doris::FragmentMgr::_exec_actual() @ 0x5584bcbf982f doris::FragmentMgr::exec_plan_fragment()::$_0::operator()() @ 0x5584bcbf9715 std::__invoke_impl<>() @ 0x5584bcbf96b5 _ZSt10__invoke_rIvRZN5doris11FragmentMgr18exec_plan_fragmentERKNS0_23TExecPlanFragmentParamsERKSt8functionIFvPNS0_12RuntimeStateEPNS0_6StatusEEEE3$_0JEENSt9enable_ifIX16is_invocable_r_vIT_T0_DpT1_EESH_E4typeEOSI_DpOSJ_ @ 0x5584bcbf942d std::_Function_handler<>::_M_invoke() @ 0x5584b9dfd883 std::function<>::operator()() @ 0x5584bd6e3929 doris::FunctionRunnable::run() @ 0x5584bd6cf8ce doris::ThreadPool::dispatch_thread() ``` --- .../java/org/apache/doris/catalog/ArrayType.java | 8 +-- .../java/org/apache/doris/catalog/MapType.java | 8 ++- .../org/apache/doris/catalog/TemplateType.java | 3 +- .../main/java/org/apache/doris/catalog/Type.java | 17 +---- .../apache/doris/analysis/FunctionCallExpr.java | 8 +++ .../org/apache/doris/analysis/IsNullPredicate.java | 17 +++-- .../org/apache/doris/analysis/StructLiteral.java | 7 +++ .../java/org/apache/doris/catalog/FunctionSet.java | 42 ++++++++++--- .../apache/doris/catalog/FunctionTypeDeducers.java | 34 ++++++++-- gensrc/script/doris_builtins_functions.py | 27 +++----- .../test_nested_types_insert_into_with_literal.out | 28 +++++++++ ...st_nested_types_insert_into_with_literal.groovy | 73 ++++++++++++++++++++++ 12 files changed, 204 insertions(+), 68 deletions(-) diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java index 8edcfb51730..27f02c802cb 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java @@ -88,13 +88,11 @@ public class ArrayType extends Type { return false; } - // Array(Null) is a virtual Array type, can match any Array(...) type - if (itemType.isNull() || ((ArrayType) t).getItemType().isNull()) { - return true; + if (((ArrayType) t).getContainsNull() != getContainsNull()) { + return false; } - return itemType.matchesType(((ArrayType) t).itemType) - && (((ArrayType) t).containsNull || !containsNull); + return itemType.matchesType(((ArrayType) t).itemType); } @Override diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java index e6ab17c626b..1291a5f364e 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java @@ -126,9 +126,11 @@ public class MapType extends Type { return false; } - if ((keyType.isNull() || ((MapType) t).getKeyType().isNull()) - && (valueType.isNull() || ((MapType) t).getKeyType().isNull())) { - return true; + if (((MapType) t).getIsKeyContainsNull() != getIsKeyContainsNull()) { + return false; + } + if (((MapType) t).getIsValueContainsNull() != getIsValueContainsNull()) { + return false; } return keyType.matchesType(((MapType) t).keyType) diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java index ba5ed62f9d0..3ba05614940 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java @@ -95,6 +95,7 @@ public class TemplateType extends Type { } if (specializedType != null + && !specializedType.isNull() && !specificType.equals(specializedType) && !specificType.matchesType(specializedType) && !Type.isImplicitlyCastable(specificType, specializedType, true, enableDecimal256) @@ -104,7 +105,7 @@ public class TemplateType extends Type { name, specificType, specializedType)); } - if (specializedType == null) { + if (specializedType == null || specializedType.isNull()) { specializedTypeMap.put(name, specificType); } return specializedTypeMap.get(name); diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java index ab9b56c5aa5..a7e1660dd02 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java @@ -2241,6 +2241,7 @@ public abstract class Type { } public static boolean matchExactType(Type type1, Type type2, boolean ignorePrecision) { + // we should make type decide to match other for itself to impl matchesType instead of switch case types if (type1.matchesType(type2)) { if (PrimitiveType.typeWithPrecision.contains(type2.getPrimitiveType())) { // For types which has precision and scale, we also need to check quality between precisions and scales @@ -2253,22 +2254,6 @@ public abstract class Type { return isSameDecimalTypeWithDifferentPrecision(((ScalarType) type2).decimalPrecision(), ((ScalarType) type1).decimalPrecision()); } - } else if (type2.isArrayType()) { - // For types array, we also need to check contains null for case like - // cast(array<not_null(int)> as array<int>) - if (((ArrayType) type2).getContainsNull() != ((ArrayType) type1).getContainsNull()) { - return false; - } - return matchExactType(((ArrayType) type2).getItemType(), ((ArrayType) type1).getItemType()); - } else if (type2.isMapType()) { - if (((MapType) type2).getIsKeyContainsNull() != ((MapType) type1).getIsKeyContainsNull()) { - return false; - } - if (((MapType) type2).getIsValueContainsNull() != ((MapType) type1).getIsValueContainsNull()) { - return false; - } - return matchExactType(((MapType) type2).getKeyType(), ((MapType) type1).getKeyType()) - && matchExactType(((MapType) type2).getValueType(), ((MapType) type1).getValueType()); } else { return true; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index c35b367f9bd..f38f984b717 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -1875,6 +1875,14 @@ public class FunctionCallExpr extends Expr { && fnName.getFunction().equalsIgnoreCase("map")) { ix = i % 2 == 0 ? 0 : 1; } + // array_zip varargs special case array_zip(array1, array2, ...) + // we only specialize array_zip with first array type, next type we same with custom type + if (i >= args.length && (fnName.getFunction().equalsIgnoreCase("array_zip"))) { + if (argTypes[i].isNull()) { + uncheckedCastChild(args[i - 1], i); + } + continue; + } if (i == 0 && (fnName.getFunction().equalsIgnoreCase("char"))) { continue; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java index c67ca1b0602..11a53ea5565 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java @@ -47,17 +47,14 @@ public class IsNullPredicate extends Predicate { functionSet.addBuiltinBothScalaAndVectorized(ScalarFunction.createBuiltinOperator(IS_NOT_NULL, null, Lists.newArrayList(t), Type.BOOLEAN, NullableMode.ALWAYS_NOT_NULLABLE)); + } + // for array type + for (Type complexType : Lists.newArrayList(Type.ARRAY, Type.MAP, Type.GENERIC_STRUCT)) { + functionSet.addBuiltinBothScalaAndVectorized(ScalarFunction.createBuiltinOperator(IS_NULL, null, + Lists.newArrayList(complexType), Type.BOOLEAN, NullableMode.ALWAYS_NOT_NULLABLE)); - // for array type - for (Type complexType : Lists.newArrayList(Type.ARRAY, Type.MAP, Type.GENERIC_STRUCT)) { - functionSet.addBuiltinBothScalaAndVectorized(ScalarFunction.createBuiltinOperator(IS_NULL, null, - Lists.newArrayList(complexType), Type.BOOLEAN, NullableMode.ALWAYS_NOT_NULLABLE)); - - functionSet.addBuiltinBothScalaAndVectorized(ScalarFunction.createBuiltinOperator(IS_NOT_NULL, - null, Lists.newArrayList(complexType), Type.BOOLEAN, - NullableMode.ALWAYS_NOT_NULLABLE)); - } - + functionSet.addBuiltinBothScalaAndVectorized(ScalarFunction.createBuiltinOperator(IS_NOT_NULL, null, + Lists.newArrayList(complexType), Type.BOOLEAN, NullableMode.ALWAYS_NOT_NULLABLE)); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/StructLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/StructLiteral.java index effd5c7d61f..b459e312ece 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/StructLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/StructLiteral.java @@ -23,6 +23,8 @@ import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; +import org.apache.doris.thrift.TTypeDesc; +import org.apache.doris.thrift.TTypeNode; import com.google.common.base.Preconditions; import org.apache.commons.lang3.StringUtils; @@ -106,6 +108,11 @@ public class StructLiteral extends LiteralExpr { @Override protected void toThrift(TExprNode msg) { msg.node_type = TExprNodeType.STRUCT_LITERAL; + ((StructType) type).getFields().forEach(v -> msg.setChildType(v.getType().getPrimitiveType().toThrift())); + TTypeDesc container = new TTypeDesc(); + container.setTypes(new ArrayList<TTypeNode>()); + type.toThrift(container); + msg.setType(container); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java index e5ae0d50284..c589cbbf505 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java @@ -386,16 +386,31 @@ public class FunctionSet<T> { throw new TypeException(templateFunction + " is not support for template since it's not a ScalarFunction"); } - Type[] args = specializedFunction.getArgs(); + ArrayList<Type> args = new ArrayList<>(); + Collections.addAll(args, specializedFunction.getArgs()); Map<String, Type> specializedTypeMap = Maps.newHashMap(); boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); - for (int i = 0; i < args.length; i++) { - if (args[i].hasTemplateType()) { + int i = 0; + for (; i < args.size(); i++) { + if (args.get(i).hasTemplateType()) { hasTemplateType = true; - args[i] = args[i].specializeTemplateType(requestFunction.getArgs()[i], specializedTypeMap, false, - enableDecimal256); + // if args[i] is template type, and requestFunction.getArgs()[i] NULL_TYPE, we need call function + // deduce to get the specific type + Type deduceType = requestFunction.getArgs()[i]; + if (requestFunction.getArgs()[i].isNull() + || (requestFunction.getArgs()[i] instanceof ArrayType + && ((ArrayType) requestFunction.getArgs()[i]).getItemType().isNull()) + && FunctionTypeDeducers.DEDUCERS.containsKey(specializedFunction.functionName())) { + deduceType = FunctionTypeDeducers.deduce(specializedFunction.functionName(), i, requestFunction.getArgs()); + args.set(i, args.get(i).specializeTemplateType(deduceType == null ? requestFunction.getArgs()[i] + : deduceType, specializedTypeMap, false, enableDecimal256)); + } else { + args.set(i, args.get(i).specializeTemplateType(requestFunction.getArgs()[i], + specializedTypeMap, false, enableDecimal256)); + } } } + specializedFunction.setArgs(args); if (specializedFunction.getReturnType().hasTemplateType()) { hasTemplateType = true; specializedFunction.setReturnType( @@ -426,7 +441,7 @@ public class FunctionSet<T> { newTypes[i] = inputType; } } - Type newRetType = FunctionTypeDeducers.deduce(inferenceFunction.functionName(), newTypes); + Type newRetType = FunctionTypeDeducers.deduce(inferenceFunction.functionName(), 0, newTypes); if (newRetType != null && inferenceFunction instanceof ScalarFunction) { ScalarFunction f = (ScalarFunction) inferenceFunction; return new ScalarFunction(f.getFunctionName(), Lists.newArrayList(newTypes), newRetType, f.hasVarArgs(), @@ -448,7 +463,20 @@ public class FunctionSet<T> { final Type[] candicateArgTypes = candicate.getArgs(); if (!(descArgTypes[0] instanceof ScalarType) || !(candicateArgTypes[0] instanceof ScalarType)) { - if (candicateArgTypes[0] instanceof ArrayType || candicateArgTypes[0] instanceof MapType) { + if (candicateArgTypes[0] instanceof ArrayType) { + // match is exactly type. but for null type , with in array|map elem can not return true, because for + // be will make null_type to uint8 + // so here meet null_type just make true as allowed, descArgTypes[0]).getItemType().isNull() is for + // empty literal like: []|{} + if (descArgTypes[0] instanceof ArrayType && ((ArrayType) descArgTypes[0]).getItemType().isNull()) { + return true; + } + return descArgTypes[0].matchesType(candicateArgTypes[0]); + } else if (candicateArgTypes[0] instanceof MapType) { + if (descArgTypes[0] instanceof MapType && ((MapType) descArgTypes[0]).getKeyType().isNull() + && ((MapType) descArgTypes[0]).getValueType().isNull()) { + return true; + } return descArgTypes[0].matchesType(candicateArgTypes[0]); } return false; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionTypeDeducers.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionTypeDeducers.java index 80c78248ac2..34b1d1f768e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionTypeDeducers.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionTypeDeducers.java @@ -23,26 +23,48 @@ import com.google.common.collect.Lists; import java.util.List; public class FunctionTypeDeducers { - public interface TypeDeducer { - public Type deduce(Type[] args); + public Type deduce(int argIdx, Type[] args); } public static final ImmutableMap<String, TypeDeducer> DEDUCERS = ImmutableMap.<String, TypeDeducer>builder() .put("named_struct", new NamedStructDeducer()) .put("struct_element", new StructElementDeducer()) + .put("array_contains", new ArrayElemFuncDeducer()) + .put("array_pushback", new ArrayElemFuncDeducer()) + .put("element_at", new ArrayElemFuncDeducer()) .build(); - public static Type deduce(String fnName, Type[] args) { + public static Type deduce(String fnName, int argIdx, Type[] args) { if (DEDUCERS.containsKey(fnName)) { - return DEDUCERS.get(fnName).deduce(args); + return DEDUCERS.get(fnName).deduce(argIdx, args); } return null; } + public static class ArrayElemFuncDeducer implements TypeDeducer { + @Override + public Type deduce(int argIdx, Type[] args) { + if (args.length >= 2) { + if (argIdx == 0) { + // first args should only to be array or null + return args[0] instanceof ArrayType || args[0].isNull() ? new ArrayType(args[1]) : args[0]; + } else if (args[0].isNull()) { + // first arg is null, later element is not contains + return args[argIdx]; + } else if (Type.isImplicitlyCastable(args[argIdx], ((ArrayType) args[0]).getItemType(), false, true)) { + return args[argIdx]; + } else { + return null; + } + } + return null; + } + } + public static class NamedStructDeducer implements TypeDeducer { @Override - public Type deduce(Type[] args) { + public Type deduce(int argIdx, Type[] args) { List<Type> evenArgs = Lists.newArrayList(); for (int i = 0; i < args.length; i++) { if ((i & 1) == 1) { @@ -55,7 +77,7 @@ public class FunctionTypeDeducers { public static class StructElementDeducer implements TypeDeducer { @Override - public Type deduce(Type[] args) { + public Type deduce(int argIdx, Type[] args) { if (args[0] instanceof StructType) { return Type.ANY_ELEMENT_TYPE; } diff --git a/gensrc/script/doris_builtins_functions.py b/gensrc/script/doris_builtins_functions.py index 91166a6dfb3..e756e238c09 100644 --- a/gensrc/script/doris_builtins_functions.py +++ b/gensrc/script/doris_builtins_functions.py @@ -165,24 +165,7 @@ visible_functions = { [['arrays_overlap'], 'BOOLEAN', ['ARRAY_VARCHAR', 'ARRAY_VARCHAR'], 'ALWAYS_NULLABLE'], [['arrays_overlap'], 'BOOLEAN', ['ARRAY_STRING', 'ARRAY_STRING'], 'ALWAYS_NULLABLE'], - [['array_contains'], 'BOOLEAN', ['ARRAY_BOOLEAN', 'BOOLEAN'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_TINYINT', 'TINYINT'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_SMALLINT', 'SMALLINT'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_INT', 'INT'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_BIGINT', 'BIGINT'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_LARGEINT', 'LARGEINT'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DATETIME', 'DATETIME'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DATE', 'DATE'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DATETIMEV2', 'DATETIMEV2'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DATEV2', 'DATEV2'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_FLOAT', 'FLOAT'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DOUBLE', 'DOUBLE'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DECIMALV2', 'DECIMALV2'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DECIMAL32', 'DECIMAL32'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DECIMAL64', 'DECIMAL64'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_DECIMAL128', 'DECIMAL128'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_VARCHAR', 'VARCHAR'], 'CUSTOM'], - [['array_contains'], 'BOOLEAN', ['ARRAY_STRING', 'STRING'], 'CUSTOM'], + [['array_contains'], 'BOOLEAN', ['ARRAY<T>', 'T'], 'CUSTOM', ['T']], [['array_cum_sum'], 'ARRAY_BIGINT', ['ARRAY_TINYINT'], ''], [['array_cum_sum'], 'ARRAY_BIGINT', ['ARRAY_SMALLINT'], ''], @@ -272,7 +255,7 @@ visible_functions = { [['array_position'], 'BIGINT', ['ARRAY_VARCHAR', 'VARCHAR'], 'CUSTOM'], [['array_position'], 'BIGINT', ['ARRAY_STRING', 'STRING'], 'CUSTOM'], - [['cardinality', 'size', 'array_size'], 'BIGINT', ['ARRAY'], ''], + [['cardinality', 'size', 'array_size'], 'BIGINT', ['ARRAY<T>'], '', ['T']], [['array_distinct'], 'ARRAY_BOOLEAN', ['ARRAY_BOOLEAN'], ''], [['array_distinct'], 'ARRAY_TINYINT', ['ARRAY_TINYINT'], ''], [['array_distinct'], 'ARRAY_SMALLINT', ['ARRAY_SMALLINT'], ''], @@ -772,6 +755,7 @@ visible_functions = { [['array_pushfront'], 'ARRAY_VARCHAR', ['ARRAY_VARCHAR', 'VARCHAR'], 'ALWAYS_NULLABLE'], [['array_pushfront'], 'ARRAY_STRING', ['ARRAY_STRING', 'STRING'], 'ALWAYS_NULLABLE'], + [['array_pushback'], 'ARRAY<T>', ['ARRAY<T>', 'T'], 'ALWAYS_NULLABLE', ['T']], [['array_pushback'], 'ARRAY_BOOLEAN', ['ARRAY_BOOLEAN', 'BOOLEAN'], 'ALWAYS_NULLABLE'], [['array_pushback'], 'ARRAY_TINYINT', ['ARRAY_TINYINT', 'TINYINT'], 'ALWAYS_NULLABLE'], [['array_pushback'], 'ARRAY_SMALLINT', ['ARRAY_SMALLINT', 'SMALLINT'], 'ALWAYS_NULLABLE'], @@ -833,7 +817,7 @@ visible_functions = { [['array_range'], 'ARRAY_INT', ['INT', 'INT'], 'ALWAYS_NULLABLE'], [['array_range'], 'ARRAY_INT', ['INT', 'INT', 'INT'], 'ALWAYS_NULLABLE'], - [['array_zip'], 'ARRAY', ['ARRAY', '...'], ''], + [['array_zip'], 'ARRAY', ['ARRAY<T>', '...'], '', ['T']], # reverse function for string builtin @@ -1469,6 +1453,9 @@ visible_functions = { [['nullif'], 'VARCHAR', ['VARCHAR', 'VARCHAR'], 'ALWAYS_NULLABLE'], [['nullif'], 'STRING', ['STRING', 'STRING'], 'ALWAYS_NULLABLE'], + [['is_null_pred'], "BOOLEAN", ['T', '...'], 'ALWAYS_NULLABLE', ['T']], + [['is_not_null_pred'], "BOOLEAN", ['T', '...'], 'ALWAYS_NULLABLE', ['T']], + [['ifnull', 'nvl'], 'BOOLEAN', ['BOOLEAN', 'BOOLEAN'], 'CUSTOM'], [['ifnull', 'nvl'], 'TINYINT', ['TINYINT', 'TINYINT'], 'CUSTOM'], [['ifnull', 'nvl'], 'SMALLINT', ['SMALLINT', 'SMALLINT'], 'CUSTOM'], diff --git a/regression-test/data/datatype_p0/nested_types/query/test_nested_types_insert_into_with_literal.out b/regression-test/data/datatype_p0/nested_types/query/test_nested_types_insert_into_with_literal.out new file mode 100644 index 00000000000..74c8c2da0a8 --- /dev/null +++ b/regression-test/data/datatype_p0/nested_types/query/test_nested_types_insert_into_with_literal.out @@ -0,0 +1,28 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql -- +1 [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] [[]] + +-- !sql -- +1 [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] + +-- !sql -- +1 [{"col1": null, "col2": null, "col3": null, "col4": null, "col5": null, "col6": null, "col7": null, "col8": null, "col9": null, "col10": null, "col11": null, "col12": null, "col13": null, "col14": null, "col15": null, "col16": null, "col17": null}] [{"col1": null, "col2": null, "col3": null, "col4": null, "col5": null, "col6": null, "col7": null, "col8": null, "col9": null, "col10": null, "col11": null, "col12": null, "col13": null, "col14": null, "col15": null, "col16": null, "col17": [...] + +-- !sql -- +1 {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} {null:[]} + +-- !sql -- +1 {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} {null:{}} + +-- !sql -- +1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} + +-- !sql -- +1 {"col_1": []} {"col_2": []} {"col_3": []} {"col_4": []} {"col_5": []} {"col_6": []} {"col_7": []} {"col_8": []} {"col_9": []} {"col_10": []} {"col_11": []} {"col_12": []} {"col_13": []} {"col_14": []} {"col_15": []} {"col_16": []} {"col_17": []} + +-- !sql -- +1 {"col_1": {}} {"col_2": {}} {"col_3": {}} {"col_4": {}} {"col_5": {}} {"col_6": {}} {"col_7": {}} {"col_8": {}} {"col_9": {}} {"col_10": {}} {"col_11": {}} {"col_12": {}} {"col_13": {}} {"col_14": {}} {"col_15": {}} {"col_16": {}} {"col_17": {}} + +-- !sql -- +1 {"col_1": {"col1": null, "col2": null, "col3": null, "col4": null, "col5": null, "col6": null, "col7": null, "col8": null, "col9": null, "col10": null, "col11": null, "col12": null, "col13": null, "col14": null, "col15": null, "col16": null, "col17": null}} {"col_2": {"col1": null, "col2": null, "col3": null, "col4": null, "col5": null, "col6": null, "col7": null, "col8": null, "col9": null, "col10": null, "col11": null, "col12": null, "col13": null, "col14": null, "col15": null, "col1 [...] + diff --git a/regression-test/suites/datatype_p0/nested_types/query/test_nested_types_insert_into_with_literal.groovy b/regression-test/suites/datatype_p0/nested_types/query/test_nested_types_insert_into_with_literal.groovy new file mode 100644 index 00000000000..da3262858ae --- /dev/null +++ b/regression-test/suites/datatype_p0/nested_types/query/test_nested_types_insert_into_with_literal.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. + + +import com.google.common.collect.Lists +import org.apache.commons.lang3.StringUtils +import org.codehaus.groovy.runtime.IOGroovyMethods + +suite("test_nested_types_insert_into_with_literal", "p0") { + sql 'use regression_test_datatype_p0_nested_types' + // old planner does not support cast empty + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + sql """ADMIN SET FRONTEND CONFIG ('disable_nested_complex_type' = 'false')""" + + def table_names = [ + "two_level_array_array_a", + "two_level_array_map_a", + "two_level_array_struct_a", + + "two_level_map_array_a", + "two_level_map_map_a", + "two_level_map_struct_a", + + "two_level_struct_array_a", + "two_level_struct_map_a", + "two_level_struct_struct_a" + ] + + // notice : we do not suggest to use this literal {} to present empty struct, please use struct() instead + def null_literals = ["[[]]", "[{}]", "array(struct(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null))", + "{null:[]}", "{null:{}}", "{}", + "struct([])", "struct({})", "struct(struct(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null))"] + + def colNameArr = ["c_bool", "c_tinyint", "c_smallint", "c_int", "c_bigint", "c_largeint", "c_float", + "c_double", "c_decimal", "c_decimalv3", "c_date", "c_datetime", "c_datev2", "c_datetimev2", + "c_char", "c_varchar", "c_string"] + + // create tables + // (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2) + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + sql """ DROP TABLE IF EXISTS ${table_names[i*3+j]} """ + String result = create_table_with_nested_type(2, [i, j], table_names[i*3+j]) + sql result + } + } + + // insert into empty literal + for (int i = 0; i < 9; ++i) { + String insertSql = "INSERT INTO ${table_names[i]} VALUES(1, " + for (int j = 0; j < colNameArr.size(); ++j) { + insertSql += "${null_literals[i]}," + } + insertSql = insertSql.substring(0, insertSql.length() - 1) + ")" + sql insertSql + qt_sql """ select * from ${table_names[i]} order by k1 """ + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org