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 2015/03/10 16:58:57 UTC
phoenix git commit: PHOENIX-1709 And expression of primary key RVCs
can not compile
Repository: phoenix
Updated Branches:
refs/heads/master 44a7064bb -> dee6f9d38
PHOENIX-1709 And expression of primary key RVCs can not compile
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/dee6f9d3
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/dee6f9d3
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/dee6f9d3
Branch: refs/heads/master
Commit: dee6f9d3850e80ea6bb2bd9d002b4acba15750ea
Parents: 44a7064
Author: James Taylor <jt...@salesforce.com>
Authored: Sat Mar 7 10:24:18 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Tue Mar 10 08:58:46 2015 -0700
----------------------------------------------------------------------
.../apache/phoenix/compile/WhereOptimizer.java | 28 +++++++-------
.../org/apache/phoenix/schema/RowKeySchema.java | 39 ++++++++++++++++++--
.../phoenix/compile/WhereOptimizerTest.java | 38 +++++++++++++++++++
3 files changed, 86 insertions(+), 19 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/dee6f9d3/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
index a1a349a..713076e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
@@ -71,7 +71,6 @@ import org.apache.phoenix.util.ScanUtil;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.StringUtil;
-import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -1068,9 +1067,6 @@ public class WhereOptimizer {
}
public final KeySlot intersect(KeySlot that) {
- Preconditions.checkArgument(!this.keyRanges.isEmpty());
- Preconditions.checkArgument(!that.keyRanges.isEmpty());
-
if (this.getPKSpan() == 1 && that.getPKSpan() == 1) {
if (this.getPKPosition() != that.getPKPosition()) {
throw new IllegalArgumentException("Position must be equal for intersect");
@@ -1102,8 +1098,6 @@ public class WhereOptimizer {
} else {
assert(this.getPKSpan() > 1);
assert(this.getPKPosition() <= that.getPKPosition());
- int position = this.getPKPosition();
- int thatPosition = that.getPKPosition();
List<KeyRange> newKeyRanges = Lists.newArrayListWithExpectedSize(this.getKeyRanges().size());
// We know we have a set of RVCs (i.e. multi-span key ranges)
// Get the PK slot value in the RVC for the position of the other KeySlot
@@ -1112,17 +1106,21 @@ public class WhereOptimizer {
for (KeyRange keyRange : this.getKeyRanges()) {
assert(keyRange.isSingleKey());
byte[] key = keyRange.getLowerRange();
- schema.iterator(key, ptr); // initialize for iteration
- while (position < thatPosition) { // skip to part of RVC that overlaps
- schema.next(ptr, position++, key.length);
- }
- // Create a range just for the overlapping column
- List<KeyRange> slotKeyRanges = Collections.singletonList(KeyRange.getKeyRange(ByteUtil.copyKeyBytesIfNecessary(ptr)));
- // Intersect with other ranges and add to list if it overlaps
- if (!isDegenerate(KeyRange.intersect(slotKeyRanges, that.getKeyRanges()))) {
- newKeyRanges.add(keyRange);
+ int position = this.getPKPosition();
+ int thatPosition = that.getPKPosition();
+ ptr.set(key);
+ if (schema.position(ptr, position, thatPosition)) {
+ // Create a range just for the overlapping column
+ List<KeyRange> slotKeyRanges = Collections.singletonList(KeyRange.getKeyRange(ByteUtil.copyKeyBytesIfNecessary(ptr)));
+ // Intersect with other ranges and add to list if it overlaps
+ if (!isDegenerate(KeyRange.intersect(slotKeyRanges, that.getKeyRanges()))) {
+ newKeyRanges.add(keyRange);
+ }
}
}
+ if (isDegenerate(newKeyRanges)) {
+ return null;
+ }
return new KeySlot(
new BaseKeyPart(this.getKeyPart().getColumn(),
SchemaUtil.concat(this.getKeyPart().getExtractNodes(),
http://git-wip-us.apache.org/repos/asf/phoenix/blob/dee6f9d3/phoenix-core/src/main/java/org/apache/phoenix/schema/RowKeySchema.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/RowKeySchema.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/RowKeySchema.java
index 7c36e41..e5aa571 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/RowKeySchema.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/RowKeySchema.java
@@ -23,7 +23,6 @@ import java.util.Collections;
import java.util.List;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
-
import org.apache.phoenix.query.QueryConstants;
@@ -111,17 +110,23 @@ public class RowKeySchema extends ValueSchema {
// navigation methods that "select" different chunks of the row key held in a bytes ptr
/**
- * Move the bytes ptr to the next position in the row key relative to its current position
+ * Move the bytes ptr to the next position in the row key relative to its current position. You
+ * must have a complete row key. Use @link {@link #position(ImmutableBytesWritable, int, int)}
+ * if you have a partial row key.
* @param ptr bytes pointer pointing to the value at the positional index provided.
* @param position zero-based index of the next field in the value schema
* @param maxOffset max possible offset value when iterating
* @return true if a value was found and ptr was set, false if the value is null and ptr was not
* set, and null if the value is null and there are no more values
*/
+ public Boolean next(ImmutableBytesWritable ptr, int position, int maxOffset) {
+ return next(ptr, position, maxOffset, false);
+ }
+
@edu.umd.cs.findbugs.annotations.SuppressWarnings(
value="NP_BOOLEAN_RETURN_NULL",
justification="Designed to return null.")
- public Boolean next(ImmutableBytesWritable ptr, int position, int maxOffset) {
+ private Boolean next(ImmutableBytesWritable ptr, int position, int maxOffset, boolean isFirst) {
if (ptr.getOffset() + ptr.getLength() >= maxOffset) {
ptr.set(ptr.get(), maxOffset, 0);
return null;
@@ -134,7 +139,9 @@ public class RowKeySchema extends ValueSchema {
// backing byte array.
ptr.set(ptr.get(), ptr.getOffset() + ptr.getLength(), 0);
// If positioned at SEPARATOR_BYTE, skip it.
- if (position > 0 && !getField(position-1).getDataType().isFixedWidth()) {
+ // Don't look back at previous fields if this is our first next call, as
+ // we may have a partial key for RVCs that doesn't include the leading field.
+ if (position > 0 && !isFirst && !getField(position-1).getDataType().isFixedWidth()) {
ptr.set(ptr.get(), ptr.getOffset()+ptr.getLength()+1, 0);
}
Field field = this.getField(position);
@@ -270,6 +277,30 @@ public class RowKeySchema extends ValueSchema {
readExtraFields(ptr, newPosition + 1, maxOffset, extraSpan);
return returnValue;
}
+
+
+ /**
+ * Positions ptr at the part of the row key for the field at endPosition,
+ * starting from the field at position.
+ * @param ptr bytes pointer that points to row key being traversed.
+ * @param position the starting field position
+ * @param endPosition the ending field position
+ * @return true if the row key has a value at endPosition with ptr pointing to
+ * that value and false otherwise with ptr not necessarily set.
+ */
+ public boolean position(ImmutableBytesWritable ptr, int position, int endPosition) {
+ int maxOffset = ptr.getLength();
+ this.iterator(ptr); // initialize for iteration
+ boolean isFirst = true;
+ while (position <= endPosition) {
+ if (this.next(ptr, position++, maxOffset, isFirst) == null) {
+ return false;
+ }
+ isFirst = false;
+ }
+ return true;
+ }
+
/**
* Extends the boundaries of the {@code ptr} to contain the next {@code extraSpan} fields in the row key.
http://git-wip-us.apache.org/repos/asf/phoenix/blob/dee6f9d3/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 ddbacb7..0ec6b45 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
@@ -57,6 +57,7 @@ import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.ColumnNotFoundException;
import org.apache.phoenix.schema.types.PChar;
import org.apache.phoenix.schema.types.PDate;
+import org.apache.phoenix.schema.types.PInteger;
import org.apache.phoenix.schema.types.PUnsignedLong;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.util.ByteUtil;
@@ -1818,4 +1819,41 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
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());
}
+
+ @Test
+ public void testAndWithRVC() throws Exception {
+ String ddl;
+ String query;
+ StatementContext context;
+ Connection conn = DriverManager.getConnection(getUrl());
+
+ ddl = "create table t (a integer not null, b integer not null, c integer constraint pk primary key (a,b))";
+ conn.createStatement().execute(ddl);
+ conn.close();
+
+ query = "select c from t where (a,b) in ( (1,2) , (1,3) ) and b = 4";
+ context = compileStatement(query, Collections.<Object>emptyList());
+ assertDegenerate(context.getScan());
+
+ query = "select c from t where a in (1,2) and b = 3 and (a,b) in ( (1,2) , (1,3))";
+ context = compileStatement(query, Collections.<Object>emptyList());
+ assertArrayEquals(ByteUtil.concat(PInteger.INSTANCE.toBytes(1), PInteger.INSTANCE.toBytes(3)), context.getScan().getStartRow());
+ assertArrayEquals(ByteUtil.concat(PInteger.INSTANCE.toBytes(1), ByteUtil.nextKey(PInteger.INSTANCE.toBytes(3))), context.getScan().getStopRow());
+
+ query = "select c from t where a = 1 and b = 3 and (a,b) in ( (1,2) , (1,3))";
+ context = compileStatement(query, Collections.<Object>emptyList());
+ assertArrayEquals(ByteUtil.concat(PInteger.INSTANCE.toBytes(1), PInteger.INSTANCE.toBytes(3)), context.getScan().getStartRow());
+ assertArrayEquals(ByteUtil.concat(PInteger.INSTANCE.toBytes(1), ByteUtil.nextKey(PInteger.INSTANCE.toBytes(3))), context.getScan().getStopRow());
+
+ // Test with RVC occurring later in the PK
+ ddl = "create table t1 (d varchar, e char(3) not null, a integer not null, b integer not null, c integer constraint pk primary key (d, e, a,b))";
+ conn.createStatement().execute(ddl);
+ conn.close();
+
+ query = "select c from t1 where d = 'a' and e = 'foo' and a in (1,2) and b = 3 and (a,b) in ( (1,2) , (1,3))";
+ context = compileStatement(query, Collections.<Object>emptyList());
+ assertArrayEquals(ByteUtil.concat(PVarchar.INSTANCE.toBytes("a"), QueryConstants.SEPARATOR_BYTE_ARRAY, PChar.INSTANCE.toBytes("foo"), PInteger.INSTANCE.toBytes(1), PInteger.INSTANCE.toBytes(3)), context.getScan().getStartRow());
+ assertArrayEquals(ByteUtil.concat(PVarchar.INSTANCE.toBytes("a"), QueryConstants.SEPARATOR_BYTE_ARRAY, PChar.INSTANCE.toBytes("foo"), PInteger.INSTANCE.toBytes(1), ByteUtil.nextKey(PInteger.INSTANCE.toBytes(3))), context.getScan().getStopRow());
+ }
+
}