This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.1 by this push:
new e4fb506c200 [fix](Nereids) null type in result set will be cast to
tinyint (#37019) (#37281)
e4fb506c200 is described below
commit e4fb506c2001366ce94740f09c11bf1c9bdb74aa
Author: morrySnow <[email protected]>
AuthorDate: Thu Jul 4 19:18:35 2024 +0800
[fix](Nereids) null type in result set will be cast to tinyint (#37019)
(#37281)
pick from master #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: [email protected]
For additional commands, e-mail: [email protected]