You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/11/07 07:46:28 UTC

[2/5] phoenix git commit: PHOENIX-1416 Given a schema name, DatabaseMetadata.getTables and getColumns calls erroneously match tables without schema

PHOENIX-1416 Given a schema name, DatabaseMetadata.getTables and getColumns calls erroneously match tables without schema


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

Branch: refs/heads/3.0
Commit: 6abe4df01e4c298a16f029c40e3b8cb120702f18
Parents: c971557
Author: James Taylor <jt...@salesforce.com>
Authored: Thu Nov 6 17:57:57 2014 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Thu Nov 6 22:38:19 2014 -0800

----------------------------------------------------------------------
 .../end2end/QueryDatabaseMetaDataIT.java        | 43 ++++++++++++++++++
 .../org/apache/phoenix/compile/ScanRanges.java  |  8 +++-
 .../phoenix/expression/AndExpression.java       |  4 +-
 .../phoenix/expression/AndOrExpression.java     | 11 +----
 .../apache/phoenix/expression/OrExpression.java |  4 +-
 .../phoenix/compile/WhereOptimizerTest.java     | 47 ++++++++++++++++++++
 6 files changed, 102 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/6abe4df0/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java
index 9bf2b0c..83bb91d 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java
@@ -1058,4 +1058,47 @@ public class QueryDatabaseMetaDataIT extends BaseClientManagedTimeIT {
         }
         conn5.close();
     }
+    
+
+    @Test
+    public void testTableWithScemaMetadataScan() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = new Properties();
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        
+        conn.createStatement().execute("create table foo.bar(k varchar primary key)");
+        conn.createStatement().execute("create table bar(k varchar primary key)");       
+        conn.close();
+        
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 10));
+        conn = DriverManager.getConnection(getUrl(), props);
+        
+        DatabaseMetaData metaData = conn.getMetaData();
+        ResultSet rs;
+        
+        // Tricky case that requires returning false for null AND true expression
+        rs = metaData.getTables(null, "FOO", "BAR", null);
+        assertTrue(rs.next());
+        assertEquals("FOO",rs.getString("TABLE_SCHEM"));
+        assertEquals("BAR", rs.getString("TABLE_NAME"));
+        assertFalse(rs.next());
+
+        // Tricky case that requires end key to maintain trailing nulls
+        rs = metaData.getTables("", "FOO", "BAR", null);
+        assertTrue(rs.next());
+        assertEquals("FOO",rs.getString("TABLE_SCHEM"));
+        assertEquals("BAR", rs.getString("TABLE_NAME"));
+        assertFalse(rs.next());
+
+        rs = metaData.getTables("", null, "BAR", null);
+        assertTrue(rs.next());
+        assertEquals(null,rs.getString("TABLE_SCHEM"));
+        assertEquals("BAR", rs.getString("TABLE_NAME"));
+        assertTrue(rs.next());
+        assertEquals("FOO",rs.getString("TABLE_SCHEM"));
+        assertEquals("BAR", rs.getString("TABLE_NAME"));
+        assertFalse(rs.next());
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/6abe4df0/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
index d60a288..61b6451 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ScanRanges.java
@@ -440,9 +440,13 @@ public class ScanRanges {
         if (ScanUtil.getTotalSpan(ranges, slotSpan) < schema.getMaxFields()) {
             return false;
         }
-        for (List<KeyRange> orRanges : ranges) {
+        int lastIndex = ranges.size()-1;
+        for (int i = lastIndex; i >= 0; i--) {
+            List<KeyRange> orRanges = ranges.get(i);
             for (KeyRange keyRange : orRanges) {
-                if (!keyRange.isSingleKey()) {
+                // Special case for single trailing IS NULL. We cannot consider this as a point key because
+                // we strip trailing nulls when we form the key.
+                if (!keyRange.isSingleKey() || (i == lastIndex && keyRange == KeyRange.IS_NULL_RANGE)) {
                     return false;
                 }
             }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/6abe4df0/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
index e9c2740..bb2dc7e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
@@ -79,8 +79,8 @@ public class AndExpression extends AndOrExpression {
     }
 
     @Override
-    protected boolean getStopValue() {
-        return Boolean.FALSE;
+    protected boolean isStopValue(Boolean value) {
+        return !Boolean.TRUE.equals(value);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/6abe4df0/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
index eebcd34..89ad02e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
@@ -21,7 +21,6 @@ import java.util.BitSet;
 import java.util.List;
 
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
-
 import org.apache.phoenix.schema.PDataType;
 import org.apache.phoenix.schema.tuple.Tuple;
 
@@ -45,11 +44,6 @@ public abstract class AndOrExpression extends BaseCompoundExpression {
     }
     
     @Override
-    public int hashCode() {
-        return 31 * super.hashCode() + Boolean.valueOf(this.getStopValue()).hashCode();
-    }
-
-    @Override
     public PDataType getDataType() {
         return PDataType.BOOLEAN;
     }
@@ -67,7 +61,6 @@ public abstract class AndOrExpression extends BaseCompoundExpression {
     @Override
     public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
         boolean isNull = false;
-        boolean stopValue = getStopValue();
         for (int i = 0; i < children.size(); i++) {
             Expression child = children.get(i);
             // If partial state is available, then use that to know we've already evaluated this
@@ -77,7 +70,7 @@ public abstract class AndOrExpression extends BaseCompoundExpression {
                 // evaluate versus getValue code path.
                 if (child.evaluate(tuple, ptr)) {
                     // Short circuit if we see our stop value
-                    if (Boolean.valueOf(stopValue).equals(PDataType.BOOLEAN.toObject(ptr, child.getDataType()))) {
+                    if (isStopValue((Boolean)PDataType.BOOLEAN.toObject(ptr, child.getDataType()))) {
                         return true;
                     } else if (partialEvalState != null) {
                         partialEvalState.set(i);
@@ -93,5 +86,5 @@ public abstract class AndOrExpression extends BaseCompoundExpression {
         return true;
     }
 
-    protected abstract boolean getStopValue();
+    protected abstract boolean isStopValue(Boolean value);
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/6abe4df0/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java
index e8565c5..5b1b62e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java
@@ -38,8 +38,8 @@ public class OrExpression extends AndOrExpression {
     }
 
     @Override
-    protected boolean getStopValue() {
-        return Boolean.TRUE;
+    protected boolean isStopValue(Boolean value) {
+        return Boolean.TRUE.equals(value);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/6abe4df0/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
index 032768b..1ce6c02 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
@@ -45,6 +45,7 @@ import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.filter.Filter;
 import org.apache.hadoop.hbase.filter.FilterList;
+import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.phoenix.filter.RowKeyComparisonFilter;
 import org.apache.phoenix.filter.SingleKeyValueComparisonFilter;
 import org.apache.phoenix.filter.SkipScanFilter;
@@ -1734,4 +1735,50 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
         return conn;
     }
     
+    @Test
+    public void testTrailingIsNull() throws Exception {
+        String baseTableDDL = "CREATE TABLE t(\n " + 
+                "  a VARCHAR,\n" + 
+                "  b VARCHAR,\n" + 
+                "  CONSTRAINT pk PRIMARY KEY (a, b))";
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute(baseTableDDL);
+        conn.close();
+        
+        String query = "SELECT * FROM t WHERE a = 'a' and b is null";
+        StatementContext context = compileStatement(query, Collections.<Object>emptyList());
+        Scan scan = context.getScan();
+        Filter filter = scan.getFilter();
+        assertNull(filter);
+        assertArrayEquals(Bytes.toBytes("a"), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("a"), QueryConstants.SEPARATOR_BYTE_ARRAY, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+    }
+    
+    
+    @Test
+    public void testTrailingIsNullWithOr() throws Exception {
+        String baseTableDDL = "CREATE TABLE t(\n " + 
+                "  a VARCHAR,\n" + 
+                "  b VARCHAR,\n" + 
+                "  CONSTRAINT pk PRIMARY KEY (a, b))";
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute(baseTableDDL);
+        conn.close();
+        
+        String query = "SELECT * FROM t WHERE a = 'a' and (b is null or b = 'b')";
+        StatementContext context = compileStatement(query, Collections.<Object>emptyList());
+        Scan scan = context.getScan();
+        Filter filter = scan.getFilter();
+        assertTrue(filter instanceof SkipScanFilter);
+        SkipScanFilter skipScan = (SkipScanFilter)filter;
+        List<List<KeyRange>>slots = skipScan.getSlots();
+        assertEquals(2,slots.size());
+        assertEquals(1,slots.get(0).size());
+        assertEquals(2,slots.get(1).size());
+        assertEquals(KeyRange.getKeyRange(Bytes.toBytes("a")), slots.get(0).get(0));
+        assertTrue(KeyRange.IS_NULL_RANGE == slots.get(1).get(0));
+        assertEquals(KeyRange.getKeyRange(Bytes.toBytes("b")), slots.get(1).get(1));
+        assertArrayEquals(Bytes.toBytes("a"), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("a"), QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes("b"), QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+    }
 }