Repository: phoenix
Updated Branches:
  refs/heads/4.x-HBase-1.0 95cff2d49 -> b35cb98ca


PHOENIX-1312 Do not always project the empty column family (Ram)


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

Branch: refs/heads/4.x-HBase-1.0
Commit: b35cb98caece0183ce4dc29fcae4bfc80dbdc504
Parents: 95cff2d
Author: ramkrishna <ramkrishna.s.vasude...@gmail.com>
Authored: Mon Dec 21 13:35:40 2015 +0530
Committer: ramkrishna <ramkrishna.s.vasude...@gmail.com>
Committed: Mon Dec 21 13:40:05 2015 +0530

----------------------------------------------------------------------
 .../phoenix/end2end/MultiCfQueryExecIT.java     | 69 +++++++++++++++-
 .../phoenix/compile/ProjectionCompiler.java     | 16 ++--
 .../apache/phoenix/compile/QueryCompiler.java   |  2 +-
 .../apache/phoenix/compile/RowProjector.java    | 18 +++--
 .../phoenix/compile/StatementContext.java       |  2 +-
 .../phoenix/iterate/BaseResultIterators.java    | 84 ++++++++++++--------
 .../phoenix/compile/QueryCompilerTest.java      | 33 +++++++-
 .../java/org/apache/phoenix/util/TestUtil.java  | 12 +--
 8 files changed, 179 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java
index 2edf189..f5566ce 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MultiCfQueryExecIT.java
@@ -172,17 +172,80 @@ public class MultiCfQueryExecIT extends 
BaseOwnClusterClientManagedTimeIT {
             assertFalse(rs.next());
             // Use E column family. Since the column family with the empty key 
value (the first one, A)
             // is always added to the scan, we never really use other 
guideposts (but this may change).
-            List<KeyRange> splits = getAllSplits(conn, "MULTI_CF", 
"e.cpu_utilization IS NOT NULL");
+            List<KeyRange> splits = getAllSplits(conn, "MULTI_CF", 
"e.cpu_utilization IS NOT NULL", "COUNT(*)");
             // Since the E column family is not populated, it won't have as 
many splits
             assertEquals(3, splits.size());
             // Same as above for G column family.
-            splits = getAllSplits(conn, "MULTI_CF", "g.response_time IS NOT 
NULL");
+            splits = getAllSplits(conn, "MULTI_CF", "g.response_time IS NOT 
NULL", "COUNT(*)");
             assertEquals(3, splits.size());
         } finally {
             conn.close();
         }
     }
-    
+
+    @Test
+    public void testGuidePostsRetrievedForMultiCF() throws Exception {
+      Connection conn;
+      PreparedStatement stmt;
+      ResultSet rs;
+
+      long ts = nextTimestamp();
+      Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+      props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 
10));
+      conn = DriverManager.getConnection(getUrl(), props);
+      conn.createStatement()
+              .execute(
+                      "CREATE TABLE T (  k INTEGER PRIMARY KEY, A.V1 VARCHAR, 
B.V2 VARCHAR, C.V3 VARCHAR)");
+      conn.close();
+
+      props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 
30));
+      conn = DriverManager.getConnection(getUrl(), props);
+      stmt = conn.prepareStatement("UPSERT INTO T VALUES(?,?,?,?)");
+      stmt.setInt(1, 1);
+      stmt.setString(2, "A");
+      stmt.setString(3, "B");
+      stmt.setString(4, "C");
+      stmt.execute();
+      conn.commit();
+      
+      stmt = conn.prepareStatement("UPSERT INTO T VALUES(?,?,?,?)");
+      stmt.setInt(1, 2);
+      stmt.setString(2, "D");
+      stmt.setString(3, "E");
+      stmt.setString(4, "F");
+      stmt.execute();
+      conn.commit();
+      
+      stmt = conn.prepareStatement("UPSERT INTO T(k, A.V1, C.V3) 
VALUES(?,?,?)");
+      stmt.setInt(1, 3);
+      stmt.setString(2, "E");
+      stmt.setString(3, "X");
+      stmt.execute();
+      conn.commit();
+      
+      stmt = conn.prepareStatement("UPSERT INTO T(k, A.V1, C.V3) 
VALUES(?,?,?)");
+      stmt.setInt(1, 4);
+      stmt.setString(2, "F");
+      stmt.setString(3, "F");
+      stmt.execute();
+      conn.commit();
+ 
+      conn.close();
+ 
+      analyzeTable(getUrl(), ts + 50, "T");
+
+      props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 
60));
+      conn = DriverManager.getConnection(getUrl(), props);
+      rs = conn.createStatement().executeQuery("SELECT B.V2 FROM T WHERE B.V2 
= 'B'");
+      assertTrue(rs.next());
+      assertEquals("B",rs.getString(1));
+      List<KeyRange> splits = getAllSplits(conn, "T", "C.V3 = 'X'", "A.V1");
+      assertEquals(5, splits.size());
+      splits = getAllSplits(conn, "T", "B.V2 = 'B'", "B.V2");
+      assertEquals(3, splits.size());
+      conn.close();
+    }
+
     @Test
     public void testCFToDisambiguate2() throws Exception {
         long ts = nextTimestamp();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
index 7cc2e66..3cf3934 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
@@ -79,7 +79,6 @@ import org.apache.phoenix.schema.PDatum;
 import org.apache.phoenix.schema.PName;
 import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.PTable.IndexType;
-import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.schema.PTableKey;
 import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.schema.RowKeySchema;
@@ -107,6 +106,7 @@ import com.google.common.collect.Sets;
  * @since 0.1
  */
 public class ProjectionCompiler {
+    private static final Expression NULL_EXPRESSION = 
LiteralExpression.newConstant(null);
     private ProjectionCompiler() {
     }
     
@@ -116,7 +116,9 @@ public class ProjectionCompiler {
     }
     
     public static RowProjector compile(StatementContext context, 
SelectStatement statement, GroupBy groupBy) throws SQLException  {
-        return compile(context, statement, groupBy, 
Collections.<PColumn>emptyList());
+        return compile(context, statement, groupBy, 
Collections.<PColumn>emptyList(), 
+                NULL_EXPRESSION// Pass null expression because we don't want 
empty key value to be projected
+                );
     }
     
     private static int getMinPKOffset(PTable table, PName tenantId) {
@@ -338,7 +340,7 @@ public class ProjectionCompiler {
      * @return projector used to access row values during scan
      * @throws SQLException 
      */
-    public static RowProjector compile(StatementContext context, 
SelectStatement statement, GroupBy groupBy, List<? extends PDatum> 
targetColumns) throws SQLException {
+    public static RowProjector compile(StatementContext context, 
SelectStatement statement, GroupBy groupBy, List<? extends PDatum> 
targetColumns, Expression where) throws SQLException {
         List<KeyValueColumnExpression> arrayKVRefs = new 
ArrayList<KeyValueColumnExpression>();
         List<ProjectedColumnExpression> arrayProjectedColumnRefs = new 
ArrayList<ProjectedColumnExpression>();
         List<Expression> arrayKVFuncs = new ArrayList<Expression>();
@@ -384,7 +386,7 @@ public class ProjectionCompiler {
                 } else {
                     projectAllTableColumns(context, tRef, true, 
projectedExpressions, projectedColumns, targetColumns);
                 }                
-            } else if (node instanceof  FamilyWildcardParseNode){
+            } else if (node instanceof  FamilyWildcardParseNode) {
                 if (tableRef == TableRef.EMPTY_TABLE_REF) {
                     throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.NO_TABLE_SPECIFIED_FOR_WILDCARD_SELECT).build().buildException();
                 }
@@ -483,16 +485,16 @@ public class ProjectionCompiler {
         }
         
         selectVisitor.compile();
-        boolean isProjectEmptyKeyValue = (table.getType() != PTableType.VIEW 
|| table.getViewType() != ViewType.MAPPED)
-                && !isWildcard;
+        boolean isProjectEmptyKeyValue = false;
         if (isWildcard) {
             projectAllColumnFamilies(table, scan);
         } else {
+            isProjectEmptyKeyValue = where == null || 
LiteralExpression.isTrue(where) || where.requiresFinalEvaluation();
             for (byte[] family : projectedFamilies) {
                 projectColumnFamily(table, scan, family);
             }
         }
-        return new RowProjector(projectedColumns, estimatedByteSize, 
isProjectEmptyKeyValue, resolver.hasUDFs());
+        return new RowProjector(projectedColumns, estimatedByteSize, 
isProjectEmptyKeyValue, resolver.hasUDFs(), isWildcard);
     }
 
     private static void projectAllColumnFamilies(PTable table, Scan scan) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
index ad65c1c..70bb815 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
@@ -542,7 +542,7 @@ public class QueryCompiler {
         Set<SubqueryParseNode> subqueries = Sets.<SubqueryParseNode> 
newHashSet();
         Expression where = WhereCompiler.compile(context, select, viewWhere, 
subqueries);
         context.setResolver(resolver); // recover resolver
-        RowProjector projector = ProjectionCompiler.compile(context, select, 
groupBy, asSubquery ? Collections.<PDatum>emptyList() : targetColumns);
+        RowProjector projector = ProjectionCompiler.compile(context, select, 
groupBy, asSubquery ? Collections.<PDatum>emptyList() : targetColumns, where);
         OrderBy orderBy = OrderByCompiler.compile(context, select, groupBy, 
limit, projector, groupBy == GroupBy.EMPTY_GROUP_BY ? innerPlanTupleProjector : 
null, isInRowKeyOrder); 
         // Final step is to build the query plan
         if (!asSubquery) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
index 99ab5d4..2123788 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
@@ -25,7 +25,6 @@ import java.util.List;
 import org.apache.phoenix.expression.Determinism;
 import org.apache.phoenix.expression.Expression;
 import 
org.apache.phoenix.expression.visitor.CloneNonDeterministicExpressionVisitor;
-import org.apache.phoenix.schema.AmbiguousColumnException;
 import org.apache.phoenix.schema.ColumnNotFoundException;
 import org.apache.phoenix.util.SchemaUtil;
 
@@ -50,12 +49,13 @@ public class RowProjector {
     private final boolean allCaseSensitive;
     private final boolean someCaseSensitive;
     private final int estimatedSize;
+    private final boolean isProjectAll;
     private final boolean isProjectEmptyKeyValue;
     private final boolean cloneRequired;
     private final boolean hasUDFs;
     
     public RowProjector(RowProjector projector, boolean 
isProjectEmptyKeyValue) {
-        this(projector.getColumnProjectors(), 
projector.getEstimatedRowByteSize(), isProjectEmptyKeyValue, projector.hasUDFs);
+        this(projector.getColumnProjectors(), 
projector.getEstimatedRowByteSize(), isProjectEmptyKeyValue, projector.hasUDFs, 
projector.isProjectAll);
     }
     /**
      * Construct RowProjector based on a list of ColumnProjectors.
@@ -65,7 +65,7 @@ public class RowProjector {
      * @param estimatedRowSize 
      */
     public RowProjector(List<? extends ColumnProjector> columnProjectors, int 
estimatedRowSize, boolean isProjectEmptyKeyValue) {
-        this(columnProjectors, estimatedRowSize, isProjectEmptyKeyValue, 
false);
+        this(columnProjectors, estimatedRowSize, isProjectEmptyKeyValue, 
false, false);
     }
     /**
      * Construct RowProjector based on a list of ColumnProjectors.
@@ -76,7 +76,7 @@ public class RowProjector {
      * @param isProjectEmptyKeyValue
      * @param hasUDFs
      */
-    public RowProjector(List<? extends ColumnProjector> columnProjectors, int 
estimatedRowSize, boolean isProjectEmptyKeyValue, boolean hasUDFs) {
+    public RowProjector(List<? extends ColumnProjector> columnProjectors, int 
estimatedRowSize, boolean isProjectEmptyKeyValue, boolean hasUDFs, boolean 
isProjectAll) {
         this.columnProjectors = Collections.unmodifiableList(columnProjectors);
         int position = columnProjectors.size();
         reverseIndex = ArrayListMultimap.<String, Integer>create();
@@ -95,6 +95,7 @@ public class RowProjector {
         this.someCaseSensitive = someCaseSensitive;
         this.estimatedSize = estimatedRowSize;
         this.isProjectEmptyKeyValue = isProjectEmptyKeyValue;
+        this.isProjectAll = isProjectAll;
         this.hasUDFs = hasUDFs;
         boolean hasPerInvocationExpression = false;
         if (!hasUDFs) {
@@ -129,14 +130,17 @@ public class RowProjector {
             }
         }
         return new RowProjector(clonedColProjectors, 
-                this.getEstimatedRowByteSize(),
-                this.isProjectEmptyKeyValue(), this.hasUDFs);
+                this.estimatedSize, this.isProjectEmptyKeyValue, this.hasUDFs, 
this.isProjectAll);
     }
 
-    public boolean isProjectEmptyKeyValue() {
+    public boolean projectEveryRow() {
         return isProjectEmptyKeyValue;
     }
     
+    public boolean projectEverything() {
+        return isProjectAll;
+    }
+    
     public List<? extends ColumnProjector> getColumnProjectors() {
         return columnProjectors;
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java
index 80c4b89..9f4562a 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/StatementContext.java
@@ -280,7 +280,7 @@ public class StatementContext {
         whereConditionColumns.add(new Pair<byte[], byte[]>(cf, q));
     }
 
-    public List<Pair<byte[], byte[]>> getWhereCoditionColumns() {
+    public List<Pair<byte[], byte[]>> getWhereConditionColumns() {
         return whereConditionColumns;
     }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java
index 19c60bf..21f082f 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java
@@ -25,6 +25,7 @@ import static 
org.apache.phoenix.util.ByteUtil.EMPTY_BYTE_ARRAY;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -158,32 +159,38 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
         } else {
             FilterableStatement statement = plan.getStatement();
             RowProjector projector = plan.getProjector();
-            boolean keyOnlyFilter = familyMap.isEmpty() && 
context.getWhereCoditionColumns().isEmpty();
-            if (projector.isProjectEmptyKeyValue()) {
+            boolean keyOnlyFilter = familyMap.isEmpty() && 
context.getWhereConditionColumns().isEmpty();
+            if (!projector.projectEverything()) {
                 // If nothing projected into scan and we only have one column 
family, just allow everything
                 // to be projected and use a FirstKeyOnlyFilter to skip from 
row to row. This turns out to
                 // be quite a bit faster.
                 // Where condition columns also will get added into familyMap
                 // When where conditions are present, we can not add 
FirstKeyOnlyFilter at beginning.
-                if (familyMap.isEmpty() && 
context.getWhereCoditionColumns().isEmpty()
+                if (familyMap.isEmpty() && 
context.getWhereConditionColumns().isEmpty()
                         && table.getColumnFamilies().size() == 1) {
                     // Project the one column family. We must project a column 
family since it's possible
                     // that there are other non declared column families that 
we need to ignore.
                     
scan.addFamily(table.getColumnFamilies().get(0).getName().getBytes());
                 } else {
-                    byte[] ecf = SchemaUtil.getEmptyColumnFamily(table);
-                    // Project empty key value unless the column family 
containing it has
-                    // been projected in its entirety.
-                    if (!familyMap.containsKey(ecf) || familyMap.get(ecf) != 
null) {
-                        scan.addColumn(ecf, QueryConstants.EMPTY_COLUMN_BYTES);
+                    if (projector.projectEveryRow()) {
+                        byte[] ecf = SchemaUtil.getEmptyColumnFamily(table);
+                        // Project empty key value unless the column family 
containing it has
+                        // been projected in its entirety.
+                        if (!familyMap.containsKey(ecf) || familyMap.get(ecf) 
!= null) {
+                            scan.addColumn(ecf, 
QueryConstants.EMPTY_COLUMN_BYTES);
+                        }
                     }
                 }
-            } else if (table.getViewType() == ViewType.MAPPED) {
-                // Since we don't have the empty key value in MAPPED tables, 
we must select all CFs in HRS. But only the
-                // selected column values are returned back to client
-                for (PColumnFamily family : table.getColumnFamilies()) {
-                    scan.addFamily(family.getName().getBytes());
-                }
+                if (table.getViewType() == ViewType.MAPPED) {
+                    if (projector.projectEveryRow()) {
+                        // Since we don't have the empty key value in MAPPED 
tables, 
+                        // we must select all CFs in HRS. However, only the
+                        // selected column values are returned back to client.
+                        for (PColumnFamily family : table.getColumnFamilies()) 
{
+                            scan.addFamily(family.getName().getBytes());
+                        }
+                    }
+            } 
             }
             // Add FirstKeyOnlyFilter if there are no references to key value 
columns
             if (keyOnlyFilter) {
@@ -236,7 +243,7 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
                     new TreeMap<ImmutableBytesPtr, 
NavigableSet<ImmutableBytesPtr>>();
             Set<byte[]> conditionOnlyCfs = new 
TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
             int referencedCfCount = familyMap.size();
-            for (Pair<byte[], byte[]> whereCol : 
context.getWhereCoditionColumns()) {
+            for (Pair<byte[], byte[]> whereCol : 
context.getWhereConditionColumns()) {
                 if (!(familyMap.containsKey(whereCol.getFirst()))) {
                     referencedCfCount++;
                 }
@@ -267,7 +274,7 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
                 }
             }
             // Making sure that where condition CFs are getting scanned at HRS.
-            for (Pair<byte[], byte[]> whereCol : 
context.getWhereCoditionColumns()) {
+            for (Pair<byte[], byte[]> whereCol : 
context.getWhereConditionColumns()) {
                 if (useOptimization) {
                     if (!(familyMap.containsKey(whereCol.getFirst()))) {
                         scan.addFamily(whereCol.getFirst());
@@ -350,7 +357,7 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
         return guideIndex;
     }
     
-    private List<byte[]> getGuidePosts() {
+    private List<byte[]> getGuidePosts(Set<byte[]> whereConditions) {
         /*
          *  Don't use guide posts if:
          *  1) We're doing a point lookup, as HBase is fast enough at those
@@ -368,22 +375,26 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
         byte[] defaultCF = SchemaUtil.getEmptyColumnFamily(getTable());
         if (table.getColumnFamilies().isEmpty()) {
             // For sure we can get the defaultCF from the table
-            if (guidePostMap.get(defaultCF) != null) {
-                gps = guidePostMap.get(defaultCF).getGuidePosts();
-            }
+            gps = getDefaultFamilyGuidePosts(guidePostMap, defaultCF);
         } else {
-            Scan scan = context.getScan();
-            if (scan.getFamilyMap().size() > 0 && 
!scan.getFamilyMap().containsKey(defaultCF)) {
-                // If default CF is not used in scan, use first CF referenced 
in scan
-                GuidePostsInfo guidePostsInfo = 
guidePostMap.get(scan.getFamilyMap().keySet().iterator().next());
-                if (guidePostsInfo != null) {
-                    gps = guidePostsInfo.getGuidePosts();
+            byte[] familyInWhere = null;
+            if (!whereConditions.isEmpty()) {
+              if (whereConditions.contains(defaultCF)) {
+                gps = getDefaultFamilyGuidePosts(guidePostMap, defaultCF);
+              } else {
+                familyInWhere = whereConditions.iterator().next();
+                if(familyInWhere != null) {
+                  GuidePostsInfo guidePostsInfo = 
guidePostMap.get(familyInWhere);
+                  if (guidePostsInfo != null) {
+                      gps = guidePostsInfo.getGuidePosts();
+                  } else {
+                    // As there are no guideposts collected for the where 
family we go with the default CF
+                    gps = getDefaultFamilyGuidePosts(guidePostMap, defaultCF);
+                  }
                 }
+              }
             } else {
-                // Otherwise, favor use of default CF.
-                if (guidePostMap.get(defaultCF) != null) {
-                    gps = guidePostMap.get(defaultCF).getGuidePosts();
-                }
+              gps = getDefaultFamilyGuidePosts(guidePostMap, defaultCF);
             }
         }
         if (gps == null) {
@@ -391,6 +402,13 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
         }
         return gps;
     }
+
+    private List<byte[]> getDefaultFamilyGuidePosts(Map<byte[], 
GuidePostsInfo> guidePostMap, byte[] defaultCF) {
+      if (guidePostMap.get(defaultCF) != null) {
+          return guidePostMap.get(defaultCF).getGuidePosts();
+      }
+      return null;
+    }
     
     private static String toString(List<byte[]> gps) {
         StringBuilder buf = new StringBuilder(gps.size() * 100);
@@ -439,7 +457,11 @@ public abstract class BaseResultIterators extends 
ExplainTable implements Result
         PTable table = getTable();
         boolean isSalted = table.getBucketNum() != null;
         boolean isLocalIndex = table.getIndexType() == IndexType.LOCAL;
-        List<byte[]> gps = getGuidePosts();
+        HashSet<byte[]> whereConditions = new 
HashSet<byte[]>(context.getWhereConditionColumns().size());
+        for(Pair<byte[], byte[]> where : context.getWhereConditionColumns()) {
+          whereConditions.add(where.getFirst());
+        }
+        List<byte[]> gps = getGuidePosts(whereConditions);
         if (logger.isDebugEnabled()) {
             logger.debug("Guideposts: " + toString(gps));
         }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
index bea222b..9411549 100644
--- 
a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
+++ 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
@@ -441,6 +441,12 @@ public class QueryCompilerTest extends 
BaseConnectionlessQueryTest {
         return plan.getContext().getScan();
     }
     
+    private Scan projectQuery(String query) throws SQLException {
+        QueryPlan plan = getQueryPlan(query, Collections.emptyList());
+        plan.iterator(); // Forces projection
+        return plan.getContext().getScan();
+    }
+    
     private QueryPlan getQueryPlan(String query, List<Object> binds) throws 
SQLException {
         Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
         Connection conn = DriverManager.getConnection(getUrl(), props);
@@ -449,7 +455,8 @@ public class QueryCompilerTest extends 
BaseConnectionlessQueryTest {
             for (Object bind : binds) {
                 statement.setObject(1, bind);
             }
-            return statement.compileQuery(query);
+            QueryPlan plan = statement.compileQuery(query);
+            return plan;
         } finally {
             conn.close();
         }
@@ -2146,5 +2153,29 @@ public class QueryCompilerTest extends 
BaseConnectionlessQueryTest {
         }
     }
 
+    private static void assertFamilies(Scan s, String... families) {
+        assertEquals(families.length, s.getFamilyMap().size());
+        for (String fam : families) {
+            byte[] cf = Bytes.toBytes(fam);
+            assertTrue("Expected to contain " + fam, 
s.getFamilyMap().containsKey(cf));
+        }
+    }
+    
+    @Test
+    public void testProjection() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t(k INTEGER PRIMARY 
KEY, a.v1 VARCHAR, b.v2 VARCHAR, c.v3 VARCHAR)");
+            assertFamilies(projectQuery("SELECT k FROM t"), "A");
+            assertFamilies(projectQuery("SELECT k FROM t WHERE k = 5"), "A");
+            assertFamilies(projectQuery("SELECT v2 FROM t WHERE k = 5"), "A", 
"B");
+            assertFamilies(projectQuery("SELECT v2 FROM t WHERE v2 = 'a'"), 
"B");
+            assertFamilies(projectQuery("SELECT v3 FROM t WHERE v2 = 'a'"), 
"B", "C");
+            assertFamilies(projectQuery("SELECT v3 FROM t WHERE v2 = 'a' AND 
v3 is null"), "A", "B", "C");
+        } finally {
+            conn.close();
+        }
+    }
+    
 
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/b35cb98c/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java 
b/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
index 451ce62..e66f8ca 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
@@ -490,20 +490,20 @@ public class TestUtil {
     }
     
     public static List<KeyRange> getAllSplits(Connection conn, String 
tableName) throws SQLException {
-        return getSplits(conn, tableName, null, null, null, null);
+        return getSplits(conn, tableName, null, null, null, null, null);
     }
     
-    public static List<KeyRange> getAllSplits(Connection conn, String 
tableName, String where) throws SQLException {
-        return getSplits(conn, tableName, null, null, null, where);
+    public static List<KeyRange> getAllSplits(Connection conn, String 
tableName, String where, String selectClause) throws SQLException {
+        return getSplits(conn, tableName, null, null, null, where, 
selectClause);
     }
     
-    public static List<KeyRange> getSplits(Connection conn, String tableName, 
String pkCol, byte[] lowerRange, byte[] upperRange, String whereClauseSuffix) 
throws SQLException {
+    public static List<KeyRange> getSplits(Connection conn, String tableName, 
String pkCol, byte[] lowerRange, byte[] upperRange, String whereClauseSuffix, 
String selectClause) throws SQLException {
         String whereClauseStart = 
                 (lowerRange == null && upperRange == null ? "" : 
                     " WHERE " + ((lowerRange != null ? (pkCol + " >= ? " + 
(upperRange != null ? " AND " : "")) : "") 
                               + (upperRange != null ? (pkCol + " < ?") : "" 
)));
         String whereClause = whereClauseSuffix == null ? whereClauseStart : 
whereClauseStart.length() == 0 ? (" WHERE " + whereClauseSuffix) : (" AND " + 
whereClauseSuffix);
-        String query = "SELECT /*+ NO_INDEX */ COUNT(*) FROM " + tableName + 
whereClause;
+        String query = "SELECT /*+ NO_INDEX */ "+selectClause+" FROM " + 
tableName + whereClause;
         PhoenixPreparedStatement pstmt = 
conn.prepareStatement(query).unwrap(PhoenixPreparedStatement.class);
         if (lowerRange != null) {
             pstmt.setBytes(1, lowerRange);
@@ -548,7 +548,7 @@ public class TestUtil {
     }
 
     public static List<KeyRange> getSplits(Connection conn, byte[] lowerRange, 
byte[] upperRange) throws SQLException {
-        return getSplits(conn, STABLE_NAME, STABLE_PK_NAME, lowerRange, 
upperRange, null);
+        return getSplits(conn, STABLE_NAME, STABLE_PK_NAME, lowerRange, 
upperRange, null, "COUNT(*)");
     }
 
     public static List<KeyRange> getAllSplits(Connection conn) throws 
SQLException {

Reply via email to