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 cea84ba5794b..6e24f5e8fe55 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.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; @@ -687,39 +689,59 @@ private IQueryExecution createQueryExecutionForTableModel( List parameters = Collections.emptyList(); Map, 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 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 1721ad9b80dc..59fefd8d169f 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 Node visitStatementDefault(RelationalSqlParser.StatementDefaultContext ct @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 08a8b4c2e82a..8a2df109c506 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 @@ -912,8 +912,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