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 a0d3206d78 [fix](Nereids) support nested complex type literal (#25287)
a0d3206d78 is described below

commit a0d3206d78d94334728a6a547e7913e1f0ca1103
Author: morrySnow <101034200+morrys...@users.noreply.github.com>
AuthorDate: Thu Oct 12 14:17:38 2023 +0800

    [fix](Nereids) support nested complex type literal (#25287)
---
 .../org/apache/doris/analysis/ArrayLiteral.java    |   2 +-
 .../doris/nereids/parser/LogicalPlanBuilder.java   |  48 +++++++--
 .../expression/rules/FoldConstantRuleOnFE.java     |   3 +-
 .../rules/expression/rules/FunctionBinder.java     |   2 +-
 .../trees/expressions/functions/scalar/Array.java  |   5 +-
 .../trees/expressions/literal/ArrayLiteral.java    |  66 ++++++-------
 .../nereids/trees/expressions/literal/Literal.java |   7 ++
 .../trees/expressions/literal/MapLiteral.java      |  24 ++---
 .../trees/expressions/literal/StructLiteral.java   | 107 +++++++++++++++++++++
 .../expressions/visitor/ExpressionVisitor.java     |   5 +
 .../trees/plans/logical/LogicalSetOperation.java   |   2 +-
 .../org/apache/doris/nereids/types/JsonType.java   |   8 +-
 .../apache/doris/nereids/types/StructField.java    |   2 +-
 .../doris/nereids/util/TypeCoercionUtils.java      |  61 +++++++++++-
 .../suites/nereids_syntax_p0/array_function.groovy |  39 ++++----
 15 files changed, 288 insertions(+), 93 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java
index b7d95af1dd..37245ed524 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java
@@ -40,7 +40,7 @@ public class ArrayLiteral extends LiteralExpr {
         children = new ArrayList<>();
     }
 
-    public ArrayLiteral(Type type, LiteralExpr... exprs) throws 
AnalysisException {
+    public ArrayLiteral(Type type, LiteralExpr... exprs) {
         this.type = type;
         children = new ArrayList<>(Arrays.asList(exprs));
         analysisDone();
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index 2685d8471b..6867c9c465 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -224,8 +224,6 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.Array;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ArraySlice;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Char;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTo;
-import org.apache.doris.nereids.trees.expressions.functions.scalar.CreateMap;
-import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CreateStruct;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.DayCeil;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.DayFloor;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd;
@@ -264,6 +262,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.YearFloor;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsDiff;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.YearsSub;
+import org.apache.doris.nereids.trees.expressions.literal.ArrayLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
@@ -276,9 +275,11 @@ import 
org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.Interval;
 import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
+import org.apache.doris.nereids.trees.expressions.literal.MapLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StructLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
 import org.apache.doris.nereids.trees.plans.JoinHint;
@@ -1759,22 +1760,49 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return sb.toString();
     }
 
+    /**
+     * cast all items to same types.
+     * TODO remove this function after we refactor type coercion.
+     */
+    private List<Literal> typeCoercionItems(List<Literal> items) {
+        DataType dataType = new Array(items.toArray(new 
Literal[0])).expectedInputTypes().get(0);
+        return items.stream()
+                .map(item -> item.checkedCastTo(dataType))
+                .map(Literal.class::cast)
+                .collect(Collectors.toList());
+    }
+
     @Override
-    public Object visitArrayLiteral(ArrayLiteralContext ctx) {
-        Literal[] items = 
ctx.items.stream().<Literal>map(this::typedVisit).toArray(Literal[]::new);
-        return new Array(items);
+    public ArrayLiteral visitArrayLiteral(ArrayLiteralContext ctx) {
+        List<Literal> items = 
ctx.items.stream().<Literal>map(this::typedVisit).collect(Collectors.toList());
+        if (items.isEmpty()) {
+            return new ArrayLiteral(items);
+        }
+        return new ArrayLiteral(typeCoercionItems(items));
     }
 
     @Override
-    public Object visitMapLiteral(MapLiteralContext ctx) {
-        Literal[] items = 
ctx.items.stream().<Literal>map(this::typedVisit).toArray(Literal[]::new);
-        return new CreateMap(items);
+    public MapLiteral visitMapLiteral(MapLiteralContext ctx) {
+        List<Literal> items = 
ctx.items.stream().<Literal>map(this::typedVisit).collect(Collectors.toList());
+        if (items.size() % 2 != 0) {
+            throw new ParseException("map can't be odd parameters, need even 
parameters", ctx);
+        }
+        List<Literal> keys = Lists.newArrayList();
+        List<Literal> values = Lists.newArrayList();
+        for (int i = 0; i < items.size(); i++) {
+            if (i % 2 == 0) {
+                keys.add(items.get(i));
+            } else {
+                values.add(items.get(i));
+            }
+        }
+        return new MapLiteral(typeCoercionItems(keys), 
typeCoercionItems(values));
     }
 
     @Override
     public Object visitStructLiteral(StructLiteralContext ctx) {
-        Literal[] items = 
ctx.items.stream().<Literal>map(this::typedVisit).toArray(Literal[]::new);
-        return new CreateStruct(items);
+        List<Literal> fields = 
ctx.items.stream().<Literal>map(this::typedVisit).collect(Collectors.toList());
+        return new StructLiteral(fields);
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
index 00230b1894..321465082d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
@@ -507,7 +507,8 @@ public class FoldConstantRuleOnFE extends 
AbstractExpressionRewriteRule {
             return checkedExpr.get();
         }
         List<Literal> arguments = (List) array.getArguments();
-        return new ArrayLiteral(arguments);
+        // we should pass dataType to constructor because arguments maybe empty
+        return new ArrayLiteral(arguments, array.getDataType());
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java
index 63591bc3e0..4f5def6f1e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FunctionBinder.java
@@ -336,7 +336,7 @@ public class FunctionBinder extends 
AbstractExpressionRewriteRule {
     public Expression visitCast(Cast cast, ExpressionRewriteContext context) {
         cast = (Cast) super.visitCast(cast, context);
         // NOTICE: just for compatibility with legacy planner.
-        if (cast.child().getDataType() instanceof ArrayType || 
cast.getDataType() instanceof ArrayType) {
+        if (cast.child().getDataType().isComplexType() || 
cast.getDataType().isComplexType()) {
             TypeCoercionUtils.checkCanCastTo(cast.child().getDataType(), 
cast.getDataType());
         }
         return cast;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Array.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Array.java
index a377cec5f9..ea74eaefdf 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Array.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Array.java
@@ -25,7 +25,6 @@ import 
org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.DataType;
-import org.apache.doris.nereids.types.StringType;
 import org.apache.doris.nereids.util.TypeCoercionUtils;
 
 import com.google.common.collect.ImmutableList;
@@ -76,7 +75,9 @@ public class Array extends ScalarFunction
                     
.collect(Collectors.partitioningBy(TypeCoercionUtils::hasCharacterType));
             List<DataType> needTypeCoercion = 
Lists.newArrayList(Sets.newHashSet(partitioned.get(true)));
             if (needTypeCoercion.size() > 1 || 
!partitioned.get(false).isEmpty()) {
-                needTypeCoercion = Lists.newArrayList(StringType.INSTANCE);
+                needTypeCoercion = needTypeCoercion.stream()
+                        .map(TypeCoercionUtils::replaceCharacterToString)
+                        .collect(Collectors.toList());
             }
             needTypeCoercion.addAll(partitioned.get(false));
             return needTypeCoercion.stream()
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/ArrayLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/ArrayLiteral.java
index daee005522..307e300930 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/ArrayLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/ArrayLiteral.java
@@ -19,17 +19,22 @@ package org.apache.doris.nereids.trees.expressions.literal;
 
 import org.apache.doris.analysis.LiteralExpr;
 import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.NullType;
 
 import com.google.common.collect.ImmutableList;
+import org.springframework.util.CollectionUtils;
 
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
-/** ArrayLiteral */
+/**
+ * ArrayLiteral
+ */
 public class ArrayLiteral extends Literal {
 
     private final List<Literal> items;
@@ -38,15 +43,16 @@ public class ArrayLiteral extends Literal {
      * construct array literal
      */
     public ArrayLiteral(List<Literal> items) {
-        super(computeDataType(items));
-        this.items = items.stream()
-                .map(i -> {
-                    if (i instanceof NullLiteral) {
-                        DataType type = ((ArrayType) 
(this.getDataType())).getItemType();
-                        return new NullLiteral(type);
-                    }
-                    return i;
-                }).collect(ImmutableList.toImmutableList());
+        super(ArrayType.of(CollectionUtils.isEmpty(items) ? NullType.INSTANCE 
: items.get(0).getDataType()));
+        this.items = ImmutableList.copyOf(Objects.requireNonNull(items, "items 
should not null"));
+    }
+
+    /**
+     * when items is empty, we could not get dataType from items, so we need 
pass dataType explicitly.
+     */
+    public ArrayLiteral(List<Literal> items, DataType dataType) {
+        super(dataType);
+        this.items = ImmutableList.copyOf(Objects.requireNonNull(items, "items 
should not null"));
     }
 
     @Override
@@ -56,17 +62,24 @@ public class ArrayLiteral extends Literal {
 
     @Override
     public LiteralExpr toLegacyLiteral() {
-        if (items.isEmpty()) {
-            return new org.apache.doris.analysis.ArrayLiteral();
+        LiteralExpr[] itemExprs = items.stream()
+                .map(Literal::toLegacyLiteral)
+                .toArray(LiteralExpr[]::new);
+        return new 
org.apache.doris.analysis.ArrayLiteral(getDataType().toCatalogDataType(), 
itemExprs);
+    }
+
+    @Override
+    protected Expression uncheckedCastTo(DataType targetType) throws 
AnalysisException {
+        if (this.dataType.equals(targetType)) {
+            return this;
+        } else if (targetType instanceof ArrayType) {
+            // we should pass dataType to constructor because arguments maybe 
empty
+            return new ArrayLiteral(items.stream()
+                    .map(i -> i.uncheckedCastTo(((ArrayType) 
targetType).getItemType()))
+                    .map(Literal.class::cast)
+                    .collect(ImmutableList.toImmutableList()), targetType);
         } else {
-            LiteralExpr[] itemExprs = items.stream()
-                    .map(Literal::toLegacyLiteral)
-                    .toArray(LiteralExpr[]::new);
-            try {
-                return new 
org.apache.doris.analysis.ArrayLiteral(getDataType().toCatalogDataType(), 
itemExprs);
-            } catch (Throwable t) {
-                throw new AnalysisException(t.getMessage(), t);
-            }
+            return super.uncheckedCastTo(targetType);
         }
     }
 
@@ -90,17 +103,4 @@ public class ArrayLiteral extends Literal {
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
         return visitor.visitArrayLiteral(this, context);
     }
-
-    private static DataType computeDataType(List<Literal> items) {
-        if (items.isEmpty()) {
-            return ArrayType.SYSTEM_DEFAULT;
-        }
-        DataType dataType = NullType.INSTANCE;
-        for (Literal item : items) {
-            if (!item.dataType.isNullType()) {
-                dataType = item.dataType;
-            }
-        }
-        return ArrayType.of(dataType);
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
index 3397d92f5e..1a28817ce8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java
@@ -197,6 +197,13 @@ public abstract class Literal extends Expression 
implements LeafExpression, Comp
 
     @Override
     protected Expression uncheckedCastTo(DataType targetType) throws 
AnalysisException {
+        if (this.dataType.equals(targetType)) {
+            return this;
+        }
+        if (this instanceof NullLiteral) {
+            return new NullLiteral(targetType);
+        }
+        // TODO support string to complex
         String desc = getStringValue();
         if (targetType.isBooleanType()) {
             if ("0".equals(desc) || 
"false".equals(desc.toLowerCase(Locale.ROOT))) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/MapLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/MapLiteral.java
index 12b0cb8ca7..47b09de04d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/MapLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/MapLiteral.java
@@ -18,7 +18,6 @@
 package org.apache.doris.nereids.trees.expressions.literal;
 
 import org.apache.doris.analysis.LiteralExpr;
-import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.MapType;
@@ -58,22 +57,13 @@ public class MapLiteral extends Literal {
 
     @Override
     public LiteralExpr toLegacyLiteral() {
-        if (keys.isEmpty()) {
-            return new org.apache.doris.analysis.MapLiteral();
-        } else {
-            List<LiteralExpr> keyExprs = keys.stream()
-                    .map(Literal::toLegacyLiteral)
-                    .collect(Collectors.toList());
-            List<LiteralExpr> valueExprs = values.stream()
-                    .map(Literal::toLegacyLiteral)
-                    .collect(Collectors.toList());
-            try {
-                return new org.apache.doris.analysis.MapLiteral(
-                        getDataType().toCatalogDataType(), keyExprs, 
valueExprs);
-            } catch (Throwable t) {
-                throw new AnalysisException(t.getMessage(), t);
-            }
-        }
+        List<LiteralExpr> keyExprs = keys.stream()
+                .map(Literal::toLegacyLiteral)
+                .collect(Collectors.toList());
+        List<LiteralExpr> valueExprs = values.stream()
+                .map(Literal::toLegacyLiteral)
+                .collect(Collectors.toList());
+        return new 
org.apache.doris.analysis.MapLiteral(getDataType().toCatalogDataType(), 
keyExprs, valueExprs);
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StructLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StructLiteral.java
new file mode 100644
index 0000000000..0041673770
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StructLiteral.java
@@ -0,0 +1,107 @@
+// 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.
+
+package org.apache.doris.nereids.trees.expressions.literal;
+
+import org.apache.doris.analysis.LiteralExpr;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.StructField;
+import org.apache.doris.nereids.types.StructType;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * struct literal
+ */
+public class StructLiteral extends Literal {
+
+    private final List<Literal> fields;
+
+    public StructLiteral() {
+        super(StructType.SYSTEM_DEFAULT);
+        this.fields = ImmutableList.of();
+    }
+
+    public StructLiteral(List<Literal> fields) {
+        super(computeDataType(fields));
+        this.fields = ImmutableList.copyOf(fields);
+    }
+
+    @Override
+    public List<Literal> getValue() {
+        return fields;
+    }
+
+    @Override
+    public LiteralExpr toLegacyLiteral() {
+        try {
+            return new org.apache.doris.analysis.StructLiteral(
+                    
fields.stream().map(Literal::toLegacyLiteral).toArray(LiteralExpr[]::new)
+            );
+        } catch (Exception e) {
+            throw new AnalysisException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+        StructLiteral that = (StructLiteral) o;
+        return Objects.equals(fields, that.fields);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), fields);
+    }
+
+    @Override
+    public String toString() {
+        return toSql();
+    }
+
+    @Override
+    public String toSql() {
+        return "{" + 
fields.stream().map(Literal::toSql).collect(Collectors.joining(",")) + "}";
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitStructLiteral(this, context);
+    }
+
+    private static StructType computeDataType(List<Literal> fields) {
+        ImmutableList.Builder<StructField> structFields = 
ImmutableList.builder();
+        for (int i = 0; i < fields.size(); i++) {
+            structFields.add(new StructField(String.valueOf(i + 1), 
fields.get(i).getDataType(), true, ""));
+        }
+        return new StructType(structFields.build());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
index 0f3bbf3b31..a275cadd87 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java
@@ -107,6 +107,7 @@ import 
org.apache.doris.nereids.trees.expressions.literal.MapLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StructLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
 
@@ -309,6 +310,10 @@ public abstract class ExpressionVisitor<R, C>
         return visitLiteral(mapLiteral, context);
     }
 
+    public R visitStructLiteral(StructLiteral structLiteral, C context) {
+        return visitLiteral(structLiteral, context);
+    }
+
     public R visitCompoundPredicate(CompoundPredicate compoundPredicate, C 
context) {
         return visitBinaryOperator(compoundPredicate, context);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
index d19b939876..71c1f08745 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
@@ -245,7 +245,7 @@ public abstract class LogicalSetOperation extends 
AbstractLogicalPlan implements
                 boolean nullable = leftFields.get(i).isNullable() || 
rightFields.get(i).isNullable();
                 DataType commonType = getAssignmentCompatibleType(
                         leftFields.get(i).getDataType(), 
rightFields.get(i).getDataType());
-                StructField commonField = 
leftFields.get(i).withDataTypeAndNulalble(commonType, nullable);
+                StructField commonField = 
leftFields.get(i).withDataTypeAndNullable(commonType, nullable);
                 commonFields.add(commonField);
             }
             return new StructType(commonFields.build());
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/JsonType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/JsonType.java
index 8455daaac2..b958e9acf3 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/JsonType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/JsonType.java
@@ -19,12 +19,13 @@ package org.apache.doris.nereids.types;
 
 import org.apache.doris.catalog.Type;
 import org.apache.doris.nereids.annotation.Developing;
+import org.apache.doris.nereids.types.coercion.PrimitiveType;
 
 /**
  * Json type in Nereids.
  */
 @Developing
-public class JsonType extends DataType {
+public class JsonType extends PrimitiveType {
 
     public static final JsonType INSTANCE = new JsonType();
 
@@ -62,9 +63,4 @@ public class JsonType extends DataType {
     public int width() {
         return WIDTH;
     }
-
-    @Override
-    public String toSql() {
-        return "JSON";
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java
index fed07259be..73533fc0a5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java
@@ -71,7 +71,7 @@ public class StructField {
         return new StructField(name, dataType, nullable, comment);
     }
 
-    public StructField withDataTypeAndNulalble(DataType dataType, boolean 
nullable) {
+    public StructField withDataTypeAndNullable(DataType dataType, boolean 
nullable) {
         return new StructField(name, dataType, nullable, comment);
     }
 
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 b8c4f1366b..3adda07c3f 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
@@ -265,7 +265,6 @@ public class TypeCoercionUtils {
     /**
      * return ture if datatype has character type in it, cannot use instance 
of CharacterType because of complex type.
      */
-    @Developing
     public static boolean hasCharacterType(DataType dataType) {
         if (dataType instanceof ArrayType) {
             return hasCharacterType(((ArrayType) dataType).getItemType());
@@ -278,6 +277,27 @@ public class TypeCoercionUtils {
         return dataType instanceof CharacterType;
     }
 
+    /**
+     * replace all character types to string for correct type coercion
+     */
+    public static DataType replaceCharacterToString(DataType dataType) {
+        if (dataType instanceof ArrayType) {
+            return ArrayType.of(replaceCharacterToString(((ArrayType) 
dataType).getItemType()));
+        } else if (dataType instanceof MapType) {
+            return MapType.of(replaceCharacterToString(((MapType) 
dataType).getKeyType()),
+                    replaceCharacterToString(((MapType) 
dataType).getValueType()));
+        } else if (dataType instanceof StructType) {
+            List<StructField> newFields = ((StructType) 
dataType).getFields().stream()
+                    .map(f -> 
f.withDataType(replaceCharacterToString(f.getDataType())))
+                    .collect(ImmutableList.toImmutableList());
+            return new StructType(newFields);
+        } else if (dataType instanceof CharacterType) {
+            return StringType.INSTANCE;
+        } else {
+            return dataType;
+        }
+    }
+
     /**
      * The type used for arithmetic operations.
      */
@@ -825,6 +845,10 @@ public class TypeCoercionUtils {
 
         // same type
         if (left.getDataType().equals(right.getDataType())) {
+            if (!supportCompare(left.getDataType())) {
+                throw new AnalysisException("data type " + left.getDataType()
+                        + " could not used in ComparisonPredicate " + 
comparisonPredicate.toSql());
+            }
             return comparisonPredicate.withChildren(left, right);
         }
 
@@ -837,6 +861,10 @@ public class TypeCoercionUtils {
         Optional<DataType> commonType = findWiderTypeForTwoForComparison(
                 left.getDataType(), right.getDataType(), false);
         if (commonType.isPresent()) {
+            if (!supportCompare(commonType.get())) {
+                throw new AnalysisException("data type " + commonType.get()
+                        + " could not used in ComparisonPredicate " + 
comparisonPredicate.toSql());
+            }
             left = castIfNotSameType(left, commonType.get());
             right = castIfNotSameType(right, commonType.get());
         }
@@ -852,6 +880,10 @@ public class TypeCoercionUtils {
 
         if (inPredicate.getOptions().stream().map(Expression::getDataType)
                 .allMatch(dt -> 
dt.equals(inPredicate.getCompareExpr().getDataType()))) {
+            if (!supportCompare(inPredicate.getCompareExpr().getDataType())) {
+                throw new AnalysisException("data type " + 
inPredicate.getCompareExpr().getDataType()
+                        + " could not used in InPredicate " + 
inPredicate.toSql());
+            }
             return inPredicate;
         }
         Optional<DataType> optionalCommonType = 
TypeCoercionUtils.findWiderCommonTypeForComparison(
@@ -859,6 +891,10 @@ public class TypeCoercionUtils {
                         .stream()
                         
.map(Expression::getDataType).collect(Collectors.toList()),
                 true);
+        if (optionalCommonType.isPresent() && 
!supportCompare(optionalCommonType.get())) {
+            throw new AnalysisException("data type " + optionalCommonType.get()
+                    + " could not used in InPredicate " + inPredicate.toSql());
+        }
 
         return optionalCommonType
                 .map(commonType -> {
@@ -969,6 +1005,11 @@ public class TypeCoercionUtils {
         Map<Boolean, List<DataType>> partitioned = dataTypes.stream()
                 
.collect(Collectors.partitioningBy(TypeCoercionUtils::hasCharacterType));
         List<DataType> needTypeCoercion = 
Lists.newArrayList(Sets.newHashSet(partitioned.get(true)));
+        if (needTypeCoercion.size() > 1 || !partitioned.get(false).isEmpty()) {
+            needTypeCoercion = needTypeCoercion.stream()
+                    .map(TypeCoercionUtils::replaceCharacterToString)
+                    .collect(Collectors.toList());
+        }
         needTypeCoercion.addAll(partitioned.get(false));
         return 
needTypeCoercion.stream().map(Optional::of).reduce(Optional.of(NullType.INSTANCE),
                 (r, c) -> {
@@ -1175,6 +1216,11 @@ public class TypeCoercionUtils {
         Map<Boolean, List<DataType>> partitioned = dataTypes.stream()
                 
.collect(Collectors.partitioningBy(TypeCoercionUtils::hasCharacterType));
         List<DataType> needTypeCoercion = 
Lists.newArrayList(Sets.newHashSet(partitioned.get(true)));
+        if (needTypeCoercion.size() > 1 || !partitioned.get(false).isEmpty()) {
+            needTypeCoercion = needTypeCoercion.stream()
+                    .map(TypeCoercionUtils::replaceCharacterToString)
+                    .collect(Collectors.toList());
+        }
         needTypeCoercion.addAll(partitioned.get(false));
         return 
needTypeCoercion.stream().map(Optional::of).reduce(Optional.of(NullType.INSTANCE),
                 (r, c) -> {
@@ -1493,4 +1539,17 @@ public class TypeCoercionUtils {
         return binaryArithmetic.withChildren(castIfNotSameType(left, dt1),
                 castIfNotSameType(right, dt2));
     }
+
+    private static boolean supportCompare(DataType dataType) {
+        if (!(dataType instanceof PrimitiveType)) {
+            return false;
+        }
+        if (dataType.isObjectType()) {
+            return false;
+        }
+        if (dataType instanceof JsonType) {
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/regression-test/suites/nereids_syntax_p0/array_function.groovy 
b/regression-test/suites/nereids_syntax_p0/array_function.groovy
index 8cc857f07d..e05dd92ec9 100644
--- a/regression-test/suites/nereids_syntax_p0/array_function.groovy
+++ b/regression-test/suites/nereids_syntax_p0/array_function.groovy
@@ -24,25 +24,26 @@ suite("array_function") {
     qt_3 "SELECT ARRAY_MAP((x,y)->x+y, ARRAY(-41, NULL, -18), ARRAY(98, 47, 
NULL))"
     qt_4 "SELECT ARRAY_MAP(x->x+1, ARRAY(-82.31, -72.18, 35.59, -67.13))"
     qt_5 "SELECT ARRAY_MAP((x,y)->x+y, ARRAY(-37.03, 81.89, 56.38, -36.76), 
ARRAY(1.56, -14.58, 42.22, -56.13))"    
-    // test {
-    //     sql "select array(), array(null), array(1), array('abc'), 
array(null, 1), array(1, null)"
-    //     result([["[]", "[NULL]", "[1]", "['abc']", "[NULL, 1]", "[1, 
NULL]"]])
-    // }
+     test {
+         sql "select array(), array(null), array(1), array('abc'), array(null, 
1), array(1, null)"
+         result([["[]", "[NULL]", "[1]", "[\"abc\"]", "[NULL, 1]", "[1, 
NULL]"]])
+     }
 
-    // test {
-    //     sql "select array(), array('a'), array(number, 'a') from 
numbers('number'='3')"
-    //     result([
-    //         ["[]", "['a']", "['0', 'a']"],
-    //         ["[]", "['a']", "['1', 'a']"],
-    //         ["[]", "['a']", "['2', 'a']"]
-    //     ])
-    // }
+     test {
+         sql "select array(), array('a'), array(number, 'a') from 
numbers('number'='3')"
+         result([
+             ["[]", "[\"a\"]", "[\"0\", \"a\"]"],
+             ["[]", "[\"a\"]", "[\"1\", \"a\"]"],
+             ["[]", "[\"a\"]", "[\"2\", \"a\"]"]
+         ])
+     }
 
-    // test {
-    //     sql """select
-    //                  array_min(array(5, 4, 3, 2, 1, null)),
-    //                  array_join(array(5, 4, 3, 2, 1, null), ','),
-    //                  array_union(array(1, 2, 3), array(4.0, 5.0, 6.1))"""
-    //     result([[1, "5,4,3,2,1", "[1, 2, 3, 4, 5, 6.1]"]])
-    // }
+    test {
+        sql """
+            SELECT [[[2]], [['aa'],[2,1.0]]]
+        """
+        result([
+                ["""[[["2"]], [["aa"], ["2.0", "1.0"]]]"""]
+        ])
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org


Reply via email to