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());
+    }
+    
 }