ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [2/5] ignite git commit: master - fixes for push down with LEFT OUTER JOIN
Date Thu, 08 Jun 2017 20:19:39 GMT
master - fixes for push down with LEFT OUTER JOIN


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/e3ff16ab
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/e3ff16ab
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/e3ff16ab

Branch: refs/heads/ignite-5272-tx
Commit: e3ff16abed72e2b8a897a2699fe23e0e614f502d
Parents: d2efe78
Author: Sergi Vladykin <sergi.vladykin@gmail.com>
Authored: Thu Jun 8 20:39:05 2017 +0300
Committer: Sergi Vladykin <sergi.vladykin@gmail.com>
Committed: Thu Jun 8 20:39:05 2017 +0300

----------------------------------------------------------------------
 .../processors/query/h2/sql/GridSqlJoin.java    |  7 ++
 .../query/h2/sql/GridSqlQuerySplitter.java      | 82 ++++++++++++++++++--
 .../query/IgniteSqlSplitterSelfTest.java        | 50 ++++++++++++
 3 files changed, 131 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/e3ff16ab/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlJoin.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlJoin.java
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlJoin.java
index afe4a53..9546223 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlJoin.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlJoin.java
@@ -93,6 +93,13 @@ public class GridSqlJoin extends GridSqlElement {
         return child(ON_CHILD);
     }
 
+    /**
+     * @return {@code true} If this is a LEFT OUTER JOIN.
+     */
+    public boolean isLeftOuter() {
+        return leftOuter;
+    }
+
     /** {@inheritDoc} */
     @Override public String getSQL() {
         StatementBuilder buff = new StatementBuilder();

http://git-wip-us.apache.org/repos/asf/ignite/blob/e3ff16ab/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 e87a032..25d97fc 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
@@ -106,6 +106,9 @@ public class GridSqlQuerySplitter {
     private Set<QueryTable> tbls = new HashSet<>();
 
     /** */
+    private Set<String> pushedDownCols = new HashSet<>();
+
+    /** */
     private boolean rdcQrySimple;
 
     /** */
@@ -337,22 +340,75 @@ public class GridSqlQuerySplitter {
     @SuppressWarnings("unused")
     private static void debug(String label, String info) {
         X.println();
-        X.println("  ==" + label + "== ");
+        X.println("  == " + label + " == ");
         X.println(info);
-        X.println("  ======== ");
+        X.println("  ======================= ");
+    }
+
+    /**
+     * @param expr Expression.
+     * @return {@code true} If the expression contains pushed down columns.
+     */
+    private boolean hasPushedDownColumn(GridSqlAst expr) {
+        if (expr instanceof GridSqlColumn)
+            return pushedDownCols.contains(((GridSqlColumn)expr).columnName());
+
+        for (int i = 0; i < expr.size(); i++) {
+            if (hasPushedDownColumn(expr.child(i)))
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param from FROM clause.
+     * @return {@code true} If contains LEFT OUTER JOIN.
+     */
+    private static boolean hasLeftJoin(GridSqlAst from) {
+        while (from instanceof GridSqlJoin) {
+            GridSqlJoin join = (GridSqlJoin)from;
+
+            assert !(join.rightTable() instanceof GridSqlJoin);
+
+            if (join.isLeftOuter())
+                return true;
+
+            from = join.leftTable();
+        }
+
+        return false;
     }
 
     /**
      * @param qrym Query model for the SELECT.
      */
     private void pushDownQueryModelSelect(QueryModel qrym) {
+        assert qrym.type == Type.SELECT: qrym.type;
+
+        boolean hasLeftJoin = hasLeftJoin(qrym.<GridSqlSelect>ast().from());
+
         int begin = -1;
 
         // Here we iterate over joined FROM table filters.
+        // !!! qrym.size() can change, never assign it to a variable.
         for (int i = 0; i < qrym.size(); i++) {
             QueryModel child = qrym.get(i);
 
-            if (child.isQuery() && (child.needSplitChild || child.needSplit)) {
+            boolean hasPushedDownCol = false;
+
+            // It is either splittable subquery (it must remain in REDUCE query)
+            // or left join condition with pushed down columns (this condition
+            // can not be pushed down into a wrap query).
+            if ((child.isQuery() && (child.needSplitChild || child.needSplit)) ||
+                // We always must be at the right side of the join here to push down
+                // range on the left side. If there are no LEFT JOINs in the SELECT, then
+                // we will never have ON conditions, they are getting moved to WHERE clause.
+                (hasPushedDownCol = (hasLeftJoin && i != 0 && hasPushedDownColumn(findJoin(qrym,
i).on())))) {
+                // Handle a single table push down case.
+                if (hasPushedDownCol && begin == -1)
+                    begin = i - 1;
+
                 // Push down the currently collected range.
                 if (begin != -1) {
                     pushDownQueryModelRange(qrym, begin, i - 1);
@@ -361,8 +417,10 @@ public class GridSqlQuerySplitter {
 
                     assert qrym.get(i) == child; // Adjustment check: we have to return to
the same point.
 
-                    // Reset range begin.
-                    begin = -1;
+                    // Reset range begin: in case of pushed down column we can assume current
child as
+                    // as new begin (because it is not a splittable subquery), otherwise
reset begin
+                    // and try to find next range begin further.
+                    begin = hasPushedDownCol ? i : -1;
                 }
 
                 if (child.needSplitChild)
@@ -394,7 +452,7 @@ public class GridSqlQuerySplitter {
                 for (int i = 0; i < qrym.size(); i++) {
                     QueryModel child = qrym.get(i);
 
-                    assert child.isQuery() : qrym.type;
+                    assert child.isQuery() : child.type;
 
                     if (child.needSplit)
                         needSplitChild = true;
@@ -579,9 +637,12 @@ public class GridSqlQuerySplitter {
     /**
      * @param qrym Query model.
      */
-    private void setNeedSplit(QueryModel qrym) {
-        if (qrym.type == Type.SELECT)
+    private static void setNeedSplit(QueryModel qrym) {
+        if (qrym.type == Type.SELECT) {
+            assert !qrym.needSplitChild;
+
             qrym.needSplit = true;
+        }
         else if (qrym.type == Type.UNION) {
             qrym.needSplitChild = true;
 
@@ -816,6 +877,8 @@ public class GridSqlQuerySplitter {
 
         // Push down related ON conditions for all the related joins.
         while (from instanceof GridSqlJoin) {
+            assert !(((GridSqlJoin)from).rightTable() instanceof GridSqlJoin);
+
             pushDownColumnsInExpression(tblAliases, cols, wrapAlias, from, ON_CHILD);
 
             from = from.child(LEFT_TABLE_CHILD);
@@ -909,6 +972,9 @@ public class GridSqlQuerySplitter {
 
             // We have this map to avoid column duplicates in wrap query.
             cols.put(uniqueColAlias, colAlias);
+
+            if (!pushedDownCols.add(uniqueColAlias)) // Must be globally unique.
+                throw new IllegalStateException(uniqueColAlias);
         }
 
         col = column(uniqueColAlias);

http://git-wip-us.apache.org/repos/asf/ignite/blob/e3ff16ab/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
index 8b743bf..6c61988 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/IgniteSqlSplitterSelfTest.java
@@ -211,6 +211,56 @@ public class IgniteSqlSplitterSelfTest extends GridCommonAbstractTest
{
 
     /**
      */
+    public void testPushDownLeftJoin() {
+        IgniteCache<Integer, Person> c = ignite(0).getOrCreateCache(cacheConfig("ps",
true,
+            Integer.class, Person.class));
+
+        try {
+            String subqryAgg = "(select max(p.id) as id, p.depId from Person p group by p.depId)";
+            String subqrySimple = "(select p.id, p.depId from Person p)";
+
+            for (int i = 0; i < 5; i++) {
+                for (int k = 0; k < 5; k++) {
+                    SB qry = new SB("select * from ");
+
+                    for (int j = 0; j < 5; j++) {
+                        if (j != 0)
+                            qry.a(j == i ? " left join " : " join ");
+
+                        if (j == 2)
+                            qry.a(subqryAgg);
+                        else
+                            qry.a(j == k ? subqrySimple : "Person");
+
+                        qry.a(" p").a(j);
+
+                        if (j != 0) {
+                            qry.a(" on ");
+
+                            qry.a(" p0.id").a(" = ").a("p").a(j).a(".depId");
+                        }
+                    }
+
+
+                    X.println(" ---> ik: : " + i + " " + k);
+                    X.println("\nqry: \n" + qry.toString());
+
+                    c.query(new SqlFieldsQuery(qry.toString())
+                        .setEnforceJoinOrder(true)).getAll();
+
+                    X.println("\nPlan:\n" +
+                        c.query(new SqlFieldsQuery("explain " + qry.toString())
+                            .setEnforceJoinOrder(true)).getAll());
+                }
+            }
+        }
+        finally {
+            c.destroy();
+        }
+    }
+
+    /**
+     */
     public void testReplicatedTablesUsingPartitionedCache() {
         doTestReplicatedTablesUsingPartitionedCache(1, false, false);
     }


Mime
View raw message