This is an automated email from the ASF dual-hosted git repository.
jackietien pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 936af64f79e support EXPLAIN and EXPLAIN ANALYZE for EXECUTE prepared
statement (#17318)
936af64f79e is described below
commit 936af64f79ebe2fef7e3cdab6ec372c95da59985
Author: Le Yang <[email protected]>
AuthorDate: Wed Mar 25 11:26:50 2026 +0800
support EXPLAIN and EXPLAIN ANALYZE for EXECUTE prepared statement (#17318)
---
.../it/insertquery/IoTDBInsertQueryIT.java | 5 ++-
.../iotdb/db/queryengine/plan/Coordinator.java | 50 ++++++++++++++++------
.../plan/relational/sql/parser/AstBuilder.java | 21 +++++++--
.../db/relational/grammar/sql/RelationalSql.g4 | 4 +-
4 files changed, 59 insertions(+), 21 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/relational/it/insertquery/IoTDBInsertQueryIT.java
b/integration-test/src/test/java/org/apache/iotdb/relational/it/insertquery/IoTDBInsertQueryIT.java
index 816e7da3b91..b67fe732f16 100644
---
a/integration-test/src/test/java/org/apache/iotdb/relational/it/insertquery/IoTDBInsertQueryIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/relational/it/insertquery/IoTDBInsertQueryIT.java
@@ -459,7 +459,8 @@ public class IoTDBInsertQueryIT {
Assert.assertTrue(
e.getMessage(),
e.getMessage()
- .contains("700: line 1:9: mismatched input 'INSERT'. Expecting:
'ANALYZE', <query>"));
+ .contains(
+ "700: line 1:9: mismatched input 'INSERT'. Expecting:
'ANALYZE', 'EXECUTE', <query>"));
}
try {
@@ -471,7 +472,7 @@ public class IoTDBInsertQueryIT {
e.getMessage(),
e.getMessage()
.contains(
- "700: line 1:17: mismatched input 'INSERT'. Expecting:
'VERBOSE', <query>"));
+ "700: line 1:17: mismatched input 'INSERT'. Expecting:
'EXECUTE', 'VERBOSE', <query>"));
}
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
index c67b3bd527d..b0d28f03c02 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/Coordinator.java
@@ -86,6 +86,8 @@ import
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropModel;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.DropTable;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Execute;
import
org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ExecuteImmediate;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Explain;
+import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ExplainAnalyze;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Expression;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.ExtendRegion;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Flush;
@@ -689,39 +691,59 @@ public class Coordinator {
List<Expression> parameters = Collections.emptyList();
Map<NodeRef<Parameter>, Expression> parameterLookup =
Collections.emptyMap();
- if (statement instanceof Execute) {
- Execute executeStatement = (Execute) statement;
+ // Unwrap Explain/ExplainAnalyze to check for inner
Execute/ExecuteImmediate
+ org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement
innerStatement = statement;
+ if (statement instanceof Explain) {
+ innerStatement = ((Explain) statement).getStatement();
+ } else if (statement instanceof ExplainAnalyze) {
+ innerStatement = ((ExplainAnalyze) statement).getStatement();
+ }
+
+ if (innerStatement instanceof Execute) {
+ Execute executeStatement = (Execute) innerStatement;
String statementName = executeStatement.getStatementName().getValue();
- // Get prepared statement from session (contains cached AST)
PreparedStatementInfo preparedInfo =
clientSession.getPreparedStatement(statementName);
if (preparedInfo == null) {
throw new SemanticException(
String.format("Prepared statement '%s' does not exist",
statementName));
}
- // Use cached AST
- statementToUse = preparedInfo.getSql();
-
- // Bind parameters: create parameterLookup map
- // Note: bindParameters() internally validates parameter count
+ org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement
resolvedSql =
+ preparedInfo.getSql();
parameterLookup =
- ParameterExtractor.bindParameters(statementToUse,
executeStatement.getParameters());
+ ParameterExtractor.bindParameters(resolvedSql,
executeStatement.getParameters());
parameters = new ArrayList<>(executeStatement.getParameters());
- } else if (statement instanceof ExecuteImmediate) {
- ExecuteImmediate executeImmediateStatement = (ExecuteImmediate)
statement;
+ if (statement instanceof Explain) {
+ statementToUse = new Explain(resolvedSql);
+ } else if (statement instanceof ExplainAnalyze) {
+ statementToUse = new ExplainAnalyze(resolvedSql, ((ExplainAnalyze)
statement).isVerbose());
+ } else {
+ statementToUse = resolvedSql;
+ }
+
+ } else if (innerStatement instanceof ExecuteImmediate) {
+ ExecuteImmediate executeImmediateStatement = (ExecuteImmediate)
innerStatement;
- // EXECUTE IMMEDIATE needs to parse SQL first
String sql = executeImmediateStatement.getSqlString();
List<Literal> literalParameters =
executeImmediateStatement.getParameters();
- statementToUse = sqlParser.createStatement(sql,
clientSession.getZoneId(), clientSession);
+ org.apache.iotdb.db.queryengine.plan.relational.sql.ast.Statement
resolvedSql =
+ sqlParser.createStatement(sql, clientSession.getZoneId(),
clientSession);
if (!literalParameters.isEmpty()) {
- parameterLookup = ParameterExtractor.bindParameters(statementToUse,
literalParameters);
+ parameterLookup = ParameterExtractor.bindParameters(resolvedSql,
literalParameters);
parameters = new ArrayList<>(literalParameters);
}
+
+ if (statement instanceof Explain) {
+ statementToUse = new Explain(resolvedSql);
+ } else if (statement instanceof ExplainAnalyze) {
+ statementToUse = new ExplainAnalyze(resolvedSql, ((ExplainAnalyze)
statement).isVerbose());
+ } else {
+ statementToUse = resolvedSql;
+ }
}
if (statement instanceof WrappedInsertStatement) {
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
index 1721ad9b80d..59fefd8d169 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/parser/AstBuilder.java
@@ -1790,13 +1790,28 @@ public class AstBuilder extends
RelationalSqlBaseVisitor<Node> {
@Override
public Node visitExplain(RelationalSqlParser.ExplainContext ctx) {
- return new Explain(getLocation(ctx), (Statement) visit(ctx.query()));
+ Statement innerStatement;
+ if (ctx.query() != null) {
+ innerStatement = (Statement) visit(ctx.query());
+ } else if (ctx.executeStatement() != null) {
+ innerStatement = (Statement) visit(ctx.executeStatement());
+ } else {
+ innerStatement = (Statement) visit(ctx.executeImmediateStatement());
+ }
+ return new Explain(getLocation(ctx), innerStatement);
}
@Override
public Node visitExplainAnalyze(RelationalSqlParser.ExplainAnalyzeContext
ctx) {
- return new ExplainAnalyze(
- getLocation(ctx), ctx.VERBOSE() != null, (Statement)
visit(ctx.query()));
+ Statement innerStatement;
+ if (ctx.query() != null) {
+ innerStatement = (Statement) visit(ctx.query());
+ } else if (ctx.executeStatement() != null) {
+ innerStatement = (Statement) visit(ctx.executeStatement());
+ } else {
+ innerStatement = (Statement) visit(ctx.executeImmediateStatement());
+ }
+ return new ExplainAnalyze(getLocation(ctx), ctx.VERBOSE() != null,
innerStatement);
}
// ********************** author expressions ********************
diff --git
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
index c8c30ae3d6d..291aa1ea1ae 100644
---
a/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
+++
b/iotdb-core/relational-grammar/src/main/antlr4/org/apache/iotdb/db/relational/grammar/sql/RelationalSql.g4
@@ -911,8 +911,8 @@ deallocateStatement
// ------------------------------------------- Query Statement
---------------------------------------------------------
queryStatement
: query
#statementDefault
- | EXPLAIN query #explain
- | EXPLAIN ANALYZE VERBOSE? query
#explainAnalyze
+ | EXPLAIN (query | executeStatement | executeImmediateStatement) #explain
+ | EXPLAIN ANALYZE VERBOSE? (query | executeStatement |
executeImmediateStatement) #explainAnalyze
;
query