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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]