# 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();
 

Reply via email to