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 b262f985342 [fix](Nereids) null type in result set will be cast to tinyint (#37019) b262f985342 is described below commit b262f9853421ccdaa0f6e98243dd114eb23e06fd Author: morrySnow <101034200+morrys...@users.noreply.github.com> AuthorDate: Tue Jul 2 14:01:51 2024 +0800 [fix](Nereids) null type in result set will be cast to tinyint (#37019) --- .../nereids/rules/analysis/BindExpression.java | 34 +++++++++--- .../doris/nereids/util/TypeCoercionUtils.java | 3 +- .../data/mtmv_p0/test_create_with_null_type.out | 7 +++ .../mtmv_p0/test_create_with_null_type.groovy | 64 ++++++++++++++++++++++ 4 files changed, 100 insertions(+), 8 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java index c1080adf3b7..ad8dec4ac7c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java @@ -42,6 +42,7 @@ import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.BoundStar; +import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.DefaultValueSlot; import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.ExprId; @@ -89,8 +90,11 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalTVFRelation; import org.apache.doris.nereids.trees.plans.logical.UsingJoin; import org.apache.doris.nereids.trees.plans.visitor.InferPlanOutputAlias; import org.apache.doris.nereids.types.BooleanType; +import org.apache.doris.nereids.types.DataType; +import org.apache.doris.nereids.types.NullType; import org.apache.doris.nereids.types.StructField; import org.apache.doris.nereids.types.StructType; +import org.apache.doris.nereids.types.TinyIntType; import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.PlanUtils; import org.apache.doris.nereids.util.TypeCoercionUtils; @@ -208,22 +212,38 @@ public class BindExpression implements AnalysisRuleFactory { private LogicalResultSink<Plan> bindResultSink(MatchingContext<UnboundResultSink<Plan>> ctx) { LogicalSink<Plan> sink = ctx.root; + Plan child = sink.child(); + List<Slot> output = child.getOutput(); + List<NamedExpression> castNullToTinyInt = Lists.newArrayListWithCapacity(output.size()); + boolean needProject = false; + for (Slot slot : output) { + DataType newType = TypeCoercionUtils.replaceSpecifiedType( + slot.getDataType(), NullType.class, TinyIntType.INSTANCE); + if (!newType.equals(slot.getDataType())) { + needProject = true; + castNullToTinyInt.add(new Alias(new Cast(slot, newType))); + } else { + castNullToTinyInt.add(slot); + } + } + if (needProject) { + child = new LogicalProject<>(castNullToTinyInt, child); + } if (ctx.connectContext.getState().isQuery()) { - List<NamedExpression> outputExprs = sink.child().getOutput().stream() + List<NamedExpression> outputExprs = child.getOutput().stream() .map(NamedExpression.class::cast) .collect(ImmutableList.toImmutableList()); - return new LogicalResultSink<>(outputExprs, sink.child()); + return new LogicalResultSink<>(outputExprs, child); } // Should infer column name for expression when query command - final ImmutableListMultimap.Builder<ExprId, Integer> exprIdToIndexMapBuilder = - ImmutableListMultimap.builder(); - List<Slot> childOutput = sink.child().getOutput(); + final ImmutableListMultimap.Builder<ExprId, Integer> exprIdToIndexMapBuilder = ImmutableListMultimap.builder(); + List<Slot> childOutput = child.getOutput(); for (int index = 0; index < childOutput.size(); index++) { exprIdToIndexMapBuilder.put(childOutput.get(index).getExprId(), index); } InferPlanOutputAlias aliasInfer = new InferPlanOutputAlias(childOutput); - List<NamedExpression> output = aliasInfer.infer(sink.child(), exprIdToIndexMapBuilder.build()); - return new LogicalResultSink<>(output, sink.child()); + List<NamedExpression> sinkExpr = aliasInfer.infer(child, exprIdToIndexMapBuilder.build()); + return new LogicalResultSink<>(sinkExpr, child); } private LogicalSubQueryAlias<Plan> bindSubqueryAlias(MatchingContext<LogicalSubQueryAlias<Plan>> ctx) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java index 0bbd11007a0..96cbcca642d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java @@ -341,7 +341,8 @@ public class TypeCoercionUtils { public static DataType replaceSpecifiedType(DataType dataType, Class<? extends DataType> specifiedType, DataType newType) { if (dataType instanceof ArrayType) { - return ArrayType.of(replaceSpecifiedType(((ArrayType) dataType).getItemType(), specifiedType, newType)); + return ArrayType.of(replaceSpecifiedType(((ArrayType) dataType).getItemType(), specifiedType, newType), + ((ArrayType) dataType).containsNull()); } else if (dataType instanceof MapType) { return MapType.of(replaceSpecifiedType(((MapType) dataType).getKeyType(), specifiedType, newType), replaceSpecifiedType(((MapType) dataType).getValueType(), specifiedType, newType)); diff --git a/regression-test/data/mtmv_p0/test_create_with_null_type.out b/regression-test/data/mtmv_p0/test_create_with_null_type.out new file mode 100644 index 00000000000..de8fa5e4403 --- /dev/null +++ b/regression-test/data/mtmv_p0/test_create_with_null_type.out @@ -0,0 +1,7 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select -- +\N + +-- !desc -- +test_create_with_null_type DUP_KEYS __cast_0 TINYINT TINYINT Yes true \N true + diff --git a/regression-test/suites/mtmv_p0/test_create_with_null_type.groovy b/regression-test/suites/mtmv_p0/test_create_with_null_type.groovy new file mode 100644 index 00000000000..b749c95c8e1 --- /dev/null +++ b/regression-test/suites/mtmv_p0/test_create_with_null_type.groovy @@ -0,0 +1,64 @@ +// 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 org.junit.Assert; + +suite("test_create_with_null_type") { + def tableName = "t_test_create_with_null_type" + def mvName = "test_create_with_null_type" + def dbName = "regression_test_mtmv_p0" + sql """drop table if exists `${tableName}`""" + sql """drop materialized view if exists ${mvName};""" + + sql """ + CREATE TABLE `${tableName}` ( + `user_id` LARGEINT NOT NULL COMMENT '\"用户id\"', + `num` SMALLINT SUM NOT NULL COMMENT '\"数量\"' + ) ENGINE=OLAP + AGGREGATE KEY(`user_id`) + COMMENT 'OLAP' + DISTRIBUTED BY HASH(`user_id`) BUCKETS 2 + PROPERTIES ('replication_num' = '1') ; + """ + sql """ + insert into ${tableName} values (1,1),(1,2); + """ + + sql """ + CREATE MATERIALIZED VIEW ${mvName} + BUILD DEFERRED REFRESH AUTO ON MANUAL + DISTRIBUTED BY RANDOM BUCKETS 2 + PROPERTIES ('replication_num' = '1') + AS + SELECT null FROM ${tableName}; + """ + + sql """ + REFRESH MATERIALIZED VIEW ${mvName} AUTO; + """ + + def jobName = getJobName(dbName, mvName); + log.info(jobName) + waitingMTMVTaskFinished(jobName) + + order_qt_select "SELECT * FROM ${mvName}" + + qt_desc "desc ${mvName} all" + + sql """drop table if exists `${tableName}`""" + sql """drop materialized view if exists ${mvName};""" +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org