Repository: phoenix
Updated Branches:
  refs/heads/4.x-HBase-0.98 ea57ee008 -> 63fa82e63


PHOENIX-4586 UPSERT SELECT doesn't take in account comparison operators for 
subqueries.


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

Branch: refs/heads/4.x-HBase-0.98
Commit: 63fa82e6374a03f0d243820b1e135cc88e185381
Parents: ea57ee0
Author: maryannxue <maryann....@gmail.com>
Authored: Thu Feb 8 12:51:16 2018 -0800
Committer: maryannxue <maryann....@gmail.com>
Committed: Thu Feb 8 12:51:16 2018 -0800

----------------------------------------------------------------------
 .../apache/phoenix/end2end/join/SubqueryIT.java | 41 ++++++++++++++++++++
 .../apache/phoenix/compile/UpsertCompiler.java  |  3 +-
 .../org/apache/phoenix/parse/ParseNode.java     | 26 ++++++++++++-
 3 files changed, 68 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/63fa82e6/phoenix-core/src/it/java/org/apache/phoenix/end2end/join/SubqueryIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/join/SubqueryIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/join/SubqueryIT.java
index 604db63..1da98d2 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/join/SubqueryIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/join/SubqueryIT.java
@@ -744,6 +744,47 @@ public class SubqueryIT extends BaseJoinIT {
     }
 
     @Test
+    public void testNoncorrelatedSubqueryWithUpsert() throws Exception {
+        String tempTable = generateUniqueName();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        conn.setAutoCommit(true);
+        try {
+            conn.createStatement().execute("CREATE TABLE " + tempTable
+                    + "   (item_id varchar not null primary key, "
+                    + "    name varchar)");
+            conn.createStatement().execute("UPSERT INTO " + tempTable + " 
VALUES('1', 'a')");
+            conn.createStatement().execute("UPSERT INTO " + tempTable + " 
VALUES('2', 'b')");
+            conn.createStatement().execute("UPSERT INTO " + tempTable + 
"(item_id, name)"
+                    + "   SELECT item_id, 'x' FROM " + tempTable
+                    + "   WHERE item_id < 'z' AND name > ALL (SELECT name FROM 
" + tempTable + ")");
+
+            String query = "SELECT name FROM " + tempTable + " ORDER BY 
item_id";
+            PreparedStatement statement = conn.prepareStatement(query);
+            ResultSet rs = statement.executeQuery();
+            assertTrue(rs.next());
+            assertEquals("a", rs.getString(1));
+            assertTrue(rs.next());
+            assertEquals("b", rs.getString(1));
+            assertFalse(rs.next());
+
+            conn.createStatement().execute("UPSERT INTO " + tempTable + 
"(item_id, name)"
+                    + "   SELECT item_id, 'x' FROM " + tempTable
+                    + "   WHERE item_id < 'z' AND name > ANY (SELECT name FROM 
" + tempTable + ")");
+
+            statement = conn.prepareStatement(query);
+            rs = statement.executeQuery();
+            assertTrue(rs.next());
+            assertEquals("a", rs.getString(1));
+            assertTrue(rs.next());
+            assertEquals("x", rs.getString(1));
+            assertFalse(rs.next());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
     public void testSubqueryWithDelete() throws Exception {
         String tempTable = generateUniqueName();
         Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/63fa82e6/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
index fcac335..ea32b9f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UpsertCompiler.java
@@ -532,9 +532,10 @@ public class UpsertCompiler {
                 // region space managed by region servers. So we bail out on 
executing on server side.
                 // Disable running upsert select on server side if a table has 
global mutable secondary indexes on it
                 boolean hasGlobalMutableIndexes = 
SchemaUtil.hasGlobalIndex(table) && !table.isImmutableRows();
+                boolean hasWhereSubquery = select.getWhere() != null && 
select.getWhere().hasSubquery();
                 runOnServer = (sameTable || (serverUpsertSelectEnabled && 
!hasGlobalMutableIndexes)) && isAutoCommit && !table.isTransactional()
                         && !(table.isImmutableRows() && 
!table.getIndexes().isEmpty())
-                        && !select.isJoin() && table.getRowTimestampColPos() 
== -1;
+                        && !select.isJoin() && !hasWhereSubquery && 
table.getRowTimestampColPos() == -1;
             }
             // If we may be able to run on the server, add a hint that favors 
using the data table
             // if all else is equal.

http://git-wip-us.apache.org/repos/asf/phoenix/blob/63fa82e6/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNode.java 
b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNode.java
index b32674e..362e657 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNode.java
@@ -56,6 +56,30 @@ public abstract class ParseNode {
         toSQL(null, buf);
         return buf.toString();
     }
-    
+
+    /**
+     * Returns whether this ParseNode is a SubqueryParseNode
+     * or contains any SubqueryParseNode descendant.
+     */
+    public boolean hasSubquery() {
+        SubqueryFinder finder = new SubqueryFinder();
+        try {
+            this.accept(finder);
+        } catch (SQLException e) {
+            // Not possible.
+        }
+        return finder.hasSubquery;
+    }
+
     public abstract void toSQL(ColumnResolver resolver, StringBuilder buf);
+
+    private static class SubqueryFinder extends 
StatelessTraverseAllParseNodeVisitor {
+        private boolean hasSubquery = false;
+
+        @Override
+        public Void visit(SubqueryParseNode node) throws SQLException {
+            hasSubquery = true;
+            return null;
+        }
+    }
 }

Reply via email to