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

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


The following commit(s) were added to refs/heads/branch-3.0 by this push:
     new fe564902378 branch-3.0: [Fix](PreparedStatement) nondeterministic 
functions in prepared statement should not be short circuited #46003 (#46108)
fe564902378 is described below

commit fe5649023785d02cbee5b90abe7921fec87925c8
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Dec 27 21:02:02 2024 +0800

    branch-3.0: [Fix](PreparedStatement) nondeterministic functions in prepared 
statement should not be short circuited #46003 (#46108)
    
    Cherry-picked from #46003
    
    Co-authored-by: lihangyu <lihan...@selectdb.com>
---
 .../org/apache/doris/nereids/StatementContext.java | 10 ++++++++
 .../nereids/rules/analysis/ExpressionAnalyzer.java |  5 ++++
 .../trees/plans/commands/ExecuteCommand.java       |  7 +++---
 .../suites/point_query_p0/test_point_query.groovy  | 27 ++++++++++++++++++++++
 4 files changed, 46 insertions(+), 3 deletions(-)

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 4cc4a6c8600..0add923eec5 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
@@ -118,6 +118,8 @@ public class StatementContext implements Closeable {
 
     private boolean isDpHyp = false;
 
+    private boolean hasNondeterministic = false;
+
     // hasUnknownColStats true if any column stats in the tables used by this 
sql is unknown
     // the algorithm to derive plan when column stats are unknown is 
implemented in cascading framework, not in dphyper.
     // And hence, when column stats are unknown, even if the tables used by a 
sql is more than
@@ -303,6 +305,14 @@ public class StatementContext implements Closeable {
         this.connectContext = connectContext;
     }
 
+    public void setHasNondeterministic(boolean hasNondeterministic) {
+        this.hasNondeterministic = hasNondeterministic;
+    }
+
+    public boolean hasNondeterministic() {
+        return hasNondeterministic;
+    }
+
     public ConnectContext getConnectContext() {
         return connectContext;
     }
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 5ef3d0fbff3..26c25a4e012 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
@@ -403,6 +403,11 @@ public class ExpressionAnalyzer extends 
SubExprAnalyzer<ExpressionRewriteContext
         Pair<? extends Expression, ? extends BoundFunction> buildResult = 
builder.build(functionName, arguments);
         buildResult.second.checkOrderExprIsValid();
         Optional<SqlCacheContext> sqlCacheContext = Optional.empty();
+
+        if (!buildResult.second.isDeterministic() && context != null) {
+            StatementContext statementContext = 
context.cascadesContext.getStatementContext();
+            statementContext.setHasNondeterministic(true);
+        }
         if (wantToParseSqlFromSqlCache) {
             StatementContext statementContext = 
context.cascadesContext.getStatementContext();
             if (!buildResult.second.isDeterministic()) {
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
index 08e351041a2..47ba6ed3f4c 100644
--- 
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
@@ -70,14 +70,15 @@ public class ExecuteCommand extends Command {
         LogicalPlanAdapter planAdapter = new 
LogicalPlanAdapter(prepareCommand.getLogicalPlan(), executor.getContext()
                 .getStatementContext());
         executor.setParsedStmt(planAdapter);
-        // If it's not a short circuit query or schema version is 
different(indicates schema changed),
-        // need to do reanalyze and plan
+        // If it's not a short circuit query or schema version is 
different(indicates schema changed) or
+        // has nondeterministic functions in statement, then need to do 
reanalyze and plan
         boolean isShortCircuit = 
executor.getContext().getStatementContext().isShortCircuitQuery();
         boolean hasShortCircuitContext = 
preparedStmtCtx.shortCircuitQueryContext.isPresent();
         boolean schemaVersionMismatch = hasShortCircuitContext
                     && 
preparedStmtCtx.shortCircuitQueryContext.get().tbl.getBaseSchemaVersion()
                     != 
preparedStmtCtx.shortCircuitQueryContext.get().schemaVersion;
-        boolean needAnalyze = !isShortCircuit || schemaVersionMismatch || 
!hasShortCircuitContext;
+        boolean needAnalyze = !isShortCircuit || schemaVersionMismatch || 
!hasShortCircuitContext
+                        || 
executor.getContext().getStatementContext().hasNondeterministic();
         if (needAnalyze) {
             // execute real statement
             preparedStmtCtx.shortCircuitQueryContext = Optional.empty();
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 a15b48084ca..237103435a9 100644
--- a/regression-test/suites/point_query_p0/test_point_query.groovy
+++ b/regression-test/suites/point_query_p0/test_point_query.groovy
@@ -16,6 +16,17 @@
 // under the License.
 
 import java.math.BigDecimal;
+import com.mysql.cj.ServerPreparedQuery
+import com.mysql.cj.jdbc.ConnectionImpl
+import com.mysql.cj.jdbc.JdbcStatement
+import com.mysql.cj.jdbc.ServerPreparedStatement
+import com.mysql.cj.jdbc.StatementImpl
+import org.apache.doris.regression.util.JdbcUtils
+
+import java.lang.reflect.Field
+import java.sql.PreparedStatement
+import java.sql.ResultSet
+import java.util.concurrent.CopyOnWriteArrayList
 
 suite("test_point_query", "nonConcurrent") {
     def backendId_to_backendIP = [:]
@@ -383,5 +394,21 @@ suite("test_point_query", "nonConcurrent") {
         partial_prepared_stmt.setString(2, "feature")
         qe_point_select partial_prepared_stmt
         qe_point_select partial_prepared_stmt
+
+        // test prepared statement should not be short-circuited plan which 
use nondeterministic function
+        try (PreparedStatement pstmt = prepareStatement("select now(3) 
data_time from regression_test_point_query_p0.test_partial_prepared_statement 
where sk = 'sk' and user_guid = 'user_guid' and  feature = 'feature'")) {
+            def result1 = ""
+            def result2 = ""
+            try (ResultSet rs = pstmt.executeQuery()) {
+                result1 = JdbcUtils.toList(rs).v1
+                logger.info("result: {}", result1)
+            }
+            sleep(100)
+            try (ResultSet rs = pstmt.executeQuery()) {
+                result2 = JdbcUtils.toList(rs).v1
+                logger.info("result: {}", result2)
+            }
+            assertNotEquals(result1, result2)
+        }
     }
 } 
\ 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

Reply via email to