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

dataroaring 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 380d5355a21 branch-3.0: [fix](sql cache) fix prepare statement with 
sql cache throw NullPointerException #48902 (#48976)
380d5355a21 is described below

commit 380d5355a21e898a45939ca1740d546125070c97
Author: 924060929 <lanhuaj...@selectdb.com>
AuthorDate: Sat Mar 15 10:12:05 2025 +0800

    branch-3.0: [fix](sql cache) fix prepare statement with sql cache throw 
NullPointerException #48902 (#48976)
    
    cherry pick from #48902
---
 .../doris/common/NereidsSqlCacheManager.java       | 19 +++++++++++++
 .../org/apache/doris/nereids/StatementContext.java |  2 +-
 .../trees/plans/commands/ExecuteCommand.java       | 12 ++++++--
 .../java/org/apache/doris/qe/ConnectProcessor.java | 11 ++++++++
 .../doris/regression/action/TestAction.groovy      |  2 +-
 .../cache/parse_sql_from_sql_cache.groovy          |  7 +----
 .../cache/prepare_stmt_with_sql_cache.groovy       | 33 ++++++++++++++++------
 7 files changed, 66 insertions(+), 20 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java 
b/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java
index 93e4aebb8f8..62d052f18b6 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/common/NereidsSqlCacheManager.java
@@ -127,6 +127,13 @@ public class NereidsSqlCacheManager {
      * tryAddFeCache
      */
     public void tryAddFeSqlCache(ConnectContext connectContext, String sql) {
+        switch (connectContext.getCommand()) {
+            case COM_STMT_EXECUTE:
+            case COM_STMT_PREPARE:
+                return;
+            default: { }
+        }
+
         Optional<SqlCacheContext> sqlCacheContextOpt = 
connectContext.getStatementContext().getSqlCacheContext();
         if (!sqlCacheContextOpt.isPresent()) {
             return;
@@ -146,6 +153,12 @@ public class NereidsSqlCacheManager {
      * tryAddBeCache
      */
     public void tryAddBeCache(ConnectContext connectContext, String sql, 
CacheAnalyzer analyzer) {
+        switch (connectContext.getCommand()) {
+            case COM_STMT_EXECUTE:
+            case COM_STMT_PREPARE:
+                return;
+            default: { }
+        }
         Optional<SqlCacheContext> sqlCacheContextOpt = 
connectContext.getStatementContext().getSqlCacheContext();
         if (!sqlCacheContextOpt.isPresent()) {
             return;
@@ -177,6 +190,12 @@ public class NereidsSqlCacheManager {
      * tryParseSql
      */
     public Optional<LogicalSqlCache> tryParseSql(ConnectContext 
connectContext, String sql) {
+        switch (connectContext.getCommand()) {
+            case COM_STMT_EXECUTE:
+            case COM_STMT_PREPARE:
+                return Optional.empty();
+            default: { }
+        }
         String key = generateCacheKey(connectContext, 
normalizeSql(sql.trim()));
         SqlCacheContext sqlCacheContext = sqlCaches.getIfPresent(key);
         if (sqlCacheContext == null) {
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 b82c48a7fda..ffe9f38a262 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
@@ -164,7 +164,7 @@ public class StatementContext implements Closeable {
     private final Stack<CloseableResource> plannerResources = new Stack<>();
 
     // placeholder params for prepared statement
-    private List<Placeholder> placeholders;
+    private List<Placeholder> placeholders = new ArrayList<>();
 
     // all tables in query
     private boolean needLockTables = true;
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 c4031c0f9e5..c67ab1597cc 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
@@ -25,6 +25,8 @@ 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.commands.insert.OlapGroupCommitInsertExecutor;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalSqlCache;
 import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
 import org.apache.doris.planner.GroupCommitPlanner;
 import org.apache.doris.qe.ConnectContext;
@@ -68,9 +70,13 @@ public class ExecuteCommand extends Command {
             throw new AnalysisException(
                     "prepare statement " + stmtName + " not found,  maybe 
expired");
         }
-        PrepareCommand prepareCommand = (PrepareCommand) 
preparedStmtCtx.command;
-        LogicalPlanAdapter planAdapter = new 
LogicalPlanAdapter(prepareCommand.getLogicalPlan(), executor.getContext()
-                .getStatementContext());
+        PrepareCommand prepareCommand = preparedStmtCtx.command;
+        LogicalPlan logicalPlan = prepareCommand.getLogicalPlan();
+        if (logicalPlan instanceof LogicalSqlCache) {
+            throw new AnalysisException("Unsupported sql cache for server 
prepared statement");
+        }
+        LogicalPlanAdapter planAdapter = new LogicalPlanAdapter(
+                logicalPlan, executor.getContext().getStatementContext());
         executor.setParsedStmt(planAdapter);
         // 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
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 6da6a703e69..55c4488e7ac 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
@@ -400,6 +400,17 @@ public abstract class ConnectProcessor {
     private List<StatementBase> parseFromSqlCache(String originStmt) {
         StatementContext statementContext = new StatementContext(ctx, new 
OriginStatement(originStmt, 0));
         ctx.setStatementContext(statementContext);
+
+        // the mysql protocol has different between COM_QUERY and 
COM_STMT_EXECUTE,
+        // the sql cache use the result of COM_QUERY, so we can not provide the
+        // result of sql cache for COM_STMT_EXECUTE/COM_STMT_PREPARE
+        switch (ctx.getCommand()) {
+            case COM_STMT_EXECUTE:
+            case COM_STMT_PREPARE:
+                return null;
+            default: { }
+        }
+
         try {
             Optional<Pair<ExplainOptions, String>> explainPlan = 
NereidsParser.tryParseExplainPlan(originStmt);
             String cacheSqlKey = originStmt;
diff --git 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/TestAction.groovy
 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/TestAction.groovy
index 3febe6bbad5..ebee498da98 100644
--- 
a/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/TestAction.groovy
+++ 
b/regression-test/framework/src/main/groovy/org/apache/doris/regression/action/TestAction.groovy
@@ -68,7 +68,7 @@ class TestAction implements SuiteAction {
             } else {
                 if (exception != null || result.exception != null) {
                     def msg = result.exception?.toString()
-                    log.info("Exception: ${msg}")
+                    log.error("Exception: ${msg}", exception != null ? 
exception : result.exception)
                     Assert.assertTrue("Expect exception msg contains 
'${exception}', but meet '${msg}'",
                             msg != null && exception != null && 
msg.contains(exception))
                 }
diff --git 
a/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy 
b/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy
index 765d1208426..1542efe984a 100644
--- a/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy
+++ b/regression-test/suites/nereids_p0/cache/parse_sql_from_sql_cache.groovy
@@ -33,12 +33,7 @@ suite("parse_sql_from_sql_cache") {
     }
 
     def dbName = (sql "select database()")[0][0].toString()
-    foreachFrontends { fe ->
-        def url = "jdbc:mysql://${fe.Host}:${fe.QueryPort}/${dbName}"
-        connect(context.config.jdbcUser, context.config.jdbcPassword, url) {
-            sql "ADMIN SET FRONTEND CONFIG 
('cache_last_version_interval_second' = '10')"
-        }
-    }
+    sql "ADMIN SET ALL FRONTENDS CONFIG ('cache_last_version_interval_second' 
= '10')"
 
     // make sure if the table has been dropped, the cache should invalidate,
     // so we should retry multiple times to check
diff --git 
a/regression-test/suites/nereids_p0/cache/prepare_stmt_with_sql_cache.groovy 
b/regression-test/suites/nereids_p0/cache/prepare_stmt_with_sql_cache.groovy
index 7819a6ca09d..1d358adfbff 100644
--- a/regression-test/suites/nereids_p0/cache/prepare_stmt_with_sql_cache.groovy
+++ b/regression-test/suites/nereids_p0/cache/prepare_stmt_with_sql_cache.groovy
@@ -15,17 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 
-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("prepare_stmt_with_sql_cache") {
 
@@ -38,11 +31,13 @@ suite("prepare_stmt_with_sql_cache") {
         insert into test_prepare_stmt_with_sql_cache select * from 
numbers('number'='100');
         """
 
+    sql "ADMIN SET ALL FRONTENDS CONFIG ('cache_last_version_interval_second' 
= '10')"
+
     def db = (sql "select database()")[0][0].toString()
 
-    def url = getServerPrepareJdbcUrl(context.config.jdbcUrl, db)
+    def serverPrepareUrl = getServerPrepareJdbcUrl(context.config.jdbcUrl, db)
 
-    connect(context.config.jdbcUser, context.config.jdbcPassword, url) {
+    connect(context.config.jdbcUser, context.config.jdbcPassword, 
serverPrepareUrl) {
         sql "set enable_sql_cache=true"
         for (def i in 0..<10) {
             try (PreparedStatement pstmt = prepareStatement("select * from 
test_prepare_stmt_with_sql_cache where id=?")) {
@@ -54,4 +49,24 @@ suite("prepare_stmt_with_sql_cache") {
             }
         }
     }
+
+    sleep(10 * 1000)
+
+    connect(context.config.jdbcUser, context.config.jdbcPassword, 
context.config.jdbcUrl) {
+        sql "use ${db}"
+        sql "set enable_sql_cache=true"
+        test {
+            sql "select * from test_prepare_stmt_with_sql_cache where id=10"
+            result([[10]])
+        }
+    }
+
+    connect(context.config.jdbcUser, context.config.jdbcPassword, 
serverPrepareUrl) {
+        sql "use ${db}"
+        sql "set enable_sql_cache=true"
+        test {
+            sql "select * from test_prepare_stmt_with_sql_cache where id=10"
+            result(([[10]]))
+        }
+    }
 }


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

Reply via email to