This is an automated email from the ASF dual-hosted git repository.

kxiao pushed a commit to branch branch-2.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.1 by this push:
     new 9708ca8fcb9 [Feature](Prepared Statment) Implement in nereids planner 
(#35318) (#36172)
9708ca8fcb9 is described below

commit 9708ca8fcb9e26cca1284138fbf588e9b6055776
Author: lihangyu <[email protected]>
AuthorDate: Wed Jun 12 19:54:17 2024 +0800

    [Feature](Prepared Statment) Implement in nereids planner (#35318) (#36172)
---
 .../org/apache/doris/catalog/MysqlColType.java     |  15 ++
 .../antlr4/org/apache/doris/nereids/DorisLexer.g4  |   1 +
 .../antlr4/org/apache/doris/nereids/DorisParser.g4 |   1 +
 .../org/apache/doris/nereids/StatementContext.java |  26 +++
 .../doris/nereids/parser/LogicalPlanBuilder.java   |  21 ++
 .../nereids/rules/analysis/ExpressionAnalyzer.java |   8 +
 .../nereids/trees/expressions/Placeholder.java     |  78 +++++++
 .../nereids/trees/expressions/literal/Literal.java | 169 ++++++++++++++
 .../expressions/visitor/ExpressionVisitor.java     |   5 +
 .../doris/nereids/trees/plans/PlaceholderId.java   |  58 +++++
 .../apache/doris/nereids/trees/plans/PlanType.java |   5 +-
 .../trees/plans/commands/ExecuteCommand.java       |  83 +++++++
 .../trees/plans/commands/PrepareCommand.java       | 120 ++++++++++
 .../java/org/apache/doris/qe/ConnectContext.java   |  13 ++
 .../java/org/apache/doris/qe/ConnectProcessor.java |   7 +-
 .../org/apache/doris/qe/MysqlConnectProcessor.java | 145 +++++++++---
 .../org/apache/doris/qe/PrepareStmtContext.java    |  12 +-
 ...tContext.java => PreparedStatementContext.java} |  31 +--
 .../java/org/apache/doris/qe/StmtExecutor.java     |  76 ++++---
 .../data/prepared_stmt_p0/prepared_stmt.out        |  53 +++--
 .../suites/point_query_p0/test_point_query.groovy  |   5 +-
 .../suites/prepared_stmt_p0/prepared_stmt.groovy   | 249 +++++++++------------
 22 files changed, 914 insertions(+), 267 deletions(-)

diff --git 
a/fe/fe-common/src/main/java/org/apache/doris/catalog/MysqlColType.java 
b/fe/fe-common/src/main/java/org/apache/doris/catalog/MysqlColType.java
index 0008f16ab10..cd48b0afd94 100644
--- a/fe/fe-common/src/main/java/org/apache/doris/catalog/MysqlColType.java
+++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/MysqlColType.java
@@ -17,6 +17,9 @@
 
 package org.apache.doris.catalog;
 
+import java.util.HashMap;
+import java.util.Map;
+
 // MySQL column type
 // TYPE codes are defined in the file 'mysql/include/mysql_com.h' enum 
enum_field_types
 // which is also demostrated in
@@ -55,6 +58,14 @@ public enum MysqlColType {
     MYSQL_TYPE_GEOMETRY(255, "GEOMETRY", "GEOMETRY"),
     MYSQL_TYPE_MAP(400, "MAP", "MAP");
 
+    private static final Map<Integer, MysqlColType> CODE_MAP = new HashMap<>();
+
+    static {
+        for (MysqlColType type : MysqlColType.values()) {
+            CODE_MAP.put(type.code, type);
+        }
+    }
+
     private MysqlColType(int code, String desc, String jdbcColumnTypeName) {
         this.code = code;
         this.desc = desc;
@@ -77,6 +88,10 @@ public enum MysqlColType {
         return code;
     }
 
+    public static MysqlColType fromCode(int code) {
+        return CODE_MAP.get(code);
+    }
+
     public String getJdbcColumnTypeName() {
         return jdbcColumnTypeName;
     }
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 6169a082e68..2b4dc38dc14 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
@@ -408,6 +408,7 @@ PERCENT: 'PERCENT';
 PERIOD: 'PERIOD';
 PERMISSIVE: 'PERMISSIVE';
 PHYSICAL: 'PHYSICAL';
+PLACEHOLDER: '?';
 PLAN: 'PLAN';
 PROCESS: 'PROCESS';
 PLUGIN: 'PLUGIN';
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 923a642a541..63a653983e2 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
@@ -878,6 +878,7 @@ constant
     | 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
+    | PLACEHOLDER                                                              
               #placeholder
     ;
 
 comparisonOperator
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
index f4a32d723a6..deb7f5f76cc 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/StatementContext.java
@@ -29,10 +29,12 @@ import 
org.apache.doris.nereids.rules.analysis.ColumnAliasGenerator;
 import org.apache.doris.nereids.trees.expressions.CTEId;
 import org.apache.doris.nereids.trees.expressions.ExprId;
 import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Placeholder;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator;
 import org.apache.doris.nereids.trees.plans.ObjectId;
+import org.apache.doris.nereids.trees.plans.PlaceholderId;
 import org.apache.doris.nereids.trees.plans.RelationId;
 import org.apache.doris.nereids.trees.plans.TableId;
 import org.apache.doris.nereids.trees.plans.algebra.Relation;
@@ -118,6 +120,11 @@ public class StatementContext implements Closeable {
     private final Set<String> viewDdlSqlSet = Sets.newHashSet();
     private final SqlCacheContext sqlCacheContext;
 
+    // generate for next id for prepared statement's placeholders, which is 
connection level
+    private final IdGenerator<PlaceholderId> placeHolderIdGenerator = 
PlaceholderId.createGenerator();
+    // relation id to placeholders for prepared statement
+    private final Map<PlaceholderId, Expression> idToPlaceholderRealExpr = new 
HashMap<>();
+
     // collect all hash join conditions to compute node connectivity in join 
graph
     private final List<Expression> joinFilters = new ArrayList<>();
 
@@ -141,6 +148,9 @@ public class StatementContext implements Closeable {
     // table locks
     private final Stack<CloseableResource> plannerResources = new Stack<>();
 
+    // placeholder params for prepared statement
+    private List<Placeholder> placeholders;
+
     // for create view support in nereids
     // key is the start and end position of the sql substring that needs to be 
replaced,
     // and value is the new string used for replacement.
@@ -367,6 +377,14 @@ public class StatementContext implements Closeable {
         return consumerIdToFilters;
     }
 
+    public PlaceholderId getNextPlaceholderId() {
+        return placeHolderIdGenerator.getNextId();
+    }
+
+    public Map<PlaceholderId, Expression> getIdToPlaceholderRealExpr() {
+        return idToPlaceholderRealExpr;
+    }
+
     public Map<CTEId, List<Pair<Map<Slot, Slot>, Group>>> 
getCteIdToConsumerGroup() {
         return cteIdToConsumerGroup;
     }
@@ -487,6 +505,14 @@ public class StatementContext implements Closeable {
         releasePlannerResources();
     }
 
+    public List<Placeholder> getPlaceholders() {
+        return placeholders;
+    }
+
+    public void setPlaceholders(List<Placeholder> placeholders) {
+        this.placeholders = placeholders;
+    }
+
     private static class CloseableResource implements Closeable {
         public final String resourceName;
         public final String threadName;
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 a499e0e00ce..551c9e90a5e 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
@@ -260,6 +260,7 @@ import org.apache.doris.nereids.trees.expressions.Not;
 import org.apache.doris.nereids.trees.expressions.NullSafeEqual;
 import org.apache.doris.nereids.trees.expressions.Or;
 import org.apache.doris.nereids.trees.expressions.OrderExpression;
+import org.apache.doris.nereids.trees.expressions.Placeholder;
 import org.apache.doris.nereids.trees.expressions.Properties;
 import org.apache.doris.nereids.trees.expressions.Regexp;
 import org.apache.doris.nereids.trees.expressions.ScalarSubquery;
@@ -487,6 +488,16 @@ import java.util.stream.Collectors;
 public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> {
     private final boolean forCreateView;
 
+    // Sort the parameters with token position to keep the order with original 
placeholders
+    // in prepared statement.Otherwise, the order maybe broken
+    private final Map<Token, Placeholder> tokenPosToParameters = 
Maps.newTreeMap((pos1, pos2) -> {
+        int line = pos1.getLine() - pos2.getLine();
+        if (line != 0) {
+            return line;
+        }
+        return pos1.getCharPositionInLine() - pos2.getCharPositionInLine();
+    });
+
     public LogicalPlanBuilder() {
         forCreateView = false;
     }
@@ -1003,6 +1014,9 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
             }
             logicalPlans.add(Pair.of(
                     ParserUtils.withOrigin(ctx, () -> (LogicalPlan) 
visit(statement)), statementContext));
+            List<Placeholder> params = new 
ArrayList<>(tokenPosToParameters.values());
+            statementContext.setPlaceholders(params);
+            tokenPosToParameters.clear();
         }
         return logicalPlans;
     }
@@ -2313,6 +2327,13 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         return new VarcharLiteral(s, strLength);
     }
 
+    @Override
+    public Expression visitPlaceholder(DorisParser.PlaceholderContext ctx) {
+        Placeholder parameter = new 
Placeholder(ConnectContext.get().getStatementContext().getNextPlaceholderId());
+        tokenPosToParameters.put(ctx.start, parameter);
+        return parameter;
+    }
+
     /**
      * cast all items to same types.
      * TODO remove this function after we refactor type coercion.
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
index 691e4aca1a3..0f4641cc425 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java
@@ -56,6 +56,7 @@ import org.apache.doris.nereids.trees.expressions.ListQuery;
 import org.apache.doris.nereids.trees.expressions.Match;
 import org.apache.doris.nereids.trees.expressions.NamedExpression;
 import org.apache.doris.nereids.trees.expressions.Not;
+import org.apache.doris.nereids.trees.expressions.Placeholder;
 import org.apache.doris.nereids.trees.expressions.Slot;
 import org.apache.doris.nereids.trees.expressions.SlotReference;
 import org.apache.doris.nereids.trees.expressions.TimestampArithmetic;
@@ -541,6 +542,13 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
         return expr;
     }
 
+    @Override
+    public Expression visitPlaceholder(Placeholder placeholder, 
ExpressionRewriteContext context) {
+        Expression realExpr = context.cascadesContext.getStatementContext()
+                    
.getIdToPlaceholderRealExpr().get(placeholder.getPlaceholderId());
+        return visit(realExpr, context);
+    }
+
     @Override
     public Expression visitComparisonPredicate(ComparisonPredicate cp, 
ExpressionRewriteContext context) {
         Expression left = cp.left().accept(this, context);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Placeholder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Placeholder.java
new file mode 100644
index 00000000000..9ae054d82a6
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Placeholder.java
@@ -0,0 +1,78 @@
+// 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;
+
+import org.apache.doris.catalog.MysqlColType;
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
+import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.trees.plans.PlaceholderId;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.NullType;
+
+import java.util.Optional;
+
+/**
+ * Placeholder for prepared statement
+ */
+public class Placeholder extends Expression implements LeafExpression {
+    private final PlaceholderId placeholderId;
+    private final Optional<MysqlColType> mysqlColType;
+
+    public Placeholder(PlaceholderId placeholderId) {
+        this.placeholderId = placeholderId;
+        this.mysqlColType = Optional.empty();
+    }
+
+    public Placeholder(PlaceholderId placeholderId, MysqlColType mysqlColType) 
{
+        this.placeholderId = placeholderId;
+        this.mysqlColType = Optional.of(mysqlColType);
+    }
+
+    public PlaceholderId getPlaceholderId() {
+        return placeholderId;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitPlaceholder(this, context);
+    }
+
+    @Override
+    public boolean nullable() {
+        return true;
+    }
+
+    @Override
+    public String toSql() {
+        return "?";
+    }
+
+    @Override
+    public DataType getDataType() throws UnboundException {
+        return NullType.INSTANCE;
+    }
+
+    public Placeholder withNewMysqlColType(MysqlColType mysqlColType) {
+        return new Placeholder(getPlaceholderId(), mysqlColType);
+    }
+
+    public MysqlColType getMysqlColType() {
+        return mysqlColType.get();
+    }
+}
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 c3369fc2838..9c1096799ba 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
@@ -19,8 +19,10 @@ package org.apache.doris.nereids.trees.expressions.literal;
 
 import org.apache.doris.analysis.BoolLiteral;
 import org.apache.doris.analysis.LiteralExpr;
+import org.apache.doris.catalog.MysqlColType;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.common.Config;
+import org.apache.doris.mysql.MysqlProto;
 import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.exceptions.UnboundException;
 import org.apache.doris.nereids.trees.expressions.Expression;
@@ -28,6 +30,7 @@ import 
org.apache.doris.nereids.trees.expressions.shape.LeafExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.CharType;
 import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.DateTimeType;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.types.DecimalV2Type;
 import org.apache.doris.nereids.types.DecimalV3Type;
@@ -40,6 +43,7 @@ import com.google.common.collect.ImmutableList;
 
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
@@ -396,4 +400,169 @@ public abstract class Literal extends Expression 
implements LeafExpression, Comp
         }
         return false;
     }
+
+    /**
+    ** get paramter length, port from  mysql get_param_length
+    **/
+    public static int getParmLen(ByteBuffer data) {
+        int maxLen = data.remaining();
+        if (maxLen < 1) {
+            return 0;
+        }
+        // get and advance 1 byte
+        int len = MysqlProto.readInt1(data);
+        if (len == 252) {
+            if (maxLen < 3) {
+                return 0;
+            }
+            // get and advance 2 bytes
+            return MysqlProto.readInt2(data);
+        } else if (len == 253) {
+            if (maxLen < 4) {
+                return 0;
+            }
+            // get and advance 3 bytes
+            return MysqlProto.readInt3(data);
+        } else if (len == 254) {
+            /*
+            In our client-server protocol all numbers bigger than 2^24
+            stored as 8 bytes with uint8korr. Here we always know that
+            parameter length is less than 2^4 so we don't look at the second
+            4 bytes. But still we need to obey the protocol hence 9 in the
+            assignment below.
+            */
+            if (maxLen < 9) {
+                return 0;
+            }
+            len = MysqlProto.readInt4(data);
+            MysqlProto.readFixedString(data, 4);
+            return len;
+        } else if (len == 255) {
+            return 0;
+        } else {
+            return len;
+        }
+    }
+
+    /**
+     * Retrieves a Literal object based on the MySQL type and the data 
provided.
+     *
+     * @param mysqlType the MySQL type identifier
+     * @param data      the ByteBuffer containing the data
+     * @return a Literal object corresponding to the MySQL type
+     * @throws AnalysisException if the MySQL type is unsupported or if data 
conversion fails
+     * @link  <a 
href="https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_binary_resultset.html";>...</a>.
+     */
+    public static Literal getLiteralByMysqlType(MysqlColType mysqlType, 
ByteBuffer data) throws AnalysisException {
+        switch (mysqlType) {
+            case MYSQL_TYPE_TINY:
+                return new TinyIntLiteral(data.get());
+            case MYSQL_TYPE_SHORT:
+                return new SmallIntLiteral((short) data.getChar());
+            case MYSQL_TYPE_LONG:
+                return new IntegerLiteral(data.getInt());
+            case MYSQL_TYPE_LONGLONG:
+                return new BigIntLiteral(data.getLong());
+            case MYSQL_TYPE_FLOAT:
+                return new FloatLiteral(data.getFloat());
+            case MYSQL_TYPE_DOUBLE:
+                return new DoubleLiteral(data.getDouble());
+            case MYSQL_TYPE_DECIMAL:
+            case MYSQL_TYPE_NEWDECIMAL:
+                return handleDecimalLiteral(data);
+            case MYSQL_TYPE_DATE:
+                return handleDateLiteral(data);
+            case MYSQL_TYPE_DATETIME:
+            case MYSQL_TYPE_TIMESTAMP:
+            case MYSQL_TYPE_TIMESTAMP2:
+                return handleDateTimeLiteral(data);
+            case MYSQL_TYPE_STRING:
+            case MYSQL_TYPE_VARSTRING:
+                return handleStringLiteral(data);
+            case MYSQL_TYPE_VARCHAR:
+                return handleVarcharLiteral(data);
+            default:
+                throw new AnalysisException("Unsupported MySQL type: " + 
mysqlType);
+        }
+    }
+
+    private static Literal handleDecimalLiteral(ByteBuffer data) throws 
AnalysisException {
+        int len = getParmLen(data);
+        byte[] bytes = new byte[len];
+        data.get(bytes);
+        try {
+            String value = new String(bytes);
+            BigDecimal v = new BigDecimal(value);
+            if (Config.enable_decimal_conversion) {
+                return new DecimalV3Literal(v);
+            }
+            return new DecimalLiteral(v);
+        } catch (NumberFormatException e) {
+            throw new AnalysisException("Invalid decimal literal", e);
+        }
+    }
+
+    private static Literal handleDateLiteral(ByteBuffer data) {
+        int len = getParmLen(data);
+        if (len >= 4) {
+            int year = (int) data.getChar();
+            int month = (int) data.get();
+            int day = (int) data.get();
+            if (Config.enable_date_conversion) {
+                return new DateV2Literal(year, month, day);
+            }
+            return new DateLiteral(year, month, day);
+        } else {
+            if (Config.enable_date_conversion) {
+                return new DateV2Literal(0, 1, 1);
+            }
+            return new DateLiteral(0, 1, 1);
+        }
+    }
+
+    private static Literal handleDateTimeLiteral(ByteBuffer data) {
+        int len = getParmLen(data);
+        if (len >= 4) {
+            int year = (int) data.getChar();
+            int month = (int) data.get();
+            int day = (int) data.get();
+            int hour = 0;
+            int minute = 0;
+            int second = 0;
+            int microsecond = 0;
+            if (len > 4) {
+                hour = (int) data.get();
+                minute = (int) data.get();
+                second = (int) data.get();
+            }
+            if (len > 7) {
+                microsecond = data.getInt();
+            }
+            if (Config.enable_date_conversion) {
+                return new DateTimeV2Literal(year, month, day, hour, minute, 
second, microsecond);
+            }
+            return new DateTimeLiteral(DateTimeType.INSTANCE, year, month, 
day, hour, minute, second, microsecond);
+        } else {
+            if (Config.enable_date_conversion) {
+                return new DateTimeV2Literal(0, 1, 1, 0, 0, 0);
+            }
+            return new DateTimeLiteral(0, 1, 1, 0, 0, 0);
+        }
+    }
+
+    private static Literal handleStringLiteral(ByteBuffer data) {
+        int strLen = getParmLen(data);
+        strLen = Math.min(strLen, data.remaining());
+        byte[] bytes = new byte[strLen];
+        data.get(bytes);
+        return new StringLiteral(new String(bytes));
+    }
+
+    private static Literal handleVarcharLiteral(ByteBuffer data) {
+        int strLen = getParmLen(data);
+        strLen = Math.min(strLen, data.remaining());
+        byte[] bytes = new byte[strLen];
+        data.get(bytes);
+        return new VarcharLiteral(new String(bytes));
+    }
 }
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 feea6cfe7d5..294e96319e5 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
@@ -69,6 +69,7 @@ import org.apache.doris.nereids.trees.expressions.Not;
 import org.apache.doris.nereids.trees.expressions.NullSafeEqual;
 import org.apache.doris.nereids.trees.expressions.Or;
 import org.apache.doris.nereids.trees.expressions.OrderExpression;
+import org.apache.doris.nereids.trees.expressions.Placeholder;
 import org.apache.doris.nereids.trees.expressions.Properties;
 import org.apache.doris.nereids.trees.expressions.ScalarSubquery;
 import org.apache.doris.nereids.trees.expressions.Slot;
@@ -505,6 +506,10 @@ public abstract class ExpressionVisitor<R, C>
         return visitMatch(matchPhraseEdge, context);
     }
 
+    public R visitPlaceholder(Placeholder placeholder, C context) {
+        return visit(placeholder, context);
+    }
+
     public R visitAny(Any any, C context) {
         return visit(any, context);
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlaceholderId.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlaceholderId.java
new file mode 100644
index 00000000000..f1d410100e1
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlaceholderId.java
@@ -0,0 +1,58 @@
+// 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.plans;
+
+import org.apache.doris.common.Id;
+import org.apache.doris.common.IdGenerator;
+
+/**
+ * placeholder id for prepared statement parameters
+ */
+public class PlaceholderId extends Id<PlaceholderId> {
+
+    public PlaceholderId(int id) {
+        super(id);
+    }
+
+    /**
+     * Should be only called by {@link 
org.apache.doris.nereids.StatementContext}.
+     */
+    public static IdGenerator<PlaceholderId> createGenerator() {
+        return new IdGenerator<PlaceholderId>() {
+            @Override
+            public PlaceholderId getNextId() {
+                return new PlaceholderId(nextId++);
+            }
+        };
+    }
+
+    @Override
+    public String toString() {
+        return "PlaceholderId#" + id;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return super.equals(obj);
+    }
+
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
index 71a7c24c9b6..3c10fe3e5ca 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java
@@ -156,5 +156,8 @@ public enum PlanType {
     CREATE_VIEW_COMMAND,
     ALTER_VIEW_COMMAND,
     UNSUPPORTED_COMMAND,
-    CREATE_TABLE_LIKE_COMMAND
+    CREATE_TABLE_LIKE_COMMAND,
+
+    PREPARED_COMMAND,
+    EXECUTE_COMMAND
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteCommand.java
new file mode 100644
index 00000000000..b098f883647
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteCommand.java
@@ -0,0 +1,83 @@
+// 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.plans.commands;
+
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.PreparedStatementContext;
+import org.apache.doris.qe.StmtExecutor;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Prepared Statement
+ */
+public class ExecuteCommand extends Command {
+    private final String stmtName;
+    private final PrepareCommand prepareCommand;
+    private final StatementContext statementContext;
+
+    public ExecuteCommand(String stmtName, PrepareCommand prepareCommand, 
StatementContext statementContext) {
+        super(PlanType.EXECUTE_COMMAND);
+        this.stmtName = stmtName;
+        this.prepareCommand = prepareCommand;
+        this.statementContext = statementContext;
+    }
+
+    public String getStmtName() {
+        return stmtName;
+    }
+
+    @Override
+    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+        return visitor.visit(this, context);
+    }
+
+    @Override
+    public void run(ConnectContext ctx, StmtExecutor executor) throws 
Exception {
+        PreparedStatementContext preparedStmtCtx = 
ctx.getPreparedStementContext(stmtName);
+        if (null == preparedStmtCtx) {
+            throw new AnalysisException(
+                    "prepare statement " + stmtName + " not found,  maybe 
expired");
+        }
+        PrepareCommand prepareCommand = (PrepareCommand) 
preparedStmtCtx.command;
+        LogicalPlanAdapter planAdapter = new 
LogicalPlanAdapter(prepareCommand.getLogicalPlan(), executor.getContext()
+                .getStatementContext());
+        executor.setParsedStmt(planAdapter);
+        // execute real statement
+        executor.execute();
+    }
+
+    /**
+     * return the sql representation contains real expr instead of placeholders
+     */
+    public String toSql() {
+        // maybe slow
+        List<Expression> realValueExpr = 
prepareCommand.getPlaceholders().stream()
+                .map(placeholder -> 
statementContext.getIdToPlaceholderRealExpr().get(placeholder.getPlaceholderId()))
+                .collect(Collectors.toList());
+        return "EXECUTE `" + stmtName + "`"
+                + 
realValueExpr.stream().map(Expression::toSql).collect(Collectors.joining(", ", 
" USING ", ""));
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/PrepareCommand.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/PrepareCommand.java
new file mode 100644
index 00000000000..958fc470283
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/PrepareCommand.java
@@ -0,0 +1,120 @@
+// 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.plans.commands;
+
+import org.apache.doris.mysql.MysqlCommand;
+import org.apache.doris.nereids.trees.expressions.Placeholder;
+import org.apache.doris.nereids.trees.plans.PlanType;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.OriginStatement;
+import org.apache.doris.qe.PreparedStatementContext;
+import org.apache.doris.qe.StmtExecutor;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Prepared Statement
+ */
+public class PrepareCommand extends Command {
+    private static final Logger LOG = LogManager.getLogger(StmtExecutor.class);
+
+    private final List<Placeholder> placeholders = new ArrayList<>();
+    private final LogicalPlan logicalPlan;
+
+    private final String name;
+
+    private final OriginStatement originalStmt;
+
+    /**
+     * constructor
+     * @param name the statement name which represents statement id for 
prepared statement
+     * @param plan the inner statement
+     * @param placeholders the parameters for this prepared statement
+     * @param originalStmt original statement from StmtExecutor
+     */
+    public PrepareCommand(String name, LogicalPlan plan, List<Placeholder> 
placeholders,
+                OriginStatement originalStmt) {
+        super(PlanType.PREPARED_COMMAND);
+        this.logicalPlan = plan;
+        this.placeholders.addAll(placeholders);
+        this.name = name;
+        this.originalStmt = originalStmt;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<Placeholder> getPlaceholders() {
+        return placeholders;
+    }
+
+    public int placeholderCount() {
+        return placeholders.size();
+    }
+
+    public LogicalPlan getLogicalPlan() {
+        return logicalPlan;
+    }
+
+    public OriginStatement getOriginalStmt() {
+        return originalStmt;
+    }
+
+    /**
+     * return the labels of parameters
+     */
+    public List<String> getLabels() {
+        List<String> labels = new ArrayList<>();
+        for (Placeholder parameter : placeholders) {
+            labels.add("$" + parameter.getPlaceholderId().asInt());
+        }
+        return labels;
+    }
+
+    // register prepared statement with attached statement id
+    @Override
+    public void run(ConnectContext ctx, StmtExecutor executor) throws 
Exception {
+        List<String> labels = getLabels();
+        // register prepareStmt
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("add prepared statement {}, isBinaryProtocol {}",
+                    name, ctx.getCommand() == MysqlCommand.COM_STMT_PREPARE);
+        }
+        ctx.addPreparedStatementContext(name,
+                new PreparedStatementContext(this, ctx, 
ctx.getStatementContext(), name));
+        if (ctx.getCommand() == MysqlCommand.COM_STMT_PREPARE) {
+            executor.sendStmtPrepareOK((int) ctx.getStmtId(), labels);
+        }
+    }
+
+    @Override
+    public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
+        return visitor.visit(this, context);
+    }
+
+    public PrepareCommand withPlaceholders(List<Placeholder> placeholders) {
+        return new PrepareCommand(this.name, this.logicalPlan, placeholders, 
this.originalStmt);
+    }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
index cea86554121..ef6d3b9ea7c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java
@@ -246,8 +246,13 @@ public class ConnectContext {
     }
 
     private StatementContext statementContext;
+
+    // legacy planner
     private Map<String, PrepareStmtContext> preparedStmtCtxs = 
Maps.newHashMap();
 
+    // new planner
+    private Map<String, PreparedStatementContext> preparedStatementContextMap 
= Maps.newHashMap();
+
     private List<TableIf> tables = null;
 
     private Map<String, ColumnStatistic> totalColumnStatisticMap = new 
HashMap<>();
@@ -384,6 +389,10 @@ public class ConnectContext {
         this.preparedStmtCtxs.put(stmtName, ctx);
     }
 
+    public void addPreparedStatementContext(String stmtName, 
PreparedStatementContext ctx) {
+        this.preparedStatementContextMap.put(stmtName, ctx);
+    }
+
     public void removePrepareStmt(String stmtName) {
         this.preparedStmtCtxs.remove(stmtName);
     }
@@ -392,6 +401,10 @@ public class ConnectContext {
         return this.preparedStmtCtxs.get(stmtName);
     }
 
+    public PreparedStatementContext getPreparedStementContext(String stmtName) 
{
+        return this.preparedStatementContextMap.get(stmtName);
+    }
+
     public List<TableIf> getTables() {
         return tables;
     }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java
index c81c24eb575..d54b708e818 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java
@@ -222,8 +222,11 @@ public abstract class ConnectProcessor {
         Exception nereidsParseException = null;
         long parseSqlStartTime = System.currentTimeMillis();
         List<StatementBase> cachedStmts = null;
-        // Nereids do not support prepare and execute now, so forbid prepare 
command, only process query command
-        if (mysqlCommand == MysqlCommand.COM_QUERY && 
sessionVariable.isEnableNereidsPlanner()) {
+        // Currently we add a config to decide whether using PREPARED/EXECUTE 
command for nereids
+        // TODO: after implemented full prepared, we could remove this flag
+        boolean nereidsUseServerPrep = 
sessionVariable.enableServeSidePreparedStatement
+                        || mysqlCommand == MysqlCommand.COM_QUERY;
+        if (nereidsUseServerPrep && sessionVariable.isEnableNereidsPlanner()) {
             if (wantToParseSqlFromSqlCache) {
                 cachedStmts = parseFromSqlCache(originStmt);
                 if (cachedStmts != null) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java
index d117eeba949..6c1507722d7 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java
@@ -18,15 +18,24 @@
 package org.apache.doris.qe;
 
 import org.apache.doris.analysis.ExecuteStmt;
-import org.apache.doris.analysis.InsertStmt;
 import org.apache.doris.analysis.LiteralExpr;
 import org.apache.doris.analysis.NullLiteral;
+import org.apache.doris.analysis.PrepareStmt;
 import org.apache.doris.analysis.QueryStmt;
+import org.apache.doris.analysis.StatementBase;
+import org.apache.doris.catalog.MysqlColType;
 import org.apache.doris.common.ErrorCode;
 import org.apache.doris.common.ErrorReport;
 import org.apache.doris.mysql.MysqlChannel;
 import org.apache.doris.mysql.MysqlCommand;
 import org.apache.doris.mysql.MysqlProto;
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
+import org.apache.doris.nereids.trees.expressions.Placeholder;
+import org.apache.doris.nereids.trees.expressions.literal.Literal;
+import org.apache.doris.nereids.trees.plans.PlaceholderId;
+import org.apache.doris.nereids.trees.plans.commands.ExecuteCommand;
+import org.apache.doris.nereids.trees.plans.commands.PrepareCommand;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -81,35 +90,12 @@ public class MysqlConnectProcessor extends ConnectProcessor 
{
         }
     }
 
-    // process COM_EXECUTE, parse binary row data
-    // 
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html
-    private void handleExecute() {
-        // debugPacket();
-        packetBuf = packetBuf.order(ByteOrder.LITTLE_ENDIAN);
-        // parse stmt_id, flags, params
-        int stmtId = packetBuf.getInt();
-        // flag
-        packetBuf.get();
-        // iteration_count always 1,
-        packetBuf.getInt();
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("execute prepared statement {}", stmtId);
-        }
-        PrepareStmtContext prepareCtx = 
ctx.getPreparedStmt(String.valueOf(stmtId));
-        if (prepareCtx == null) {
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("No such statement in context, stmtId:{}", stmtId);
-            }
-            ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR,
-                    "msg: Not supported such prepared statement");
-            return;
-        }
-        ctx.setStartTime();
-        if (prepareCtx.stmt.getInnerStmt() instanceof QueryStmt) {
+    private void handleExecute(PrepareStmt prepareStmt, long stmtId) {
+        if (prepareStmt.getInnerStmt() instanceof QueryStmt) {
             ctx.getState().setIsQuery(true);
         }
-        prepareCtx.stmt.setIsPrepared();
-        int paramCount = prepareCtx.stmt.getParmCount();
+        prepareStmt.setIsPrepared();
+        int paramCount = prepareStmt.getParmCount();
         LOG.debug("execute prepared statement {}, paramCount {}", stmtId, 
paramCount);
         // null bitmap
         String stmtStr = "";
@@ -124,7 +110,7 @@ public class MysqlConnectProcessor extends ConnectProcessor 
{
                     for (int i = 0; i < paramCount; ++i) {
                         int typeCode = packetBuf.getChar();
                         LOG.debug("code {}", typeCode);
-                        
prepareCtx.stmt.placeholders().get(i).setTypeCode(typeCode);
+                        
prepareStmt.placeholders().get(i).setTypeCode(typeCode);
                     }
                 }
                 // parse param data
@@ -133,7 +119,7 @@ public class MysqlConnectProcessor extends ConnectProcessor 
{
                         realValueExprs.add(new NullLiteral());
                         continue;
                     }
-                    LiteralExpr l = 
prepareCtx.stmt.placeholders().get(i).createLiteralFromType();
+                    LiteralExpr l = 
prepareStmt.placeholders().get(i).createLiteralFromType();
                     l.setupParamFromBinary(packetBuf);
                     realValueExprs.add(l);
                 }
@@ -149,7 +135,7 @@ public class MysqlConnectProcessor extends ConnectProcessor 
{
             ctx.setExecutor(executor);
             executor.execute();
             PrepareStmtContext preparedStmtContext = 
ConnectContext.get().getPreparedStmt(String.valueOf(stmtId));
-            if (preparedStmtContext != null && 
!(preparedStmtContext.stmt.getInnerStmt() instanceof InsertStmt)) {
+            if (preparedStmtContext != null) {
                 stmtStr = executeStmt.toSql();
             }
         } catch (Throwable e)  {
@@ -159,8 +145,101 @@ public class MysqlConnectProcessor extends 
ConnectProcessor {
             ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR,
                     e.getClass().getSimpleName() + ", msg: " + e.getMessage());
         }
-        if (!stmtStr.isEmpty()) {
-            auditAfterExec(stmtStr, prepareCtx.stmt.getInnerStmt(), null, 
false);
+        auditAfterExec(stmtStr, executor.getParsedStmt(), 
executor.getQueryStatisticsForAuditLog(), true);
+    }
+
+    private void handleExecute(PrepareCommand prepareCommand, long stmtId, 
PreparedStatementContext prepCtx) {
+        int paramCount = prepareCommand.placeholderCount();
+        LOG.debug("execute prepared statement {}, paramCount {}", stmtId, 
paramCount);
+        // null bitmap
+        String stmtStr = "";
+        try {
+            StatementContext statementContext = prepCtx.statementContext;
+            if (paramCount > 0) {
+                byte[] nullbitmapData = new byte[(paramCount + 7) / 8];
+                packetBuf.get(nullbitmapData);
+                // new_params_bind_flag
+                if ((int) packetBuf.get() != 0) {
+                    List<Placeholder> typedPlaceholders = new ArrayList<>();
+                    // parse params's types
+                    for (int i = 0; i < paramCount; ++i) {
+                        int typeCode = packetBuf.getChar();
+                        LOG.debug("code {}", typeCode);
+                        // assign type to placeholders
+                        typedPlaceholders.add(
+                                prepareCommand.getPlaceholders().get(i)
+                                        
.withNewMysqlColType(MysqlColType.fromCode(typeCode)));
+                    }
+                    // rewrite with new prepared statment with type info in 
placeholders
+                    prepCtx.command = 
prepareCommand.withPlaceholders(typedPlaceholders);
+                    prepareCommand = (PrepareCommand) prepCtx.command;
+                }
+                // parse param data
+                for (int i = 0; i < paramCount; ++i) {
+                    PlaceholderId exprId = 
prepareCommand.getPlaceholders().get(i).getPlaceholderId();
+                    if (isNull(nullbitmapData, i)) {
+                        
statementContext.getIdToPlaceholderRealExpr().put(exprId,
+                                    new 
org.apache.doris.nereids.trees.expressions.literal.NullLiteral());
+                        continue;
+                    }
+                    MysqlColType type = 
prepareCommand.getPlaceholders().get(i).getMysqlColType();
+                    Literal l = Literal.getLiteralByMysqlType(type, packetBuf);
+                    statementContext.getIdToPlaceholderRealExpr().put(exprId, 
l);
+                }
+            }
+            ExecuteCommand executeStmt = new 
ExecuteCommand(String.valueOf(stmtId), prepareCommand, statementContext);
+            // TODO set real origin statement
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("executeStmt {}", executeStmt);
+            }
+            StatementBase stmt = new LogicalPlanAdapter(executeStmt, 
statementContext);
+            stmt.setOrigStmt(prepareCommand.getOriginalStmt());
+            executor = new StmtExecutor(ctx, stmt);
+            ctx.setExecutor(executor);
+            executor.execute();
+            stmtStr = executeStmt.toSql();
+        } catch (Throwable e)  {
+            // Catch all throwable.
+            // If reach here, maybe doris bug.
+            LOG.warn("Process one query failed because unknown reason: ", e);
+            ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR,
+                    e.getClass().getSimpleName() + ", msg: " + e.getMessage());
+        }
+        auditAfterExec(stmtStr, executor.getParsedStmt(), 
executor.getQueryStatisticsForAuditLog(), true);
+    }
+
+    // process COM_EXECUTE, parse binary row data
+    // 
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html
+    private void handleExecute() {
+        // debugPacket();
+        packetBuf = packetBuf.order(ByteOrder.LITTLE_ENDIAN);
+        // parse stmt_id, flags, params
+        int stmtId = packetBuf.getInt();
+        // flag
+        packetBuf.get();
+        // iteration_count always 1,
+        packetBuf.getInt();
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("execute prepared statement {}", stmtId);
+        }
+
+        PrepareStmtContext prepareCtx = 
ctx.getPreparedStmt(String.valueOf(stmtId));
+        ctx.setStartTime();
+        if (prepareCtx != null) {
+            // get from lagacy planner context, to be removed
+            handleExecute((PrepareStmt) prepareCtx.stmt, stmtId);
+        } else {
+            // nererids
+            PreparedStatementContext preparedStatementContext = 
ctx.getPreparedStementContext(String.valueOf(stmtId));
+            if (preparedStatementContext == null) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("No such statement in context, stmtId:{}", 
stmtId);
+                }
+                ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR,
+                        "msg: Not supported such prepared statement");
+                return;
+            }
+            handleExecute(preparedStatementContext.command, stmtId, 
preparedStatementContext);
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java
index 400f5047b53..3c3707e8b66 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java
@@ -18,17 +18,15 @@
 package org.apache.doris.qe;
 
 import org.apache.doris.analysis.Analyzer;
-import org.apache.doris.analysis.PrepareStmt;
-import org.apache.doris.planner.OriginalPlanner;
+import org.apache.doris.analysis.StatementBase;
 import org.apache.doris.planner.Planner;
 
-import com.google.common.base.Preconditions;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 public class PrepareStmtContext {
     private static final Logger LOG = 
LogManager.getLogger(PrepareStmtContext.class);
-    public PrepareStmt stmt;
+    public StatementBase stmt;
     public ConnectContext ctx;
     public Planner planner;
     public Analyzer analyzer;
@@ -37,15 +35,11 @@ public class PrepareStmtContext {
     // Timestamp in millisecond last command starts at
     protected volatile long startTime;
 
-    public PrepareStmtContext(PrepareStmt stmt, ConnectContext ctx, Planner 
planner,
+    public PrepareStmtContext(StatementBase stmt, ConnectContext ctx, Planner 
planner,
                                     Analyzer analyzer, String stmtString) {
         this.stmt = stmt;
         this.ctx = ctx;
         this.planner = planner;
-        // Only support OriginalPlanner for now
-        if (planner != null) {
-            Preconditions.checkState(planner instanceof OriginalPlanner);
-        }
         this.analyzer = analyzer;
         this.stmtString = stmtString;
     }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/PreparedStatementContext.java
similarity index 56%
copy from fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java
copy to 
fe/fe-core/src/main/java/org/apache/doris/qe/PreparedStatementContext.java
index 400f5047b53..d54b2e5291c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/PrepareStmtContext.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/PreparedStatementContext.java
@@ -17,36 +17,23 @@
 
 package org.apache.doris.qe;
 
-import org.apache.doris.analysis.Analyzer;
-import org.apache.doris.analysis.PrepareStmt;
-import org.apache.doris.planner.OriginalPlanner;
-import org.apache.doris.planner.Planner;
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.trees.plans.commands.PrepareCommand;
 
-import com.google.common.base.Preconditions;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-public class PrepareStmtContext {
-    private static final Logger LOG = 
LogManager.getLogger(PrepareStmtContext.class);
-    public PrepareStmt stmt;
+public class PreparedStatementContext {
+    public PrepareCommand command;
     public ConnectContext ctx;
-    public Planner planner;
-    public Analyzer analyzer;
+    StatementContext statementContext;
     public String stmtString;
 
     // Timestamp in millisecond last command starts at
     protected volatile long startTime;
 
-    public PrepareStmtContext(PrepareStmt stmt, ConnectContext ctx, Planner 
planner,
-                                    Analyzer analyzer, String stmtString) {
-        this.stmt = stmt;
+    public PreparedStatementContext(PrepareCommand command,
+                ConnectContext ctx, StatementContext statementContext, String 
stmtString) {
+        this.command = command;
         this.ctx = ctx;
-        this.planner = planner;
-        // Only support OriginalPlanner for now
-        if (planner != null) {
-            Preconditions.checkState(planner instanceof OriginalPlanner);
-        }
-        this.analyzer = analyzer;
+        this.statementContext = statementContext;
         this.stmtString = stmtString;
     }
 
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java 
b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
index ba6d200847c..a0ba53f1fee 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java
@@ -141,6 +141,7 @@ import 
org.apache.doris.nereids.trees.plans.commands.Command;
 import org.apache.doris.nereids.trees.plans.commands.CreateTableCommand;
 import org.apache.doris.nereids.trees.plans.commands.Forward;
 import org.apache.doris.nereids.trees.plans.commands.NotAllowFallback;
+import org.apache.doris.nereids.trees.plans.commands.PrepareCommand;
 import 
org.apache.doris.nereids.trees.plans.commands.insert.BatchInsertIntoTableCommand;
 import 
org.apache.doris.nereids.trees.plans.commands.insert.InsertIntoTableCommand;
 import 
org.apache.doris.nereids.trees.plans.commands.insert.InsertOverwriteTableCommand;
@@ -261,7 +262,7 @@ public class StmtExecutor {
     private Data.PQueryStatistics.Builder statisticsForAuditLog;
     private boolean isCached;
     private String stmtName;
-    private PrepareStmt prepareStmt = null;
+    private StatementBase prepareStmt = null;
     private String mysqlLoadId;
     // Distinguish from prepare and execute command
     private boolean isExecuteStmt = false;
@@ -644,6 +645,14 @@ public class StmtExecutor {
                 "Nereids only process LogicalPlanAdapter, but parsedStmt is " 
+ parsedStmt.getClass().getName());
         context.getState().setNereids(true);
         LogicalPlan logicalPlan = ((LogicalPlanAdapter) 
parsedStmt).getLogicalPlan();
+        if (context.getCommand() == MysqlCommand.COM_STMT_PREPARE) {
+            if (isForwardToMaster()) {
+                throw new UserException("Forward master command is not 
supported for prepare statement");
+            }
+            logicalPlan = new 
PrepareCommand(String.valueOf(context.getStmtId()),
+                    logicalPlan, statementContext.getPlaceholders(), 
originStmt);
+
+        }
         // when we in transaction mode, we only support insert into command 
and transaction command
         if (context.isTxnModel()) {
             if (!(logicalPlan instanceof BatchInsertIntoTableCommand
@@ -1075,8 +1084,8 @@ public class StmtExecutor {
                 throw new UserException("Could not execute, since `" + 
execStmt.getName() + "` not exist");
             }
             // parsedStmt may already by set when constructing this 
StmtExecutor();
-            preparedStmtCtx.stmt.asignValues(execStmt.getArgs());
-            parsedStmt = preparedStmtCtx.stmt.getInnerStmt();
+            ((PrepareStmt) 
preparedStmtCtx.stmt).asignValues(execStmt.getArgs());
+            parsedStmt = ((PrepareStmt) preparedStmtCtx.stmt).getInnerStmt();
             planner = preparedStmtCtx.planner;
             analyzer = preparedStmtCtx.analyzer;
             prepareStmt = preparedStmtCtx.stmt;
@@ -1084,7 +1093,7 @@ public class StmtExecutor {
                 LOG.debug("already prepared stmt: {}", 
preparedStmtCtx.stmtString);
             }
             isExecuteStmt = true;
-            if (!preparedStmtCtx.stmt.needReAnalyze()) {
+            if (!((PrepareStmt) preparedStmtCtx.stmt).needReAnalyze()) {
                 // Return directly to bypass analyze and plan
                 return;
             }
@@ -1106,15 +1115,15 @@ public class StmtExecutor {
         if (parsedStmt instanceof PrepareStmt || context.getCommand() == 
MysqlCommand.COM_STMT_PREPARE) {
             if (context.getCommand() == MysqlCommand.COM_STMT_PREPARE) {
                 prepareStmt = new PrepareStmt(parsedStmt,
-                        String.valueOf(context.getEnv().getNextStmtId()));
+                        String.valueOf(String.valueOf(context.getStmtId())));
             } else {
                 prepareStmt = (PrepareStmt) parsedStmt;
             }
-            prepareStmt.setContext(context);
+            ((PrepareStmt) prepareStmt).setContext(context);
             prepareStmt.analyze(analyzer);
             // Need analyze inner statement
-            parsedStmt = prepareStmt.getInnerStmt();
-            if (prepareStmt.getPreparedType() == 
PrepareStmt.PreparedType.STATEMENT) {
+            parsedStmt =  ((PrepareStmt) prepareStmt).getInnerStmt();
+            if (((PrepareStmt) prepareStmt).getPreparedType() == 
PrepareStmt.PreparedType.STATEMENT) {
                 // Skip analyze, do it lazy
                 return;
             }
@@ -1207,15 +1216,15 @@ public class StmtExecutor {
             }
         }
         if (preparedStmtReanalyzed
-                && preparedStmtCtx.stmt.getPreparedType() == 
PrepareStmt.PreparedType.FULL_PREPARED) {
-            prepareStmt.asignValues(execStmt.getArgs());
+                && ((PrepareStmt) preparedStmtCtx.stmt).getPreparedType() == 
PrepareStmt.PreparedType.FULL_PREPARED) {
+            ((PrepareStmt) prepareStmt).asignValues(execStmt.getArgs());
             if (LOG.isDebugEnabled()) {
                 LOG.debug("update planner and analyzer after prepared 
statement reanalyzed");
             }
             preparedStmtCtx.planner = planner;
             preparedStmtCtx.analyzer = analyzer;
             Preconditions.checkNotNull(preparedStmtCtx.stmt);
-            preparedStmtCtx.analyzer.setPrepareStmt(preparedStmtCtx.stmt);
+            preparedStmtCtx.analyzer.setPrepareStmt(((PrepareStmt) 
preparedStmtCtx.stmt));
         }
     }
 
@@ -1273,9 +1282,9 @@ public class StmtExecutor {
             }
         }
         if (prepareStmt != null) {
-            analyzer.setPrepareStmt(prepareStmt);
-            if (execStmt != null && prepareStmt.getPreparedType() != 
PreparedType.FULL_PREPARED) {
-                prepareStmt.asignValues(execStmt.getArgs());
+            analyzer.setPrepareStmt(((PrepareStmt) prepareStmt));
+            if (execStmt != null &&  ((PrepareStmt) 
prepareStmt).getPreparedType() != PreparedType.FULL_PREPARED) {
+                ((PrepareStmt) prepareStmt).asignValues(execStmt.getArgs());
             }
         }
         parsedStmt.analyze(analyzer);
@@ -1342,9 +1351,10 @@ public class StmtExecutor {
                 // query re-analyze
                 parsedStmt.reset();
                 if (prepareStmt != null) {
-                    analyzer.setPrepareStmt(prepareStmt);
-                    if (execStmt != null && prepareStmt.getPreparedType() != 
PreparedType.FULL_PREPARED) {
-                        prepareStmt.asignValues(execStmt.getArgs());
+                    analyzer.setPrepareStmt(((PrepareStmt) prepareStmt));
+                    if (execStmt != null
+                            && ((PrepareStmt) prepareStmt).getPreparedType() 
!= PreparedType.FULL_PREPARED) {
+                        ((PrepareStmt) 
prepareStmt).asignValues(execStmt.getArgs());
                     }
                 }
                 analyzer.setReAnalyze(true);
@@ -2373,16 +2383,17 @@ public class StmtExecutor {
     }
 
     private void handlePrepareStmt() throws Exception {
+        List<String> labels = ((PrepareStmt) 
prepareStmt).getColLabelsOfPlaceHolders();
         // register prepareStmt
         if (LOG.isDebugEnabled()) {
             LOG.debug("add prepared statement {}, isBinaryProtocol {}",
-                        prepareStmt.getName(), context.getCommand() == 
MysqlCommand.COM_STMT_PREPARE);
+                    prepareStmt.toSql(), context.getCommand() == 
MysqlCommand.COM_STMT_PREPARE);
         }
-        context.addPreparedStmt(prepareStmt.getName(),
+        context.addPreparedStmt(String.valueOf(context.getStmtId()),
                 new PrepareStmtContext(prepareStmt,
-                            context, planner, analyzer, 
prepareStmt.getName()));
+                            context, planner, analyzer, 
String.valueOf(context.getStmtId())));
         if (context.getCommand() == MysqlCommand.COM_STMT_PREPARE) {
-            sendStmtPrepareOK();
+            sendStmtPrepareOK((int) context.getStmtId(), labels);
         }
     }
 
@@ -2427,19 +2438,19 @@ public class StmtExecutor {
         return exprs.stream().map(e -> 
PrimitiveType.STRING).collect(Collectors.toList());
     }
 
-    private void sendStmtPrepareOK() throws IOException {
+    public void sendStmtPrepareOK(int stmtId, List<String> labels) throws 
IOException {
         Preconditions.checkState(context.getConnectType() == 
ConnectType.MYSQL);
         // 
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_prepare.html#sect_protocol_com_stmt_prepare_response
         serializer.reset();
         // 0x00 OK
         serializer.writeInt1(0);
         // statement_id
-        serializer.writeInt4(Integer.valueOf(prepareStmt.getName()));
+        serializer.writeInt4(stmtId);
         // num_columns
         int numColumns = 0;
         serializer.writeInt2(numColumns);
         // num_params
-        int numParams = prepareStmt.getColLabelsOfPlaceHolders().size();
+        int numParams = labels.size();
         serializer.writeInt2(numParams);
         // reserved_1
         serializer.writeInt1(0);
@@ -2448,14 +2459,12 @@ public class StmtExecutor {
             // send field one by one
             // TODO use real type instead of string, for JDBC client it's ok
             // but for other client, type should be correct
-            List<PrimitiveType> types = 
exprToStringType(prepareStmt.getPlaceHolderExprList());
-            List<String> colNames = prepareStmt.getColLabelsOfPlaceHolders();
-            if (LOG.isDebugEnabled()) {
-                LOG.debug("sendFields {}, {}", colNames, types);
-            }
+            // List<PrimitiveType> types = exprToStringType(labels);
+            List<String> colNames = labels;
             for (int i = 0; i < colNames.size(); ++i) {
                 serializer.reset();
-                serializer.writeField(colNames.get(i), 
Type.fromPrimitiveType(types.get(i)));
+                // serializer.writeField(colNames.get(i), 
Type.fromPrimitiveType(types.get(i)));
+                serializer.writeField(colNames.get(i), Type.STRING);
                 
context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer());
             }
             serializer.reset();
@@ -2484,14 +2493,15 @@ public class StmtExecutor {
         // send field one by one
         for (int i = 0; i < colNames.size(); ++i) {
             serializer.reset();
-            if (prepareStmt != null && isExecuteStmt) {
+            if (prepareStmt != null && prepareStmt instanceof  PrepareStmt
+                    && context.getCommand() == MysqlCommand.COM_STMT_EXECUTE) {
                 // Using PreparedStatment pre serializedField to avoid 
serialize each time
                 // we send a field
-                byte[] serializedField = 
prepareStmt.getSerializedField(colNames.get(i));
+                byte[] serializedField = ((PrepareStmt) 
prepareStmt).getSerializedField(colNames.get(i));
                 if (serializedField == null) {
                     serializer.writeField(colNames.get(i), types.get(i));
                     serializedField = serializer.toArray();
-                    prepareStmt.setSerializedField(colNames.get(i), 
serializedField);
+                    ((PrepareStmt) 
prepareStmt).setSerializedField(colNames.get(i), serializedField);
                 }
                 
context.getMysqlChannel().sendOnePacket(ByteBuffer.wrap(serializedField));
             } else {
diff --git a/regression-test/data/prepared_stmt_p0/prepared_stmt.out 
b/regression-test/data/prepared_stmt_p0/prepared_stmt.out
index 396ee931683..bd01fbf2c59 100644
--- a/regression-test/data/prepared_stmt_p0/prepared_stmt.out
+++ b/regression-test/data/prepared_stmt_p0/prepared_stmt.out
@@ -1,30 +1,30 @@
 -- This file is automatically generated. You should know what you did if you 
want to edit this
 -- !sql --
-1231   119291.110000000        ddd     laooq   \N      2020-01-01 12:36:38     
\N      1022-01-01      ["2022-01-01 11:30:38", "2022-01-01 11:30:38", 
"2022-01-01 11:30:38"]
-1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01 12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
-1233   1.392932911     yyy     laooq   2024-01-02      2020-01-01 12:36:38     
52.862  3022-01-01      ["2024-01-01 11:30:38", "2024-01-01 11:30:38", 
"2024-01-01 11:30:38"]
-1234   12919291.129191137      xxddd   laooq   2025-01-02      2020-01-01 
12:36:38     552.872 4022-01-01      ["2025-01-01 11:30:38", "2025-01-01 
11:30:38", "2025-01-01 11:30:38"]
-1235   991129292901.111380000  dd      \N      2120-01-02      2020-01-01 
12:36:38     652.692 5022-01-01      []
-1236   100320.111390000        laa    ddd      laooq   2220-01-02      
2020-01-01 12:36:38     2.7692  6022-01-01      [null]
-1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01 12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
+1231   119291.110000000        ddd     laooq   \N      2020-01-01T12:36:38     
\N      1022-01-01      ["2022-01-01 11:30:38", "2022-01-01 11:30:38", 
"2022-01-01 11:30:38"]
+1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01T12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
+1233   1.392932911     yyy     laooq   2024-01-02      2020-01-01T12:36:38     
52.862  3022-01-01      ["2024-01-01 11:30:38", "2024-01-01 11:30:38", 
"2024-01-01 11:30:38"]
+1234   12919291.129191137      xxddd   laooq   2025-01-02      
2020-01-01T12:36:38     552.872 4022-01-01      ["2025-01-01 11:30:38", 
"2025-01-01 11:30:38", "2025-01-01 11:30:38"]
+1235   991129292901.111380000  dd      \N      2120-01-02      
2020-01-01T12:36:38     652.692 5022-01-01      []
+1236   100320.111390000        laa    ddd      laooq   2220-01-02      
2020-01-01T12:36:38     2.7692  6022-01-01      [null]
+1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
 
 -- !sql --
-1231   119291.110000000        ddd     laooq   \N      2020-01-01 12:36:38     
\N      1022-01-01      ["2022-01-01 11:30:38", "2022-01-01 11:30:38", 
"2022-01-01 11:30:38"]
-1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01 12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
-1233   1.392932911     yyy     laooq   2024-01-02      2020-01-01 12:36:38     
52.862  3022-01-01      ["2024-01-01 11:30:38", "2024-01-01 11:30:38", 
"2024-01-01 11:30:38"]
-1234   12919291.129191137      xxddd   laooq   2025-01-02      2020-01-01 
12:36:38     552.872 4022-01-01      ["2025-01-01 11:30:38", "2025-01-01 
11:30:38", "2025-01-01 11:30:38"]
-1235   991129292901.111380000  dd      \N      2120-01-02      2020-01-01 
12:36:38     652.692 5022-01-01      []
-1236   100320.111390000        laa    ddd      laooq   2220-01-02      
2020-01-01 12:36:38     2.7692  6022-01-01      [null]
-1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01 12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
+1231   119291.110000000        ddd     laooq   \N      2020-01-01T12:36:38     
\N      1022-01-01      ["2022-01-01 11:30:38", "2022-01-01 11:30:38", 
"2022-01-01 11:30:38"]
+1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01T12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
+1233   1.392932911     yyy     laooq   2024-01-02      2020-01-01T12:36:38     
52.862  3022-01-01      ["2024-01-01 11:30:38", "2024-01-01 11:30:38", 
"2024-01-01 11:30:38"]
+1234   12919291.129191137      xxddd   laooq   2025-01-02      
2020-01-01T12:36:38     552.872 4022-01-01      ["2025-01-01 11:30:38", 
"2025-01-01 11:30:38", "2025-01-01 11:30:38"]
+1235   991129292901.111380000  dd      \N      2120-01-02      
2020-01-01T12:36:38     652.692 5022-01-01      []
+1236   100320.111390000        laa    ddd      laooq   2220-01-02      
2020-01-01T12:36:38     2.7692  6022-01-01      [null]
+1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
 
 -- !select0 --
-1231   119291.110000000        ddd     laooq   \N      2020-01-01 12:36:38     
\N      1022-01-01      ["2022-01-01 11:30:38", "2022-01-01 11:30:38", 
"2022-01-01 11:30:38"]
+1231   119291.110000000        ddd     laooq   \N      2020-01-01T12:36:38     
\N      1022-01-01      ["2022-01-01 11:30:38", "2022-01-01 11:30:38", 
"2022-01-01 11:30:38"]
 
 -- !select0 --
-1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01 12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
+1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01T12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
 
 -- !select0 --
-1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01 12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
+1232   12222.991211350 xxx     laooq   2023-01-02      2020-01-01T12:36:38     
522.762 2022-01-01      ["2023-01-01 11:30:38", "2023-01-01 11:30:38"]
 
 -- !select1 --
 646464 xxxx---
@@ -36,13 +36,13 @@
 787878 yyyy---
 
 -- !select2 --
-1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01 12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"] 1237    
120939.111300000        a    ddd        laooq   2030-01-02      2020-01-01 
12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
+1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"] 1237    
120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
 
 -- !select2 --
-1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01 12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"] 1237    
120939.111300000        a    ddd        laooq   2030-01-02      2020-01-01 
12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
+1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"] 1237    
120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
 
 -- !select2 --
-1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01 12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"] 1237    
120939.111300000        a    ddd        laooq   2030-01-02      2020-01-01 
12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
+1237   120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"] 1237    
120939.111300000        a    ddd        laooq   2030-01-02      
2020-01-01T12:36:38     22.822  7022-01-01      ["2025-01-01 11:30:38"]
 
 -- !select3 --
 1      1       user1   30      1234    12345
@@ -53,3 +53,16 @@
 -- !select5 --
 1
 
+-- !select6 --
+2      1       user1   \N      1234.1111       xxxlalala
+
+-- !select7 --
+2      1       user1   \N      1111111 1111111
+
+-- !select8 --
+1
+1
+
+-- !select9 --
+2
+
diff --git a/regression-test/suites/point_query_p0/test_point_query.groovy 
b/regression-test/suites/point_query_p0/test_point_query.groovy
index 28a4eaa2a59..c1a785612fe 100644
--- a/regression-test/suites/point_query_p0/test_point_query.groovy
+++ b/regression-test/suites/point_query_p0/test_point_query.groovy
@@ -17,7 +17,7 @@
 
 import java.math.BigDecimal;
 
-suite("test_point_query") {
+suite("test_point_query", "nonConcurrent") {
     def backendId_to_backendIP = [:]
     def backendId_to_backendHttpPort = [:]
     getBackendIpHttpPort(backendId_to_backendIP, backendId_to_backendHttpPort);
@@ -30,7 +30,7 @@ suite("test_point_query") {
     try {
         set_be_config.call("disable_storage_row_cache", "false")
         // nereids do not support point query now
-        sql """set enable_nereids_planner=false"""
+        sql """set global enable_nereids_planner=false"""
 
         def user = context.config.jdbcUser
         def password = context.config.jdbcPassword
@@ -274,5 +274,6 @@ suite("test_point_query") {
         sql "select  /*+ SET_VAR(enable_nereids_planner=false) */  
substr(RPTNO,2,5) from test_ODS_EBA_LLREPORT where  RPTNO = '567890'"
     } finally {
         set_be_config.call("disable_storage_row_cache", "true")
+        sql """set global enable_nereids_planner=true"""
     }
 } 
\ No newline at end of file
diff --git a/regression-test/suites/prepared_stmt_p0/prepared_stmt.groovy 
b/regression-test/suites/prepared_stmt_p0/prepared_stmt.groovy
index 46f8d7629ca..f4c13fd04b0 100644
--- a/regression-test/suites/prepared_stmt_p0/prepared_stmt.groovy
+++ b/regression-test/suites/prepared_stmt_p0/prepared_stmt.groovy
@@ -22,158 +22,117 @@ suite("test_prepared_stmt", "nonConcurrent") {
     def user = context.config.jdbcUser
     def password = context.config.jdbcPassword
     def url = context.config.jdbcUrl + "&useServerPrepStmts=true"
-    // def url = context.config.jdbcUrl
-    def result1 = connect(user=user, password=password, url=url) {
     sql "set global enable_server_side_prepared_statement = true"
-    def insert_prepared = { stmt, k1 , k2, k3, k4, k5, k6, k7, k8, k9 ->
-        java.text.SimpleDateFormat formater = new 
java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        if (k1 == null) {
-            stmt.setNull(1, java.sql.Types.INTEGER);
-        } else {
-            stmt.setInt(1, k1)
-        }
-        if (k2 == null) {
-            stmt.setNull(2, java.sql.Types.DECIMAL);
-        } else {
-            stmt.setBigDecimal(2, k2)
-        }
-        if (k3 == null) {
-            stmt.setNull(3, java.sql.Types.VARCHAR);    
-        } else {
-            stmt.setString(3, k3)
-        }
-        if (k4 == null) {
-            stmt.setNull(4, java.sql.Types.VARCHAR);     
-        } else {
-            stmt.setString(4, k4)
-        }
-        if (k5 == null) {
-            stmt.setNull(5, java.sql.Types.DATE);     
-        } else {
-            stmt.setDate(5, java.sql.Date.valueOf(k5))
-        }
-        if (k6 == null) {
-            stmt.setNull(6, java.sql.Types.TIMESTAMP);     
-        } else {
-            stmt.setTimestamp(6, new 
java.sql.Timestamp(formater.parse(k6).getTime()))
-        }
-        if (k7 == null) {
-            stmt.setNull(7, java.sql.Types.FLOAT);
-        } else {
-            stmt.setFloat(7, k7)
-        }
-        if (k8 == null) {
-            stmt.setNull(8, java.sql.Types.DATE);
-        } else {
-            stmt.setTimestamp(8, new 
java.sql.Timestamp(formater.parse(k8).getTime()))
-        }
-        if (k9 == null) {
-            stmt.setNull(9, java.sql.Types.VARCHAR);
-        } else {
-            stmt.setString(9, k9)
-        }
-        exec stmt
-    }
-
-    sql """DROP TABLE IF EXISTS ${tableName} """
-    sql """
-        CREATE TABLE IF NOT EXISTS ${tableName} (
-                `k1` int(11) NULL COMMENT "",
-                `k2` decimalv3(27, 9) NULL COMMENT "",
-                `k3` varchar(30) NULL COMMENT "",
-                `k4` varchar(30) NULL COMMENT "",
-                `k5` date NULL COMMENT "",
-                `k6` datetime NULL COMMENT "",
-                `k7` float NULL COMMENT "",
-                `k8` datev2 NULL COMMENT "",
-                `k9` array<datetime> NULL COMMENT ""
-              ) ENGINE=OLAP
-              DUPLICATE KEY(`k1`, `k2`, `k3`)
-              DISTRIBUTED BY HASH(`k1`, k2, k3) BUCKETS 1
-              PROPERTIES (
-              "replication_allocation" = "tag.location.default: 1",
-              "light_schema_change" = "true",
-              "storage_format" = "V2"
-              )
-          """
-      
-    // def insert_stmt = prepareStatement """ INSERT INTO ${tableName} 
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?) """
-    // assertEquals(insert_stmt.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
-    // insert_prepared insert_stmt, 1231, 119291.11, "ddd", "laooq", null, 
"2020-01-01 12:36:38", null, "1022-01-01 11:30:38", "[2022-01-01 11:30:38, 
2022-01-01 11:30:38, 2022-01-01 11:30:38]"
-    // insert_prepared insert_stmt, 1232, 12222.99121135, "xxx", "laooq", 
"2023-01-02", "2020-01-01 12:36:38", 522.762, "2022-01-01 11:30:38", 
"[2023-01-01 11:30:38, 2023-01-01 11:30:38]"
-    // insert_prepared insert_stmt, 1233, 1.392932911136, "yyy", "laooq", 
"2024-01-02", "2020-01-01 12:36:38", 52.862, "3022-01-01 11:30:38", 
"[2024-01-01 11:30:38, 2024-01-01 11:30:38, 2024-01-01 11:30:38]"
-    // insert_prepared insert_stmt, 1234, 12919291.129191137, "xxddd", 
"laooq", "2025-01-02", "2020-01-01 12:36:38", 552.872, "4022-01-01 11:30:38", 
"[2025-01-01 11:30:38, 2025-01-01 11:30:38, 2025-01-01 11:30:38]"
-    // insert_prepared insert_stmt, 1235, 991129292901.11138, "dd", null, 
"2120-01-02", "2020-01-01 12:36:38", 652.692, "5022-01-01 11:30:38", "[]"
-    // insert_prepared insert_stmt, 1236, 100320.11139, "laa    ddd", "laooq", 
"2220-01-02", "2020-01-01 12:36:38", 2.7692, "6022-01-01 11:30:38", "[null]"
-    // insert_prepared insert_stmt, 1237, 120939.11130, "a    ddd", "laooq", 
"2030-01-02", "2020-01-01 12:36:38", 22.822, "7022-01-01 11:30:38", 
"[2025-01-01 11:30:38]"
+    def result1 = connect(user=user, password=password, url=url) {
+        sql """DROP TABLE IF EXISTS ${tableName} """
+        sql """
+             CREATE TABLE IF NOT EXISTS ${tableName} (
+                     `k1` int(11) NULL COMMENT "",
+                     `k2` decimalv3(27, 9) NULL COMMENT "",
+                     `k3` varchar(30) NULL COMMENT "",
+                     `k4` varchar(30) NULL COMMENT "",
+                     `k5` date NULL COMMENT "",
+                     `k6` datetime NULL COMMENT "",
+                     `k7` float NULL COMMENT "",
+                     `k8` datev2 NULL COMMENT "",
+                     `k9` array<datetime> NULL COMMENT ""
+                   ) ENGINE=OLAP
+                   DUPLICATE KEY(`k1`, `k2`, `k3`)
+                   DISTRIBUTED BY HASH(`k1`, k2, k3) BUCKETS 1
+                   PROPERTIES (
+                   "replication_allocation" = "tag.location.default: 1",
+                   "light_schema_change" = "true",
+                   "storage_format" = "V2"
+                   )
+               """
 
-    sql """ INSERT INTO ${tableName} VALUES(1231, 119291.11, "ddd", "laooq", 
null, "2020-01-01 12:36:38", null, "1022-01-01 11:30:38", "[2022-01-01 
11:30:38, 2022-01-01 11:30:38, 2022-01-01 11:30:38]") """
-    sql """ INSERT INTO ${tableName} VALUES(1232, 12222.99121135, "xxx", 
"laooq", "2023-01-02", "2020-01-01 12:36:38", 522.762, "2022-01-01 11:30:38", 
"[2023-01-01 11:30:38, 2023-01-01 11:30:38]") """
-    sql """ INSERT INTO ${tableName} VALUES(1233, 1.392932911136, "yyy", 
"laooq", "2024-01-02", "2020-01-01 12:36:38", 52.862, "3022-01-01 11:30:38", 
"[2024-01-01 11:30:38, 2024-01-01 11:30:38, 2024-01-01 11:30:38]") """
-    sql """ INSERT INTO ${tableName} VALUES(1234, 12919291.129191137, "xxddd", 
"laooq", "2025-01-02", "2020-01-01 12:36:38", 552.872, "4022-01-01 11:30:38", 
"[2025-01-01 11:30:38, 2025-01-01 11:30:38, 2025-01-01 11:30:38]") """
-    sql """ INSERT INTO ${tableName} VALUES(1235, 991129292901.11138, "dd", 
null, "2120-01-02", "2020-01-01 12:36:38", 652.692, "5022-01-01 11:30:38", 
"[]") """
-    sql """ INSERT INTO ${tableName} VALUES(1236, 100320.11139, "laa    ddd", 
"laooq", "2220-01-02", "2020-01-01 12:36:38", 2.7692, "6022-01-01 11:30:38", 
"[null]") """
-    sql """ INSERT INTO ${tableName} VALUES(1237, 120939.11130, "a    ddd", 
"laooq", "2030-01-02", "2020-01-01 12:36:38", 22.822, "7022-01-01 11:30:38", 
"[2025-01-01 11:30:38]") """
-    sql """sync"""
+        sql """ INSERT INTO ${tableName} VALUES(1231, 119291.11, "ddd", 
"laooq", null, "2020-01-01 12:36:38", null, "1022-01-01 11:30:38", "[2022-01-01 
11:30:38, 2022-01-01 11:30:38, 2022-01-01 11:30:38]") """
+        sql """ INSERT INTO ${tableName} VALUES(1232, 12222.99121135, "xxx", 
"laooq", "2023-01-02", "2020-01-01 12:36:38", 522.762, "2022-01-01 11:30:38", 
"[2023-01-01 11:30:38, 2023-01-01 11:30:38]") """
+        sql """ INSERT INTO ${tableName} VALUES(1233, 1.392932911136, "yyy", 
"laooq", "2024-01-02", "2020-01-01 12:36:38", 52.862, "3022-01-01 11:30:38", 
"[2024-01-01 11:30:38, 2024-01-01 11:30:38, 2024-01-01 11:30:38]") """
+        sql """ INSERT INTO ${tableName} VALUES(1234, 12919291.129191137, 
"xxddd", "laooq", "2025-01-02", "2020-01-01 12:36:38", 552.872, "4022-01-01 
11:30:38", "[2025-01-01 11:30:38, 2025-01-01 11:30:38, 2025-01-01 11:30:38]") 
"""
+        sql """ INSERT INTO ${tableName} VALUES(1235, 991129292901.11138, 
"dd", null, "2120-01-02", "2020-01-01 12:36:38", 652.692, "5022-01-01 
11:30:38", "[]") """
+        sql """ INSERT INTO ${tableName} VALUES(1236, 100320.11139, "laa    
ddd", "laooq", "2220-01-02", "2020-01-01 12:36:38", 2.7692, "6022-01-01 
11:30:38", "[null]") """
+        sql """ INSERT INTO ${tableName} VALUES(1237, 120939.11130, "a    
ddd", "laooq", "2030-01-02", "2020-01-01 12:36:38", 22.822, "7022-01-01 
11:30:38", "[2025-01-01 11:30:38]") """
+        sql """sync"""
 
-    qt_sql """select * from  ${tableName} order by 1, 2, 3"""
-    qt_sql """select * from  ${tableName} order by 1, 2, 3"""
+        qt_sql """select * from  ${tableName} order by 1, 2, 3"""
+        qt_sql """select * from  ${tableName} order by 1, 2, 3"""
 
-    def stmt_read = prepareStatement "select * from ${tableName} where k1 = ? 
order by k1"
-    assertEquals(stmt_read.class, com.mysql.cj.jdbc.ServerPreparedStatement);
-    stmt_read.setInt(1, 1231)
-    qe_select0 stmt_read
-    stmt_read.setInt(1, 1232)
-    qe_select0 stmt_read
-    qe_select0 stmt_read
-    def stmt_read1 = prepareStatement "select hex(k3), ? from ${tableName} 
where k1 = ? order by 1"
-    assertEquals(stmt_read1.class, com.mysql.cj.jdbc.ServerPreparedStatement);
-    stmt_read1.setString(1, "xxxx---")
-    stmt_read1.setInt(2, 1231)
-    qe_select1 stmt_read1
-    stmt_read1.setString(1, "yyyy---")
-    stmt_read1.setInt(2, 1232)
-    qe_select1 stmt_read1
-    qe_select1 stmt_read1
-      def stmt_read2 = prepareStatement "select * from ${tableName} as t1 join 
${tableName} as t2 on t1.`k1` = t2.`k1` where t1.`k1` >= ? and t1.`k2` >= ? and 
size(t1.`k9`) > ? order by 1, 2, 3"
-      assertEquals(stmt_read2.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
-      stmt_read2.setInt(1, 1237)
-      stmt_read2.setBigDecimal(2, new BigDecimal("120939.11130"))
-      stmt_read2.setInt(3, 0)
-      qe_select2 stmt_read2
-      qe_select2 stmt_read2
-      qe_select2 stmt_read2
+        def stmt_read = prepareStatement "select * from ${tableName} where k1 
= ? order by k1"
+        assertEquals(stmt_read.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        stmt_read.setInt(1, 1231)
+        qe_select0 stmt_read
+        stmt_read.setInt(1, 1232)
+        qe_select0 stmt_read
+        qe_select0 stmt_read
+        def stmt_read1 = prepareStatement "select hex(k3), ? \n from 
${tableName} where k1 = ? order by 1"
+        assertEquals(stmt_read1.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        stmt_read1.setString(1, "xxxx---")
+        stmt_read1.setInt(2, 1231)
+        qe_select1 stmt_read1
+        stmt_read1.setString(1, "yyyy---")
+        stmt_read1.setInt(2, 1232)
+        qe_select1 stmt_read1
+        qe_select1 stmt_read1
+        def stmt_read2 = prepareStatement "select * from ${tableName} as t1 
join ${tableName} as t2 on t1.`k1` = t2.`k1` where t1.`k1` >= ? and t1.`k2` >= 
? and size(t1.`k9`) > ? order by 1, 2, 3"
+        assertEquals(stmt_read2.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        stmt_read2.setInt(1, 1237)
+        stmt_read2.setBigDecimal(2, new BigDecimal("120939.11130"))
+        stmt_read2.setInt(3, 0)
+        qe_select2 stmt_read2
+        qe_select2 stmt_read2
+        qe_select2 stmt_read2
 
-      sql "DROP TABLE IF EXISTS mytable1"
-      sql """
-        CREATE TABLE mytable1
-        (
-            siteid INT DEFAULT '10',
-            citycode SMALLINT,
-            username VARCHAR(32) DEFAULT '',
-            pv BIGINT SUM DEFAULT '0'
-        )
-        AGGREGATE KEY(siteid, citycode, username)
-        DISTRIBUTED BY HASH(siteid) BUCKETS 10
-        PROPERTIES("replication_num" = "1");
-        """
+        sql "DROP TABLE IF EXISTS mytable1"
+        sql """
+          CREATE TABLE mytable1
+          (
+              siteid INT DEFAULT '10',
+              citycode SMALLINT,
+              username VARCHAR(32) DEFAULT '',
+              pv BIGINT SUM DEFAULT '0'
+          )
+          AGGREGATE KEY(siteid, citycode, username)
+          DISTRIBUTED BY HASH(siteid) BUCKETS 10
+          PROPERTIES("replication_num" = "1");
+          """
     
-     sql """insert into mytable1 values(1,1,'user1',10);"""
-     sql """insert into mytable1 values(1,1,'user1',10);"""
-     sql """insert into mytable1 values(1,1,'user1',10);"""
-     sql "sync"
-     stmt_read = prepareStatement "SELECT *, ? FROM (select *, ? from mytable1 
where citycode = ?) AS `SpotfireCustomQuery1` WHERE 1 = 1"
-     stmt_read.setInt(1, 12345)
-     stmt_read.setInt(2, 1234)
-     stmt_read.setInt(3, 1)
-     qe_select3 stmt_read
+        sql """insert into mytable1 values(1,1,'user1',10);"""
+        sql """insert into mytable1 values(1,1,'user1',10);"""
+        sql """insert into mytable1 values(1,1,'user1',10);"""
+        sql "sync"
+        stmt_read = prepareStatement "SELECT *, ? FROM (select *, ? from 
mytable1 where citycode = ?) AS `SpotfireCustomQuery1` WHERE 1 = 1"
+        assertEquals(stmt_read.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        stmt_read.setInt(1, 12345)
+        stmt_read.setInt(2, 1234)
+        stmt_read.setInt(3, 1)
+        qe_select3 stmt_read
+
+        stmt_read = prepareStatement "SELECT 10"
+        assertEquals(stmt_read.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        qe_select4 stmt_read
+        stmt_read = prepareStatement "SELECT 1"
+        assertEquals(stmt_read.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        qe_select5 stmt_read
+
+        sql """insert into mytable1 values(2,1,'user1',null);"""
+        stmt_read = prepareStatement "SELECT *, ? FROM (select *, ? from 
mytable1 where pv is null) AS `SpotfireCustomQuery1` WHERE 1 = 1"
+        assertEquals(stmt_read.class, 
com.mysql.cj.jdbc.ServerPreparedStatement);
+        stmt_read.setString(1, "xxxlalala")
+        stmt_read.setDouble(2, 1234.1111)
+        qe_select6 stmt_read
+        stmt_read.setString(1, "1111111")
+        stmt_read.setString(2, "1111111")
+        qe_select7 stmt_read
+
+        stmt_read = prepareStatement "SELECT COUNT() from mytable1 WHERE 
citycode = ? GROUP BY siteid"
+        stmt_read.setString(1, "1")
+        qe_select8 stmt_read
 
-     stmt_read = prepareStatement "SELECT 10"
-     assertEquals(stmt_read.class, com.mysql.cj.jdbc.ServerPreparedStatement);
-     qe_select4 stmt_read
-     stmt_read = prepareStatement "SELECT 1"
-     assertEquals(stmt_read.class, com.mysql.cj.jdbc.ServerPreparedStatement);
-     qe_select5 stmt_read
+        stmt_read = prepareStatement "SELECT COUNT() from mytable1 WHERE 
citycode = ? GROUP BY ?"
+        stmt_read.setString(1, "1")
+        stmt_read.setString(2, "1")
+        qe_select9 stmt_read
     }
 
     sql "set global enable_server_side_prepared_statement = false"


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

Reply via email to