# IGNITE-624 Make GridSqlQueryParser able to parse SQL query with UNION expression. Created class GridSqlUnion.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/98de490f Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/98de490f Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/98de490f Branch: refs/heads/ignite-624 Commit: 98de490fbb4bb671ee28da5f9ad7d0911cf9b190 Parents: b297a4c Author: sevdokimov <sergey.evdoki...@jetbrains.com> Authored: Tue Mar 31 23:26:34 2015 +0300 Committer: sevdokimov <sergey.evdoki...@jetbrains.com> Committed: Tue Mar 31 23:26:34 2015 +0300 ---------------------------------------------------------------------- .../processors/query/h2/sql/GridSqlQuery.java | 221 +---------------- .../query/h2/sql/GridSqlQueryParser.java | 62 ++++- .../query/h2/sql/GridSqlQuerySplitter.java | 53 ++-- .../processors/query/h2/sql/GridSqlSelect.java | 243 +++++++++++++++++++ .../processors/query/h2/sql/GridSqlUnion.java | 162 +++++++++++++ .../query/h2/sql/GridQueryParsingTest.java | 18 +- 6 files changed, 515 insertions(+), 244 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/98de490f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuery.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuery.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuery.java index da71bcb..db1dcbf 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuery.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuery.java @@ -17,49 +17,29 @@ package org.apache.ignite.internal.processors.query.h2.sql; -import org.h2.util.*; - import java.util.*; /** * Select query. */ -public class GridSqlQuery implements Cloneable { - /** */ - private boolean distinct; - - /** */ - private List<GridSqlElement> allExprs; - - /** */ - private List<GridSqlElement> select = new ArrayList<>(); - +public abstract class GridSqlQuery implements Cloneable { /** */ - private List<GridSqlElement> groups = new ArrayList<>(); + protected boolean distinct; /** */ - private int[] grpCols; + protected List<GridSqlElement> allExprs; /** */ - private GridSqlElement from; + protected List<GridSqlElement> select = new ArrayList<>(); /** */ - private GridSqlElement where; + protected Map<GridSqlElement,GridSqlSortColumn> sort = new LinkedHashMap<>(); /** */ - private GridSqlElement having; + protected GridSqlElement offset; /** */ - private int havingCol = -1; - - /** */ - private Map<GridSqlElement,GridSqlSortColumn> sort = new LinkedHashMap<>(); - - /** */ - private GridSqlElement offset; - - /** */ - private GridSqlElement limit; + protected GridSqlElement limit; /** * @return Offset. @@ -106,78 +86,7 @@ public class GridSqlQuery implements Cloneable { /** * @return Generate sql. */ - public String getSQL() { - StatementBuilder buff = new StatementBuilder("SELECT"); - - if (distinct) - buff.append(" DISTINCT"); - - for (GridSqlElement expression : select) { - buff.appendExceptFirst(","); - buff.append('\n'); - buff.append(StringUtils.indent(expression.getSQL(), 4, false)); - } - - buff.append("\nFROM ").append(from.getSQL()); - - if (where != null) - buff.append("\nWHERE ").append(StringUtils.unEnclose(where.getSQL())); - - if (!groups.isEmpty()) { - buff.append("\nGROUP BY "); - - buff.resetCount(); - - for (GridSqlElement expression : groups) { - buff.appendExceptFirst(", "); - - if (expression instanceof GridSqlAlias) - buff.append(StringUtils.unEnclose((expression.child().getSQL()))); - else - buff.append(StringUtils.unEnclose(expression.getSQL())); - } - } - - if (having != null) - buff.append("\nHAVING ").append(StringUtils.unEnclose(having.getSQL())); - - if (!sort.isEmpty()) { - buff.append("\nORDER BY "); - - buff.resetCount(); - - for (Map.Entry<GridSqlElement,GridSqlSortColumn> entry : sort.entrySet()) { - buff.appendExceptFirst(", "); - - GridSqlElement expression = entry.getKey(); - - int idx = select.indexOf(expression); - - if (idx >= 0) - buff.append(idx + 1); - else - buff.append('=').append(StringUtils.unEnclose(expression.getSQL())); - - GridSqlSortColumn type = entry.getValue(); - - if (!type.asc()) - buff.append(" DESC"); - - if (type.nullsFirst()) - buff.append(" NULLS FIRST"); - else if (type.nullsLast()) - buff.append(" NULLS LAST"); - } - } - - if (limit != null) - buff.append(" LIMIT ").append(StringUtils.unEnclose(limit.getSQL())); - - if (offset != null) - buff.append(" OFFSET ").append(StringUtils.unEnclose(offset.getSQL())); - - return buff.toString(); - } + public abstract String getSQL(); /** * @param expression Expression. @@ -221,119 +130,6 @@ public class GridSqlQuery implements Cloneable { } /** - * @return Expressions. - */ - public List<GridSqlElement> groups() { - return groups; - } - - /** - * - */ - public void clearGroups() { - groups = new ArrayList<>(); - grpCols = null; - } - - /** - * @param expression Expression. - */ - public void addGroupExpression(GridSqlElement expression) { - if (expression == null) - throw new NullPointerException(); - - groups.add(expression); - } - - /** - * @return Group columns. - */ - public int[] groupColumns() { - return grpCols; - } - - /** - * @param grpCols Group columns. - */ - public void groupColumns(int[] grpCols) { - this.grpCols = grpCols; - } - - /** - * @return Tables. - */ - public GridSqlElement from() { - return from; - } - - /** - * @param from From element. - * @return {@code this}. - */ - public GridSqlQuery from(GridSqlElement from) { - this.from = from; - - return this; - } - - /** - * @return Where. - */ - public GridSqlElement where() { - return where; - } - - /** - * @param where New where. - */ - public void where(GridSqlElement where) { - this.where = where; - } - - /** - * @param condition Adds new WHERE condition using AND operator. - * @return {@code this}. - */ - public GridSqlQuery whereAnd(GridSqlElement condition) { - if (condition == null) - throw new NullPointerException(); - - GridSqlElement old = where(); - - where(old == null ? condition : new GridSqlOperation(GridSqlOperationType.AND, old, condition)); - - return this; - } - - /** - * @return Having. - */ - public GridSqlElement having() { - return having; - } - - /** - * @param having New having. - */ - public void having(GridSqlElement having) { - this.having = having; - } - - /** - * @param col Index of HAVING column. - */ - public void havingColumn(int col) { - this.havingCol = col; - } - - /** - * @return Index of HAVING column. - */ - public int havingColumn() { - return havingCol; - } - - /** * @return Sort. */ public Map<GridSqlElement,GridSqlSortColumn> sort() { @@ -362,7 +158,6 @@ public class GridSqlQuery implements Cloneable { GridSqlQuery res = (GridSqlQuery)super.clone(); res.select = new ArrayList<>(select); - res.groups = new ArrayList<>(groups); res.sort = new LinkedHashMap<>(sort); res.allExprs = null; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/98de490f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java index d3cd038..fb341c1 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java @@ -22,6 +22,7 @@ import org.h2.command.*; import org.h2.command.dml.*; import org.h2.engine.*; import org.h2.expression.*; +import org.h2.expression.Parameter; import org.h2.jdbc.*; import org.h2.result.*; import org.h2.table.*; @@ -154,6 +155,9 @@ public class GridSqlQueryParser { private static final Getter<JdbcPreparedStatement,Command> COMMAND = getter(JdbcPreparedStatement.class, "command"); /** */ + private static final Getter<SelectUnion, SortOrder> UNION_SORT = getter(SelectUnion.class, "sort"); + + /** */ private static volatile Getter<Command,Prepared> prepared; /** */ @@ -171,14 +175,14 @@ public class GridSqlQueryParser { if (p == null) { Class<? extends Command> cls = cmd.getClass(); - assert cls.getSimpleName().equals("CommandContainer"); + assert "CommandContainer".equals(cls.getSimpleName()); prepared = p = getter(cls, "prepared"); } - Prepared select = p.get(cmd); + Prepared statement = p.get(cmd); - return new GridSqlQueryParser().parse((Select)select); + return new GridSqlQueryParser().parse((Query)statement); } /** @@ -199,9 +203,8 @@ public class GridSqlQueryParser { res = new GridSqlSubquery(parse((Select)qry)); } - else if (tbl instanceof FunctionTable) { + else if (tbl instanceof FunctionTable) res = parseExpression(FUNC_EXPR.get((FunctionTable)tbl)); - } else if (tbl instanceof RangeTable) { res = new GridSqlFunction(GridSqlFunctionType.SYSTEM_RANGE); @@ -225,13 +228,13 @@ public class GridSqlQueryParser { /** * @param select Select. */ - public GridSqlQuery parse(Select select) { - GridSqlQuery res = (GridSqlQuery)h2ObjToGridObj.get(select); + public GridSqlSelect parse(Select select) { + GridSqlSelect res = (GridSqlSelect)h2ObjToGridObj.get(select); if (res != null) return res; - res = new GridSqlQuery(); + res = new GridSqlSelect(); h2ObjToGridObj.put(select, res); @@ -314,6 +317,45 @@ public class GridSqlQueryParser { } /** + * @param qry Select. + */ + public GridSqlQuery parse(Query qry) { + if (qry instanceof Select) + return parse((Select)qry); + + if (qry instanceof SelectUnion) + return parse((SelectUnion)qry); + + throw new UnsupportedOperationException("Unknown query type: " + qry); + } + + /** + * @param union Select. + */ + public GridSqlUnion parse(SelectUnion union) { + GridSqlUnion res = (GridSqlUnion)h2ObjToGridObj.get(union); + + if (res != null) + return res; + + res = new GridSqlUnion(); + + res.right(parse(union.getRight())); + res.left(parse(union.getLeft())); + + res.unionType(union.getUnionType()); + + res.limit(parseExpression(union.getLimit())); + res.offset(parseExpression(union.getOffset())); + + assert UNION_SORT.get(union) == null; // todo IGNITE-624 + + h2ObjToGridObj.put(union, res); + + return res; + } + + /** * @param expression Expression. */ private GridSqlElement parseExpression(@Nullable Expression expression) { @@ -495,8 +537,8 @@ public class GridSqlQueryParser { return res; } - if (expression instanceof org.h2.expression.Parameter) - return new GridSqlParameter(((org.h2.expression.Parameter)expression).getIndex()); + if (expression instanceof Parameter) + return new GridSqlParameter(((Parameter)expression).getIndex()); if (expression instanceof Aggregate) { GridSqlAggregateFunction res = new GridSqlAggregateFunction(DISTINCT.get((Aggregate)expression), http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/98de490f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java index 6c32e13..e98169c 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java @@ -21,6 +21,7 @@ import org.apache.ignite.*; import org.apache.ignite.internal.processors.cache.query.*; import org.h2.jdbc.*; import org.h2.value.*; +import org.jetbrains.annotations.*; import java.util.*; @@ -66,14 +67,19 @@ public class GridSqlQuerySplitter { GridSqlQuery srcQry = GridSqlQueryParser.parse(stmt); + if (!(srcQry instanceof GridSqlSelect)) + throw new UnsupportedOperationException(); // todo IGNITE-624 Support UNION, + + GridSqlSelect srcSelect = (GridSqlSelect)srcQry; + final String mergeTable = TABLE_FUNC_NAME + "()"; // table(0); TODO - GridSqlQuery mapQry = srcQry.clone(); - GridSqlQuery rdcQry = new GridSqlQuery().from(new GridSqlFunction("PUBLIC", TABLE_FUNC_NAME)); // table(mergeTable)); TODO + GridSqlSelect mapQry = srcSelect.clone(); + GridSqlSelect rdcQry = new GridSqlSelect().from(new GridSqlFunction("PUBLIC", TABLE_FUNC_NAME)); // table(mergeTable)); TODO // Split all select expressions into map-reduce parts. - List<GridSqlElement> mapExps = new ArrayList<>(srcQry.allExpressions()); - GridSqlElement[] rdcExps = new GridSqlElement[srcQry.select().size()]; + List<GridSqlElement> mapExps = new ArrayList<>(srcSelect.allExpressions()); + GridSqlElement[] rdcExps = new GridSqlElement[srcSelect.select().size()]; Set<String> colNames = new HashSet<>(); @@ -90,43 +96,43 @@ public class GridSqlQuerySplitter { rdcQry.addSelectExpression(rdcExp); // -- GROUP BY - if (!srcQry.groups().isEmpty()) { + if (!srcSelect.groups().isEmpty()) { mapQry.clearGroups(); - for (int col : srcQry.groupColumns()) + for (int col : srcSelect.groupColumns()) mapQry.addGroupExpression(column(((GridSqlAlias)mapExps.get(col)).alias())); - for (int col : srcQry.groupColumns()) + for (int col : srcSelect.groupColumns()) rdcQry.addGroupExpression(column(((GridSqlAlias)mapExps.get(col)).alias())); } // -- HAVING - if (srcQry.having() != null) { + if (srcSelect.having() != null) { // TODO Find aggregate functions in HAVING clause. - rdcQry.whereAnd(column(columnName(srcQry.havingColumn()))); + rdcQry.whereAnd(column(columnName(srcSelect.havingColumn()))); mapQry.having(null); } // -- ORDER BY - if (!srcQry.sort().isEmpty()) { - for (GridSqlSortColumn sortCol : srcQry.sort().values()) + if (!srcSelect.sort().isEmpty()) { + for (GridSqlSortColumn sortCol : srcSelect.sort().values()) rdcQry.addSort(column(((GridSqlAlias)mapExps.get(sortCol.column())).alias()), sortCol); } // -- LIMIT - if (srcQry.limit() != null) - rdcQry.limit(srcQry.limit()); + if (srcSelect.limit() != null) + rdcQry.limit(srcSelect.limit()); // -- OFFSET - if (srcQry.offset() != null) { + if (srcSelect.offset() != null) { mapQry.offset(null); - rdcQry.offset(srcQry.offset()); + rdcQry.offset(srcSelect.offset()); } // -- DISTINCT - if (srcQry.distinct()) { + if (srcSelect.distinct()) { mapQry.distinct(false); rdcQry.distinct(true); } @@ -148,6 +154,19 @@ public class GridSqlQuerySplitter { * @return Extracted parameters list. */ private static List<Object> findParams(GridSqlQuery qry, Object[] params, ArrayList<Object> target) { + if (qry instanceof GridSqlSelect) + return findParams((GridSqlSelect)qry, params, target); + + throw new UnsupportedOperationException(); // todo IGNITE-624 + } + + /** + * @param qry Select. + * @param params Parameters. + * @param target Extracted parameters. + * @return Extracted parameters list. + */ + private static List<Object> findParams(GridSqlSelect qry, Object[] params, ArrayList<Object> target) { if (params.length == 0) return target; @@ -176,7 +195,7 @@ public class GridSqlQuerySplitter { * @param params Parameters. * @param target Extracted parameters. */ - private static void findParams(GridSqlElement el, Object[] params, ArrayList<Object> target) { + private static void findParams(@Nullable GridSqlElement el, Object[] params, ArrayList<Object> target) { if (el == null) return; http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/98de490f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java new file mode 100644 index 0000000..272f8b4 --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlSelect.java @@ -0,0 +1,243 @@ +/* + * 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.ignite.internal.processors.query.h2.sql; + +import org.h2.util.*; + +import java.util.*; + +/** + * + */ +public class GridSqlSelect extends GridSqlQuery { + /** */ + private List<GridSqlElement> groups = new ArrayList<>(); + + /** */ + private int[] grpCols; + + /** */ + private GridSqlElement from; + + /** */ + private GridSqlElement where; + + /** */ + private GridSqlElement having; + + /** */ + private int havingCol = -1; + + /** {@inheritDoc} */ + @Override public String getSQL() { + StatementBuilder buff = new StatementBuilder("SELECT"); + + if (distinct) + buff.append(" DISTINCT"); + + for (GridSqlElement expression : select) { + buff.appendExceptFirst(","); + buff.append('\n'); + buff.append(StringUtils.indent(expression.getSQL(), 4, false)); + } + + buff.append("\nFROM ").append(from.getSQL()); + + if (where != null) + buff.append("\nWHERE ").append(StringUtils.unEnclose(where.getSQL())); + + if (!groups.isEmpty()) { + buff.append("\nGROUP BY "); + + buff.resetCount(); + + for (GridSqlElement expression : groups) { + buff.appendExceptFirst(", "); + + if (expression instanceof GridSqlAlias) + buff.append(StringUtils.unEnclose((expression.child().getSQL()))); + else + buff.append(StringUtils.unEnclose(expression.getSQL())); + } + } + + if (having != null) + buff.append("\nHAVING ").append(StringUtils.unEnclose(having.getSQL())); + + if (!sort.isEmpty()) { + buff.append("\nORDER BY "); + + buff.resetCount(); + + for (Map.Entry<GridSqlElement,GridSqlSortColumn> entry : sort.entrySet()) { + buff.appendExceptFirst(", "); + + GridSqlElement expression = entry.getKey(); + + int idx = select.indexOf(expression); + + if (idx >= 0) + buff.append(idx + 1); + else + buff.append('=').append(StringUtils.unEnclose(expression.getSQL())); + + GridSqlSortColumn type = entry.getValue(); + + if (!type.asc()) + buff.append(" DESC"); + + if (type.nullsFirst()) + buff.append(" NULLS FIRST"); + else if (type.nullsLast()) + buff.append(" NULLS LAST"); + } + } + + if (limit != null) + buff.append(" LIMIT ").append(StringUtils.unEnclose(limit.getSQL())); + + if (offset != null) + buff.append(" OFFSET ").append(StringUtils.unEnclose(offset.getSQL())); + + return buff.toString(); + } + + /** + * @return Expressions. + */ + public List<GridSqlElement> groups() { + return groups; + } + + /** + * + */ + public void clearGroups() { + groups = new ArrayList<>(); + grpCols = null; + } + + /** + * @param expression Expression. + */ + public void addGroupExpression(GridSqlElement expression) { + if (expression == null) + throw new NullPointerException(); + + groups.add(expression); + } + + /** + * @return Group columns. + */ + public int[] groupColumns() { + return grpCols; + } + + /** + * @param grpCols Group columns. + */ + public void groupColumns(int[] grpCols) { + this.grpCols = grpCols; + } + + /** + * @return Tables. + */ + public GridSqlElement from() { + return from; + } + + /** + * @param from From element. + * @return {@code this}. + */ + public GridSqlSelect from(GridSqlElement from) { + this.from = from; + + return this; + } + + /** + * @return Where. + */ + public GridSqlElement where() { + return where; + } + + /** + * @param where New where. + */ + public void where(GridSqlElement where) { + this.where = where; + } + + /** + * @param cond Adds new WHERE condition using AND operator. + * @return {@code this}. + */ + public GridSqlSelect whereAnd(GridSqlElement cond) { + if (cond == null) + throw new NullPointerException(); + + GridSqlElement old = where(); + + where(old == null ? cond : new GridSqlOperation(GridSqlOperationType.AND, old, cond)); + + return this; + } + + /** + * @return Having. + */ + public GridSqlElement having() { + return having; + } + + /** + * @param having New having. + */ + public void having(GridSqlElement having) { + this.having = having; + } + + /** + * @param col Index of HAVING column. + */ + public void havingColumn(int col) { + havingCol = col; + } + + /** + * @return Index of HAVING column. + */ + public int havingColumn() { + return havingCol; + } + + /** {@inheritDoc} */ + @SuppressWarnings({"CloneCallsConstructors", "CloneDoesntDeclareCloneNotSupportedException"}) + @Override public GridSqlSelect clone() { + GridSqlSelect res = (GridSqlSelect)super.clone(); + + res.groups = new ArrayList<>(groups); + res.grpCols = grpCols == null ? null : grpCols.clone(); + + return res; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/98de490f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlUnion.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlUnion.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlUnion.java new file mode 100644 index 0000000..1eae1ef --- /dev/null +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlUnion.java @@ -0,0 +1,162 @@ +/* + * 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.ignite.internal.processors.query.h2.sql; + +import org.h2.command.dml.*; +import org.h2.message.*; +import org.h2.util.*; + +import javax.cache.*; +import java.util.*; + +/** + * + */ +public class GridSqlUnion extends GridSqlQuery { + /** */ + private int unionType; + + /** */ + private GridSqlQuery right; + + /** */ + private GridSqlQuery left; + + /** {@inheritDoc} */ + @Override public String getSQL() { + StringBuilder buff = new StringBuilder(); + + buff.append('(').append(left.getSQL()).append(')'); + + switch (unionType) { + case SelectUnion.UNION_ALL: + buff.append("\nUNION ALL\n"); + break; + + case SelectUnion.UNION: + buff.append("\nUNION\n"); + break; + + case SelectUnion.INTERSECT: + buff.append("\nINTERSECT\n"); + break; + + case SelectUnion.EXCEPT: + buff.append("\nEXCEPT\n"); + break; + + default: + throw new CacheException("type=" + unionType); + } + + buff.append('(').append(right.getSQL()).append(')'); + + if (!sort.isEmpty()) { + buff.append("\nORDER BY "); + + boolean first = true; + + for (Map.Entry<GridSqlElement, GridSqlSortColumn> entry : sort.entrySet()) { + if (first) + first = false; + else + buff.append(", "); + + GridSqlElement expression = entry.getKey(); + + int idx = select.indexOf(expression); + + if (idx >= 0) + buff.append(idx + 1); + else + buff.append('=').append(StringUtils.unEnclose(expression.getSQL())); + + GridSqlSortColumn type = entry.getValue(); + + if (!type.asc()) + buff.append(" DESC"); + + if (type.nullsFirst()) + buff.append(" NULLS FIRST"); + else if (type.nullsLast()) + buff.append(" NULLS LAST"); + } + } + + if (limit != null) + buff.append(" LIMIT ").append(StringUtils.unEnclose(limit.getSQL())); + + if (offset != null) + buff.append(" OFFSET ").append(StringUtils.unEnclose(offset.getSQL())); + + return buff.toString(); + } + + /** {@inheritDoc} */ + @SuppressWarnings({"CloneCallsConstructors", "CloneDoesntDeclareCloneNotSupportedException"}) + @Override public GridSqlUnion clone() { + GridSqlUnion res = (GridSqlUnion)super.clone(); + + res.right = right.clone(); + res.left = left.clone(); + + return res; + } + + /** + * @return Union type. + */ + public int unionType() { + return unionType; + } + + /** + * @param unionType New union type. + */ + public void unionType(int unionType) { + this.unionType = unionType; + } + + /** + * @return Right. + */ + public GridSqlQuery right() { + return right; + } + + /** + * @param right New right. + */ + public void right(GridSqlQuery right) { + this.right = right; + } + + /** + * @return Left. + */ + public GridSqlQuery left() { + return left; + } + + /** + * @param left New left. + */ + public void left(GridSqlQuery left) { + this.left = left; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/98de490f/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java index db8e8bd..3eead22 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java @@ -197,13 +197,23 @@ public class GridQueryParsingTest extends GridCommonAbstractTest { checkQuery("select addr.street from Person p, (select a.street from Address a where a.street is not null) addr"); checkQuery("select p.name n from \"\".Person p order by p.old + 10"); + + checkQuery("select count(*) as a from Person union select count(*) as a from Address"); + checkQuery("select old, count(*) as a from Person group by old union select 1, count(*) as a from Address"); + checkQuery("select name from Person MINUS select street from Address"); + checkQuery("select name from Person EXCEPT select street from Address"); + checkQuery("select name from Person INTERSECT select street from Address"); + checkQuery("select name from Person UNION select street from Address limit 5"); + checkQuery("select name from Person UNION select street from Address limit ?"); + checkQuery("select name from Person UNION select street from Address limit ? offset ?"); + checkQuery("(select name from Person limit 4) UNION (select street from Address limit 1) limit ? offset ?"); } /** * */ public void testExample1() throws Exception { - Select select = parse("select p.name n, max(p.old) maxOld, min(p.old) minOld from Person p group by p.name having maxOld > 10 and min(p.old) < 1"); + Query select = parse("select p.name n, max(p.old) maxOld, min(p.old) minOld from Person p group by p.name having maxOld > 10 and min(p.old) < 1"); GridSqlQueryParser ses = new GridSqlQueryParser(); @@ -217,7 +227,7 @@ public class GridQueryParsingTest extends GridCommonAbstractTest { * */ private JdbcConnection connection() throws Exception { - GridKernalContext ctx = ((IgniteKernal)ignite).context(); + GridKernalContext ctx = ((IgniteEx)ignite).context(); GridQueryProcessor qryProcessor = ctx.query(); @@ -266,8 +276,8 @@ public class GridQueryParsingTest extends GridCommonAbstractTest { String res; - if (prepared instanceof Select) - res = ses.parse((Select) prepared).getSQL(); + if (prepared instanceof Query) + res = ses.parse((Query) prepared).getSQL(); else throw new UnsupportedOperationException();