This is an automated email from the ASF dual-hosted git repository. xuyang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new a0201ac190c [bug](prepared statement) fix prepared statement throw exception when inserting null value (#36426) a0201ac190c is described below commit a0201ac190cfe35f7ac06dcd087439c8e8dc9ac6 Author: xy720 <22125576+xy...@users.noreply.github.com> AuthorDate: Thu Jun 20 11:31:25 2024 +0800 [bug](prepared statement) fix prepared statement throw exception when inserting null value (#36426) ## Proposed changes Issue Number: close #xxx When inserting a null value using jdbc prepared statement, Fe reports the following error: ``` 2024-06-18 00:01:41,381 WARN (mysql-nio-pool-0|287) [StmtExecutor.analyze():1336] Analyze failed. stmt[38, 857b9a4c512f48b5-89ee68afc32f1828] java.lang.IllegalStateException: null at com.google.common.base.Preconditions.checkState(Preconditions.java:496) ~[guava-32.1.2-jre.jar:?] at org.apache.doris.analysis.Analyzer.materializeSlots(Analyzer.java:2624) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.planner.SingleNodePlanner.createSingleNodePlan(SingleNodePlanner.java:178) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.planner.OriginalPlanner.createPlanFragments(OriginalPlanner.java:171) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.planner.OriginalPlanner.plan(OriginalPlanner.java:102) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.StmtExecutor.analyzeAndGenerateQueryPlan(StmtExecutor.java:1512) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.StmtExecutor.analyze(StmtExecutor.java:1298) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.StmtExecutor.executeByLegacy(StmtExecutor.java:930) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.StmtExecutor.execute(StmtExecutor.java:618) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.StmtExecutor.execute(StmtExecutor.java:536) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.MysqlConnectProcessor.handleExecute(MysqlConnectProcessor.java:137) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.MysqlConnectProcessor.handleExecute(MysqlConnectProcessor.java:231) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.MysqlConnectProcessor.dispatch(MysqlConnectProcessor.java:288) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.qe.MysqlConnectProcessor.processOnce(MysqlConnectProcessor.java:339) ~[doris-fe.jar:1.2-SNAPSHOT] at org.apache.doris.mysql.ReadListener.lambda$handleEvent$0(ReadListener.java:52) ~[doris-fe.jar:1.2-SNAPSHOT] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[?:?] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[?:?] at java.lang.Thread.run(Thread.java:840) ~[?:?] ``` <!--Describe your changes.--> --- .../org/apache/doris/analysis/PlaceHolderExpr.java | 19 ++++++++++++++----- .../java/org/apache/doris/analysis/PrepareStmt.java | 1 + .../main/java/org/apache/doris/planner/ScanNode.java | 4 +++- .../apache/doris/rewrite/RewriteInPredicateRule.java | 7 ++++++- regression-test/data/insert_p0/prepare_insert.out | 1 + .../suites/insert_p0/prepare_insert.groovy | 18 ++++++++++++++++-- 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/PlaceHolderExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/PlaceHolderExpr.java index ca0596258f6..50bea1c2d56 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/PlaceHolderExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/PlaceHolderExpr.java @@ -58,6 +58,20 @@ public class PlaceHolderExpr extends LiteralExpr { this.type = literal.getType(); } + public LiteralExpr getLiteral() { + return lExpr; + } + + @Override + protected void analysisDone() { + if (lExpr != null && !lExpr.isAnalyzed) { + lExpr.analysisDone(); + } + if (!isAnalyzed) { + super.analysisDone(); + } + } + public LiteralExpr createLiteralFromType() throws AnalysisException { Preconditions.checkState(mysqlTypeCode > 0); return LiteralExpr.getLiteralByMysqlType(mysqlTypeCode, isUnsigned()); @@ -134,11 +148,6 @@ public class PlaceHolderExpr extends LiteralExpr { return "?"; } - @Override - protected Expr uncheckedCastTo(Type targetType) throws AnalysisException { - return this.lExpr.uncheckedCastTo(targetType); - } - // Swaps the sign of numeric literals. // Throws for non-numeric literals. public void swapSign() throws NotImplementedException { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/PrepareStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/PrepareStmt.java index 90da98c14f4..1c7b5459979 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/PrepareStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/PrepareStmt.java @@ -268,6 +268,7 @@ public class PrepareStmt extends StatementBase { } for (int i = 0; i < values.size(); ++i) { inner.getPlaceHolders().get(i).setLiteral(values.get(i)); + inner.getPlaceHolders().get(i).analysisDone(); } if (!values.isEmpty()) { if (LOG.isDebugEnabled()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java index 9c896bd7504..342ec3c9149 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java @@ -29,6 +29,7 @@ import org.apache.doris.analysis.InPredicate; import org.apache.doris.analysis.IsNullPredicate; import org.apache.doris.analysis.LiteralExpr; import org.apache.doris.analysis.NullLiteral; +import org.apache.doris.analysis.PlaceHolderExpr; import org.apache.doris.analysis.PredicateUtils; import org.apache.doris.analysis.SlotDescriptor; import org.apache.doris.analysis.SlotId; @@ -407,7 +408,8 @@ public abstract class ScanNode extends PlanNode implements SplitGenerator { if (null == partitionColumnFilter) { partitionColumnFilter = new PartitionColumnFilter(); } - LiteralExpr literal = (LiteralExpr) slotBinding; + LiteralExpr literal = slotBinding instanceof PlaceHolderExpr + ? ((PlaceHolderExpr) slotBinding).getLiteral() : (LiteralExpr) slotBinding; BinaryPredicate.Operator op = binPredicate.getOp(); if (!binPredicate.slotIsLeft()) { op = op.commutative(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteInPredicateRule.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteInPredicateRule.java index c04ff432961..3541690d002 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteInPredicateRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/RewriteInPredicateRule.java @@ -23,6 +23,7 @@ import org.apache.doris.analysis.CastExpr; import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.InPredicate; import org.apache.doris.analysis.LiteralExpr; +import org.apache.doris.analysis.PlaceHolderExpr; import org.apache.doris.analysis.SlotRef; import org.apache.doris.analysis.Subquery; import org.apache.doris.catalog.Type; @@ -114,7 +115,11 @@ public class RewriteInPredicateRule implements ExprRewriteRule { // For example, 2.1 is converted to 2; // 3. childExpr is precisely converted to column type. For example, 2.0 is converted to 2. // In cases 1 and 2 above, childExpr should be discarded. - LiteralExpr newExpr = (LiteralExpr) childExpr.castTo(columnType); + Expr tmpExpr = childExpr.castTo(columnType); + if (tmpExpr instanceof CastExpr && tmpExpr.getChild(0) instanceof PlaceHolderExpr) { + tmpExpr = ((PlaceHolderExpr) tmpExpr.getChild(0)).getLiteral().castTo(columnType); + } + LiteralExpr newExpr = (LiteralExpr) tmpExpr; if (childExpr.compareLiteral(newExpr) == 0) { isCast = true; newInList.add(newExpr); diff --git a/regression-test/data/insert_p0/prepare_insert.out b/regression-test/data/insert_p0/prepare_insert.out index a84bd02040e..f535890c5b8 100644 --- a/regression-test/data/insert_p0/prepare_insert.out +++ b/regression-test/data/insert_p0/prepare_insert.out @@ -1,5 +1,6 @@ -- This file is automatically generated. You should know what you did if you want to edit this -- !sql -- +\N \N \N 1 a 90 2 ab 91 3 abc 92 diff --git a/regression-test/suites/insert_p0/prepare_insert.groovy b/regression-test/suites/insert_p0/prepare_insert.groovy index 305758170d7..235adf03c1d 100644 --- a/regression-test/suites/insert_p0/prepare_insert.groovy +++ b/regression-test/suites/insert_p0/prepare_insert.groovy @@ -34,7 +34,7 @@ suite("prepare_insert") { sql """ DROP TABLE IF EXISTS ${tableName} """ sql """ CREATE TABLE ${tableName} ( - `id` int(11) NOT NULL, + `id` int(11) NULL, `name` varchar(50) NULL, `score` int(11) NULL DEFAULT "-1" ) ENGINE=OLAP @@ -141,6 +141,20 @@ suite("prepare_insert") { stmt.close() } + // insert with null + result1 = connect(user = user, password = password, url = url) { + def stmt = prepareStatement "insert into ${tableName} values(?, ?, ?)" + assertEquals(com.mysql.cj.jdbc.ServerPreparedStatement, stmt.class) + stmt.setNull(1, java.sql.Types.INTEGER) + stmt.setNull(2, java.sql.Types.VARCHAR) + stmt.setNull(3, java.sql.Types.INTEGER) + def result = stmt.execute() + logger.info("result: ${result}") + getServerInfo(stmt) + + stmt.close() + } + // insert with label def label = "insert_" + System.currentTimeMillis() result1 = connect(user = user, password = password, url = url) { @@ -238,4 +252,4 @@ suite("prepare_insert") { } qt_sql """ select * from ${tableName} order by id, name, score """ -} \ No newline at end of file +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org