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 e02747e976 [feature](Nereids) support struct type (#23597)
e02747e976 is described below

commit e02747e9761aec784e1a0aed8a60e6d489b3ba8c
Author: morrySnow <[email protected]>
AuthorDate: Tue Aug 29 20:41:24 2023 +0800

    [feature](Nereids) support struct type (#23597)
    
    1. support struct data type
    2. add array / map / struct literal syntax
    3. fix array union / intersect / except type coercion
    4. fix explict cast data type check for array
    5. fix bound function type coercion
---
 .../org/apache/doris/catalog/PrimitiveType.java    |  22 ++++-
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |   4 +-
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |  12 ++-
 .../doris/catalog/BuiltinScalarFunctions.java      |   6 ++
 .../doris/nereids/parser/LogicalPlanBuilder.java   |  46 ++++++++-
 .../nereids/rules/expression/check/CheckCast.java  |  22 +++--
 .../rules/expression/rules/FunctionBinder.java     |  18 ++++
 .../nereids/rules/rewrite/CheckDataTypes.java      |   8 +-
 .../nereids/trees/expressions/Expression.java      |  15 ++-
 .../expressions/functions/ComputeSignature.java    |   7 +-
 .../functions/ComputeSignatureHelper.java          |  18 ++--
 .../expressions/functions/scalar/ArrayExcept.java  |   3 +-
 .../functions/scalar/ArrayIntersect.java           |   3 +-
 .../expressions/functions/scalar/ArrayUnion.java   |   3 +-
 .../expressions/functions/scalar/CreateMap.java    |   4 +-
 .../{CreateMap.java => CreateNamedStruct.java}     |  61 +++++++-----
 .../scalar/{CreateMap.java => CreateStruct.java}   |  47 ++++------
 .../functions/scalar/StructElement.java            |  99 ++++++++++++++++++++
 .../expressions/literal/StringLikeLiteral.java     |   5 +
 .../trees/expressions/literal/StringLiteral.java   |   5 -
 .../trees/expressions/literal/VarcharLiteral.java  |   5 -
 .../expressions/visitor/ScalarFunctionVisitor.java |  17 ++++
 .../org/apache/doris/nereids/types/DataType.java   |   7 +-
 .../apache/doris/nereids/types/StructField.java    | 104 +++++++++++++++++++++
 .../org/apache/doris/nereids/types/StructType.java |  65 ++++++++++---
 .../doris/nereids/util/TypeCoercionUtils.java      |  66 ++++++++++++-
 .../apache/doris/nereids/UnsupportedTypeTest.java  |   8 +-
 .../nereids_syntax_p0/test_complex_type.groovy     |  63 +++++++++++++
 28 files changed, 614 insertions(+), 129 deletions(-)

diff --git 
a/fe/fe-common/src/main/java/org/apache/doris/catalog/PrimitiveType.java 
b/fe/fe-common/src/main/java/org/apache/doris/catalog/PrimitiveType.java
index d35750ee69..50fddda0f3 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/catalog/PrimitiveType.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/PrimitiveType.java
@@ -169,6 +169,8 @@ public enum PrimitiveType {
         builder.put(TINYINT, DECIMAL128);
         builder.put(TINYINT, VARCHAR);
         builder.put(TINYINT, STRING);
+        builder.put(TINYINT, TIME);
+        builder.put(TINYINT, TIMEV2);
         // Smallint
         builder.put(SMALLINT, BOOLEAN);
         builder.put(SMALLINT, TINYINT);
@@ -188,6 +190,8 @@ public enum PrimitiveType {
         builder.put(SMALLINT, DECIMAL128);
         builder.put(SMALLINT, VARCHAR);
         builder.put(SMALLINT, STRING);
+        builder.put(SMALLINT, TIME);
+        builder.put(SMALLINT, TIMEV2);
         // Int
         builder.put(INT, BOOLEAN);
         builder.put(INT, TINYINT);
@@ -207,6 +211,8 @@ public enum PrimitiveType {
         builder.put(INT, DECIMAL128);
         builder.put(INT, VARCHAR);
         builder.put(INT, STRING);
+        builder.put(INT, TIME);
+        builder.put(INT, TIMEV2);
         // Bigint
         builder.put(BIGINT, BOOLEAN);
         builder.put(BIGINT, TINYINT);
@@ -226,6 +232,8 @@ public enum PrimitiveType {
         builder.put(BIGINT, DECIMAL128);
         builder.put(BIGINT, VARCHAR);
         builder.put(BIGINT, STRING);
+        builder.put(BIGINT, TIME);
+        builder.put(BIGINT, TIMEV2);
         // Largeint
         builder.put(LARGEINT, BOOLEAN);
         builder.put(LARGEINT, TINYINT);
@@ -245,6 +253,8 @@ public enum PrimitiveType {
         builder.put(LARGEINT, DECIMAL128);
         builder.put(LARGEINT, VARCHAR);
         builder.put(LARGEINT, STRING);
+        builder.put(LARGEINT, TIME);
+        builder.put(LARGEINT, TIMEV2);
         // Float
         builder.put(FLOAT, BOOLEAN);
         builder.put(FLOAT, TINYINT);
@@ -264,6 +274,8 @@ public enum PrimitiveType {
         builder.put(FLOAT, DECIMAL128);
         builder.put(FLOAT, VARCHAR);
         builder.put(FLOAT, STRING);
+        builder.put(FLOAT, TIME);
+        builder.put(FLOAT, TIMEV2);
         // Double
         builder.put(DOUBLE, BOOLEAN);
         builder.put(DOUBLE, TINYINT);
@@ -283,6 +295,8 @@ public enum PrimitiveType {
         builder.put(DOUBLE, DECIMAL128);
         builder.put(DOUBLE, VARCHAR);
         builder.put(DOUBLE, STRING);
+        builder.put(DOUBLE, TIME);
+        builder.put(DOUBLE, TIMEV2);
         // Date
         builder.put(DATE, BOOLEAN);
         builder.put(DATE, TINYINT);
@@ -379,6 +393,8 @@ public enum PrimitiveType {
         builder.put(CHAR, DECIMAL128);
         builder.put(CHAR, VARCHAR);
         builder.put(CHAR, STRING);
+        builder.put(CHAR, TIME);
+        builder.put(CHAR, TIMEV2);
         // Varchar
         builder.put(VARCHAR, BOOLEAN);
         builder.put(VARCHAR, TINYINT);
@@ -399,8 +415,10 @@ public enum PrimitiveType {
         builder.put(VARCHAR, VARCHAR);
         builder.put(VARCHAR, JSONB);
         builder.put(VARCHAR, STRING);
+        builder.put(VARCHAR, TIME);
+        builder.put(VARCHAR, TIMEV2);
 
-        // Varchar
+        // String
         builder.put(STRING, BOOLEAN);
         builder.put(STRING, TINYINT);
         builder.put(STRING, SMALLINT);
@@ -420,6 +438,8 @@ public enum PrimitiveType {
         builder.put(STRING, VARCHAR);
         builder.put(STRING, JSONB);
         builder.put(STRING, STRING);
+        builder.put(STRING, TIME);
+        builder.put(STRING, TIMEV2);
 
         // DecimalV2
         builder.put(DECIMALV2, BOOLEAN);
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
index fa0e696ff3..35fe7f26a2 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -82,6 +82,8 @@ COMMA: ',';
 DOT: '.';
 LEFT_BRACKET: '[';
 RIGHT_BRACKET: ']';
+LEFT_BRACE: '{';
+RIGHT_BRACE: '}';
 
 // TODO: add a doc to list reserved words
 
@@ -232,7 +234,6 @@ LAST: 'LAST';
 LATERAL: 'LATERAL';
 LAZY: 'LAZY';
 LEADING: 'LEADING';
-LEFT_BRACE: '{';
 LEFT: 'LEFT';
 LIKE: 'LIKE';
 ILIKE: 'ILIKE';
@@ -319,7 +320,6 @@ RESTRICT: 'RESTRICT';
 RESTRICTIVE: 'RESTRICTIVE';
 REVOKE: 'REVOKE';
 REWRITTEN: 'REWRITTEN';
-RIGHT_BRACE: '}';
 RIGHT: 'RIGHT';
 // original optimizer only support REGEXP, the new optimizer should be 
consistent with it
 RLIKE: 'RLIKE';
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 
b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
index dd9849376a..891c3a01b8 100644
--- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -401,6 +401,7 @@ primaryExpression
     | CASE value=expression whenClause+ (ELSE elseExpression=expression)? END  
                #simpleCase
     | name=CAST LEFT_PAREN expression AS dataType RIGHT_PAREN                  
                #cast
     | constant                                                                 
                #constantDefault
+    | interval                                                                 
                #intervalLiteral
     | ASTERISK                                                                 
                #star
     | qualifiedName DOT ASTERISK                                               
                #star
     | functionIdentifier LEFT_PAREN ((DISTINCT|ALL)? arguments+=expression
@@ -468,11 +469,14 @@ specifiedPartition
 
 constant
     : NULL                                                                     
                #nullLiteral
-    | interval                                                                 
                #intervalLiteral
-    | type=(DATE | DATEV2 | TIMESTAMP) STRING_LITERAL                          
                        #typeConstructor
+    | type=(DATE | DATEV2 | TIMESTAMP) STRING_LITERAL                          
                #typeConstructor
     | number                                                                   
                #numericLiteral
     | booleanValue                                                             
                #booleanLiteral
-    | STRING_LITERAL                                                           
                        #stringLiteral
+    | STRING_LITERAL                                                           
                #stringLiteral
+    | LEFT_BRACKET items+=constant (COMMA items+=constant)* RIGHT_BRACKET      
                #arrayLiteral
+    | LEFT_BRACE items+=constant COLON items+=constant
+       (COMMA items+=constant COLON items+=constant)* RIGHT_BRACE              
                #mapLiteral
+    | LEFT_BRACE items+=constant (COMMA items+=constant)* RIGHT_BRACE          
                #structLiteral
     ;
 
 comparisonOperator
@@ -543,7 +547,7 @@ quotedIdentifier
     ;
 
 number
-    : MINUS? INTEGER_VALUE            #integerLiteral
+    : MINUS? INTEGER_VALUE                    #integerLiteral
     | MINUS? (EXPONENT_VALUE | DECIMAL_VALUE) #decimalLiteral
     ;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
index 7102526efd..8267b4f952 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/BuiltinScalarFunctions.java
@@ -93,6 +93,8 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTz;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Cos;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CountEqual;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CreateMap;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CreateNamedStruct;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CreateStruct;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentCatalog;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentDate;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentTime;
@@ -305,6 +307,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.StartsWith;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.StrLeft;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.StrRight;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.StrToDate;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.StructElement;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SubBitmap;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SubReplace;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Substring;
@@ -436,6 +439,8 @@ public class BuiltinScalarFunctions implements 
FunctionHelper {
             scalar(Cos.class, "cos"),
             scalar(CountEqual.class, "countequal"),
             scalar(CreateMap.class, "map"),
+            scalar(CreateStruct.class, "struct"),
+            scalar(CreateNamedStruct.class, "named_struct"),
             scalar(CurrentCatalog.class, "current_catalog"),
             scalar(CurrentDate.class, "curdate", "current_date"),
             scalar(CurrentTime.class, "curtime", "current_time"),
@@ -610,6 +615,7 @@ public class BuiltinScalarFunctions implements 
FunctionHelper {
             scalar(Sign.class, "sign"),
             scalar(Sin.class, "sin"),
             scalar(Sleep.class, "sleep"),
+            scalar(StructElement.class, "struct_element"),
             scalar(Sm3.class, "sm3"),
             scalar(Sm3sum.class, "sm3sum"),
             scalar(Sm4Decrypt.class, "sm4_decrypt"),
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 708b2ef86d..c7e7a19361 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
@@ -30,6 +30,7 @@ import org.apache.doris.nereids.DorisParser.AliasQueryContext;
 import org.apache.doris.nereids.DorisParser.AliasedQueryContext;
 import org.apache.doris.nereids.DorisParser.ArithmeticBinaryContext;
 import org.apache.doris.nereids.DorisParser.ArithmeticUnaryContext;
+import org.apache.doris.nereids.DorisParser.ArrayLiteralContext;
 import org.apache.doris.nereids.DorisParser.ArraySliceContext;
 import org.apache.doris.nereids.DorisParser.BitOperationContext;
 import org.apache.doris.nereids.DorisParser.BooleanExpressionContext;
@@ -41,6 +42,8 @@ import 
org.apache.doris.nereids.DorisParser.ColumnReferenceContext;
 import org.apache.doris.nereids.DorisParser.CommentJoinHintContext;
 import org.apache.doris.nereids.DorisParser.CommentRelationHintContext;
 import org.apache.doris.nereids.DorisParser.ComparisonContext;
+import org.apache.doris.nereids.DorisParser.ComplexColTypeContext;
+import org.apache.doris.nereids.DorisParser.ComplexColTypeListContext;
 import org.apache.doris.nereids.DorisParser.ComplexDataTypeContext;
 import org.apache.doris.nereids.DorisParser.ConstantContext;
 import org.apache.doris.nereids.DorisParser.CreateRowPolicyContext;
@@ -74,6 +77,7 @@ import 
org.apache.doris.nereids.DorisParser.LateralViewContext;
 import org.apache.doris.nereids.DorisParser.LimitClauseContext;
 import org.apache.doris.nereids.DorisParser.LogicalBinaryContext;
 import org.apache.doris.nereids.DorisParser.LogicalNotContext;
+import org.apache.doris.nereids.DorisParser.MapLiteralContext;
 import org.apache.doris.nereids.DorisParser.MultiStatementsContext;
 import org.apache.doris.nereids.DorisParser.MultipartIdentifierContext;
 import org.apache.doris.nereids.DorisParser.NamedExpressionContext;
@@ -105,6 +109,7 @@ import org.apache.doris.nereids.DorisParser.SortItemContext;
 import org.apache.doris.nereids.DorisParser.StarContext;
 import org.apache.doris.nereids.DorisParser.StatementDefaultContext;
 import org.apache.doris.nereids.DorisParser.StringLiteralContext;
+import org.apache.doris.nereids.DorisParser.StructLiteralContext;
 import org.apache.doris.nereids.DorisParser.SubqueryContext;
 import org.apache.doris.nereids.DorisParser.SubqueryExpressionContext;
 import org.apache.doris.nereids.DorisParser.SystemVariableContext;
@@ -187,7 +192,10 @@ import 
org.apache.doris.nereids.trees.expressions.WindowFrame;
 import org.apache.doris.nereids.trees.expressions.functions.Function;
 import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
 import org.apache.doris.nereids.trees.expressions.functions.agg.GroupConcat;
+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.CreateMap;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CreateStruct;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysAdd;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysDiff;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.DaysSub;
@@ -264,6 +272,8 @@ import 
org.apache.doris.nereids.trees.plans.logical.UsingJoin;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.MapType;
+import org.apache.doris.nereids.types.StructField;
+import org.apache.doris.nereids.types.StructType;
 import org.apache.doris.nereids.types.coercion.CharacterType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.policy.FilterType;
@@ -1311,7 +1321,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
     }
 
     @Override
-    public Expression visitTypeConstructor(TypeConstructorContext ctx) {
+    public Literal visitTypeConstructor(TypeConstructorContext ctx) {
         String value = ctx.STRING_LITERAL().getText();
         value = value.substring(1, value.length() - 1);
         String type = ctx.type.getText().toUpperCase();
@@ -1367,7 +1377,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
      * Create a NULL literal expression.
      */
     @Override
-    public Expression visitNullLiteral(NullLiteralContext ctx) {
+    public Literal visitNullLiteral(NullLiteralContext ctx) {
         return new NullLiteral();
     }
 
@@ -1444,6 +1454,24 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return sb.toString();
     }
 
+    @Override
+    public Object visitArrayLiteral(ArrayLiteralContext ctx) {
+        Literal[] items = 
ctx.items.stream().<Literal>map(this::typedVisit).toArray(Literal[]::new);
+        return new Array(items);
+    }
+
+    @Override
+    public Object visitMapLiteral(MapLiteralContext ctx) {
+        Literal[] items = 
ctx.items.stream().<Literal>map(this::typedVisit).toArray(Literal[]::new);
+        return new CreateMap(items);
+    }
+
+    @Override
+    public Object visitStructLiteral(StructLiteralContext ctx) {
+        Literal[] items = 
ctx.items.stream().<Literal>map(this::typedVisit).toArray(Literal[]::new);
+        return new CreateStruct(items);
+    }
+
     @Override
     public Expression 
visitParenthesizedExpression(ParenthesizedExpressionContext ctx) {
         return getExpression(ctx.expression());
@@ -2084,13 +2112,25 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
                 case DorisParser.MAP:
                     return MapType.of(typedVisit(ctx.dataType(0)), 
typedVisit(ctx.dataType(1)));
                 case DorisParser.STRUCT:
-                    throw new AnalysisException("do not support STRUCT type 
for Nereids");
+                    return new 
StructType(visitComplexColTypeList(ctx.complexColTypeList()));
                 default:
                     throw new AnalysisException("do not support " + 
ctx.complex.getText() + " type for Nereids");
             }
         });
     }
 
+    @Override
+    public List<StructField> visitComplexColTypeList(ComplexColTypeListContext 
ctx) {
+        return 
ctx.complexColType().stream().map(this::visitComplexColType).collect(ImmutableList.toImmutableList());
+    }
+
+    @Override
+    public StructField visitComplexColType(ComplexColTypeContext ctx) {
+        String comment = ctx.commentSpec().STRING_LITERAL().getText();
+        comment = escapeBackSlash(comment.substring(1, comment.length() - 1));
+        return new StructField(ctx.identifier().getText(), 
typedVisit(ctx.dataType()), true, comment);
+    }
+
     private Expression parseFunctionWithOrderKeys(String functionName, boolean 
isDistinct,
             List<Expression> params, List<OrderKey> orderKeys, 
ParserRuleContext ctx) {
         if (functionName.equalsIgnoreCase("group_concat")) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/check/CheckCast.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/check/CheckCast.java
index 2a5b83a06f..84abcb9d43 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/check/CheckCast.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/check/CheckCast.java
@@ -25,9 +25,11 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.DataType;
 import org.apache.doris.nereids.types.MapType;
+import org.apache.doris.nereids.types.StructField;
 import org.apache.doris.nereids.types.StructType;
+import org.apache.doris.nereids.types.coercion.CharacterType;
 
-import java.util.Map;
+import java.util.List;
 
 /**
  * check cast valid
@@ -42,7 +44,7 @@ public class CheckCast extends AbstractExpressionRewriteRule {
         DataType originalType = cast.child().getDataType();
         DataType targetType = cast.getDataType();
         if (!check(originalType, targetType)) {
-            throw new AnalysisException("cannot cast " + originalType + " to " 
+ targetType);
+            throw new AnalysisException("cannot cast " + originalType.toSql() 
+ " to " + targetType.toSql());
         }
         return cast;
     }
@@ -54,17 +56,19 @@ public class CheckCast extends 
AbstractExpressionRewriteRule {
             return check(((MapType) originalType).getKeyType(), ((MapType) 
targetType).getKeyType())
                     && check(((MapType) originalType).getValueType(), 
((MapType) targetType).getValueType());
         } else if (originalType instanceof StructType && targetType instanceof 
StructType) {
-            Map<String, DataType> targetItems = ((StructType) 
targetType).getItems();
-            for (Map.Entry<String, DataType> entry : ((StructType) 
originalType).getItems().entrySet()) {
-                if (targetItems.containsKey(entry.getKey())) {
-                    if (!check(entry.getValue(), 
targetItems.get(entry.getKey()))) {
-                        return false;
-                    }
-                } else {
+            List<StructField> targetFields = ((StructType) 
targetType).getFields();
+            List<StructField> originalFields = ((StructType) 
originalType).getFields();
+            if (targetFields.size() != originalFields.size()) {
+                return false;
+            }
+            for (int i = 0; i < targetFields.size(); i++) {
+                if (!targetFields.get(i).equals(originalFields.get(i))) {
                     return false;
                 }
             }
             return true;
+        } else if (originalType instanceof CharacterType && targetType 
instanceof StructType) {
+            return true;
         } else {
             return checkPrimitiveType(originalType, targetType);
         }
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 69a3499630..e049254368 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
@@ -46,6 +46,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.BoundFunction;
 import org.apache.doris.nereids.trees.expressions.functions.FunctionBuilder;
 import 
org.apache.doris.nereids.trees.expressions.functions.udf.AliasUdfBuilder;
 import 
org.apache.doris.nereids.trees.expressions.typecoercion.ImplicitCastInputTypes;
+import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.BigIntType;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DataType;
@@ -116,6 +117,13 @@ public class FunctionBinder extends 
AbstractExpressionRewriteRule {
         }
     }
 
+    @Override
+    public Expression visitBoundFunction(BoundFunction boundFunction, 
ExpressionRewriteContext context) {
+        boundFunction = (BoundFunction) 
boundFunction.withChildren(boundFunction.children().stream()
+                .map(e -> e.accept(this, 
context)).collect(Collectors.toList()));
+        return TypeCoercionUtils.processBoundFunction(boundFunction);
+    }
+
     /**
      * gets the method for calculating the time.
      * e.g. YEARS_ADD、YEARS_SUB、DAYS_ADD 、DAYS_SUB
@@ -271,4 +279,14 @@ public class FunctionBinder extends 
AbstractExpressionRewriteRule {
         }
         return match.withChildren(left, right);
     }
+
+    @Override
+    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) {
+            TypeCoercionUtils.checkCanCastTo(cast.child().getDataType(), 
cast.getDataType());
+        }
+        return cast;
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckDataTypes.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckDataTypes.java
index d42fc51284..e3ccfa689f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckDataTypes.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CheckDataTypes.java
@@ -40,8 +40,7 @@ import java.util.Set;
  */
 public class CheckDataTypes implements CustomRewriter {
 
-    private static final Set<Class<? extends DataType>> UNSUPPORTED_TYPE = 
ImmutableSet.of(
-            StructType.class, JsonType.class);
+    private static final Set<Class<? extends DataType>> UNSUPPORTED_TYPE = 
ImmutableSet.of(JsonType.class);
 
     @Override
     public Plan rewriteRoot(Plan rootPlan, JobContext jobContext) {
@@ -92,8 +91,9 @@ public class CheckDataTypes implements CustomRewriter {
             } else if (dataType instanceof MapType) {
                 checkTypes(((MapType) dataType).getKeyType());
                 checkTypes(((MapType) dataType).getValueType());
-            }
-            if (UNSUPPORTED_TYPE.contains(dataType.getClass())) {
+            } else if (dataType instanceof StructType) {
+                ((StructType) dataType).getFields().forEach(f -> 
this.checkTypes(f.getDataType()));
+            } else if (UNSUPPORTED_TYPE.contains(dataType.getClass())) {
                 throw new AnalysisException(String.format("type %s is 
unsupported for Nereids", dataType));
             }
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
index 86122af5ad..fd4ad63f6e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
@@ -31,6 +31,7 @@ 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.MapType;
+import org.apache.doris.nereids.types.StructField;
 import org.apache.doris.nereids.types.StructType;
 import org.apache.doris.nereids.types.coercion.AnyDataType;
 
@@ -129,7 +130,19 @@ public abstract class Expression extends 
AbstractTreeNode<Expression> implements
                     && checkInputDataTypesWithExpectType(
                     ((MapType) input).getValueType(), ((MapType) 
expected).getValueType());
         } else if (input instanceof StructType && expected instanceof 
StructType) {
-            throw new AnalysisException("not support struct type now.");
+            List<StructField> inputFields = ((StructType) input).getFields();
+            List<StructField> expectedFields = ((StructType) 
expected).getFields();
+            if (inputFields.size() != expectedFields.size()) {
+                return false;
+            }
+            for (int i = 0; i < inputFields.size(); i++) {
+                if (!checkInputDataTypesWithExpectType(
+                        inputFields.get(i).getDataType(),
+                        expectedFields.get(i).getDataType())) {
+                    return false;
+                }
+            }
+            return true;
         } else {
             return checkPrimitiveInputDataTypesWithExpectType(input, expected);
         }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignature.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignature.java
index 549053f89b..a755e3c517 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignature.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputeSignature.java
@@ -19,7 +19,6 @@ package org.apache.doris.nereids.trees.expressions.functions;
 
 import org.apache.doris.catalog.FunctionSignature;
 import org.apache.doris.nereids.annotation.Developing;
-import org.apache.doris.nereids.exceptions.AnalysisException;
 import 
org.apache.doris.nereids.trees.expressions.functions.ComputeSignatureHelper.ComputeSignatureChain;
 import 
org.apache.doris.nereids.trees.expressions.typecoercion.ImplicitCastInputTypes;
 import org.apache.doris.nereids.types.ArrayType;
@@ -117,7 +116,7 @@ public interface ComputeSignature extends FunctionTrait, 
ImplicitCastInputTypes
                 .get();
     }
 
-    /** default computeSignature */
+    /** use processor to process computeSignature */
     static boolean processComplexType(DataType signatureType, DataType 
realType,
             BiFunction<DataType, DataType, Boolean> processor) {
         if (signatureType instanceof ArrayType && realType instanceof 
ArrayType) {
@@ -127,7 +126,9 @@ public interface ComputeSignature extends FunctionTrait, 
ImplicitCastInputTypes
             return processor.apply(((MapType) signatureType).getKeyType(), 
((MapType) realType).getKeyType())
                     && processor.apply(((MapType) 
signatureType).getValueType(), ((MapType) realType).getValueType());
         } else if (signatureType instanceof StructType && realType instanceof 
StructType) {
-            throw new AnalysisException("do not support struct type now");
+            // TODO: do not support struct type now
+            // throw new AnalysisException("do not support struct type now");
+            return true;
         } else {
             return processor.apply(signatureType, realType);
         }
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 a8e03153ae..223b793a9f 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
@@ -73,7 +73,8 @@ public class ComputeSignatureHelper {
                 collectAnyDataType(((MapType) sigType).getKeyType(), 
NullType.INSTANCE, indexToArgumentTypes);
                 collectAnyDataType(((MapType) sigType).getValueType(), 
NullType.INSTANCE, indexToArgumentTypes);
             } else if (sigType instanceof StructType) {
-                throw new AnalysisException("do not support struct type now");
+                // TODO: do not support struct type now
+                // throw new AnalysisException("do not support struct type 
now");
             } else {
                 if (sigType instanceof AnyDataType && ((AnyDataType) 
sigType).getIndex() >= 0) {
                     List<DataType> dataTypes = 
indexToArgumentTypes.computeIfAbsent(
@@ -90,7 +91,8 @@ public class ComputeSignatureHelper {
             collectAnyDataType(((MapType) sigType).getValueType(),
                     ((MapType) expressionType).getValueType(), 
indexToArgumentTypes);
         } else if (sigType instanceof StructType && expressionType instanceof 
StructType) {
-            throw new AnalysisException("do not support struct type now");
+            // TODO: do not support struct type now
+            // throw new AnalysisException("do not support struct type now");
         } else {
             if (sigType instanceof AnyDataType && ((AnyDataType) 
sigType).getIndex() >= 0) {
                 List<DataType> dataTypes = 
indexToArgumentTypes.computeIfAbsent(
@@ -112,7 +114,8 @@ public class ComputeSignatureHelper {
                 collectFollowToAnyDataType(((MapType) sigType).getValueType(),
                         NullType.INSTANCE, indexToArgumentTypes, 
allNullTypeIndex);
             } else if (sigType instanceof StructType) {
-                throw new AnalysisException("do not support struct type now");
+                // TODO: do not support struct type now
+                // throw new AnalysisException("do not support struct type 
now");
             } else {
                 if (sigType instanceof FollowToAnyDataType
                         && allNullTypeIndex.contains(((FollowToAnyDataType) 
sigType).getIndex())) {
@@ -130,7 +133,8 @@ public class ComputeSignatureHelper {
             collectFollowToAnyDataType(((MapType) sigType).getValueType(),
                     ((MapType) expressionType).getValueType(), 
indexToArgumentTypes, allNullTypeIndex);
         } else if (sigType instanceof StructType && expressionType instanceof 
StructType) {
-            throw new AnalysisException("do not support struct type now");
+            // TODO: do not support struct type now
+            // throw new AnalysisException("do not support struct type now");
         } else {
             if (sigType instanceof FollowToAnyDataType
                     && allNullTypeIndex.contains(((FollowToAnyDataType) 
sigType).getIndex())) {
@@ -149,7 +153,9 @@ public class ComputeSignatureHelper {
             return MapType.of(replaceAnyDataType(((MapType) 
dataType).getKeyType(), indexToCommonTypes),
                     replaceAnyDataType(((MapType) dataType).getValueType(), 
indexToCommonTypes));
         } else if (dataType instanceof StructType) {
-            throw new AnalysisException("do not support struct type now");
+            // TODO: do not support struct type now
+            // throw new AnalysisException("do not support struct type now");
+            return dataType;
         } else {
             if (dataType instanceof AnyDataType && ((AnyDataType) 
dataType).getIndex() >= 0) {
                 Optional<DataType> optionalDataType = 
indexToCommonTypes.get(((AnyDataType) dataType).getIndex());
@@ -177,7 +183,7 @@ public class ComputeSignatureHelper {
             DataType sigType;
             if (i >= signature.argumentsTypes.size()) {
                 sigType = signature.getVarArgType().orElseThrow(
-                        () -> new IllegalStateException("function arity not 
match with signature"));
+                        () -> new AnalysisException("function arity not match 
with signature"));
             } else {
                 sigType = signature.argumentsTypes.get(i);
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayExcept.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayExcept.java
index b87460b766..c1edd9f2e5 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayExcept.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayExcept.java
@@ -25,7 +25,6 @@ import 
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.coercion.AnyDataType;
-import org.apache.doris.nereids.types.coercion.FollowToAnyDataType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -40,7 +39,7 @@ public class ArrayExcept extends ScalarFunction implements 
ExplicitlyCastableSig
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             FunctionSignature.retArgType(0)
-                    .args(ArrayType.of(new AnyDataType(0)), ArrayType.of(new 
FollowToAnyDataType(0)))
+                    .args(ArrayType.of(new AnyDataType(0)), ArrayType.of(new 
AnyDataType(0)))
     );
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayIntersect.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayIntersect.java
index 0dc4f38151..0811304e51 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayIntersect.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayIntersect.java
@@ -25,7 +25,6 @@ import 
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.coercion.AnyDataType;
-import org.apache.doris.nereids.types.coercion.FollowToAnyDataType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -40,7 +39,7 @@ public class ArrayIntersect extends ScalarFunction implements 
ExplicitlyCastable
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             FunctionSignature.retArgType(0)
-                    .args(ArrayType.of(new AnyDataType(0)), ArrayType.of(new 
FollowToAnyDataType(0)))
+                    .args(ArrayType.of(new AnyDataType(0)), ArrayType.of(new 
AnyDataType(0)))
     );
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayUnion.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayUnion.java
index 93e1ca862f..a1152b2c6d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayUnion.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ArrayUnion.java
@@ -25,7 +25,6 @@ import 
org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.ArrayType;
 import org.apache.doris.nereids.types.coercion.AnyDataType;
-import org.apache.doris.nereids.types.coercion.FollowToAnyDataType;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
@@ -40,7 +39,7 @@ public class ArrayUnion extends ScalarFunction implements 
ExplicitlyCastableSign
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
             FunctionSignature.retArgType(0)
-                    .args(ArrayType.of(new AnyDataType(0)), ArrayType.of(new 
FollowToAnyDataType(0)))
+                    .args(ArrayType.of(new AnyDataType(0)), ArrayType.of(new 
AnyDataType(0)))
     );
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
index 2ffe1b4ea9..fe966f4e38 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
@@ -32,7 +32,7 @@ import com.google.common.collect.ImmutableList;
 import java.util.List;
 
 /**
- * ScalarFunction 'array'. This class is generated by GenerateFunction.
+ * ScalarFunction 'map'.
  */
 public class CreateMap extends ScalarFunction
         implements ExplicitlyCastableSignature, AlwaysNotNullable {
@@ -59,7 +59,7 @@ public class CreateMap extends ScalarFunction
     @Override
     public void checkLegalityBeforeTypeCoercion() {
         if (arity() % 2 != 0) {
-            throw new AnalysisException("map can't be odd parameters, need 
even parameters " + this);
+            throw new AnalysisException("map can't be odd parameters, need 
even parameters " + this.toSql());
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateNamedStruct.java
similarity index 50%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateNamedStruct.java
index 2ffe1b4ea9..0184fed65a 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateNamedStruct.java
@@ -23,43 +23,54 @@ import 
org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait;
+import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DataType;
-import org.apache.doris.nereids.types.MapType;
+import org.apache.doris.nereids.types.StructField;
+import org.apache.doris.nereids.types.StructType;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
 
 import java.util.List;
+import java.util.Set;
 
 /**
- * ScalarFunction 'array'. This class is generated by GenerateFunction.
+ * ScalarFunction 'named_struct'.
  */
-public class CreateMap extends ScalarFunction
+public class CreateNamedStruct extends ScalarFunction
         implements ExplicitlyCastableSignature, AlwaysNotNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            FunctionSignature.ret(MapType.SYSTEM_DEFAULT).args()
+            FunctionSignature.ret(StructType.SYSTEM_DEFAULT).args()
     );
 
     /**
      * constructor with 0 or more arguments.
      */
-    public CreateMap(Expression... varArgs) {
-        super("map", varArgs);
-    }
-
-    @Override
-    public DataType getDataType() {
-        if (arity() >= 2) {
-            return MapType.of(child(0).getDataType(), child(1).getDataType());
-        }
-        return MapType.SYSTEM_DEFAULT;
+    public CreateNamedStruct(Expression... varArgs) {
+        super("named_struct", varArgs);
     }
 
     @Override
     public void checkLegalityBeforeTypeCoercion() {
         if (arity() % 2 != 0) {
-            throw new AnalysisException("map can't be odd parameters, need 
even parameters " + this);
+            throw new AnalysisException("named_struct can't be odd parameters, 
need even parameters " + this.toSql());
+        }
+        Set<String> names = Sets.newHashSet();
+        for (int i = 0; i < arity(); i = i + 2) {
+            if (!(child(i) instanceof StringLikeLiteral)) {
+                throw new AnalysisException("named_struct only allows"
+                        + " constant string parameter in odd position: " + 
this);
+            } else {
+                String name = ((StringLikeLiteral) child(i)).getStringValue();
+                if (names.contains(name)) {
+                    throw new AnalysisException("The name of the struct field 
cannot be repeated."
+                            + " same name fields are " + name);
+                } else {
+                    names.add(name);
+                }
+            }
         }
     }
 
@@ -67,13 +78,13 @@ public class CreateMap extends ScalarFunction
      * withChildren.
      */
     @Override
-    public CreateMap withChildren(List<Expression> children) {
-        return new CreateMap(children.toArray(new Expression[0]));
+    public CreateNamedStruct withChildren(List<Expression> children) {
+        return new CreateNamedStruct(children.toArray(new Expression[0]));
     }
 
     @Override
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitCreateMap(this, context);
+        return visitor.visitCreateNamedStruct(this, context);
     }
 
     @Override
@@ -81,12 +92,14 @@ public class CreateMap extends ScalarFunction
         if (arity() == 0) {
             return SIGNATURES;
         } else {
-            return ImmutableList.of(FunctionSignature.of(
-                    getDataType(),
-                    children.stream()
-                            .map(ExpressionTrait::getDataType)
-                            .collect(ImmutableList.toImmutableList())
-            ));
+            ImmutableList.Builder<StructField> structFields = 
ImmutableList.builder();
+            for (int i = 0; i < arity(); i = i + 2) {
+                StringLikeLiteral nameLiteral = (StringLikeLiteral) child(i);
+                structFields.add(new StructField(nameLiteral.getStringValue(),
+                        children.get(i + 1).getDataType(), true, ""));
+            }
+            return ImmutableList.of(FunctionSignature.ret(new 
StructType(structFields.build()))
+                    
.args(children.stream().map(ExpressionTrait::getDataType).toArray(DataType[]::new)));
         }
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateStruct.java
similarity index 60%
copy from 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateStruct.java
index 2ffe1b4ea9..cba64fdcce 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateMap.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/CreateStruct.java
@@ -18,62 +18,47 @@
 package org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
-import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
 import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DataType;
-import org.apache.doris.nereids.types.MapType;
+import org.apache.doris.nereids.types.StructField;
+import org.apache.doris.nereids.types.StructType;
 
 import com.google.common.collect.ImmutableList;
 
 import java.util.List;
 
 /**
- * ScalarFunction 'array'. This class is generated by GenerateFunction.
+ * ScalarFunction 'struct'.
  */
-public class CreateMap extends ScalarFunction
+public class CreateStruct extends ScalarFunction
         implements ExplicitlyCastableSignature, AlwaysNotNullable {
 
     public static final List<FunctionSignature> SIGNATURES = ImmutableList.of(
-            FunctionSignature.ret(MapType.SYSTEM_DEFAULT).args()
+            FunctionSignature.ret(StructType.SYSTEM_DEFAULT).args()
     );
 
     /**
      * constructor with 0 or more arguments.
      */
-    public CreateMap(Expression... varArgs) {
-        super("map", varArgs);
-    }
-
-    @Override
-    public DataType getDataType() {
-        if (arity() >= 2) {
-            return MapType.of(child(0).getDataType(), child(1).getDataType());
-        }
-        return MapType.SYSTEM_DEFAULT;
-    }
-
-    @Override
-    public void checkLegalityBeforeTypeCoercion() {
-        if (arity() % 2 != 0) {
-            throw new AnalysisException("map can't be odd parameters, need 
even parameters " + this);
-        }
+    public CreateStruct(Expression... varArgs) {
+        super("struct", varArgs);
     }
 
     /**
      * withChildren.
      */
     @Override
-    public CreateMap withChildren(List<Expression> children) {
-        return new CreateMap(children.toArray(new Expression[0]));
+    public CreateStruct withChildren(List<Expression> children) {
+        return new CreateStruct(children.toArray(new Expression[0]));
     }
 
     @Override
     public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
-        return visitor.visitCreateMap(this, context);
+        return visitor.visitCreateStruct(this, context);
     }
 
     @Override
@@ -81,12 +66,12 @@ public class CreateMap extends ScalarFunction
         if (arity() == 0) {
             return SIGNATURES;
         } else {
-            return ImmutableList.of(FunctionSignature.of(
-                    getDataType(),
-                    children.stream()
-                            .map(ExpressionTrait::getDataType)
-                            .collect(ImmutableList.toImmutableList())
-            ));
+            ImmutableList.Builder<StructField> structFields = 
ImmutableList.builder();
+            for (int i = 0; i < arity(); i++) {
+                structFields.add(new StructField(String.valueOf(i + 1), 
children.get(i).getDataType(), true, ""));
+            }
+            return ImmutableList.of(FunctionSignature.ret(new 
StructType(structFields.build()))
+                    
.args(children.stream().map(ExpressionTrait::getDataType).toArray(DataType[]::new)));
         }
     }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StructElement.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StructElement.java
new file mode 100644
index 0000000000..d21b365947
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/StructElement.java
@@ -0,0 +1,99 @@
+// 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.functions.scalar;
+
+import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
+import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.functions.SearchSignature;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.StructType;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * ScalarFunction 'struct_element'.
+ */
+public class StructElement extends ScalarFunction
+        implements ExplicitlyCastableSignature, AlwaysNullable {
+
+    /**
+     * constructor with 0 or more arguments.
+     */
+    public StructElement(Expression arg0, Expression arg1) {
+        super("struct_element", arg0, arg1);
+    }
+
+    @Override
+    public void checkLegalityBeforeTypeCoercion() {
+        if (!(child(0).getDataType() instanceof StructType)) {
+            SearchSignature.throwCanNotFoundFunctionException(this.getName(), 
this.getArguments());
+        }
+        if (!(child(1) instanceof StringLikeLiteral || child(1) instanceof 
IntegerLikeLiteral)) {
+            throw new AnalysisException("struct_element only allows"
+                    + " constant int or string second parameter: " + 
this.toSql());
+        }
+    }
+
+    /**
+     * withChildren.
+     */
+    @Override
+    public StructElement withChildren(List<Expression> children) {
+        Preconditions.checkArgument(children.size() == 2, "children size 
should be 2");
+        return new StructElement(children.get(0), children.get(1));
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitStructElement(this, context);
+    }
+
+    @Override
+    public List<FunctionSignature> getSignatures() {
+        StructType structArgType = (StructType) child(0).getDataType();
+        DataType retType;
+        if (child(1) instanceof IntegerLikeLiteral) {
+            int offset = ((IntegerLikeLiteral) child(1)).getIntValue();
+            if (offset <= 0 || offset > structArgType.getFields().size()) {
+                throw new AnalysisException("the specified field index out of 
bound: " + this.toSql());
+            } else {
+                retType = structArgType.getFields().get(offset - 
1).getDataType();
+            }
+        } else if (child(1) instanceof StringLikeLiteral) {
+            String name = ((StringLikeLiteral) child(1)).getStringValue();
+            if (!structArgType.getNameToFields().containsKey(name)) {
+                throw new AnalysisException("the specified field name " + name 
+ " was not found: " + this.toSql());
+            } else {
+                retType = 
structArgType.getNameToFields().get(name).getDataType();
+            }
+        } else {
+            throw new AnalysisException("struct_element only allows"
+                    + " constant int or string second parameter: " + 
this.toSql());
+        }
+        return 
ImmutableList.of(FunctionSignature.ret(retType).args(structArgType, 
child(1).getDataType()));
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
index 480ac996a1..b9cdd7eced 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
@@ -43,4 +43,9 @@ public abstract class StringLikeLiteral extends Literal {
         }
         return (double) v;
     }
+
+    @Override
+    public String toString() {
+        return "'" + value + "'";
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLiteral.java
index 588adbc0aa..603749c60b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLiteral.java
@@ -52,9 +52,4 @@ public class StringLiteral extends StringLikeLiteral {
     public LiteralExpr toLegacyLiteral() {
         return new org.apache.doris.analysis.StringLiteral(value);
     }
-
-    @Override
-    public String toString() {
-        return "'" + value + "'";
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java
index 40f3f8f8ad..75161dd000 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java
@@ -50,9 +50,4 @@ public class VarcharLiteral extends StringLikeLiteral {
     public LiteralExpr toLegacyLiteral() {
         return new StringLiteral(value);
     }
-
-    @Override
-    public String toString() {
-        return "'" + value + "'";
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
index f77d241898..0f37d870b9 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ScalarFunctionVisitor.java
@@ -97,6 +97,8 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.ConvertTz;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Cos;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CountEqual;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CreateMap;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CreateNamedStruct;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CreateStruct;
 import 
org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentCatalog;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentDate;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentTime;
@@ -309,6 +311,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.scalar.StartsWith;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.StrLeft;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.StrRight;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.StrToDate;
+import 
org.apache.doris.nereids.trees.expressions.functions.scalar.StructElement;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SubBitmap;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.SubReplace;
 import org.apache.doris.nereids.trees.expressions.functions.scalar.Substring;
@@ -1695,4 +1698,18 @@ public interface ScalarFunctionVisitor<R, C> {
     default R visitMapValues(MapValues mapValues, C context) {
         return visitScalarFunction(mapValues, context);
     }
+
+    // struct function
+
+    default R visitCreateStruct(CreateStruct createStruct, C context) {
+        return visitScalarFunction(createStruct, context);
+    }
+
+    default R visitCreateNamedStruct(CreateNamedStruct createNamedStruct, C 
context) {
+        return visitScalarFunction(createNamedStruct, context);
+    }
+
+    default R visitStructElement(StructElement structElement, C context) {
+        return visitScalarFunction(structElement, context);
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java
index b45b70b9f4..5f233c959b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java
@@ -290,8 +290,11 @@ public abstract class DataType {
         } else if (type.isJsonbType()) {
             return JsonType.INSTANCE;
         } else if (type.isStructType()) {
-            // TODO: support struct type really
-            return StructType.INSTANCE;
+            List<StructField> structFields = 
((org.apache.doris.catalog.StructType) (type)).getFields().stream()
+                    .map(cf -> new StructField(cf.getName(), 
fromCatalogType(cf.getType()),
+                            cf.getContainsNull(), cf.getComment()))
+                    .collect(ImmutableList.toImmutableList());
+            return new StructType(structFields);
         } else if (type.isMapType()) {
             org.apache.doris.catalog.MapType mapType = 
(org.apache.doris.catalog.MapType) type;
             return MapType.of(fromCatalogType(mapType.getKeyType()), 
fromCatalogType(mapType.getValueType()));
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
new file mode 100644
index 0000000000..d42d7f960a
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java
@@ -0,0 +1,104 @@
+// 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.types;
+
+import org.apache.doris.nereids.util.Utils;
+
+import java.util.Objects;
+
+/**
+ * A field inside a StructType.
+ */
+public class StructField {
+
+    private final String name;
+    private final DataType dataType;
+    private final boolean nullable;
+    private final String comment;
+
+    /**
+     * StructField Constructor
+     *  @param name The name of this field
+     *  @param dataType The data type of this field
+     *  @param nullable Indicates if values of this field can be `null` values
+     */
+    public StructField(String name, DataType dataType, boolean nullable, 
String comment) {
+        this.name = Objects.requireNonNull(name, "name should not be null");
+        this.dataType = Objects.requireNonNull(dataType, "dataType should not 
be null");
+        this.nullable = nullable;
+        this.comment = Objects.requireNonNull(comment, "comment should not be 
null");
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public DataType getDataType() {
+        return dataType;
+    }
+
+    public boolean isNullable() {
+        return nullable;
+    }
+
+    public String getComment() {
+        return comment;
+    }
+
+    public StructField withDataType(DataType dataType) {
+        return new StructField(name, dataType, nullable, comment);
+    }
+
+    public org.apache.doris.catalog.StructField toCatalogDataType() {
+        return new org.apache.doris.catalog.StructField(
+                name, dataType.toCatalogDataType(), comment, nullable);
+    }
+
+    public String toSql() {
+        return name + ":" + dataType.toSql()
+                + (nullable ? " " : " NOT NULL")
+                + (comment.isEmpty() ? "" : " COMMENT " + comment);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        StructField that = (StructField) o;
+        return nullable == that.nullable && Objects.equals(name, that.name) && 
Objects.equals(dataType,
+                that.dataType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, dataType, nullable);
+    }
+
+    @Override
+    public String toString() {
+        return Utils.toSqlString("StructField",
+                "name", name,
+                "dataType", dataType,
+                "nullable", nullable,
+                "comment", comment);
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java
index 9359df15f7..e4ca5e9db7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java
@@ -19,12 +19,18 @@ package org.apache.doris.nereids.types;
 
 import org.apache.doris.catalog.Type;
 import org.apache.doris.nereids.annotation.Developing;
+import org.apache.doris.nereids.exceptions.AnalysisException;
 
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSortedMap;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
 
 /**
  * Struct type in Nereids.
@@ -32,28 +38,43 @@ import java.util.Objects;
 @Developing
 public class StructType extends DataType {
 
-    public static final StructType INSTANCE = new StructType();
+    public static final StructType SYSTEM_DEFAULT = new StructType();
 
     public static final int WIDTH = 24;
 
-    private final Map<String, DataType> items;
+    private final List<StructField> fields;
+    private final Supplier<Map<String, StructField>> nameToFields;
 
     private StructType() {
-        items = ImmutableMap.of();
+        nameToFields = Suppliers.memoize(ImmutableMap::of);
+        fields = ImmutableList.of();
     }
 
-    public StructType(Map<String, DataType> items) {
-        this.items = ImmutableSortedMap.copyOf(Objects.requireNonNull(items, 
"items should not be null"),
-                String.CASE_INSENSITIVE_ORDER);
+    /**
+     * construct struct type.
+     */
+    public StructType(List<StructField> fields) {
+        this.fields = ImmutableList.copyOf(Objects.requireNonNull(fields, 
"fields should not be null"));
+        this.nameToFields = Suppliers.memoize(() -> 
this.fields.stream().collect(ImmutableMap.toImmutableMap(
+                StructField::getName, f -> f, (f1, f2) -> {
+                    throw new AnalysisException("The name of the struct field 
cannot be repeated."
+                            + " same name fields are " + f1 + " and " + f2);
+                })));
     }
 
-    public Map<String, DataType> getItems() {
-        return items;
+    public List<StructField> getFields() {
+        return fields;
+    }
+
+    public Map<String, StructField> getNameToFields() {
+        return nameToFields.get();
     }
 
     @Override
     public Type toCatalogDataType() {
-        return Type.STRUCT;
+        return new org.apache.doris.catalog.StructType(fields.stream()
+                .map(StructField::toCatalogDataType)
+                .collect(Collectors.toCollection(ArrayList::new)));
     }
 
     @Override
@@ -68,7 +89,22 @@ public class StructType extends DataType {
 
     @Override
     public boolean equals(Object o) {
-        return o instanceof StructType;
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        if (!super.equals(o)) {
+            return false;
+        }
+        StructType that = (StructType) o;
+        return Objects.equals(fields, that.fields);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), fields);
     }
 
     @Override
@@ -78,6 +114,11 @@ public class StructType extends DataType {
 
     @Override
     public String toSql() {
-        return "STRUCT";
+        return "STRUCT<" + 
fields.stream().map(StructField::toSql).collect(Collectors.joining(", ")) + ">";
+    }
+
+    @Override
+    public String toString() {
+        return "STRUCT<" + 
fields.stream().map(StructField::toString).collect(Collectors.joining(", ")) + 
">";
     }
 }
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 badde85c2e..185c445647 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
@@ -85,6 +85,7 @@ import org.apache.doris.nereids.types.MapType;
 import org.apache.doris.nereids.types.NullType;
 import org.apache.doris.nereids.types.SmallIntType;
 import org.apache.doris.nereids.types.StringType;
+import org.apache.doris.nereids.types.StructField;
 import org.apache.doris.nereids.types.StructType;
 import org.apache.doris.nereids.types.TimeType;
 import org.apache.doris.nereids.types.TimeV2Type;
@@ -153,7 +154,22 @@ public class TypeCoercionUtils {
             }
             return Optional.empty();
         } else if (input instanceof StructType && expected instanceof 
StructType) {
-            throw new AnalysisException("not support struct type now.");
+            List<StructField> inputFields = ((StructType) input).getFields();
+            List<StructField> expectedFields = ((StructType) 
expected).getFields();
+            if (inputFields.size() != expectedFields.size()) {
+                return Optional.empty();
+            }
+            List<StructField> newFields = Lists.newArrayList();
+            for (int i = 0; i < inputFields.size(); i++) {
+                Optional<DataType> newDataType = 
implicitCast(inputFields.get(i).getDataType(),
+                        expectedFields.get(i).getDataType());
+                if (newDataType.isPresent()) {
+                    
newFields.add(inputFields.get(i).withDataType(newDataType.get()));
+                } else {
+                    return Optional.empty();
+                }
+            }
+            return Optional.of(new StructType(newFields));
         } else {
             return implicitCastPrimitive(input, expected);
         }
@@ -247,7 +263,7 @@ public class TypeCoercionUtils {
             return hasCharacterType(((MapType) dataType).getKeyType())
                     || hasCharacterType(((MapType) dataType).getValueType());
         } else if (dataType instanceof StructType) {
-            throw new AnalysisException("do not support struct type now");
+            return ((StructType) dataType).getFields().stream().anyMatch(f -> 
hasCharacterType(f.getDataType()));
         }
         return dataType instanceof CharacterType;
     }
@@ -293,7 +309,17 @@ public class TypeCoercionUtils {
             return matchesType(((MapType) input).getKeyType(), ((MapType) 
target).getKeyType())
                     && matchesType(((MapType) input).getValueType(), 
((MapType) target).getValueType());
         } else if (input instanceof StructType && target instanceof 
StructType) {
-            throw new AnalysisException("do not support struct type now");
+            List<StructField> inputFields = ((StructType) input).getFields();
+            List<StructField> targetFields = ((StructType) target).getFields();
+            if (inputFields.size() != targetFields.size()) {
+                return false;
+            }
+            for (int i = 0; i < inputFields.size(); i++) {
+                if (!matchesType(inputFields.get(i).getDataType(), 
targetFields.get(i).getDataType())) {
+                    return false;
+                }
+            }
+            return true;
         } else {
             if (input instanceof NullType) {
                 return false;
@@ -994,7 +1020,22 @@ public class TypeCoercionUtils {
                 return Optional.of(MapType.of(keyType.get(), valueType.get()));
             }
         } else if (left instanceof StructType && right instanceof StructType) {
-            throw new AnalysisException("do not support struct type now");
+            List<StructField> leftFields = ((StructType) left).getFields();
+            List<StructField> rightFields = ((StructType) right).getFields();
+            if (leftFields.size() != rightFields.size()) {
+                return Optional.empty();
+            }
+            List<StructField> newFields = Lists.newArrayList();
+            for (int i = 0; i < leftFields.size(); i++) {
+                Optional<DataType> newDataType = 
findCommonComplexTypeForComparison(leftFields.get(i).getDataType(),
+                        rightFields.get(i).getDataType(), intStringToString);
+                if (newDataType.isPresent()) {
+                    
newFields.add(leftFields.get(i).withDataType(newDataType.get()));
+                } else {
+                    return Optional.empty();
+                }
+            }
+            return Optional.of(new StructType(newFields));
         }
         return Optional.empty();
     }
@@ -1192,7 +1233,22 @@ public class TypeCoercionUtils {
                 return Optional.of(MapType.of(keyType.get(), valueType.get()));
             }
         } else if (left instanceof StructType && right instanceof StructType) {
-            throw new AnalysisException("do not support struct type now");
+            List<StructField> leftFields = ((StructType) left).getFields();
+            List<StructField> rightFields = ((StructType) right).getFields();
+            if (leftFields.size() != rightFields.size()) {
+                return Optional.empty();
+            }
+            List<StructField> newFields = Lists.newArrayList();
+            for (int i = 0; i < leftFields.size(); i++) {
+                Optional<DataType> newDataType = 
findCommonComplexTypeForCaseWhen(leftFields.get(i).getDataType(),
+                        rightFields.get(i).getDataType());
+                if (newDataType.isPresent()) {
+                    
newFields.add(leftFields.get(i).withDataType(newDataType.get()));
+                } else {
+                    return Optional.empty();
+                }
+            }
+            return Optional.of(new StructType(newFields));
         }
         return Optional.empty();
     }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/UnsupportedTypeTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/UnsupportedTypeTest.java
index 0f379ef30e..20c26286c2 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/UnsupportedTypeTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/UnsupportedTypeTest.java
@@ -63,23 +63,23 @@ public class UnsupportedTypeTest extends TestWithFeService {
                 "select karr from type_tb",
                 "select array_range(10)",
                 "select kmap from type_tb1",
+                "select * from type_tb1",
                 "select jsonb_parse('{\"k1\":\"v31\",\"k2\":300}')",
                 "select * from type_tb",
-                "select * from type_tb1",
         };
         Class[] exceptions = {
                 null,
                 null,
                 null,
                 null,
-                AnalysisException.class,
+                null,
                 AnalysisException.class,
                 AnalysisException.class
         };
-        for (int i = 0; i < 3; ++i) {
+        for (int i = 0; i < 5; ++i) {
             runPlanner(sqls[i]);
         }
-        for (int i = 4; i < sqls.length; ++i) {
+        for (int i = 5; i < sqls.length; ++i) {
             int iCopy = i;
             Assertions.assertThrows(exceptions[i], () -> 
runPlanner(sqls[iCopy]));
         }
diff --git a/regression-test/suites/nereids_syntax_p0/test_complex_type.groovy 
b/regression-test/suites/nereids_syntax_p0/test_complex_type.groovy
new file mode 100644
index 0000000000..145e3d2eb3
--- /dev/null
+++ b/regression-test/suites/nereids_syntax_p0/test_complex_type.groovy
@@ -0,0 +1,63 @@
+// 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_complex_type") {
+    sql "SET enable_nereids_planner=true"
+    sql "SET enable_fallback_to_original_planner=false"
+
+    // array literal
+    sql "select [1, 2, 3, 4]"
+
+    // map literal
+    sql "select {1:2, 3:4}"
+
+    // struct literal
+    sql "select {1, 2, 3, 4}"
+
+    // struct constructor
+    sql "select struct(1, 2, 3, 4)"
+
+    // named struct constructor
+    sql "select named_struct('x', 1, 'y', 2)"
+
+    test {
+        sql "select named_struct('x', 1, 'x', 2)"
+        exception "The name of the struct field cannot be repeated"
+    }
+
+    // struct element with int
+    sql "select struct_element(struct('1', '2', '3', '4'), 1);"
+
+    test {
+        sql "select struct_element(struct('1', '2', '3', '4'), 5);"
+        exception "the specified field index out of bound"
+    }
+
+    test {
+        sql "select struct_element(struct('1', '2', '3', '4'), -1);"
+        exception "the specified field index out of bound"
+    }
+
+    // struct element with string
+    sql "select struct_element(named_struct('1', '2', '3', '4'), '1');"
+
+    test {
+        sql "select struct_element(named_struct('1', '2', '3', '4'), '5')"
+        exception "the specified field name 5 was not found"
+    }
+}
+


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to