Repository: phoenix
Updated Branches:
  refs/heads/4.0 9ef28f6f4 -> 338747c97


http://git-wip-us.apache.org/repos/asf/phoenix/blob/338747c9/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java 
b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java
index db2a29d..aea075d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/execute/HashJoinPlan.java
@@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.phoenix.cache.ServerCacheClient.ServerCache;
 import org.apache.phoenix.compile.ColumnProjector;
@@ -44,8 +43,6 @@ import org.apache.phoenix.compile.StatementContext;
 import org.apache.phoenix.compile.WhereCompiler;
 import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.exception.SQLExceptionInfo;
-import org.apache.phoenix.expression.AndExpression;
-import org.apache.phoenix.expression.ComparisonExpression;
 import org.apache.phoenix.expression.Determinism;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.expression.InListExpression;
@@ -58,7 +55,6 @@ import org.apache.phoenix.job.JobManager.JobCallable;
 import org.apache.phoenix.join.HashCacheClient;
 import org.apache.phoenix.join.HashJoinInfo;
 import org.apache.phoenix.parse.FilterableStatement;
-import org.apache.phoenix.parse.HintNode.Hint;
 import org.apache.phoenix.parse.ParseNode;
 import org.apache.phoenix.parse.SQLParser;
 import org.apache.phoenix.parse.SelectStatement;
@@ -82,8 +78,6 @@ public class HashJoinPlan extends DelegateQueryPlan {
     private final HashJoinInfo joinInfo;
     private final SubPlan[] subPlans;
     private final boolean recompileWhereClause;
-    private final boolean forceHashJoinRangeScan;
-    private final boolean forceHashJoinSkipScan;
     private List<SQLCloseable> dependencies;
     private HashCacheClient hashClient;
     private int maxServerCacheTimeToLive;
@@ -115,8 +109,6 @@ public class HashJoinPlan extends DelegateQueryPlan {
         this.joinInfo = joinInfo;
         this.subPlans = subPlans;
         this.recompileWhereClause = recompileWhereClause;
-        this.forceHashJoinRangeScan = 
plan.getStatement().getHint().hasHint(Hint.RANGE_SCAN_HASH_JOIN);
-        this.forceHashJoinSkipScan = 
plan.getStatement().getHint().hasHint(Hint.SKIP_SCAN_HASH_JOIN);
     }
 
     @Override
@@ -200,39 +192,14 @@ public class HashJoinPlan extends DelegateQueryPlan {
     }
 
     private Expression createKeyRangeExpression(Expression lhsExpression,
-            Expression rhsExpression, List<ImmutableBytesWritable> rhsValues, 
-            ImmutableBytesWritable ptr, boolean hasFilters) throws 
SQLException {
+            Expression rhsExpression, List<Expression> rhsValues, 
+            ImmutableBytesWritable ptr) throws SQLException {
         if (rhsValues.isEmpty())
-            return LiteralExpression.newConstant(false, PBoolean.INSTANCE, 
Determinism.ALWAYS);
+            return LiteralExpression.newConstant(false, PBoolean.INSTANCE, 
Determinism.ALWAYS);        
         
-        PDataType type = rhsExpression.getDataType();
-        if (!useInClause(hasFilters)) {
-            ImmutableBytesWritable minValue = rhsValues.get(0);
-            ImmutableBytesWritable maxValue = rhsValues.get(0);
-            for (ImmutableBytesWritable value : rhsValues) {
-                if (value.compareTo(minValue) < 0) {
-                    minValue = value;
-                }
-                if (value.compareTo(maxValue) > 0) {
-                    maxValue = value;
-                }
-            }
-            
-            return AndExpression.create(Lists.newArrayList(
-                    ComparisonExpression.create(CompareOp.GREATER_OR_EQUAL, 
Lists.newArrayList(lhsExpression, 
LiteralExpression.newConstant(type.toObject(minValue), type)), ptr), 
-                    ComparisonExpression.create(CompareOp.LESS_OR_EQUAL, 
Lists.newArrayList(lhsExpression, 
LiteralExpression.newConstant(type.toObject(maxValue), type)), ptr)));
-        }
+        rhsValues.add(0, lhsExpression);
         
-        List<Expression> children = Lists.newArrayList(lhsExpression);
-        for (ImmutableBytesWritable value : rhsValues) {
-            children.add(LiteralExpression.newConstant(type.toObject(value), 
type));
-        }
-        
-        return InListExpression.create(children, false, ptr, false);
-    }
-    
-    private boolean useInClause(boolean hasFilters) {
-        return this.forceHashJoinSkipScan || (!this.forceHashJoinRangeScan && 
hasFilters);
+        return InListExpression.create(rhsValues, false, ptr);
     }
 
     @Override
@@ -345,29 +312,26 @@ public class HashJoinPlan extends DelegateQueryPlan {
         private final boolean singleValueOnly;
         private final Expression keyRangeLhsExpression;
         private final Expression keyRangeRhsExpression;
-        private final boolean hasFilters;
         
         public HashSubPlan(int index, QueryPlan subPlan, 
                 List<Expression> hashExpressions,
                 boolean singleValueOnly,
                 Expression keyRangeLhsExpression, 
-                Expression keyRangeRhsExpression, 
-                boolean hasFilters) {
+                Expression keyRangeRhsExpression) {
             this.index = index;
             this.plan = subPlan;
             this.hashExpressions = hashExpressions;
             this.singleValueOnly = singleValueOnly;
             this.keyRangeLhsExpression = keyRangeLhsExpression;
             this.keyRangeRhsExpression = keyRangeRhsExpression;
-            this.hasFilters = hasFilters;
         }
 
         @Override
         public Object execute(HashJoinPlan parent) throws SQLException {
             ScanRanges ranges = parent.delegate.getContext().getScanRanges();
-            List<ImmutableBytesWritable> keyRangeRhsValues = null;
+            List<Expression> keyRangeRhsValues = null;
             if (keyRangeRhsExpression != null) {
-                keyRangeRhsValues = 
Lists.<ImmutableBytesWritable>newArrayList();
+                keyRangeRhsValues = Lists.<Expression>newArrayList();
             }
             ServerCache cache = null;
             if (hashExpressions != null) {
@@ -383,15 +347,11 @@ public class HashJoinPlan extends DelegateQueryPlan {
                 ResultIterator iterator = plan.iterator();
                 for (Tuple result = iterator.next(); result != null; result = 
iterator.next()) {
                     // Evaluate key expressions for hash join key range 
optimization.
-                    ImmutableBytesWritable value = new 
ImmutableBytesWritable();
-                    keyRangeRhsExpression.reset();
-                    if (keyRangeRhsExpression.evaluate(result, value)) {
-                        keyRangeRhsValues.add(value);
-                    }
+                    
keyRangeRhsValues.add(HashCacheClient.evaluateKeyExpression(keyRangeRhsExpression,
 result, plan.getContext().getTempPtr()));
                 }
             }
             if (keyRangeRhsValues != null) {
-                
parent.keyRangeExpressions.add(parent.createKeyRangeExpression(keyRangeLhsExpression,
 keyRangeRhsExpression, keyRangeRhsValues, plan.getContext().getTempPtr(), 
hasFilters));
+                
parent.keyRangeExpressions.add(parent.createKeyRangeExpression(keyRangeLhsExpression,
 keyRangeRhsExpression, keyRangeRhsValues, plan.getContext().getTempPtr()));
             }
             return cache;
         }
@@ -430,8 +390,7 @@ public class HashJoinPlan extends DelegateQueryPlan {
                 return Collections.<String> emptyList();
             
             String step = "    DYNAMIC SERVER FILTER BY " + 
keyRangeLhsExpression.toString() 
-                    + (parent.useInClause(hasFilters) ? " IN " : " BETWEEN 
MIN/MAX OF ") 
-                    + "(" + keyRangeRhsExpression.toString() + ")";
+                    + " IN (" + keyRangeRhsExpression.toString() + ")";
             return Collections.<String> singletonList(step);
         }
         

http://git-wip-us.apache.org/repos/asf/phoenix/blob/338747c9/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
index 772db97..63178db 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
@@ -58,19 +58,12 @@ public class InListExpression extends BaseSingleExpression {
     private List<Expression> keyExpressions; // client side only
 
     public static Expression create (List<Expression> children, boolean 
isNegate, ImmutableBytesWritable ptr) throws SQLException {
-        return create(children, isNegate, ptr, true);
-    }
-    
-    public static Expression create (List<Expression> children, boolean 
isNegate, ImmutableBytesWritable ptr, boolean allowShortcut) throws 
SQLException {
         Expression firstChild = children.get(0);
         
         if (firstChild.isStateless() && (!firstChild.evaluate(null, ptr) || 
ptr.getLength() == 0)) {
             return LiteralExpression.newConstant(null, PBoolean.INSTANCE, 
firstChild.getDeterminism());
         }
-        // We set allowShortcut to false for child/parent join optimization 
since we 
-        // compare RVC expressions with literal expressions and we want to 
avoid 
-        // RVC-rewrite operation in ComparisonExpression.create().
-        if (allowShortcut && children.size() == 2) {
+        if (children.size() == 2) {
             return ComparisonExpression.create(isNegate ? CompareOp.NOT_EQUAL 
: CompareOp.EQUAL, children, ptr);
         }
         

http://git-wip-us.apache.org/repos/asf/phoenix/blob/338747c9/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java 
b/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java
index 6494603..f13b28e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/join/HashCacheClient.java
@@ -30,18 +30,22 @@ import 
org.apache.phoenix.cache.ServerCacheClient.ServerCache;
 import org.apache.phoenix.compile.ScanRanges;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.expression.ExpressionType;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.RowValueConstructorExpression;
 import org.apache.phoenix.iterate.ResultIterator;
 import org.apache.phoenix.jdbc.PhoenixConnection;
 import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.query.QueryServicesOptions;
 import org.apache.phoenix.schema.TableRef;
 import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.util.ServerUtil;
 import org.apache.phoenix.util.TrustedByteArrayOutputStream;
 import org.apache.phoenix.util.TupleUtil;
-
 import org.iq80.snappy.Snappy;
 
+import com.google.common.collect.Lists;
+
 /**
  * 
  * Client for adding cache of one side of a join to region servers
@@ -70,7 +74,7 @@ public class HashCacheClient  {
      * @throws MaxServerCacheSizeExceededException if size of hash cache 
exceeds max allowed
      * size
      */
-    public ServerCache addHashCache(ScanRanges keyRanges, ResultIterator 
iterator, long estimatedSize, List<Expression> onExpressions, boolean 
singleValueOnly, TableRef cacheUsingTableRef, Expression keyRangeRhsExpression, 
List<ImmutableBytesWritable> keyRangeRhsValues) throws SQLException {
+    public ServerCache addHashCache(ScanRanges keyRanges, ResultIterator 
iterator, long estimatedSize, List<Expression> onExpressions, boolean 
singleValueOnly, TableRef cacheUsingTableRef, Expression keyRangeRhsExpression, 
List<Expression> keyRangeRhsValues) throws SQLException {
         /**
          * Serialize and compress hashCacheTable
          */
@@ -79,7 +83,7 @@ public class HashCacheClient  {
         return serverCache.addServerCache(keyRanges, ptr, new 
HashCacheFactory(), cacheUsingTableRef);
     }
     
-    private void serialize(ImmutableBytesWritable ptr, ResultIterator 
iterator, long estimatedSize, List<Expression> onExpressions, boolean 
singleValueOnly, Expression keyRangeRhsExpression, List<ImmutableBytesWritable> 
keyRangeRhsValues) throws SQLException {
+    private void serialize(ImmutableBytesWritable ptr, ResultIterator 
iterator, long estimatedSize, List<Expression> onExpressions, boolean 
singleValueOnly, Expression keyRangeRhsExpression, List<Expression> 
keyRangeRhsValues) throws SQLException {
         long maxSize = 
serverCache.getConnection().getQueryServices().getProps().getLong(QueryServices.MAX_SERVER_CACHE_SIZE_ATTRIB,
 QueryServicesOptions.DEFAULT_MAX_SERVER_CACHE_SIZE);
         estimatedSize = Math.min(estimatedSize, maxSize);
         if (estimatedSize > Integer.MAX_VALUE) {
@@ -98,6 +102,7 @@ public class HashCacheClient  {
             out.writeInt(exprSize * (singleValueOnly ? -1 : 1));
             int nRows = 0;
             out.writeInt(nRows); // In the end will be replaced with total 
number of rows            
+            ImmutableBytesWritable tempPtr = new ImmutableBytesWritable();
             for (Tuple result = iterator.next(); result != null; result = 
iterator.next()) {
                 TupleUtil.write(result, out);
                 if (baOut.size() > maxSize) {
@@ -105,11 +110,7 @@ public class HashCacheClient  {
                 }
                 // Evaluate key expressions for hash join key range 
optimization.
                 if (keyRangeRhsExpression != null) {
-                    ImmutableBytesWritable value = new 
ImmutableBytesWritable();
-                    keyRangeRhsExpression.reset();
-                    if (keyRangeRhsExpression.evaluate(result, value)) {
-                        keyRangeRhsValues.add(value);
-                    }
+                    
keyRangeRhsValues.add(evaluateKeyExpression(keyRangeRhsExpression, result, 
tempPtr));
                 }
                 nRows++;
             }
@@ -136,4 +137,45 @@ public class HashCacheClient  {
             iterator.close();
         }
     }
+    
+    /**
+     * Evaluate the RHS key expression and wrap the result as a new Expression.
+     * Unlike other types of Expression which will be evaluated and wrapped as 
a 
+     * single LiteralExpression, RowValueConstructorExpression should be 
handled 
+     * differently. We should evaluate each child of RVC and wrap them into a 
new
+     * RVC Expression, in order to make sure that the later coercion between 
the 
+     * LHS key expression and this RHS key expression will be successful.
+     * 
+     * @param keyExpression the RHS key expression
+     * @param tuple the input tuple
+     * @param ptr the temporary pointer
+     * @return the Expression containing the evaluated result
+     * @throws SQLException 
+     */
+    public static Expression evaluateKeyExpression(Expression keyExpression, 
Tuple tuple, ImmutableBytesWritable ptr) throws SQLException {
+        if (!(keyExpression instanceof RowValueConstructorExpression)) {
+            PDataType type = keyExpression.getDataType();
+            keyExpression.reset();
+            if (keyExpression.evaluate(tuple, ptr)) {
+                return LiteralExpression.newConstant(type.toObject(ptr), type);
+            }
+            
+            return LiteralExpression.newConstant(null, type);
+        }
+        
+        List<Expression> children = keyExpression.getChildren();
+        List<Expression> values = 
Lists.newArrayListWithExpectedSize(children.size());
+        for (Expression child : children) {
+            PDataType type = child.getDataType();
+            child.reset();
+            if (child.evaluate(tuple, ptr)) {
+                values.add(LiteralExpression.newConstant(type.toObject(ptr), 
type));
+            } else {
+                values.add(LiteralExpression.newConstant(null, type));
+            }
+        }
+        // The early evaluation of this constant expression is not necessary, 
for it
+        // might be coerced later.
+        return new RowValueConstructorExpression(values, false);
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/338747c9/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java 
b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
index 7a2d313..9c5c2cd 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
@@ -291,7 +291,7 @@ public class QueryOptimizer {
                         if (extractedCondition != null) {
                             outerWhere = 
FACTORY.and(Lists.newArrayList(outerWhere, extractedCondition));
                         }
-                        HintNode hint = 
HintNode.combine(HintNode.subtract(indexSelect.getHint(), new Hint[] 
{Hint.INDEX, Hint.RANGE_SCAN_HASH_JOIN}), FACTORY.hint("NO_INDEX 
SKIP_SCAN_HASH_JOIN"));
+                        HintNode hint = 
HintNode.combine(HintNode.subtract(indexSelect.getHint(), new Hint[] 
{Hint.INDEX, Hint.NO_CHILD_PARENT_JOIN_OPTIMIZATION}), 
FACTORY.hint("NO_INDEX"));
                         SelectStatement query = FACTORY.select(dataSelect, 
hint, outerWhere);
                         ColumnResolver queryResolver = 
FromCompiler.getResolverForQuery(query, statement.getConnection());
                         query = SubqueryRewriter.transform(query, 
queryResolver, statement.getConnection());

http://git-wip-us.apache.org/repos/asf/phoenix/blob/338747c9/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java 
b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
index 5ee8016..94f9bfb 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/HintNode.java
@@ -47,13 +47,9 @@ public class HintNode {
          */
         SKIP_SCAN,
         /**
-         * Forces a range scan when full or partial primary key is used as 
join keys.
+         * Prevents the usage of child-parent-join optimization.
          */
-        RANGE_SCAN_HASH_JOIN,
-        /**
-         * Forces a skip scan when full or partial primary key is used as join 
keys.
-         */
-        SKIP_SCAN_HASH_JOIN,
+        NO_CHILD_PARENT_JOIN_OPTIMIZATION,
         /**
         * Prevents the usage of indexes, forcing usage
         * of the data table for a query.

Reply via email to