Repository: phoenix Updated Branches: refs/heads/4.0 d0c9dac00 -> 4ed86c0cc
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/798531c4 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/798531c4 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/798531c4 Branch: refs/heads/4.0 Commit: 798531c45e88c92b6851de11ca0f3dd8af00e5f0 Parents: d0c9dac Author: James Taylor <jtay...@salesforce.com> Authored: Thu Nov 6 17:57:57 2014 -0800 Committer: James Taylor <jtay...@salesforce.com> Committed: Thu Nov 6 17:57:57 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/798531c4/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 f243562..4c5c828 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 @@ -1063,4 +1063,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/798531c4/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 0ab6368..0842f6a 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/798531c4/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/798531c4/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/798531c4/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/798531c4/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()); + } }