You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by kr...@apache.org on 2023/04/21 08:50:10 UTC

[hive] branch master updated: HIVE-27264: Literals in conjunction of two IN expression are considered not equals if type precision is different (Krisztian Kasa, reviewed by Stamatis Zampetakis, Aman Sinha, Laszlo Vegh)

This is an automated email from the ASF dual-hosted git repository.

krisztiankasa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new 5bec1edeb26 HIVE-27264: Literals in conjunction of two IN expression are considered not equals if type precision is different (Krisztian Kasa, reviewed by Stamatis Zampetakis, Aman Sinha, Laszlo Vegh)
5bec1edeb26 is described below

commit 5bec1edeb269383416c37b16f67b2b8ff522df41
Author: Krisztian Kasa <ka...@gmail.com>
AuthorDate: Fri Apr 21 10:50:01 2023 +0200

    HIVE-27264: Literals in conjunction of two IN expression are considered not equals if type precision is different (Krisztian Kasa, reviewed by Stamatis Zampetakis, Aman Sinha, Laszlo Vegh)
---
 .../rules/HivePointLookupOptimizerRule.java        |  80 ++++++++--
 .../rules/TestHivePointLookupOptimizerRule.java    | 171 +++++++++++++++++++++
 ql/src/test/queries/clientpositive/pointlookup6.q  |  19 +++
 .../results/clientpositive/llap/pointlookup6.q.out |  79 ++++++++++
 4 files changed, 333 insertions(+), 16 deletions(-)

diff --git a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HivePointLookupOptimizerRule.java b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HivePointLookupOptimizerRule.java
index a351a3d4952..bd43b7d6437 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HivePointLookupOptimizerRule.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/rules/HivePointLookupOptimizerRule.java
@@ -27,6 +27,7 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -41,6 +42,7 @@ import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexUtil;
@@ -592,7 +594,7 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
       // Visited nodes
       final Set<RexNode> visitedRefs = new LinkedHashSet<>();
       // IN clauses need to be combined by keeping only common elements
-      final Multimap<RexNode,RexNode> inLHSExprToRHSExprs = LinkedHashMultimap.create();
+      final Multimap<RexNode,SimilarRexNodeElement> inLHSExprToRHSExprs = LinkedHashMultimap.create();
       // We will use this set to keep those expressions that may evaluate
       // into a null value.
       final Multimap<RexNode,RexNode> inLHSExprToRHSNullableExprs = LinkedHashMultimap.create();
@@ -611,15 +613,15 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
             inLHSExprToRHSNullableExprs.put(ref, ref);
           }
           if (inLHSExprToRHSExprs.containsKey(ref)) {
-            Set<RexNode> expressions = Sets.newHashSet();
+            Set<SimilarRexNodeElement> expressions = Sets.newHashSet();
             for (int j = 1; j < inCall.getOperands().size(); j++) {
               RexNode constNode = inCall.getOperands().get(j);
-              expressions.add(constNode);
+              expressions.add(new SimilarRexNodeElement(constNode));
               if (constNode.getType().isNullable()) {
                 inLHSExprToRHSNullableExprs.put(ref, constNode);
               }
             }
-            Collection<RexNode> knownConstants = inLHSExprToRHSExprs.get(ref);
+            Collection<SimilarRexNodeElement> knownConstants = inLHSExprToRHSExprs.get(ref);
             if (!shareSameType(knownConstants, expressions)) {
               return call;
             }
@@ -627,7 +629,7 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
           } else {
             for (int j = 1; j < inCall.getOperands().size(); j++) {
               RexNode constNode = inCall.getOperands().get(j);
-              inLHSExprToRHSExprs.put(ref, constNode);
+              inLHSExprToRHSExprs.put(ref, new SimilarRexNodeElement(constNode));
               if (constNode.getType().isNullable()) {
                 inLHSExprToRHSNullableExprs.put(ref, constNode);
               }
@@ -648,14 +650,14 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
             inLHSExprToRHSNullableExprs.put(c.exprNode, c.constNode);
           }
           if (inLHSExprToRHSExprs.containsKey(c.exprNode)) {
-            Collection<RexNode> knownConstants = inLHSExprToRHSExprs.get(c.exprNode);
-            Collection<RexNode> nextConstant = Collections.singleton(c.constNode);
+            Collection<SimilarRexNodeElement> knownConstants = inLHSExprToRHSExprs.get(c.exprNode);
+            Collection<SimilarRexNodeElement> nextConstant = Collections.singleton(new SimilarRexNodeElement(c.constNode));
             if (!shareSameType(knownConstants, nextConstant)) {
               return call;
             }
             knownConstants.retainAll(nextConstant);
           } else {
-            inLHSExprToRHSExprs.put(c.exprNode, c.constNode);
+            inLHSExprToRHSExprs.put(c.exprNode, new SimilarRexNodeElement(c.constNode));
           }
           operands.remove(i);
           --i;
@@ -669,6 +671,51 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
       return RexUtil.composeConjunction(rexBuilder, newOperands, false);
     }
 
+    protected static class SimilarRexNodeElement {
+      private final RexNode rexNode;
+
+      protected SimilarRexNodeElement(RexNode rexNode) {
+        this.rexNode = rexNode;
+      }
+
+      public RexNode getRexNode() {
+        return rexNode;
+      }
+
+      @Override
+      public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SimilarRexNodeElement that = (SimilarRexNodeElement) o;
+        return equalsWithSimilarType(rexNode, that.rexNode);
+      }
+
+      private static boolean equalsWithSimilarType(RexNode rexNode1, RexNode rexNode2) {
+        if (!(rexNode1 instanceof RexLiteral) || !(rexNode2 instanceof RexLiteral)) {
+          return rexNode1.equals(rexNode2);
+        }
+
+        RexLiteral rexLiteral1 = (RexLiteral) rexNode1;
+        RexLiteral rexLiteral2 = (RexLiteral) rexNode2;
+
+        if (rexLiteral1.getValue() == null && rexLiteral2.getValue() == null) {
+          return true;
+        }
+
+        return rexLiteral1.getValue() != null && rexLiteral1.getValue().compareTo(rexLiteral2.getValue()) == 0 &&
+                rexLiteral1.getType().getSqlTypeName().equals(rexLiteral2.getType().getSqlTypeName());
+      }
+
+      @Override
+      public int hashCode() {
+        if (rexNode instanceof RexLiteral) {
+          RexLiteral rexLiteral = (RexLiteral) rexNode;
+          return Objects.hash(rexLiteral.getValue(), rexLiteral.getType().getSqlTypeName());
+        }
+        return Objects.hash(rexNode);
+      }
+    }
+
     /**
      * Check if the type of nodes in the two collections is homogeneous within the collections
      * and identical between them.
@@ -676,9 +723,10 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
      * @param nodes2 the second collection of nodes
      * @return true if nodes in both collections is unique and identical, false otherwise
      */
-    private static boolean shareSameType(Collection<RexNode> nodes1, Collection<RexNode> nodes2) {
+    private static boolean shareSameType(
+            Collection<SimilarRexNodeElement> nodes1, Collection<SimilarRexNodeElement> nodes2) {
       return Stream.of(nodes1, nodes2).flatMap(Collection::stream)
-          .map(n -> n.getType().getSqlTypeName())
+          .map(n -> n.getRexNode().getType().getSqlTypeName())
           .distinct()
           .count() == 1;
     }
@@ -686,7 +734,7 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
     private static RexNode handleOR(RexBuilder rexBuilder, RexCall call) {
       // IN clauses need to be combined by keeping all elements
       final List<RexNode> operands = new ArrayList<>(RexUtil.flattenOr(call.getOperands()));
-      final Multimap<RexNode,RexNode> inLHSExprToRHSExprs = LinkedHashMultimap.create();
+      final Multimap<RexNode,SimilarRexNodeElement> inLHSExprToRHSExprs = LinkedHashMultimap.create();
       for (int i = 0; i < operands.size(); i++) {
         RexNode operand = operands.get(i);
         if (operand.getKind() == SqlKind.IN) {
@@ -696,7 +744,7 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
           }
           RexNode ref = inCall.getOperands().get(0);
           for (int j = 1; j < inCall.getOperands().size(); j++) {
-            inLHSExprToRHSExprs.put(ref, inCall.getOperands().get(j));
+            inLHSExprToRHSExprs.put(ref, new SimilarRexNodeElement(inCall.getOperands().get(j)));
           }
           operands.remove(i);
           --i;
@@ -733,22 +781,22 @@ public abstract class HivePointLookupOptimizerRule extends RelOptRule {
     }
 
     private static List<RexNode> createInClauses(RexBuilder rexBuilder, Set<RexNode> visitedRefs,
-        Multimap<RexNode, RexNode> inLHSExprToRHSExprs, Multimap<RexNode,RexNode> inLHSExprToRHSNullableExprs) {
+        Multimap<RexNode, SimilarRexNodeElement> inLHSExprToRHSExprs, Multimap<RexNode,RexNode> inLHSExprToRHSNullableExprs) {
       final List<RexNode> newExpressions = new ArrayList<>();
       for (RexNode ref : visitedRefs) {
-        Collection<RexNode> exprs = inLHSExprToRHSExprs.get(ref);
+        Collection<SimilarRexNodeElement> exprs = inLHSExprToRHSExprs.get(ref);
         if (exprs.isEmpty()) {
           // Note that Multimap does not keep a key if all its values are removed.
           newExpressions.add(createResultFromEmptySet(rexBuilder, ref, inLHSExprToRHSNullableExprs));
         } else if (exprs.size() == 1) {
           List<RexNode> newOperands = new ArrayList<>(2);
           newOperands.add(ref);
-          newOperands.add(exprs.iterator().next());
+          newOperands.add(exprs.iterator().next().getRexNode());
           newExpressions.add(rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, newOperands));
         } else {
           List<RexNode> newOperands = new ArrayList<>(exprs.size() + 1);
           newOperands.add(ref);
-          newOperands.addAll(exprs);
+          newOperands.addAll(exprs.stream().map(SimilarRexNodeElement::getRexNode).collect(Collectors.toList()));
           newExpressions.add(rexBuilder.makeCall(HiveIn.INSTANCE, newOperands));
         }
       }
diff --git a/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/rules/TestHivePointLookupOptimizerRule.java b/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/rules/TestHivePointLookupOptimizerRule.java
index ba695f44af2..8e06699e316 100644
--- a/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/rules/TestHivePointLookupOptimizerRule.java
+++ b/ql/src/test/org/apache/hadoop/hive/ql/optimizer/calcite/rules/TestHivePointLookupOptimizerRule.java
@@ -21,17 +21,25 @@ package org.apache.hadoop.hive.ql.optimizer.calcite.rules;
 import org.apache.calcite.plan.AbstractRelOptPlanner;
 import org.apache.calcite.plan.RelOptSchema;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.sql.SqlCollation;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.RelBuilder;
+import org.apache.calcite.util.ConversionUtil;
 import org.apache.hadoop.hive.ql.metadata.Table;
 import org.apache.hadoop.hive.ql.optimizer.calcite.RelOptHiveTable;
 import org.apache.hadoop.hive.ql.optimizer.calcite.reloperators.HiveFilter;
+import org.apache.hadoop.hive.ql.parse.type.RexNodeExprFactory;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.nio.charset.Charset;
 import java.util.Collections;
 
 import static org.apache.hadoop.hive.ql.optimizer.calcite.rules.TestRuleHelper.buildPlanner;
@@ -348,4 +356,167 @@ public class TestHivePointLookupOptimizerRule {
         condition.toString());
   }
 
+  @Test
+  public void testSameVarcharLiteralDifferentPrecision() {
+
+    final RexBuilder rexBuilder = relBuilder.getRexBuilder();
+    RelDataType stringType30 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 30),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita30 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType30, true);
+    RexNode litb30 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType30, true);
+
+    RelDataType stringType14 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 14),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita14 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType14, true);
+    RexNode litb14 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType14, true);
+
+    final RelNode basePlan = relBuilder
+          .scan("t")
+          .filter(and(relBuilder,
+                  relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita30, litb30),
+                  relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita14, litb14)))
+          .build();
+
+    planner.setRoot(basePlan);
+    RelNode optimizedRelNode = planner.findBestExp();
+
+    HiveFilter filter = (HiveFilter) optimizedRelNode;
+    RexNode condition = filter.getCondition();
+    System.out.println(condition);
+    assertEquals("IN($1, " +
+                    "_UTF-16LE'AAA111':VARCHAR(30) CHARACTER SET \"UTF-16LE\", " +
+                    "_UTF-16LE'BBB222':VARCHAR(30) CHARACTER SET \"UTF-16LE\")",
+            condition.toString());
+  }
+
+  @Test
+  public void testSameVarcharLiteralDifferentPrecisionValueOverflow() {
+
+    final RexBuilder rexBuilder = relBuilder.getRexBuilder();
+    RelDataType stringType30 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 30),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita30 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType30, true);
+    RexNode litb30 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType30, true);
+
+    RelDataType stringType4 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 4),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode litaOverflow =
+            rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType4, true);
+    RexNode litbOverflow =
+            rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType4, true);
+
+    final RelNode basePlan = relBuilder
+          .scan("t")
+          .filter(and(relBuilder,
+                  relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita30, litb30),
+                  relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), litaOverflow, litbOverflow)))
+          .build();
+
+    planner.setRoot(basePlan);
+    RelNode optimizedRelNode = planner.findBestExp();
+
+    HiveFilter filter = (HiveFilter) optimizedRelNode;
+    RexNode condition = filter.getCondition();
+    System.out.println(condition);
+    assertEquals("false", condition.toString());
+  }
+
+  @Test
+  public void testSameVarcharAndNullLiterals() {
+
+    final RexBuilder rexBuilder = relBuilder.getRexBuilder();
+    RelDataType stringType30 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 30),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita30 = rexBuilder.makeNullLiteral(stringType30);
+    RexNode litb30 = rexBuilder.makeNullLiteral(stringType30);
+
+    RelDataType stringType14 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 14),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita14 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType14, true);
+    RexNode litb14 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType14, true);
+
+    final RelNode basePlan = relBuilder
+            .scan("t")
+            .filter(and(relBuilder,
+                    relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita30, litb30),
+                    relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita14, litb14)))
+            .build();
+
+    planner.setRoot(basePlan);
+    RelNode optimizedRelNode = planner.findBestExp();
+
+    HiveFilter filter = (HiveFilter) optimizedRelNode;
+    RexNode condition = filter.getCondition();
+    System.out.println(condition);
+    assertEquals("AND(IS NULL(null:VARCHAR(30) CHARACTER SET \"UTF-16LE\"), null)", condition.toString());
+  }
+
+  @Test
+  public void testSameVarcharLiteralsDifferentPrecisionInOrExpression() {
+
+    final RexBuilder rexBuilder = relBuilder.getRexBuilder();
+    RelDataType stringType30 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 30),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita30 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType30, true);
+    RexNode litb30 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType30, true);
+
+    RelDataType stringType14 = rexBuilder.getTypeFactory().createTypeWithCharsetAndCollation(
+            rexBuilder.getTypeFactory().createSqlType(SqlTypeName.VARCHAR, 14),
+            Charset.forName(ConversionUtil.NATIVE_UTF16_CHARSET_NAME), SqlCollation.IMPLICIT);
+    RexNode lita14 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("AAA111"), stringType14, true);
+    RexNode litb14 = rexBuilder.makeLiteral(RexNodeExprFactory.makeHiveUnicodeString("BBB222"), stringType14, true);
+
+    final RelNode basePlan = relBuilder
+            .scan("t")
+            .filter(or(relBuilder,
+                    relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita30, litb30),
+                    relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita14, litb14)))
+            .build();
+
+    planner.setRoot(basePlan);
+    RelNode optimizedRelNode = planner.findBestExp();
+
+    HiveFilter filter = (HiveFilter) optimizedRelNode;
+    RexNode condition = filter.getCondition();
+    System.out.println(condition);
+    assertEquals("IN($1, " +
+                    "_UTF-16LE'AAA111':VARCHAR(30) CHARACTER SET \"UTF-16LE\", " +
+                    "_UTF-16LE'BBB222':VARCHAR(30) CHARACTER SET \"UTF-16LE\")",
+            condition.toString());
+  }
+
+  @Test
+  public void testSameDecimalLiteralDifferentPrecision() {
+
+    final RexBuilder rexBuilder = relBuilder.getRexBuilder();
+    RelDataType decimalType30 = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.DECIMAL, 30, 5);
+    RexNode lita30 = rexBuilder.makeLiteral(10000, decimalType30, true);
+    RexNode litb30 = rexBuilder.makeLiteral(11000, decimalType30, true);
+
+    RelDataType decimalType14 = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.DECIMAL, 14, 5);
+    RexNode lita14 = rexBuilder.makeLiteral(10000, decimalType14, true);
+    RexNode litb14 = rexBuilder.makeLiteral(11000, decimalType14, true);
+
+    final RelNode basePlan = relBuilder
+          .scan("t")
+          .filter(and(relBuilder,
+                  relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita30, litb30),
+                  relBuilder.call(SqlStdOperatorTable.IN, relBuilder.field("f2"), lita14, litb14)))
+          .build();
+
+    planner.setRoot(basePlan);
+    RelNode optimizedRelNode = planner.findBestExp();
+
+    HiveFilter filter = (HiveFilter) optimizedRelNode;
+    RexNode condition = filter.getCondition();
+    System.out.println(condition);
+    assertEquals("IN($1, 10000:DECIMAL(19, 5), 11000:DECIMAL(19, 5))", condition.toString());
+  }
 }
diff --git a/ql/src/test/queries/clientpositive/pointlookup6.q b/ql/src/test/queries/clientpositive/pointlookup6.q
new file mode 100644
index 00000000000..d1b05e7fc0b
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/pointlookup6.q
@@ -0,0 +1,19 @@
+set hive.optimize.point.lookup.min=2;
+
+create table r_table (
+  string_col varchar(30)
+);
+
+create table l_table (
+  string_col varchar(14)
+);
+
+insert into r_table VALUES ('AAA111');
+insert into l_table VALUES ('AAA111');
+
+explain cbo
+SELECT l_table.string_col from l_table, r_table
+WHERE r_table.string_col = l_table.string_col AND l_table.string_col IN ('AAA111', 'BBB222') AND r_table.string_col IN ('AAA111', 'BBB222');
+
+SELECT l_table.string_col from l_table, r_table
+WHERE r_table.string_col = l_table.string_col AND l_table.string_col IN ('AAA111', 'BBB222') AND r_table.string_col IN ('AAA111', 'BBB222');
diff --git a/ql/src/test/results/clientpositive/llap/pointlookup6.q.out b/ql/src/test/results/clientpositive/llap/pointlookup6.q.out
new file mode 100644
index 00000000000..830ce446a86
--- /dev/null
+++ b/ql/src/test/results/clientpositive/llap/pointlookup6.q.out
@@ -0,0 +1,79 @@
+PREHOOK: query: create table r_table (
+  string_col varchar(30)
+)
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@r_table
+POSTHOOK: query: create table r_table (
+  string_col varchar(30)
+)
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@r_table
+PREHOOK: query: create table l_table (
+  string_col varchar(14)
+)
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@l_table
+POSTHOOK: query: create table l_table (
+  string_col varchar(14)
+)
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@l_table
+PREHOOK: query: insert into r_table VALUES ('AAA111')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@r_table
+POSTHOOK: query: insert into r_table VALUES ('AAA111')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@r_table
+POSTHOOK: Lineage: r_table.string_col SCRIPT []
+PREHOOK: query: insert into l_table VALUES ('AAA111')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@l_table
+POSTHOOK: query: insert into l_table VALUES ('AAA111')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@l_table
+POSTHOOK: Lineage: l_table.string_col SCRIPT []
+PREHOOK: query: explain cbo
+SELECT l_table.string_col from l_table, r_table
+WHERE r_table.string_col = l_table.string_col AND l_table.string_col IN ('AAA111', 'BBB222') AND r_table.string_col IN ('AAA111', 'BBB222')
+PREHOOK: type: QUERY
+PREHOOK: Input: default@l_table
+PREHOOK: Input: default@r_table
+#### A masked pattern was here ####
+POSTHOOK: query: explain cbo
+SELECT l_table.string_col from l_table, r_table
+WHERE r_table.string_col = l_table.string_col AND l_table.string_col IN ('AAA111', 'BBB222') AND r_table.string_col IN ('AAA111', 'BBB222')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@l_table
+POSTHOOK: Input: default@r_table
+#### A masked pattern was here ####
+CBO PLAN:
+HiveProject(string_col=[$0])
+  HiveJoin(condition=[=($1, $0)], joinType=[inner], algorithm=[none], cost=[not available])
+    HiveProject(string_col=[$0])
+      HiveFilter(condition=[IN($0, _UTF-16LE'AAA111':VARCHAR(14) CHARACTER SET "UTF-16LE", _UTF-16LE'BBB222':VARCHAR(14) CHARACTER SET "UTF-16LE")])
+        HiveTableScan(table=[[default, l_table]], table:alias=[l_table])
+    HiveProject(string_col=[$0])
+      HiveFilter(condition=[IN($0, _UTF-16LE'AAA111':VARCHAR(30) CHARACTER SET "UTF-16LE", _UTF-16LE'BBB222':VARCHAR(30) CHARACTER SET "UTF-16LE")])
+        HiveTableScan(table=[[default, r_table]], table:alias=[r_table])
+
+PREHOOK: query: SELECT l_table.string_col from l_table, r_table
+WHERE r_table.string_col = l_table.string_col AND l_table.string_col IN ('AAA111', 'BBB222') AND r_table.string_col IN ('AAA111', 'BBB222')
+PREHOOK: type: QUERY
+PREHOOK: Input: default@l_table
+PREHOOK: Input: default@r_table
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT l_table.string_col from l_table, r_table
+WHERE r_table.string_col = l_table.string_col AND l_table.string_col IN ('AAA111', 'BBB222') AND r_table.string_col IN ('AAA111', 'BBB222')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@l_table
+POSTHOOK: Input: default@r_table
+#### A masked pattern was here ####
+AAA111