diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index 491d4db81f4907..1dbd7dddcf238c 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -1455,9 +1455,9 @@ create_stmt ::= {: RESULT = new CreateFileStmt(fileName, db, properties); :} - | KW_CREATE KW_MATERIALIZED KW_VIEW ident:mvName KW_AS select_stmt:selectStmt opt_properties:properties + | KW_CREATE KW_MATERIALIZED KW_VIEW ident:mvName KW_AS query_stmt:queryStmt opt_properties:properties {: - RESULT = new CreateMaterializedViewStmt(mvName, selectStmt, properties); + RESULT = new CreateMaterializedViewStmt(mvName, queryStmt, properties); :} | KW_CREATE KW_MATERIALIZED KW_VIEW ident:mvName build_mv:buildMethod opt_mv_refersh_info:refreshInfo @@ -2903,13 +2903,13 @@ show_param ::= {: SelectList list = new SelectList(); list.addItem(new SelectListItem(new IntLiteral((long)0), null)); - RESULT = new SelectStmt(list, null, null, null, null, null, null); + RESULT = new SelectStmt(list, null, null, null, null); :} | KW_COUNT LPAREN STAR RPAREN KW_ERRORS {: SelectList list = new SelectList(); list.addItem(new SelectListItem(new IntLiteral((long)0), null)); - RESULT = new SelectStmt(list, null, null, null, null, null, null); + RESULT = new SelectStmt(list, null, null, null, null); :} | KW_WARNINGS limit_clause {: @@ -3436,86 +3436,113 @@ with_view_def_list ::= :} ; -// We must have a non-empty order by or limit for them to bind to the union. -// We cannot reuse the existing order_by_clause or -// limit_clause because they would introduce conflicts with EOF, -// which, unfortunately, cannot be accessed in the parser as a nonterminal -// making this issue unresolvable. -// We rely on the left precedence of KW_ORDER, KW_BY, and KW_LIMIT, -// to resolve the ambiguity with select_stmt in favor of select_stmt -// (i.e., ORDER BY and LIMIT bind to the select_stmt by default, and not the set operation). -// There must be at least two set operands for ORDER BY or LIMIT to bind to a set operation, -// and we manually throw a parse error if we reach this production -// with only a single operand. set_operation_with_order_by_or_limit ::= set_operand_list:operands KW_LIMIT INTEGER_LITERAL:limit {: + LimitElement limitElement = new LimitElement(limit.longValue()); if (operands.size() == 1) { - parser.parseError("limit", SqlParserSymbols.KW_LIMIT); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, null, limitElement); } - RESULT = new SetOperationStmt(operands, null, new LimitElement(limit.longValue())); :} | set_operand_list:operands KW_LIMIT INTEGER_LITERAL:offset COMMA INTEGER_LITERAL:limit {: + LimitElement limitElement = new LimitElement(offset.longValue(), limit.longValue()); if (operands.size() == 1) { - parser.parseError("limit", SqlParserSymbols.KW_LIMIT); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, null, limitElement); } - RESULT = new SetOperationStmt(operands, null, new LimitElement(offset.longValue(), limit.longValue())); :} | set_operand_list:operands KW_LIMIT INTEGER_LITERAL:limit KW_OFFSET INTEGER_LITERAL:offset {: + LimitElement limitElement = new LimitElement(offset.longValue(), limit.longValue()); if (operands.size() == 1) { - parser.parseError("limit", SqlParserSymbols.KW_LIMIT); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, null, limitElement); } - RESULT = new SetOperationStmt(operands, null, new LimitElement(offset.longValue(), limit.longValue())); :} | set_operand_list:operands KW_ORDER KW_BY order_by_elements:orderByClause {: + LimitElement limitElement = LimitElement.NO_LIMIT; if (operands.size() == 1) { - parser.parseError("order", SqlParserSymbols.KW_ORDER); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + queryStmt.setOrderByElements(orderByClause); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, orderByClause, limitElement); } - RESULT = new SetOperationStmt(operands, orderByClause, LimitElement.NO_LIMIT); :} | set_operand_list:operands KW_ORDER KW_BY order_by_elements:orderByClause KW_LIMIT INTEGER_LITERAL:limit {: + LimitElement limitElement = new LimitElement(limit.longValue()); if (operands.size() == 1) { - parser.parseError("order", SqlParserSymbols.KW_ORDER); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + queryStmt.setOrderByElements(orderByClause); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, orderByClause, limitElement); } - RESULT = new SetOperationStmt(operands, orderByClause, new LimitElement(limit.longValue())); :} | set_operand_list:operands KW_ORDER KW_BY order_by_elements:orderByClause KW_LIMIT INTEGER_LITERAL:offset COMMA INTEGER_LITERAL:limit {: + LimitElement limitElement = new LimitElement(offset.longValue(), limit.longValue()); if (operands.size() == 1) { - parser.parseError("order", SqlParserSymbols.KW_ORDER); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + queryStmt.setOrderByElements(orderByClause); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, orderByClause, limitElement); } - RESULT = new SetOperationStmt(operands, orderByClause, new LimitElement(offset.longValue(), limit.longValue())); :} | set_operand_list:operands KW_ORDER KW_BY order_by_elements:orderByClause KW_LIMIT INTEGER_LITERAL:limit KW_OFFSET INTEGER_LITERAL:offset {: + LimitElement limitElement = new LimitElement(offset.longValue(), limit.longValue()); if (operands.size() == 1) { - parser.parseError("order", SqlParserSymbols.KW_ORDER); + SetOperand setOperand = operands.get(0); + QueryStmt queryStmt = setOperand.getQueryStmt(); + queryStmt.setLimitElement(limitElement); + queryStmt.setOrderByElements(orderByClause); + RESULT = queryStmt; + } else { + RESULT = new SetOperationStmt(operands, orderByClause, limitElement); } - RESULT = new SetOperationStmt(operands, orderByClause, new LimitElement(offset.longValue(), limit.longValue())); :} ; - set_operand ::= select_stmt:select {: @@ -4034,23 +4061,19 @@ set_expr_or_default ::= select_stmt ::= select_clause:selectList - limit_clause:limitClause - {: RESULT = new SelectStmt(selectList, null, null, null, null, null, limitClause); :} + {: RESULT = new SelectStmt(selectList, null, null, null, null); :} | select_clause:selectList from_clause:fromClause where_clause:wherePredicate group_by_clause:groupByClause having_clause:havingPredicate - order_by_clause:orderByClause - limit_clause:limitClause {: RESULT = new SelectStmt(selectList, fromClause, wherePredicate, - groupByClause, havingPredicate, orderByClause, - limitClause); + groupByClause, havingPredicate); :} - | value_clause:valueClause order_by_clause:orderByClause limit_clause:limitClause + | value_clause:valueClause {: - RESULT = new SelectStmt(valueClause, orderByClause, limitClause); + RESULT = new SelectStmt(valueClause); :} ; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java index 28926ac73ee5c2..02319c91dd6ec8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java @@ -75,6 +75,7 @@ public class CreateMaterializedViewStmt extends DdlStmt { } private String mvName; + private QueryStmt queryStmt; private SelectStmt selectStmt; private Map properties; @@ -95,9 +96,16 @@ public class CreateMaterializedViewStmt extends DdlStmt { // only in Rollup or MaterializedIndexMeta is true private boolean isReplay = false; - public CreateMaterializedViewStmt(String mvName, SelectStmt selectStmt, Map properties) { + /** + * Constructor. + * + * @param mvName materialized view name + * @param queryStmt query stmt for construct materialized view. Must be SelectStmt + * @param properties properties for materialized view + */ + public CreateMaterializedViewStmt(String mvName, QueryStmt queryStmt, Map properties) { this.mvName = mvName; - this.selectStmt = selectStmt; + this.queryStmt = queryStmt; this.properties = properties; } @@ -109,10 +117,6 @@ public String getMVName() { return mvName; } - public SelectStmt getSelectStmt() { - return selectStmt; - } - public List getMVColumnItemList() { return mvColumnItemList; } @@ -137,6 +141,11 @@ public KeysType getMVKeysType() { public void analyze(Analyzer analyzer) throws UserException { super.analyze(analyzer); FeNameFormat.checkTableName(mvName); + if (!(queryStmt instanceof SelectStmt)) { + throw new AnalysisException("Set operation is not supported in add materialized view clause, statement."); + } + selectStmt = (SelectStmt) queryStmt; + // TODO(ml): The mv name in from clause should pass the analyze without error. selectStmt.forbiddenMVRewrite(); selectStmt.analyze(analyzer); diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java index 7c4079dedd0ca7..5199fc61f9e2ce 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/QueryStmt.java @@ -569,6 +569,10 @@ public abstract void getTables(Analyzer analyzer, Map tables, Set abstract List collectTupleIds(); + public void setOrderByElements(ArrayList orderByElements) { + this.orderByElements = orderByElements; + } + public ArrayList getOrderByElements() { return orderByElements; } @@ -615,6 +619,10 @@ public void setLimit(long limit) throws AnalysisException { limitElement = new LimitElement(newLimit); } + public void setLimitElement(LimitElement limitElement) { + this.limitElement = limitElement; + } + public void removeLimitElement() { limitElement = LimitElement.NO_LIMIT; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java index 0fa4d0f9c76258..3b97bdc8b7de7c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java @@ -118,23 +118,26 @@ public class SelectStmt extends QueryStmt { // Members that need to be reset to origin private SelectList originSelectList; - public SelectStmt(ValueList valueList, ArrayList orderByElement, LimitElement limitElement) { - super(orderByElement, limitElement); + /** + * Constructor for SelectStmt. This is used for the following cases. + * 1. SELECT * FROM VALUES(a1, b1, c1), (a2, b2, c2); + * + * @param valueList value list + */ + public SelectStmt(ValueList valueList) { + super(null, LimitElement.NO_LIMIT); this.valueList = valueList; this.selectList = new SelectList(); this.fromClause = new FromClause(); this.colLabels = Lists.newArrayList(); } - SelectStmt( - SelectList selectList, + SelectStmt(SelectList selectList, FromClause fromClause, Expr wherePredicate, GroupByClause groupByClause, - Expr havingPredicate, - ArrayList orderByElements, - LimitElement limitElement) { - super(orderByElements, limitElement); + Expr havingPredicate) { + super(null, LimitElement.NO_LIMIT); this.selectList = selectList; this.originSelectList = selectList.clone(); if (fromClause == null) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetOperationStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetOperationStmt.java index 5d81c38b59b160..dc796a4b56ba27 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SetOperationStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SetOperationStmt.java @@ -681,18 +681,12 @@ public String toSql() { strBuilder.append(" "); } Preconditions.checkState(operands.size() > 0); - strBuilder.append(operands.get(0).getQueryStmt().toSql()); + strBuilder.append("(").append(operands.get(0).getQueryStmt().toSql()).append(")"); for (int i = 1; i < operands.size() - 1; ++i) { strBuilder.append(" " + operands.get(i).getOperation().toString() + " " + ((operands.get(i).getQualifier() == Qualifier.ALL) ? "ALL " : "")); - if (operands.get(i).getQueryStmt() instanceof SetOperationStmt) { - strBuilder.append("("); - } - strBuilder.append(operands.get(i).getQueryStmt().toSql()); - if (operands.get(i).getQueryStmt() instanceof SetOperationStmt) { - strBuilder.append(")"); - } + strBuilder.append("(").append(operands.get(i).getQueryStmt().toSql()).append(")"); } // Determine whether we need parenthesis around the last Set operand. SetOperand lastOperand = operands.get(operands.size() - 1); diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowColumnStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowColumnStmt.java index f50e698cda2cca..364d7ddc7da859 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowColumnStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowColumnStmt.java @@ -163,7 +163,7 @@ public SelectStmt toSelectStmt(Analyzer analyzer) throws AnalysisException { where = where.substitute(aliasMap); selectStmt = new SelectStmt(selectList, new FromClause(Lists.newArrayList(new TableRef(TABLE_NAME, null))), - where, null, null, null, LimitElement.NO_LIMIT); + where, null, null); analyzer.setSchemaInfo(tableName.getDb(), tableName.getTbl(), null); return selectStmt; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java index 29d65c9febb253..282a7200c05580 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowDbStmt.java @@ -87,7 +87,7 @@ public SelectStmt toSelectStmt(Analyzer analyzer) { where = where.substitute(aliasMap); selectStmt = new SelectStmt(selectList, new FromClause(Lists.newArrayList(new TableRef(TABLE_NAME, null))), - where, null, null, null, LimitElement.NO_LIMIT); + where, null, null); return selectStmt; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStatusStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStatusStmt.java index 956735b3c8294c..9ed5c4bfdc5fe8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStatusStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStatusStmt.java @@ -182,7 +182,7 @@ public SelectStmt toSelectStmt(Analyzer analyzer) throws AnalysisException { where = where.substitute(aliasMap); selectStmt = new SelectStmt(selectList, new FromClause(Lists.newArrayList(new TableRef(TABLE_NAME, null))), - where, null, null, null, LimitElement.NO_LIMIT); + where, null, null); analyzer.setSchemaInfo(db, null, null); return selectStmt; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStmt.java index dc5acfd09d63d8..fe5b7bb6a027fb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowTableStmt.java @@ -112,7 +112,7 @@ public SelectStmt toSelectStmt(Analyzer analyzer) throws AnalysisException { where = where.substitute(aliasMap); selectStmt = new SelectStmt(selectList, new FromClause(Lists.newArrayList(new TableRef(TABLE_NAME, null))), - where, null, null, null, LimitElement.NO_LIMIT); + where, null, null); analyzer.setSchemaInfo(ClusterNamespace.getNameFromFullName(db), null, null); diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowVariablesStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowVariablesStmt.java index bce1499ef9a35e..049168dbb1a379 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowVariablesStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ShowVariablesStmt.java @@ -101,7 +101,7 @@ public SelectStmt toSelectStmt(Analyzer analyzer) { where = where.substitute(aliasMap); selectStmt = new SelectStmt(selectList, new FromClause(Lists.newArrayList(new TableRef(tableName, null))), - where, null, null, null, LimitElement.NO_LIMIT); + where, null, null); LOG.debug("select stmt is {}", selectStmt.toSql()); // DB: type diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/StmtRewriter.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/StmtRewriter.java index 5cdb4bba36ee11..d68b60e4a3a5b9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/StmtRewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/StmtRewriter.java @@ -273,8 +273,9 @@ private static SelectStmt rewriteHavingClauseSubqueries(SelectStmt stmt, Analyze List newTableRefList = Lists.newArrayList(); newTableRefList.add(inlineViewRef); FromClause newFromClause = new FromClause(newTableRefList); - SelectStmt result = new SelectStmt(newSelectList, newFromClause, newWherePredicate, null, null, - newOrderByElements, limitElement); + SelectStmt result = new SelectStmt(newSelectList, newFromClause, newWherePredicate, null, null); + result.setOrderByElements(newOrderByElements); + result.setLimitElement(limitElement); result.setTableAliasGenerator(tableAliasGenerator); try { result.analyze(analyzer); @@ -1205,9 +1206,7 @@ public static boolean rewriteByPolicy(StatementBase statementBase, Analyzer anal new FromClause(Lists.newArrayList(tableRef)), matchPolicy.getWherePredicate(), null, - null, - null, - LimitElement.NO_LIMIT); + null); selectStmt.fromClause.set(i, new InlineViewRef(tableRef.getAliasAsName().getTbl(), stmt)); selectStmt.analyze(analyzer); reAnalyze = true; diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java index 6513170ba21405..da183db58d3685 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/CreateMaterializedViewStmtTest.java @@ -66,7 +66,7 @@ public void testFunctionColumnInSelectClause(@Injectable ArithmeticExpr arithmet SelectListItem selectListItem = new SelectListItem(arithmeticExpr, null); selectList.addItem(selectListItem); FromClause fromClause = new FromClause(); - SelectStmt selectStmt = new SelectStmt(selectList, fromClause, null, null, null, null, LimitElement.NO_LIMIT); + SelectStmt selectStmt = new SelectStmt(selectList, fromClause, null, null, null); new Expectations() { { diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/QueryOrganizationTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/QueryOrganizationTest.java new file mode 100644 index 00000000000000..83b95ba35a1f79 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/QueryOrganizationTest.java @@ -0,0 +1,116 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.analysis; + +import org.apache.doris.common.UserException; +import org.apache.doris.common.util.SqlParserUtils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.StringReader; + +public class QueryOrganizationTest { + @Test + public void testOneSetOperand() throws Exception { + String sql = "SELECT * FROM tbl WHERE a = 1 ORDER BY b LIMIT 10"; + org.apache.doris.analysis.SqlScanner input = new org.apache.doris.analysis.SqlScanner( + new StringReader(sql), 0L); + org.apache.doris.analysis.SqlParser parser = new org.apache.doris.analysis.SqlParser(input); + StatementBase statementBase = SqlParserUtils.getFirstStmt(parser); + + Assertions.assertTrue(statementBase instanceof SelectStmt); + SelectStmt selectStmt = (SelectStmt) statementBase; + Assertions.assertEquals(10, selectStmt.getLimit()); + Assertions.assertEquals(1, selectStmt.getOrderByElements().size()); + } + + @Test + public void testTwoSetOperandWithSecondInnerOrganization() throws Exception { + String sql = "SELECT * FROM tbl WHERE a = 1 UNION (SELECT * FROM tbl WHERE a = 2 ORDER BY b LIMIT 10)"; + org.apache.doris.analysis.SqlScanner input = new org.apache.doris.analysis.SqlScanner( + new StringReader(sql), 0L); + org.apache.doris.analysis.SqlParser parser = new org.apache.doris.analysis.SqlParser(input); + StatementBase statementBase = SqlParserUtils.getFirstStmt(parser); + + Assertions.assertTrue(statementBase instanceof SetOperationStmt); + SetOperationStmt setOperationStmt = (SetOperationStmt) statementBase; + Assertions.assertEquals(-1, setOperationStmt.getLimit()); + Assertions.assertNull(setOperationStmt.getOrderByElements()); + Assertions.assertEquals(2, setOperationStmt.getOperands().size()); + + QueryStmt secondQueryStmt = setOperationStmt.getOperands().get(1).getQueryStmt(); + Assertions.assertEquals(10, secondQueryStmt.getLimit()); + Assertions.assertEquals(1, secondQueryStmt.getOrderByElements().size()); + } + + @Test + public void testTwoSetOperandWithFirstInnerOrganization() throws Exception { + String sql = "(SELECT * FROM tbl WHERE a = 1 ORDER BY b LIMIT 10) UNION SELECT * FROM tbl WHERE a = 2"; + org.apache.doris.analysis.SqlScanner input = new org.apache.doris.analysis.SqlScanner( + new StringReader(sql), 0L); + org.apache.doris.analysis.SqlParser parser = new org.apache.doris.analysis.SqlParser(input); + StatementBase statementBase = SqlParserUtils.getFirstStmt(parser); + + Assertions.assertTrue(statementBase instanceof SetOperationStmt); + SetOperationStmt setOperationStmt = (SetOperationStmt) statementBase; + Assertions.assertEquals(-1, setOperationStmt.getLimit()); + Assertions.assertNull(setOperationStmt.getOrderByElements()); + Assertions.assertEquals(2, setOperationStmt.getOperands().size()); + + QueryStmt secondQueryStmt = setOperationStmt.getOperands().get(0).getQueryStmt(); + Assertions.assertEquals(10, secondQueryStmt.getLimit()); + Assertions.assertEquals(1, secondQueryStmt.getOrderByElements().size()); + } + + @Test + public void testTwoSetOperandWithOuterOrganization() throws Exception { + String sql = "SELECT * FROM tbl WHERE a = 1 UNION SELECT * FROM tbl WHERE a = 2 ORDER BY b LIMIT 10"; + org.apache.doris.analysis.SqlScanner input = new org.apache.doris.analysis.SqlScanner( + new StringReader(sql), 0L); + org.apache.doris.analysis.SqlParser parser = new org.apache.doris.analysis.SqlParser(input); + StatementBase statementBase = SqlParserUtils.getFirstStmt(parser); + + Assertions.assertTrue(statementBase instanceof SetOperationStmt); + SetOperationStmt setOperationStmt = (SetOperationStmt) statementBase; + Assertions.assertEquals(10, setOperationStmt.getLimit()); + Assertions.assertEquals(1, setOperationStmt.getOrderByElements().size()); + Assertions.assertEquals(2, setOperationStmt.getOperands().size()); + + QueryStmt secondQueryStmt = setOperationStmt.getOperands().get(1).getQueryStmt(); + Assertions.assertEquals(-1, secondQueryStmt.getLimit()); + Assertions.assertNull(secondQueryStmt.getOrderByElements()); + } + + @Test + public void testInvalidSyntax() throws Exception { + String sql = "SELECT * FROM tbl WHERE a = 1 ORDER BY b LIMIT 10 " + + "UNION SELECT * FROM tbl WHERE a = 2 ORDER BY b LIMIT 10"; + org.apache.doris.analysis.SqlScanner input = new org.apache.doris.analysis.SqlScanner( + new StringReader(sql), 0L); + org.apache.doris.analysis.SqlParser parser = new org.apache.doris.analysis.SqlParser(input); + + UserException thrown = Assertions.assertThrows( + UserException.class, + () -> SqlParserUtils.getFirstStmt(parser), + "Expected parser throw exception, but it didn't" + ); + + Assertions.assertTrue(thrown.getMessage().contains("Syntax error")); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java index b8ff5879673a5f..4bd9917f6376df 100755 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java @@ -780,7 +780,7 @@ public void testWithUnionToSql() throws Exception { Assert.assertEquals("SELECT `t`.`k1` AS `k1` " + "FROM (WITH v1 AS (SELECT `t1`.`k1` AS `k1` FROM `default_cluster:db1`.`tbl1` t1)," + "v2 AS (SELECT `t2`.`k1` AS `k1` FROM `default_cluster:db1`.`tbl1` t2) " - + "SELECT `v1`.`k1` AS `k1` FROM `v1` UNION SELECT `v2`.`k1` AS `k1` FROM `v2`) t", stmt1.toSql()); + + "(SELECT `v1`.`k1` AS `k1` FROM `v1`) UNION SELECT `v2`.`k1` AS `k1` FROM `v2`) t", stmt1.toSql()); String sql2 = "with\n" diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java index 8dac6ddaec101c..3113845c22ee4b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/CreateViewTest.java @@ -91,14 +91,14 @@ public void testNormal() throws DdlException { // test union all ExceptionChecker.expectThrowsNoException( () -> createView("create view test.view6 as " - + "select * from test.tbl1 where curdate() > '2021-06-26' order by k1 limit 10 " + + "(select * from test.tbl1 where curdate() > '2021-06-26' order by k1 limit 10) " + "union all " - + "select * from test.tbl1 where curdate() > '2021-06-26' order by k2 limit 10, 50;")); + + "(select * from test.tbl1 where curdate() > '2021-06-26' order by k2 limit 10, 50);")); ExceptionChecker.expectThrowsNoException( () -> createView("create view test.view7 (k1, k2) as " - + "select k1, k2 from test.tbl1 where curdate() > '2021-06-26' order by k1 limit 10 " + + "(select k1, k2 from test.tbl1 where curdate() > '2021-06-26' order by k1 limit 10) " + "union all " - + "select k1, k2 from test.tbl1 where curdate() > '2021-06-26' order by k2 limit 10, 50;")); + + "(select k1, k2 from test.tbl1 where curdate() > '2021-06-26' order by k2 limit 10, 50);")); Database db = Env.getCurrentInternalCatalog().getDbOrDdlException("default_cluster:test");