morrySnow commented on code in PR #39627:
URL: https://github.com/apache/doris/pull/39627#discussion_r1738049286


##########
fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableQueryPlanAction.java:
##########
@@ -163,65 +170,78 @@ public Object query_plan(
      */
     private void handleQuery(ConnectContext context, String requestDb, String 
requestTable, String sql,
             Map<String, Object> result) throws DorisHttpException {
-        // use SE to resolve sql
-        StmtExecutor stmtExecutor = new StmtExecutor(context, new 
OriginStatement(sql, 0), false);
+        List<StatementBase> stmts = null;
         try {
-            TQueryOptions tQueryOptions = 
context.getSessionVariable().toThrift();
-            // Conduct Planner create SingleNodePlan#createPlanFragments
-            tQueryOptions.num_nodes = 1;
-            // analyze sql
-            stmtExecutor.analyze(tQueryOptions);
+            stmts = new NereidsParser().parseSQL(sql, 
context.getSessionVariable());
         } catch (Exception e) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST, 
e.getMessage());
         }
         // the parsed logical statement
-        StatementBase query = stmtExecutor.getParsedStmt();
-        // only process select semantic
-        if (!(query instanceof SelectStmt)) {
+        StatementBase query = stmts.get(0);
+        if (!(query instanceof LogicalPlanAdapter)) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
                     "Select statement needed, but found [" + sql + " ]");
         }
-        SelectStmt stmt = (SelectStmt) query;
-        // just only process sql like `select * from table where <predicate>`, 
only support executing scan semantic
-        if (stmt.hasAggInfo() || stmt.hasAnalyticInfo()
-                || stmt.hasOrderByClause() || stmt.hasOffset() || 
stmt.hasLimit() || stmt.isExplain()) {
+        LogicalPlan parsedPlan = ((LogicalPlanAdapter) query).getLogicalPlan();
+        // only process select semantic
+        if (parsedPlan instanceof Command) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
-                    "only support single table filter-prune-scan, but found [ 
" + sql + "]");
+                    "Select statement needed, but found [" + sql + " ]");
         }
-        // process only one table by one http query
-        List<TableRef> fromTables = stmt.getTableRefs();
-        if (fromTables.size() != 1) {
+
+        if 
(!parsedPlan.collectToList(LogicalSubQueryAlias.class::isInstance).isEmpty()) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
-                    "Select statement must have only one table");
+                    "Select statement must not embed another statement");
         }
 
-        TableRef fromTable = fromTables.get(0);
-        if (fromTable instanceof InlineViewRef) {
+        List<UnboundRelation> unboundRelations = 
parsedPlan.collectToList(UnboundRelation.class::isInstance);
+        if (unboundRelations.size() != 1) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
-                    "Select statement must not embed another statement");
+                    "Select statement must have only one table");
         }
+
         // check consistent http requested resource with sql referenced
         // if consistent in this way, can avoid check privilege
-        TableName tableAndDb = fromTables.get(0).getName();
-        int lower = GlobalVariable.lowerCaseTableNames;
-        //Determine whether table names are case-sensitive
-        if (lower == 0) {
-            if (!(tableAndDb.getDb().equals(requestDb) && 
tableAndDb.getTbl().equals(requestTable))) {
+        List<String> tableQualifier = RelationUtil.getQualifierName(context,
+                unboundRelations.get(0).getNameParts());
+        if (tableQualifier.size() != 3) {
+            throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
+                    "can't find table " + String.join(",", tableQualifier));
+        }
+        String dbName = tableQualifier.get(1);
+        String tableName = tableQualifier.get(2);
+
+        if (GlobalVariable.lowerCaseTableNames == 0) {
+            if (!(dbName.equals(requestDb) && tableName.equals(requestTable))) 
{
                 throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
                         "requested database and table must consistent with 
sql: request [ "
-                                + requestDb + "." + requestTable + "]" + "and 
sql [" + tableAndDb.toString() + "]");
+                                + requestDb + "." + requestTable + "]" + "and 
sql [" + dbName + "." + tableName + "]");
             }
         } else {
-            if (!(tableAndDb.getDb().equalsIgnoreCase(requestDb)
-                    && tableAndDb.getTbl().equalsIgnoreCase(requestTable))) {
+            if (!(dbName.equalsIgnoreCase(requestDb)
+                    && tableName.equalsIgnoreCase(requestTable))) {
                 throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
                         "requested database and table must consistent with 
sql: request [ "
-                                + requestDb + "." + requestTable + "]" + "and 
sql [" + tableAndDb.toString() + "]");
+                                + requestDb + "." + requestTable + "]" + "and 
sql [" + dbName + "." + tableName + "]");
             }
         }
+        NereidsPlanner nereidsPlanner = new 
NereidsPlanner(context.getStatementContext());
+        LogicalPlan rewrittenPlan = (LogicalPlan) 
nereidsPlanner.planWithLock(parsedPlan,
+                PhysicalProperties.GATHER, 
ExplainCommand.ExplainLevel.REWRITTEN_PLAN);
+        if (rewrittenPlan.anyMatch(planTreeNode -> planTreeNode instanceof 
LogicalAggregate
+                || planTreeNode instanceof LogicalWindow || planTreeNode 
instanceof LogicalSort
+                || planTreeNode instanceof LogicalTopN || planTreeNode 
instanceof LogicalLimit)) {
+            throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
+                    "only support single table filter-prune-scan, but found [ 
" + sql + "]");
+        }

Review Comment:
   black list is not a good idea, because we may add new node type.
   use white list, check only have
   - unbound relation
   - filter
   - project
   - result sink



##########
fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableQueryPlanAction.java:
##########
@@ -163,65 +170,78 @@ public Object query_plan(
      */
     private void handleQuery(ConnectContext context, String requestDb, String 
requestTable, String sql,
             Map<String, Object> result) throws DorisHttpException {
-        // use SE to resolve sql
-        StmtExecutor stmtExecutor = new StmtExecutor(context, new 
OriginStatement(sql, 0), false);
+        List<StatementBase> stmts = null;
         try {
-            TQueryOptions tQueryOptions = 
context.getSessionVariable().toThrift();
-            // Conduct Planner create SingleNodePlan#createPlanFragments
-            tQueryOptions.num_nodes = 1;
-            // analyze sql
-            stmtExecutor.analyze(tQueryOptions);
+            stmts = new NereidsParser().parseSQL(sql, 
context.getSessionVariable());
         } catch (Exception e) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST, 
e.getMessage());
         }
         // the parsed logical statement
-        StatementBase query = stmtExecutor.getParsedStmt();
-        // only process select semantic
-        if (!(query instanceof SelectStmt)) {
+        StatementBase query = stmts.get(0);
+        if (!(query instanceof LogicalPlanAdapter)) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
                     "Select statement needed, but found [" + sql + " ]");
         }
-        SelectStmt stmt = (SelectStmt) query;
-        // just only process sql like `select * from table where <predicate>`, 
only support executing scan semantic
-        if (stmt.hasAggInfo() || stmt.hasAnalyticInfo()
-                || stmt.hasOrderByClause() || stmt.hasOffset() || 
stmt.hasLimit() || stmt.isExplain()) {
+        LogicalPlan parsedPlan = ((LogicalPlanAdapter) query).getLogicalPlan();
+        // only process select semantic
+        if (parsedPlan instanceof Command) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
-                    "only support single table filter-prune-scan, but found [ 
" + sql + "]");
+                    "Select statement needed, but found [" + sql + " ]");
         }
-        // process only one table by one http query
-        List<TableRef> fromTables = stmt.getTableRefs();
-        if (fromTables.size() != 1) {
+
+        if 
(!parsedPlan.collectToList(LogicalSubQueryAlias.class::isInstance).isEmpty()) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
-                    "Select statement must have only one table");
+                    "Select statement must not embed another statement");
         }
 
-        TableRef fromTable = fromTables.get(0);
-        if (fromTable instanceof InlineViewRef) {
+        List<UnboundRelation> unboundRelations = 
parsedPlan.collectToList(UnboundRelation.class::isInstance);
+        if (unboundRelations.size() != 1) {
             throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
-                    "Select statement must not embed another statement");
+                    "Select statement must have only one table");
         }
+
         // check consistent http requested resource with sql referenced
         // if consistent in this way, can avoid check privilege
-        TableName tableAndDb = fromTables.get(0).getName();
-        int lower = GlobalVariable.lowerCaseTableNames;
-        //Determine whether table names are case-sensitive
-        if (lower == 0) {
-            if (!(tableAndDb.getDb().equals(requestDb) && 
tableAndDb.getTbl().equals(requestTable))) {
+        List<String> tableQualifier = RelationUtil.getQualifierName(context,
+                unboundRelations.get(0).getNameParts());
+        if (tableQualifier.size() != 3) {
+            throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
+                    "can't find table " + String.join(",", tableQualifier));
+        }
+        String dbName = tableQualifier.get(1);
+        String tableName = tableQualifier.get(2);
+
+        if (GlobalVariable.lowerCaseTableNames == 0) {
+            if (!(dbName.equals(requestDb) && tableName.equals(requestTable))) 
{
                 throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
                         "requested database and table must consistent with 
sql: request [ "
-                                + requestDb + "." + requestTable + "]" + "and 
sql [" + tableAndDb.toString() + "]");
+                                + requestDb + "." + requestTable + "]" + "and 
sql [" + dbName + "." + tableName + "]");
             }
         } else {
-            if (!(tableAndDb.getDb().equalsIgnoreCase(requestDb)
-                    && tableAndDb.getTbl().equalsIgnoreCase(requestTable))) {
+            if (!(dbName.equalsIgnoreCase(requestDb)
+                    && tableName.equalsIgnoreCase(requestTable))) {
                 throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
                         "requested database and table must consistent with 
sql: request [ "
-                                + requestDb + "." + requestTable + "]" + "and 
sql [" + tableAndDb.toString() + "]");
+                                + requestDb + "." + requestTable + "]" + "and 
sql [" + dbName + "." + tableName + "]");
             }
         }
+        NereidsPlanner nereidsPlanner = new 
NereidsPlanner(context.getStatementContext());
+        LogicalPlan rewrittenPlan = (LogicalPlan) 
nereidsPlanner.planWithLock(parsedPlan,
+                PhysicalProperties.GATHER, 
ExplainCommand.ExplainLevel.REWRITTEN_PLAN);
+        if (rewrittenPlan.anyMatch(planTreeNode -> planTreeNode instanceof 
LogicalAggregate
+                || planTreeNode instanceof LogicalWindow || planTreeNode 
instanceof LogicalSort
+                || planTreeNode instanceof LogicalTopN || planTreeNode 
instanceof LogicalLimit)) {
+            throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
+                    "only support single table filter-prune-scan, but found [ 
" + sql + "]");
+        }
+        NereidsPlanner planner = new 
NereidsPlanner(context.getStatementContext());
+        try {
+            planner.plan(query, context.getSessionVariable().toThrift());
+        } catch (Exception ex) {
+            throw new DorisHttpException(HttpResponseStatus.BAD_REQUEST,
+                    "only support single table filter-prune-scan, but found [ 
" + sql + "]");
+        }
 
-        // acquired Planner to get PlanNode and fragment templates
-        Planner planner = stmtExecutor.planner();

Review Comment:
   we need to forbid some rules to avoid generate empty relation
   - PRUNE_EMPTY_PARTITION
   - ELIMINATE_FILTER
   



##########
fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/TableQueryPlanAction.java:
##########
@@ -163,65 +170,78 @@ public Object query_plan(
      */
     private void handleQuery(ConnectContext context, String requestDb, String 
requestTable, String sql,
             Map<String, Object> result) throws DorisHttpException {
-        // use SE to resolve sql
-        StmtExecutor stmtExecutor = new StmtExecutor(context, new 
OriginStatement(sql, 0), false);
+        List<StatementBase> stmts = null;
         try {
-            TQueryOptions tQueryOptions = 
context.getSessionVariable().toThrift();
-            // Conduct Planner create SingleNodePlan#createPlanFragments
-            tQueryOptions.num_nodes = 1;

Review Comment:
   this is used to ensure generate one fragment plan. and will be check 
fragment num later. so in nereids, we should set enable_parallel_result_sink = 
true



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to