morrySnow commented on code in PR #35318:
URL: https://github.com/apache/doris/pull/35318#discussion_r1615523932


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/PlaceholderExpr.java:
##########
@@ -0,0 +1,82 @@
+// 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.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DataType;
+
+/**
+ * Placeholder for prepared statement
+ */
+public class PlaceholderExpr extends Expression {
+    private final int exprId;

Review Comment:
   use a IdGenenator to generate id, refer to 
`org.apache.doris.nereids.trees.plans.RelationId`, 
`org.apache.doris.nereids.StatementContext#relationIdGenerator` and 
`org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator#newRelationId`



##########
fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4:
##########
@@ -392,6 +392,7 @@ ORDER: 'ORDER';
 OUTER: 'OUTER';
 OUTFILE: 'OUTFILE';
 OVER: 'OVER';
+PLACEHOLDER: '?';

Review Comment:
   Newly added keywords, please sort in alphabetical order.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/PlaceholderExpr.java:
##########
@@ -0,0 +1,82 @@
+// 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.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DataType;
+
+/**
+ * Placeholder for prepared statement
+ */
+public class PlaceholderExpr extends Expression {

Review Comment:
   rename it `PlaceholderExpr` -> `Placeholder`



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java:
##########
@@ -396,4 +400,153 @@ public boolean isZero() {
         }
         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
+     */
+    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 DecimalLiteral 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);
+            return new DecimalLiteral(v);
+        } catch (NumberFormatException e) {
+            throw new AnalysisException("Invalid decimal literal", e);
+        }
+    }
+
+    private static DateLiteral 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();
+            return new DateLiteral(year, month, day);
+        } else {
+            return new DateLiteral(0, 1, 1);
+        }
+    }
+
+    private static DateTimeLiteral 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();
+            }
+            return new DateTimeLiteral(DateTimeType.INSTANCE, year, month, 
day, hour, minute, second, microsecond);

Review Comment:
   should use `DateTimeV2Literal` if Config.enable_date_conversion == true



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java:
##########
@@ -396,4 +400,153 @@ public boolean isZero() {
         }
         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.

Review Comment:
   add mysql doc link in java doc



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/PlaceholderExpr.java:
##########
@@ -0,0 +1,82 @@
+// 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.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DataType;
+
+/**
+ * Placeholder for prepared statement
+ */
+public class PlaceholderExpr extends Expression {
+    private final int exprId;
+    private Expression expr;
+
+    private MysqlColType mysqlTypeCode;
+
+    public PlaceholderExpr(int exprId) {
+        this.exprId = exprId;
+    }
+
+    protected PlaceholderExpr(int exprId, Expression expr) {
+        this.exprId = exprId;
+        this.expr = expr;
+    }
+
+    public Expression getExpr() {
+        return expr;
+    }
+
+    public int getExprId() {
+        return exprId;
+    }
+
+    public void setExpr(Expression expr) {
+        this.expr = expr;
+    }
+
+    @Override
+    public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
+        return visitor.visitPlaceholderExpr(this, context);
+    }
+
+    public void setTypeCode(int mysqlTypeCode) {
+        this.mysqlTypeCode = MysqlColType.fromCode(mysqlTypeCode);

Review Comment:
   all nereids data structure of plan should be immutable. btw not see 
`mysqlTypeCode` in this class



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/ExecuteCommand.java:
##########
@@ -0,0 +1,71 @@
+// 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.analysis.RedirectStatus;
+import org.apache.doris.nereids.StatementContext;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.qe.OriginStatement;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Prepared Statement
+ */
+public class ExecuteCommand extends LogicalPlanAdapter {

Review Comment:
   ExecuteCommand should extends Command



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/PreparedCommand.java:
##########
@@ -0,0 +1,111 @@
+// 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.analysis.RedirectStatus;
+import org.apache.doris.analysis.StatementBase;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.PlaceholderExpr;
+
+import com.google.common.base.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Prepared Statement
+ */
+public class PreparedCommand extends LogicalPlanAdapter {

Review Comment:
   PreparedCommand should extends Command



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java:
##########
@@ -396,4 +400,153 @@ public boolean isZero() {
         }
         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
+     */
+    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 DecimalLiteral 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);
+            return new DecimalLiteral(v);
+        } catch (NumberFormatException e) {
+            throw new AnalysisException("Invalid decimal literal", e);
+        }
+    }
+
+    private static DateLiteral 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();
+            return new DateLiteral(year, month, day);

Review Comment:
   should use `DateV2Literal` if Config.enable_date_conversion == true



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/PlaceholderExpr.java:
##########
@@ -0,0 +1,82 @@
+// 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.visitor.ExpressionVisitor;
+import org.apache.doris.nereids.types.DataType;
+
+/**
+ * Placeholder for prepared statement
+ */
+public class PlaceholderExpr extends Expression {
+    private final int exprId;
+    private Expression expr;

Review Comment:
   remove this, we can use StatementContext to store the mapping relationship 
between placeholders and actual expressions.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java:
##########
@@ -505,6 +506,10 @@ public R visitMatchPhraseEdge(MatchPhraseEdge 
matchPhraseEdge, C context) {
         return visitMatch(matchPhraseEdge, context);
     }
 
+    public R visitPlaceholderExpr(PlaceholderExpr placeholderExpr, C context) {
+        return null;

Review Comment:
   should not return null. return `visit(placeholderExpr, context)`



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/TinyIntLiteral.java:
##########
@@ -65,4 +65,5 @@ public int getIntValue() {
     public Number getNumber() {
         return value;
     }
+

Review Comment:
   remove this line



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java:
##########
@@ -396,4 +400,153 @@ public boolean isZero() {
         }
         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
+     */
+    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 DecimalLiteral 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);
+            return new DecimalLiteral(v);

Review Comment:
   should use DecimalV3Literal if enable_decimal_conversion == true



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/PreparedCommand.java:
##########
@@ -0,0 +1,111 @@
+// 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.analysis.RedirectStatus;
+import org.apache.doris.analysis.StatementBase;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.PlaceholderExpr;
+
+import com.google.common.base.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Prepared Statement
+ */
+public class PreparedCommand extends LogicalPlanAdapter {
+    protected List<PlaceholderExpr> params;
+    private final StatementBase inner;
+
+    private String stmtName;
+
+    public PreparedCommand(String name, StatementBase originStmt, 
List<PlaceholderExpr> placeholders) {
+        super(null, null);
+        this.inner = originStmt;
+        this.params = placeholders;
+        this.stmtName = name;
+    }
+
+    public String getName() {
+        return stmtName;
+    }
+
+    public void setName(String name) {
+        this.stmtName = name;
+    }
+
+    public List<PlaceholderExpr> params() {
+        return params;
+    }
+
+    public int getParamLen() {
+        if (params == null) {
+            return 0;
+        }
+        return params.size();
+    }
+
+    public void setParams(List<PlaceholderExpr> params) {
+        this.params = params;
+    }
+
+    public StatementBase getInnerStmt() {
+        return inner;
+    }
+
+    /**
+    *  assign real value to placeholders and return the assigned statement
+    */
+    public StatementBase assignValues(List<Expression> values) {

Review Comment:
   assignValues should be done with ExpressionRewriter to replace PlaceHolder 
by real Expression. u could use `ExpressionRewrite` with an exprssion rule 
(refer to `SimplifyCastRule`) to impl it easily. This rule should be execute 
before real analyze. so it should be put before any analye rules in `Analyzer`



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/PreparedCommand.java:
##########
@@ -0,0 +1,111 @@
+// 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.analysis.RedirectStatus;
+import org.apache.doris.analysis.StatementBase;
+import org.apache.doris.nereids.glue.LogicalPlanAdapter;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.PlaceholderExpr;
+
+import com.google.common.base.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Prepared Statement
+ */
+public class PreparedCommand extends LogicalPlanAdapter {
+    protected List<PlaceholderExpr> params;
+    private final StatementBase inner;

Review Comment:
   the inner should be LogicalPlan, not StatementBase



##########
fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java:
##########
@@ -124,7 +105,7 @@ private void handleExecute() {
                     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);

Review Comment:
   in nerieds all these info should be record into context mapping by 
PlaceHolderId, not PlaceHolder itself



##########
fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java:
##########
@@ -81,35 +85,12 @@ private void debugPacket() {
         }
     }
 
-    // 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) {

Review Comment:
   all prepare and execute code should be put into PrepareCommand#run and 
ExecuteCommand#run



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


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

Reply via email to