You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ya...@apache.org on 2020/03/26 00:17:47 UTC

[phoenix] branch master updated: PHOENIX-5698 Phoenix Query with RVC IN list expression generates wrong scan with non-pk ordered pks

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 14a17d8  PHOENIX-5698 Phoenix Query with RVC IN list expression generates wrong scan with non-pk ordered pks
14a17d8 is described below

commit 14a17d8f9b23089bea4c2a910430a73c669bc0fb
Author: Xinyi Yan <xy...@salesforce.com>
AuthorDate: Mon Mar 16 16:59:25 2020 -0700

    PHOENIX-5698 Phoenix Query with RVC IN list expression generates wrong scan with non-pk ordered pks
    
    Signed-off-by: Xinyi Yan <ya...@apache.org>
---
 .../java/org/apache/phoenix/end2end/InListIT.java  | 1140 ++++++++++++++++++--
 .../phoenix/expression/InListExpression.java       |  118 +-
 .../org/apache/phoenix/iterate/ExplainTable.java   |    3 +-
 .../phoenix/expression/InListExpressionTest.java   |  207 +++-
 4 files changed, 1350 insertions(+), 118 deletions(-)

diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/InListIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/InListIT.java
index 7e0a7a5..ba4a511 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/InListIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/InListIT.java
@@ -29,18 +29,21 @@ import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.PreparedStatement;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.phoenix.compile.QueryPlan;
+import org.apache.phoenix.iterate.ExplainTable;
 import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.TypeMismatchException;
 import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PInteger;
-import org.apache.phoenix.schema.types.PLong;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.PropertiesUtil;
+import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.base.Function;
@@ -49,8 +52,19 @@ import com.google.common.collect.Lists;
 
 
 public class InListIT extends ParallelStatsDisabledIT {
-    
-    private final String TENANT_SPECIFIC_URL1 = getUrl() + ';' + TENANT_ID_ATTRIB + "=tenant1";
+    private static final String TENANT_SPECIFIC_URL1 = getUrl() + ';' + TENANT_ID_ATTRIB + "=tenant1";
+    String tableName;
+    String descViewName;
+    String ascViewName;
+
+    @Before
+    public void setup() throws Exception {
+        tableName = generateUniqueName();
+        descViewName = generateUniqueName();
+        ascViewName = generateUniqueName();
+        buildSchema(tableName, generateUniqueName(), true);
+        buildSchema(generateUniqueName(), generateUniqueName(), false);
+    }
 
     @Test
     public void testLeadingPKWithTrailingRVC() throws Exception {
@@ -71,7 +85,7 @@ public class InListIT extends ParallelStatsDisabledIT {
         assertTrue(rs.next());
         assertEquals("c", rs.getString(1));
         assertFalse(rs.next());
-        
+
         conn.close();
     }
 
@@ -90,10 +104,10 @@ public class InListIT extends ParallelStatsDisabledIT {
         assertTrue(rs.next());
         assertEquals(1, rs.getInt(1));
         assertFalse(rs.next());
-        
+
         conn.close();
     }
-    
+
     /**
      * Builds the DDL statement that will create a table with the given properties.
      * Assumes 5 pk columns of the given type.
@@ -107,7 +121,7 @@ public class InListIT extends ParallelStatsDisabledIT {
     private static String createTableDDL(String tableName, PDataType pkType, int saltBuckets, boolean isMultiTenant) {
         StringBuilder ddlBuilder = new StringBuilder();
         ddlBuilder.append("CREATE TABLE ").append(tableName).append(" ( ");
-        
+
         // column declarations
         if(isMultiTenant) {
             ddlBuilder.append("tenantId VARCHAR(5) NOT NULL, ");
@@ -116,14 +130,14 @@ public class InListIT extends ParallelStatsDisabledIT {
             ddlBuilder.append("pk").append(i + 1).append(" ").append(pkType.getSqlTypeName()).append(" NOT NULL, ");
         }
         ddlBuilder.append("nonPk VARCHAR ");
-        
+
         // primary key constraint declaration
         ddlBuilder.append("CONSTRAINT pk PRIMARY KEY (");
         if(isMultiTenant) {
             ddlBuilder.append("tenantId, ");
         }
         ddlBuilder.append("pk1, pk2, pk3, pk4, pk5) ) ");
-        
+
         // modifier declarations
         if(saltBuckets != 0) {
             ddlBuilder.append("SALT_BUCKETS = ").append(saltBuckets);
@@ -134,10 +148,10 @@ public class InListIT extends ParallelStatsDisabledIT {
         if(isMultiTenant) {
             ddlBuilder.append("MULTI_TENANT=true");
         }
-        
+
         return ddlBuilder.toString();
     }
-    
+
     /**
      * Creates a table with the given properties and returns its name. If the table is multi-tenant,
      * also creates a tenant view for that table and returns the name of the view instead.
@@ -149,32 +163,32 @@ public class InListIT extends ParallelStatsDisabledIT {
      * @return  the table or view name that should be used to access the created table
      */
     private static String initializeAndGetTable(Connection baseConn, Connection conn, boolean isMultiTenant, PDataType pkType, int saltBuckets) throws SQLException {
-            String tableName = generateUniqueName() + "in_test" + pkType.getSqlTypeName() + saltBuckets + (isMultiTenant ? "_multi" : "_single");
-            String tableDDL = createTableDDL(tableName, pkType, saltBuckets, isMultiTenant);
-            baseConn.createStatement().execute(tableDDL);
-            
-            // if requested, create a tenant specific view and return the view name instead
-            if(isMultiTenant) {
-                String viewName = tableName + "_view";
-                String viewDDL = "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName;
-                conn.createStatement().execute(viewDDL);
-                return viewName;
-            }
-            else {
-                return tableName;
-            }
+        String tableName = generateUniqueName() + "in_test" + pkType.getSqlTypeName() + saltBuckets + (isMultiTenant ? "_multi" : "_single");
+        String tableDDL = createTableDDL(tableName, pkType, saltBuckets, isMultiTenant);
+        baseConn.createStatement().execute(tableDDL);
+
+        // if requested, create a tenant specific view and return the view name instead
+        if(isMultiTenant) {
+            String viewName = tableName + "_view";
+            String viewDDL = "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName;
+            conn.createStatement().execute(viewDDL);
+            return viewName;
+        }
+        else {
+            return tableName;
+        }
     }
-    
+
     private static final String TENANT_ID = "ABC";
     private static final String TENANT_URL = getUrl() + ";" + PhoenixRuntime.TENANT_ID_ATTRIB + '=' + TENANT_ID;
-    
+
     // the different combinations to check each test against
     private static final List<Boolean> TENANCIES = Arrays.asList(false, true);
     private static final List<? extends PDataType> INTEGER_TYPES = Arrays.asList(PInteger.INSTANCE);
     private static final List<Integer> SALT_BUCKET_NUMBERS = Arrays.asList(0, 4);
 
     private static final List<String> HINTS = Arrays.asList("/*+ SKIP_SCAN */", "/*+ RANGE_SCAN */");
-    
+
     /**
      * Tests the given where clause against the given upserts by comparing against the list of
      * expected result strings.
@@ -187,9 +201,9 @@ public class InListIT extends ParallelStatsDisabledIT {
         // test single and multitenant tables
         for(boolean isMultiTenant : TENANCIES) {
             Connection baseConn = DriverManager.getConnection(getUrl());
-            Connection conn = isMultiTenant ? DriverManager.getConnection(TENANT_URL) 
-                                            : baseConn;
-                    
+            Connection conn = isMultiTenant ? DriverManager.getConnection(TENANT_URL)
+                    : baseConn;
+
             try {
                 // test each combination of types and salting
                 for(PDataType pkType : INTEGER_TYPES) {
@@ -197,7 +211,7 @@ public class InListIT extends ParallelStatsDisabledIT {
                         // use a different table with a unique name for each variation
                         String tableName = initializeAndGetTable(baseConn, conn, isMultiTenant, pkType, saltBuckets);
 
-                        // upsert the given data 
+                        // upsert the given data
                         for(String upsertBody : upsertBodies) {
                             conn.createStatement().execute("UPSERT INTO " + tableName + " " + upsertBody);
                         }
@@ -228,224 +242,224 @@ public class InListIT extends ParallelStatsDisabledIT {
             }
         }
     }
-    
+
     List<List<Object>> DEFAULT_UPSERTS = Arrays.asList(Arrays.<Object>asList(1, 2, 4, 5, 6, "row1"),
-                                                       Arrays.<Object>asList(2, 3, 4, 5, 6, "row2"),
-                                                       Arrays.<Object>asList(2, 3, 6, 4, 5, "row3"),
-                                                       Arrays.<Object>asList(6, 5, 4, 3, 2, "row4"));
-    
+            Arrays.<Object>asList(2, 3, 4, 5, 6, "row2"),
+            Arrays.<Object>asList(2, 3, 6, 4, 5, "row3"),
+            Arrays.<Object>asList(6, 5, 4, 3, 2, "row4"));
+
     List<String> DEFAULT_UPSERT_BODIES = Lists.transform(DEFAULT_UPSERTS, new Function<List<Object>, String>() {
         @Override
         public String apply(List<Object> input) {
             List<Object> pks = input.subList(0, 5);
             Object nonPk = input.get(5);
-            
+
             return "(pk1, pk2, pk3, pk4, pk5, nonPk) VALUES ( "
-                + Joiner.on(", ").join(pks) + ", '" + nonPk + "')";
+                    + Joiner.on(", ").join(pks) + ", '" + nonPk + "')";
         }
     });
-    
+
     // test variations used:
     // 1. queries with no results
     // 2. queries with fully qualified row keys
     // 3. queries with partiall qualified row keys, starting from the beginning
     // 4. queries with partially qualified row keys, but not the beginning
     // 5. queries with partially qualified row keys with a "hole slot" in the middle
-    
+
     @Test
     public void testPlainRVCNoResults() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3, pk4, pk5) IN ((1, 2, 3, 4, 5), (1, 2, 4, 5, 3))";
         List<String> expecteds = Collections.<String>emptyList();
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testPlainRVCFullyQualified() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3, pk4, pk5) IN ((1, 2, 3, 4, 5), (1, 2, 4, 5, 6))";
         List<String> expecteds = singletonList("row1");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testPlainRVCPartiallyQualifiedBegin() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3, pk4) IN ((2, 3, 4, 5), (1, 2, 4, 5))";
         List<String> expecteds = Arrays.asList("row1", "row2");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testPlainRVCPartiallyQualifiedEnd() throws Exception {
         String whereClause = "WHERE (pk2, pk3, pk4, pk5) IN ((2, 3, 4, 5), (2, 4, 5, 6))";
         List<String> expecteds = singletonList("row1");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testPlainRVCSlotHole() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk4, pk5) IN ((1, 2, 4, 5), (6, 5, 3, 2))";
         List<String> expecteds = singletonList("row4");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingPKWithTrailingRVCNoResults() throws Exception {
         String whereClause = "WHERE pk1 != 2 AND (pk3, pk4, pk5) IN ((6, 4, 5), (5, 6, 4))";
         List<String> expecteds = Collections.<String>emptyList();
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingPKWithTrailingRVCFullyQualified() throws Exception {
         String whereClause = "WHERE pk1 = 2 AND (pk2, pk3, pk4, pk5) IN ((2, 4, 5, 6), (3, 4, 5, 6))";
         List<String> expecteds = singletonList("row2");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingPKWithTrailingRVCPartiallyQualifiedBegin() throws Exception {
         String whereClause = "WHERE pk1 = 2 AND (pk2, pk3) IN ((3, 6), (5, 4))";
         List<String> expecteds = singletonList("row3");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingPKWithTrailingRVCPartiallyQualifiedEnd() throws Exception {
         String whereClause = "WHERE pk2 = 2 AND (pk3, pk4, pk5) IN ((4, 5, 6), (5, 6, 4))";
         List<String> expecteds = singletonList("row1");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingPKWithTrailingRVCSlotHole() throws Exception {
         String whereClause = "WHERE pk1 = 2 AND (pk3, pk4, pk5) IN ((4, 5, 6), (5, 6, 4))";
         List<String> expecteds = singletonList("row2");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingRVCWithTrailingPKNoResults() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3) IN ((2, 3, 4), (2, 3, 6)) AND pk4 = 3";
         List<String> expecteds = Collections.<String>emptyList();
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingRVCWithTrailingPKFullyQualified() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3, pk4) IN ((1, 2, 4, 5), (2, 3, 4, 5)) AND pk5 = 6";
         List<String> expecteds = Arrays.asList("row1", "row2");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingRVCWithTrailingPKPartiallyQualifiedBegin() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3) IN ((2, 3, 4), (2, 3, 6)) AND pk4 = 4";
         List<String> expecteds = singletonList("row3");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingRVCWithTrailingPKPartiallyQualifiedEnd() throws Exception {
         String whereClause = "WHERE (pk2, pk3, pk4) IN ((3, 4, 5), (3, 6, 4)) AND pk5 = 5";
         List<String> expecteds = singletonList("row3");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testLeadingRVCWithTrailingPKSlotHole() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3) IN ((2, 3, 4), (2, 3, 6)) AND pk5 = 5";
         List<String> expecteds = singletonList("row3");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndPKNoResults() throws Exception {
         String whereClause = "WHERE (pk1, pk2) IN ((1, 2), (2, 3)) AND pk2 = 4";
         List<String> expecteds = Collections.<String>emptyList();
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndPKFullyQualified() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3, pk4, pk5) IN ((1, 2, 4, 5, 6), (2, 3, 4, 5, 6)) AND pk1 = 2";
         List<String> expecteds = singletonList("row2");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndPKPartiallyQualifiedBegin() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3) IN ((1, 2, 4), (2, 3, 6)) AND pk3 = 4";
         List<String> expecteds = singletonList("row1");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndPKPartiallyQualifiedEnd() throws Exception {
         String whereClause = "WHERE (pk3, pk4, pk5) IN ((4, 5, 6), (4, 3, 2)) AND pk5 = 2";
         List<String> expecteds = singletonList("row4");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndRVCNoResults() throws Exception {
         String whereClause = "WHERE (pk1, pk2) IN ((1, 2), (2, 3)) AND (pk2, pk3) IN ((4, 4), (4, 6))";
         List<String> expecteds = Collections.<String>emptyList();
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndRVCFullyQualified() throws Exception {
         String whereClause = "WHERE (pk1, pk2, pk3) IN ((2, 3, 6), (2, 3, 4)) AND (pk3, pk4, pk5) IN ((4, 5, 6), (4, 3, 2))";
         List<String> expecteds = singletonList("row2");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndRVCPartiallyQualifiedBegin() throws Exception {
         String whereClause = "WHERE (pk1, pk2) IN ((1, 2), (2, 3)) AND (pk2, pk3) IN ((3, 4), (3, 6))";
         List<String> expecteds = Arrays.asList("row2", "row3");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testOverlappingRVCAndRVCPartiallyQualifiedEnd() throws Exception {
         String whereClause = "WHERE (pk3, pk4) IN ((4, 5), (4, 3)) AND (pk4, pk5) IN ((3, 2), (4, 5))";
         List<String> expecteds = singletonList("row4");
-        
+
         testWithIntegerTypesWithVariedSaltingAndTenancy(DEFAULT_UPSERT_BODIES, whereClause, expecteds);
     }
-    
+
     @Test
     public void testWithFixedLengthDescPK() throws Exception {
         testWithFixedLengthPK(SortOrder.DESC);
     }
-    
+
     @Test
     public void testWithFixedLengthAscPK() throws Exception {
-        testWithFixedLengthPK(SortOrder.ASC);        
+        testWithFixedLengthPK(SortOrder.ASC);
     }
-    
+
     @Test
     public void testWithFixedLengthKV() throws Exception {
         Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
@@ -463,7 +477,7 @@ public class InListIT extends ParallelStatsDisabledIT {
         assertTrue(rs.next());
         assertEquals("bb", rs.getString(1));
         assertFalse(rs.next());
-        
+
         conn.close();
     }
 
@@ -483,7 +497,7 @@ public class InListIT extends ParallelStatsDisabledIT {
         assertTrue(rs.next());
         assertEquals(sortOrder == SortOrder.ASC ? "bb" : "aa", rs.getString(1));
         assertFalse(rs.next());
-        
+
         conn.close();
     }
 
@@ -534,7 +548,7 @@ public class InListIT extends ParallelStatsDisabledIT {
             assertEquals(0, rs.getInt(1));
         }
     }
-    
+
     @Test
     public void testInListExpressionWithDesc() throws Exception {
         String fullTableName = generateUniqueName();
@@ -543,38 +557,38 @@ public class InListIT extends ParallelStatsDisabledIT {
         // create base table and global view using global connection
         try (Connection conn = DriverManager.getConnection(getUrl())) {
             Statement stmt = conn.createStatement();
-            stmt.execute("CREATE TABLE " + fullTableName + "(\n" + 
-                    "    TENANT_ID CHAR(15) NOT NULL,\n" + 
-                    "    KEY_PREFIX CHAR(3) NOT NULL,\n" + 
-                    "    CREATED_DATE DATE,\n" + 
-                    "    CREATED_BY CHAR(15),\n" + 
-                    "    SYSTEM_MODSTAMP DATE\n" + 
-                    "    CONSTRAINT PK PRIMARY KEY (\n" + 
-                    "       TENANT_ID," + 
-                    "       KEY_PREFIX" + 
+            stmt.execute("CREATE TABLE " + fullTableName + "(\n" +
+                    "    TENANT_ID CHAR(15) NOT NULL,\n" +
+                    "    KEY_PREFIX CHAR(3) NOT NULL,\n" +
+                    "    CREATED_DATE DATE,\n" +
+                    "    CREATED_BY CHAR(15),\n" +
+                    "    SYSTEM_MODSTAMP DATE\n" +
+                    "    CONSTRAINT PK PRIMARY KEY (\n" +
+                    "       TENANT_ID," +
+                    "       KEY_PREFIX" +
                     ")) MULTI_TENANT=TRUE");
-            
-            stmt.execute("CREATE VIEW " + fullViewName + "(\n" + 
-                    "    MODEL VARCHAR NOT NULL,\n" + 
-                    "    MILEAGE  BIGINT NOT NULL,\n" +  
-                    "    MILES_DRIVEN BIGINT NOT NULL,\n" + 
-                    "    MAKE VARCHAR,\n" + 
-                    "    CONSTRAINT PKVIEW PRIMARY KEY\n" + 
-                    "    (\n" + 
-                    "    MODEL, MILEAGE DESC, MILES_DRIVEN\n" + 
+
+            stmt.execute("CREATE VIEW " + fullViewName + "(\n" +
+                    "    MODEL VARCHAR NOT NULL,\n" +
+                    "    MILEAGE  BIGINT NOT NULL,\n" +
+                    "    MILES_DRIVEN BIGINT NOT NULL,\n" +
+                    "    MAKE VARCHAR,\n" +
+                    "    CONSTRAINT PKVIEW PRIMARY KEY\n" +
+                    "    (\n" +
+                    "    MODEL, MILEAGE DESC, MILES_DRIVEN\n" +
                     ")) AS SELECT * FROM " + fullTableName + " WHERE KEY_PREFIX = '0CY'");
-            
+
         }
-        
+
         // create and use a tenant specific view to write data
-        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1) ) { 
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1) ) {
             Statement stmt = viewConn.createStatement();
             stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + " AS SELECT * FROM " + fullViewName );
             viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(CREATED_BY, CREATED_DATE, SYSTEM_MODSTAMP, MODEL, MILEAGE, MILES_DRIVEN, MAKE) VALUES ('005xx000001Sv6o', 1532458254819, 1532458254819, 'a5', 23, 10000, 'AUDI')");
             viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(CREATED_BY, CREATED_DATE, SYSTEM_MODSTAMP, MODEL, MILEAGE, MILES_DRIVEN, MAKE) VALUES ('005xx000001Sv6o', 1532458254819, 1532458254819, 'a4', 27, 30000, 'AUDI')");
             viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(CREATED_BY, CREATED_DATE, SYSTEM_MODSTAMP, MODEL, MILEAGE, MILES_DRIVEN, MAKE) VALUES ('005xx000001Sv6o', 1532458254819, 1532458254819, '328i', 32, 40000, 'BMW')");
             viewConn.commit();
-            
+
             ResultSet rs = stmt.executeQuery("SELECT Make, Model FROM " + tenantView + " WHERE MILEAGE IN (32, 27)");
             assertTrue(rs.next());
             assertEquals("BMW", rs.getString(1));
@@ -603,4 +617,900 @@ public class InListIT extends ParallelStatsDisabledIT {
         }
     }
 
+    private void buildSchema(String fullTableName, String fullViewName, boolean isDecOrder) throws Exception {
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.setAutoCommit(true);
+            try (Statement stmt = conn.createStatement()) {
+                stmt.execute("CREATE TABLE " + fullTableName + "(\n" + " TENANT_ID CHAR(15) NOT NULL,\n" + " KEY_PREFIX CHAR(3) NOT NULL, ID5 BIGINT \n" +
+                        " CONSTRAINT PK PRIMARY KEY (\n" + " TENANT_ID," + " KEY_PREFIX" + ")) MULTI_TENANT=TRUE");
+                if (isDecOrder) {
+                    stmt.execute("CREATE VIEW " + fullViewName + "(\n" + " ID1 VARCHAR NOT NULL,\n" + " ID2 VARCHAR NOT NULL,\n" + " ID3 BIGINT, ID4 BIGINT \n" +
+                            " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (\n" + " ID1, ID2 DESC\n" + ")) " +
+                            "AS SELECT * FROM " + fullTableName + " WHERE KEY_PREFIX = '0CY'");
+                    try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+                        viewConn.setAutoCommit(true);
+                        try (Statement tenantStmt = viewConn.createStatement()) {
+                            tenantStmt.execute("CREATE VIEW IF NOT EXISTS " + this.descViewName + " AS SELECT * FROM " + fullViewName);
+                        }
+                    }
+                } else {
+                    stmt.execute("CREATE VIEW " + fullViewName + "(\n" + " ID1 VARCHAR NOT NULL,\n" + " ID2 VARCHAR NOT NULL,\n" + " ID3 BIGINT, ID4 BIGINT \n" +
+                            " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (ID1, ID2)) " +
+                            "AS SELECT * FROM " + fullTableName + " WHERE KEY_PREFIX = '0CY'");
+                    try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+                        viewConn.setAutoCommit(true);
+                        try (Statement tenantStmt = viewConn.createStatement()) {
+                            tenantStmt.execute("CREATE VIEW IF NOT EXISTS " + this.ascViewName + " AS SELECT * FROM " + fullViewName);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testPkDescOrderedTenantViewOnGlobalViewWithRightQueryPlan() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + " AS SELECT * FROM " + descViewName);
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('foo', '000000000000300')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('005xx000001Sv6o', '000000000000500')");
+                viewConn.commit();
+
+                try (PreparedStatement preparedStmt = viewConn.prepareStatement(
+                        "SELECT * FROM " + tenantView + " WHERE (ID1, ID2) " +
+                                "IN (('005xx000001Sv6o', '000000000000500'))")) {
+                    QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                    assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+                }
+
+                try (PreparedStatement preparedStmt = viewConn.prepareStatement(
+                        "SELECT * FROM " + tenantView + " WHERE (ID2, ID1) " +
+                                "IN (('000000000000500', '005xx000001Sv6o'))")) {
+                    QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                    assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+                }
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "(('bar', '005xx000001Sv6o'))");
+
+                ResultSet rs = stmt.executeQuery("SELECT ID2 FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals("000000000000500", rs.getString(1));
+            }
+        }
+    }
+
+    @Test
+    public void testColumnDescOrderedTenantViewOnGlobalViewWithStringValue() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + " AS SELECT * FROM " + descViewName);
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('foo', '000000000000300')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('bar', '000000000000400')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('005xx000001Sv6o', '000000000000500')");
+                viewConn.commit();
+
+                try (PreparedStatement preparedStmt = viewConn.prepareStatement(
+                        "SELECT * FROM " + tenantView + " WHERE (ID1, ID2) " +
+                                "IN (('005xx000001Sv6o', '000000000000500')," +
+                                "('bar', '000000000000400')," +
+                                "('foo', '000000000000300'))")) {
+                    QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                    assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+                }
+
+                try (PreparedStatement preparedStmt = viewConn.prepareStatement(
+                        "SELECT * FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                                "(('bar', '005xx000001Sv6o')," +
+                                "('foo', '005xx000001Sv6o'))")) {
+                    QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                    assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+                }
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "(('000000000000400', 'bar')," +
+                        "('000000000000300', 'foo'))");
+
+                ResultSet rs = stmt.executeQuery("SELECT ID2 FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals("000000000000500", rs.getString(1));
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(1, rs.getInt(1));
+                stmt.execute("DELETE FROM " + tenantView);
+            }
+        }
+    }
+
+    @Test
+    public void testInListExpressionWithRightQueryPlanForTenantViewOnGlobalView() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + " AS SELECT * FROM " + ascViewName);
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('005xx000001Sv6o', '000000000000300')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('005xx000001Sv6o', '000000000000400')");
+                viewConn.commit();
+
+                try (PreparedStatement preparedStmt = viewConn.prepareStatement(
+                        "SELECT * FROM " + tenantView + " WHERE (ID1, ID2) IN " +
+                                "(('005xx000001Sv6o', '000000000000500')," +
+                                "('005xx000001Sv6o', '000000000000400')," +
+                                "('005xx000001Sv6o', '000000000000300'))")) {
+                    QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                    assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+                }
+
+                try (PreparedStatement preparedStmt = viewConn.prepareStatement(
+                        "SELECT * FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                                "(('000000000000400', '005xx000001Sv6o')," +
+                                "('000000000000300', '005xx000001Sv6o'))")) {
+                    QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                    assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+                }
+                ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "(('000000000000400', '005xx000001Sv6o')," +
+                        "('000000000000300', '005xx000001Sv6o'))");
+                assertTrue(rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "(('000000000000300', '005xx000001Sv6o'))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(1, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testInListExpressionGeneratesRightScanForAsc() throws Exception {
+        testFullPkListPlan(this.ascViewName);
+        testPartialPkListPlan(this.ascViewName);
+        testPartialPkPlusNonPkListPlan(this.ascViewName);
+        testNonPkListPlan(this.ascViewName);
+    }
+
+    @Test
+    public void testInListExpressionGeneratesRightScanForDesc() throws Exception {
+        testFullPkListPlan(this.descViewName);
+        testPartialPkListPlan(this.descViewName);
+        testPartialPkPlusNonPkListPlan(this.descViewName);
+        testNonPkListPlan(this.descViewName);
+    }
+
+    private void testFullPkListPlan(String tenantView) throws Exception {
+        Long numberOfRowsToScan = new Long(2);
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1) ) {
+            PreparedStatement preparedStmt = viewConn.prepareStatement("SELECT * FROM " + tenantView + " WHERE (ID1, ID2) IN " +
+                    "(('005xx000001Sv6o', '000000000000500')," +
+                    "('005xx000001Sv6o', '000000000000400'))");
+            QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertEquals(numberOfRowsToScan, queryPlan.getEstimatedRowsToScan());
+            assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+
+            viewConn.prepareStatement("DELETE FROM " + tenantView + " WHERE (ID1, ID2) IN " +
+                    "(('005xx000001Sv6o', '000000000000500')," +
+                    "('005xx000001Sv6o', '000000000000400'))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertEquals(numberOfRowsToScan, queryPlan.getEstimatedRowsToScan());
+            assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+        }
+    }
+
+    private void testPartialPkListPlan(String tenantView) throws Exception {
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1) ) {
+            PreparedStatement preparedStmt = viewConn.prepareStatement("SELECT * FROM " + tenantView + " WHERE (ID1) IN " +
+                    "(('005xx000001Sv6o')," +
+                    "('005xx000001Sv6o'))");
+            QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            viewConn.prepareStatement("DELETE FROM " + tenantView + " WHERE (ID1) IN " +
+                    "(('005xx000001Sv6o')," +
+                    "('005xx000001Sv6o'))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            preparedStmt = viewConn.prepareStatement("SELECT * FROM " + tenantView + " WHERE (ID2) IN " +
+                    "(('000000000000500')," +
+                    "('000000000000400'))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            viewConn.prepareStatement("DELETE FROM " + tenantView + " WHERE (ID2) IN " +
+                    "(('000000000000500')," +
+                    "('000000000000400'))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+        }
+    }
+
+    private void testPartialPkPlusNonPkListPlan(String tenantView) throws Exception {
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1) ) {
+            PreparedStatement preparedStmt = viewConn.prepareStatement("SELECT * FROM " + tenantView + " WHERE (ID1, ID3) IN " +
+                    "(('005xx000001Sv6o', 1)," +
+                    "('005xx000001Sv6o', 2))");
+            QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            viewConn.prepareStatement("DELETE FROM " + tenantView + " WHERE (ID1, ID3) IN " +
+                    "(('005xx000001Sv6o', 1)," +
+                    "('005xx000001Sv6o', 2))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            preparedStmt = viewConn.prepareStatement("SELECT * FROM " + tenantView + " WHERE (ID2, ID3) IN " +
+                    "(('000000000000500', 1)," +
+                    "('000000000000400', 2))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            viewConn.prepareStatement("DELETE FROM " + tenantView + " WHERE (ID2, ID3) IN " +
+                    "(('000000000000500', 1)," +
+                    "('000000000000400', 2))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+        }
+    }
+
+    private void testNonPkListPlan(String tenantView) throws Exception {
+        // Tenant connection should generate a range scan because tenant id is the leading PK.
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1) ) {
+            PreparedStatement preparedStmt = viewConn.prepareStatement("SELECT * FROM " + tenantView + " WHERE (ID3, ID4) IN " +
+                    "((1, 1)," +
+                    "(2, 2))");
+            QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+
+            viewConn.prepareStatement("DELETE FROM " + tenantView + " WHERE (ID3, ID4) IN " +
+                    "((1, 1)," +
+                    "(2, 2))");
+            queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            assertTrue(queryPlan.getExplainPlan().toString().contains("CLIENT PARALLEL 1-WAY RANGE SCAN OVER"));
+        }
+    }
+
+    @Test
+    public void testInListExpressionWithRightQueryPlanForNumericalValue() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(DOUBLE1 DOUBLE NOT NULL, INT1 BIGINT NOT NULL " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (DOUBLE1, INT1)) " +
+                        " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(DOUBLE1, INT1) VALUES " +
+                        "(12.0, 8)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(DOUBLE1, INT1) VALUES " +
+                        "(13.0, 9)");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView + " WHERE (INT1, DOUBLE1) IN " +
+                        "((8, 12.0)," +
+                        "(9, 13.0))");
+                assertTrue(rs.next());
+                assertEquals(2, rs.getInt(1));
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (INT1, DOUBLE1) IN " +
+                        "((8, 12.0)," +
+                        "(9, 13.0))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testQueryPlanForPkDescOrderedTenantViewOnGlobalViewForStringValue() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + " AS SELECT * FROM " + descViewName);
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('foo', '000000000000300')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('bar', '000000000000400')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2) VALUES " +
+                        "('005xx000001Sv6o', '000000000000500')");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "(('000000000000400', 'bar')," +
+                        "('000000000000300','foo'))");
+
+                assertTrue(rs.next());
+                assertEquals(2, rs.getInt(1));
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "(('000000000000400', 'bar')," +
+                        "('000000000000300','foo'))");
+
+                rs = stmt.executeQuery("SELECT ID2 FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals("000000000000500", rs.getString(1));
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(1, rs.getInt(1));
+                stmt.execute("DELETE FROM " + tenantView);
+            }
+        }
+    }
+
+    @Test
+    public void testQueryPlanForTenantViewOnBaseTableWithVarcharValue() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(DOUBLE1 VARCHAR NOT NULL, INT1 VARCHAR NOT NULL " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (DOUBLE1, INT1)) " +
+                        " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(DOUBLE1, INT1) VALUES " +
+                        "('12.0', '8')");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(DOUBLE1, INT1) VALUES " +
+                        "('13.0', '9')");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView + " WHERE (INT1, DOUBLE1) IN " +
+                        "(('8', '12.0')," +
+                        "('9', '13.0'))");
+                assertTrue(rs.next());
+                assertEquals(2, rs.getInt(1));
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (INT1, DOUBLE1) IN " +
+                        "(('8', '12.0')," +
+                        "('9', '13.0'))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testQueryPlanForTenantViewOnBaseTableWithNumericalValue() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView +
+                        " (ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY " + " (ID1, ID2)) " +
+                        " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(12, 8, 7, 6)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(13, 9, 13, 9)");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView +
+                        " WHERE (ID1, ID5) IN " +
+                        "((12, 7)," +
+                        "(12, 13))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID4, ID1) IN " +
+                        "((9, 13)," +
+                        "(12, 13))");
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "((8, 12)," +
+                        "(9, 13))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2, ID1) IN " +
+                        "((8, 12)," +
+                        "(9, 13))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testInListExpressionWithFunction() throws Exception {
+        String tenantView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (ID1, ID2)) " +
+                        " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(12, 8, 7, 6)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(13, 9, 13, 9)");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID1 + 1, ID5) IN " +
+                        "((13, 7)," +
+                        "(13, 13))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID4 - 1, ID1) IN " +
+                        "((8, 13)," +
+                        "(11, 13))");
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID2 + 1 , ID1 - 1) IN " +
+                        "((9, 11)," +
+                        "(10, 12))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2 -1, ID1 + 1) IN " +
+                        "((7, 13)," +
+                        "(8, 14))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testInListExpressionWithFunctionAndIndex() throws Exception {
+        String tenantView = generateUniqueName();
+        String tenantIndexView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (ID1, ID2)) " +
+                        " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(12, 8, 7, 6)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(13, 9, 13, 9)");
+                viewConn.commit();
+
+                stmt.execute("CREATE INDEX " + tenantIndexView + " ON " + tenantView + " (ID5) INCLUDE (ID4, ID1)");
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID1 + 1, ID5) IN " +
+                        "((13, 7)," +
+                        "(13, 13))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID5 - 1, ID1) IN " +
+                        "((6, 13)," +
+                        "(12, 13))");
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID5 + 1 , ID1 - 1) IN " +
+                        "((8, 11)," +
+                        "(14, 12))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID5 -1, ID1 + 1) IN " +
+                        "((6, 13)," +
+                        "(12, 14))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testInListExpressionWithIndex() throws Exception {
+        String tenantView = generateUniqueName();
+        String tenantIndexView = generateUniqueName();
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (ID1, ID2)) " +
+                        " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(12, 8, 7, 6)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(13, 9, 13, 9)");
+                viewConn.commit();
+
+                stmt.execute("CREATE INDEX " + tenantIndexView + " ON " + tenantView + " (ID5) INCLUDE (ID4)");
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID5, ID1) IN " +
+                        "((7, 12)," +
+                        "(7, 13))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID2, ID5) IN " +
+                        "((8, 13)," +
+                        "(9, 13))");
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID5, ID4) IN " +
+                        "((7, 6)," +
+                        "(13, 9))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID1, ID5) IN " +
+                        "((12, 7)," +
+                        "(13, 13))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testInListExpressionWithGlobalViewAndFunction() throws Exception {
+        String tenantView = generateUniqueName();
+        String globalView = generateUniqueName();
+
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.setAutoCommit(true);
+            try (Statement stmt = conn.createStatement()) {
+                stmt.execute("CREATE VIEW " + globalView + " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+            }
+        }
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (ID1, ID2)) " +
+                        " AS SELECT * FROM " + globalView);
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(12, 8, 7, 6)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(13, 9, 13, 9)");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID1 + 1, ID5) IN " +
+                        "((13, 7)," +
+                        "(13, 13))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID4 - 1, ID1) IN " +
+                        "((8, 13)," +
+                        "(11, 13))");
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (ID2 + 1 , ID1 - 1) IN " +
+                        "((9, 11)," +
+                        "(10, 12))");
+                assertTrue(rs.next());
+                assertEquals(12, rs.getInt(1));
+                assertEquals(8, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(rs.next());
+                assertEquals(13, rs.getInt(1));
+                assertEquals(9, rs.getInt(2));
+                assertEquals(13, rs.getInt(3));
+                assertEquals(9, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (ID2 -1, ID1 + 1) IN " +
+                        "((7, 13)," +
+                        "(8, 14))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testGlobalViewWithPowerFunction() throws Exception {
+        String tenantView = generateUniqueName();
+        String globalView = generateUniqueName();
+
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.setAutoCommit(true);
+            try (Statement stmt = conn.createStatement()) {
+                stmt.execute("CREATE VIEW " + globalView + " AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+            }
+        }
+
+        try (Connection viewConn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            viewConn.setAutoCommit(true);
+            try (Statement stmt = viewConn.createStatement()) {
+                stmt.execute("CREATE VIEW IF NOT EXISTS " + tenantView + "(ID1 DOUBLE NOT NULL, ID2 DOUBLE NOT NULL, ID4 BIGINT " +
+                        " CONSTRAINT PKVIEW PRIMARY KEY\n" + " (ID1, ID2)) " +
+                        " AS SELECT * FROM " + globalView);
+
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(9, 2, 7, 6)");
+                viewConn.createStatement().execute("UPSERT INTO " + tenantView + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(2, 9, 13, 9)");
+                viewConn.commit();
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + tenantView + " WHERE (POWER(ID2, 2), ID1) IN " +
+                        "((4.0, 9)," +
+                        "(10, 12))");
+                assertTrue(rs.next());
+                assertEquals(9, rs.getInt(1));
+                assertEquals(2, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + tenantView + " WHERE (POWER(ID1,2), ID2) IN " +
+                        "((81, 2)," +
+                        "(4, 9))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + tenantView);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testBaseTableAndIndexTableHaveReversePKOrder() throws Exception {
+        String view = generateUniqueName();
+        String index = generateUniqueName();
+
+        try (Connection conn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            conn.setAutoCommit(true);
+            try (Statement stmt = conn.createStatement()) {
+                stmt.execute("CREATE VIEW " + view + " (ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        "CONSTRAINT PKVIEW PRIMARY KEY (ID1, ID2)) AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                conn.createStatement().execute("UPSERT INTO " + view + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(9, 2, 7, 6)");
+                conn.createStatement().execute("UPSERT INTO " + view + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(2, 9, 13, 9)");
+                conn.commit();
+
+                stmt.execute("CREATE INDEX " + index + " ON " + view + " (ID2, ID1) INCLUDE (ID5, ID4)");
+
+                // TESTING for optimized scan
+                PreparedStatement preparedStmt = conn.prepareStatement("SELECT * FROM " + view + " WHERE (ID1, ID2) IN " +
+                        "((1, 1)," +
+                        "(2, 2))");
+                QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                assertEquals(new Long(2), queryPlan.getEstimatedRowsToScan());
+                assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+
+                preparedStmt = conn.prepareStatement("SELECT * FROM " + view + " WHERE (ID2, ID1) IN ((1, 1),(2, 2))");
+                queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                assertEquals(new Long(2), queryPlan.getEstimatedRowsToScan());
+                assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+
+
+                preparedStmt = conn.prepareStatement("SELECT * FROM " + view + " WHERE (ID2, ID1) IN ((1, 1),(2, 2))");
+                queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                assertEquals(new Long(2), queryPlan.getEstimatedRowsToScan());
+                assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + view + " WHERE (POWER(ID2, 2), ID1) IN " +
+                        "((4.0, 9)," +
+                        "(10, 12))");
+                assertTrue(rs.next());
+                assertEquals(9, rs.getInt(1));
+                assertEquals(2, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + view + " WHERE (POWER(ID1,2), ID2) IN " +
+                        "((81, 2)," +
+                        "(4, 9))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + view);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testDeletionFromTenantViewAndViewIndex() throws Exception {
+        String view = generateUniqueName();
+        String index = generateUniqueName();
+
+        try (Connection conn = DriverManager.getConnection(TENANT_SPECIFIC_URL1)) {
+            conn.setAutoCommit(true);
+            try (Statement stmt = conn.createStatement()) {
+                stmt.execute("CREATE VIEW " + view + " (ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, ID4 BIGINT " +
+                        "CONSTRAINT PKVIEW PRIMARY KEY (ID1, ID2)) AS SELECT * FROM " + tableName + " WHERE KEY_PREFIX = 'ABC'");
+
+                conn.createStatement().execute("UPSERT INTO " + view + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(9, 2, 7, 6)");
+                conn.createStatement().execute("UPSERT INTO " + view + "(ID1, ID2, ID5, ID4) VALUES " +
+                        "(2, 9, 13, 9)");
+                conn.commit();
+
+                stmt.execute("CREATE INDEX " + index + " ON " + view + " (ID4, ID2) INCLUDE (ID1, ID5)");
+
+                // TESTING for optimized scan
+                PreparedStatement preparedStmt = conn.prepareStatement("SELECT * FROM " + view + " WHERE (ID4, ID2) IN " +
+                        "((1, 1)," +
+                        "(2, 2))");
+                QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                assertTrue(queryPlan.getExplainPlan().toString().contains("RANGE SCAN"));
+
+                preparedStmt = conn.prepareStatement("SELECT ID1,ID5 FROM " + view + " WHERE (ID1, ID2) IN " +
+                        "((1, 1),(2, 2))");
+                queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                assertEquals(new Long(2), queryPlan.getEstimatedRowsToScan());
+                assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+
+
+                preparedStmt = conn.prepareStatement("SELECT * FROM " + view + " WHERE (ID2, ID1) IN ((1, 1),(2, 2))");
+                queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+                assertEquals(new Long(2), queryPlan.getEstimatedRowsToScan());
+                assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+
+
+                ResultSet rs = stmt.executeQuery("SELECT ID1, ID2, ID5, ID4 FROM " + view + " WHERE (POWER(ID2, 2), ID1) IN " +
+                        "((4.0, 9)," +
+                        "(10, 12))");
+                assertTrue(rs.next());
+                assertEquals(9, rs.getInt(1));
+                assertEquals(2, rs.getInt(2));
+                assertEquals(7, rs.getInt(3));
+                assertEquals(6, rs.getInt(4));
+                assertTrue(!rs.next());
+
+                stmt.execute("DELETE FROM " + view + " WHERE (POWER(ID1,2), ID2) IN " +
+                        "((81, 2)," +
+                        "(4, 9))");
+
+                rs = stmt.executeQuery("SELECT COUNT(*) FROM " + view);
+                assertTrue(rs.next());
+                assertEquals(0, rs.getInt(1));
+            }
+        }
+    }
+
+    @Test
+    public void testBaseTableAndIndexTableHaveRightScan() throws Exception {
+        String index = generateUniqueName();
+        String fullTableName = generateUniqueName();
+
+        try (Connection conn = DriverManager.getConnection(getUrl())) {
+            conn.setAutoCommit(true);
+            try (Statement stmt = conn.createStatement()) {
+                stmt.execute("CREATE TABLE " + fullTableName + "(ID1 BIGINT NOT NULL, ID2 BIGINT NOT NULL, " +
+                        "VAL1 BIGINT, VAL2 BIGINT CONSTRAINT PK PRIMARY KEY (ID1,ID2))");
+                stmt.execute("CREATE INDEX " + index + " ON " + fullTableName + " (ID2, ID1) INCLUDE (VAL2)");
+            }
+
+            PreparedStatement preparedStmt = conn.prepareStatement("SELECT VAL2 FROM " + fullTableName +
+                    " WHERE (ID2, ID1) IN ((1, 1),(2, 2))");
+            QueryPlan queryPlan = PhoenixRuntime.getOptimizedQueryPlan(preparedStmt);
+            queryPlan.getTableRef().getTable().getType();
+            assertTrue(queryPlan.getExplainPlan().toString().contains(ExplainTable.POINT_LOOKUP_ON_STRING));
+        }
+    }
 }
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 fc276c8..900350d 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
@@ -26,7 +26,7 @@ import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.ArrayList;
 
 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@@ -85,12 +85,24 @@ public class InListExpression extends BaseSingleExpression {
             // In case of after removing nulls there is no remaining element in the IN list
             return LiteralExpression.newConstant(false);
         }
+
+        if (firstChild instanceof RowValueConstructorExpression) {
+            List<InListColumnKeyValuePair> inListColumnKeyValuePairList =
+                    getSortedInListColumnKeyValuePair(childrenWithoutNulls);
+            if (inListColumnKeyValuePairList != null) {
+                childrenWithoutNulls = getSortedRowValueConstructorExpressionList(
+                        inListColumnKeyValuePairList, firstChild.isStateless(),children.size() - 1);
+                firstChild = childrenWithoutNulls.get(0);
+            }
+        }
+
         boolean nullInList = children.size() != childrenWithoutNulls.size();
 
         if (childrenWithoutNulls.size() == 2 && !nullInList) {
             return ComparisonExpression.create(isNegate ? CompareOp.NOT_EQUAL : CompareOp.EQUAL,
                     childrenWithoutNulls, ptr, rowKeyOrderOptimizable);
         }
+
         SQLException sqlE = null;
         List<Expression> coercedKeyExpressions = Lists.newArrayListWithExpectedSize(childrenWithoutNulls.size());
         coercedKeyExpressions.add(firstChild);
@@ -334,4 +346,108 @@ public class InListExpression extends BaseSingleExpression {
     public InListExpression clone(List<Expression> l) {
         return new InListExpression(l, this.rowKeyOrderOptimizable);
     }
+
+    /**
+     * get list of InListColumnKeyValuePair with a PK ordered structure
+     * @param children children from rvc
+     * @return the list of InListColumnKeyValuePair
+     */
+    public static List<InListColumnKeyValuePair> getSortedInListColumnKeyValuePair(List<Expression> children) {
+        List<InListColumnKeyValuePair> inListColumnKeyValuePairList = new ArrayList<>();
+        int numberOfColumns = 0;
+
+        for (int i = 0; i < children.size(); i++) {
+            Expression child = children.get(i);
+            if (i == 0) {
+                numberOfColumns = child.getChildren().size();
+                for (int j = 0; j < child.getChildren().size(); j++) {
+                    if (child.getChildren().get(j) instanceof RowKeyColumnExpression) {
+                        RowKeyColumnExpression rowKeyColumnExpression =
+                                (RowKeyColumnExpression)child.getChildren().get(j);
+                        InListColumnKeyValuePair inListColumnKeyValuePair =
+                                new InListColumnKeyValuePair(rowKeyColumnExpression);
+                        inListColumnKeyValuePairList.add(inListColumnKeyValuePair);
+                    } else {
+                        // if one of the columns is not part of the pk, we ignore.
+                        return null;
+                    }
+                }
+            } else {
+                if (numberOfColumns != child.getChildren().size()) {
+                    // if the number of the PK columns doesn't match number of values,
+                    // it should not sort it in PK position.
+                    return null;
+                }
+
+                for (int j = 0; j < child.getChildren().size(); j++) {
+                    LiteralExpression literalExpression = (LiteralExpression) child.getChildren().get(j);
+                    inListColumnKeyValuePairList.get(j).addToLiteralExpressionList(literalExpression);
+                }
+            }
+        }
+        Collections.sort(inListColumnKeyValuePairList);
+        return inListColumnKeyValuePairList;
+    }
+
+    /**
+     * get a PK ordered Expression RowValueConstructor
+     * @param inListColumnKeyValuePairList the object stores RowKeyColumnExpression and List of LiteralExpression
+     * @param isStateless
+     * @param numberOfRows number of literalExpressions
+     * @return the new RowValueConstructorExpression with PK ordered expressions
+     */
+    public static List<Expression> getSortedRowValueConstructorExpressionList(
+            List<InListColumnKeyValuePair> inListColumnKeyValuePairList, boolean isStateless, int numberOfRows) {
+        List<Expression> l = new ArrayList<>();
+        //reconstruct columns
+        List<Expression> keyExpressions = new ArrayList<>();
+        for (int i = 0; i < inListColumnKeyValuePairList.size(); i++) {
+            keyExpressions.add(inListColumnKeyValuePairList.get(i).getRowKeyColumnExpression());
+        }
+        l.add(new RowValueConstructorExpression(keyExpressions,isStateless));
+
+        //reposition to corresponding values
+        List<List<Expression>> valueExpressionsList = new ArrayList<>();
+
+        for (int j = 0; j < inListColumnKeyValuePairList.size(); j++) {
+            List<LiteralExpression> valueList = inListColumnKeyValuePairList.get(j).getLiteralExpressionList();
+            for (int i = 0; i < numberOfRows; i++) {
+                if (j == 0) {
+                    valueExpressionsList.add(new ArrayList<Expression>());
+                }
+                valueExpressionsList.get(i).add(valueList.get(i));
+            }
+        }
+        for (List<Expression> valueExpressions: valueExpressionsList) {
+            l.add(new RowValueConstructorExpression(valueExpressions, isStateless));
+        }
+        return l;
+    }
+
+    public static class InListColumnKeyValuePair implements Comparable<InListColumnKeyValuePair> {
+        RowKeyColumnExpression rowKeyColumnExpression;
+        List<LiteralExpression> literalExpressionList;
+
+        public InListColumnKeyValuePair(RowKeyColumnExpression rowKeyColumnExpression) {
+            this.rowKeyColumnExpression = rowKeyColumnExpression;
+            this.literalExpressionList = new ArrayList<>();
+        }
+
+        public RowKeyColumnExpression getRowKeyColumnExpression() {
+            return this.rowKeyColumnExpression;
+        }
+
+        public void addToLiteralExpressionList(LiteralExpression literalExpression) {
+            this.literalExpressionList.add(literalExpression);
+        }
+
+        public List<LiteralExpression> getLiteralExpressionList() {
+            return this.literalExpressionList;
+        }
+
+        @Override
+        public int compareTo(InListColumnKeyValuePair o) {
+            return rowKeyColumnExpression.getPosition() - o.getRowKeyColumnExpression().getPosition();
+        }
+    }
 }
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
index d8a0de9..1aaa3f9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
@@ -54,6 +54,7 @@ import org.apache.phoenix.util.StringUtil;
 
 public abstract class ExplainTable {
     private static final List<KeyRange> EVERYTHING = Collections.singletonList(KeyRange.EVERYTHING_RANGE);
+    public static final String POINT_LOOKUP_ON_STRING = "POINT LOOKUP ON ";
     protected final StatementContext context;
     protected final TableRef tableRef;
     protected final GroupBy groupBy;
@@ -81,7 +82,7 @@ public abstract class ExplainTable {
         ScanRanges scanRanges = context.getScanRanges();
         if (scanRanges.isPointLookup()) {
             int keyCount = scanRanges.getPointLookupCount();
-            buf.append("POINT LOOKUP ON " + keyCount + " KEY" + (keyCount > 1 ? "S " : " "));
+            buf.append(POINT_LOOKUP_ON_STRING + keyCount + " KEY" + (keyCount > 1 ? "S " : " "));
         } else if (scanRanges.useSkipScanFilter()) {
             buf.append("SKIP SCAN ");
             int count = 1;
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/InListExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/InListExpressionTest.java
index 3d765ab..2cbc02b 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/expression/InListExpressionTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/InListExpressionTest.java
@@ -19,13 +19,22 @@ package org.apache.phoenix.expression;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.Lists;
+
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
+
+
+import org.apache.phoenix.schema.types.PInteger;
+import org.junit.Test;
+import org.mockito.Mockito;
+
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
-import org.junit.Test;
+
 
 public class InListExpressionTest {
 
@@ -62,4 +71,200 @@ public class InListExpressionTest {
                     + hashCode, firstHashCode, hashCode);
         }
     }
+
+    @Test
+    public void testGetSortedInListColumnKeyValuePairWithNoPkOrder() {
+        testGetSortedInListColumnKeyValuePair(false);
+    }
+
+    @Test
+    public void testGetSortedInListColumnKeyValuePairWithPkOrder() {
+        testGetSortedInListColumnKeyValuePair(true);
+    }
+
+    private void testGetSortedInListColumnKeyValuePair(boolean isPkOrder) {
+        // mock literal
+        List<Expression> expressionList = new ArrayList<>();
+        LiteralExpression literalChild1 = Mockito.mock(LiteralExpression.class);
+        List<Expression> literalExpressions = new ArrayList<>();
+        when(literalChild1.getDataType()).thenReturn(PInteger.INSTANCE);
+        when(literalChild1.getBytes()).thenReturn(null);
+        when(literalChild1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        literalExpressions.add(literalChild1);
+        literalExpressions.add(literalChild1);
+
+        // mock row key column
+        List<Expression> expressionChildren = new ArrayList<>();
+        RowKeyColumnExpression rowKeyColumnExpressionMock1 = Mockito.mock(RowKeyColumnExpression.class);
+        RowKeyColumnExpression rowKeyColumnExpressionMock2 = Mockito.mock(RowKeyColumnExpression.class);
+
+        when(rowKeyColumnExpressionMock1.getPosition()).thenReturn(1);
+        when(rowKeyColumnExpressionMock1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        when(rowKeyColumnExpressionMock2.getPosition()).thenReturn(2);
+        when(rowKeyColumnExpressionMock2.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        when(rowKeyColumnExpressionMock1.getChildren()).thenReturn(expressionChildren);
+        when(rowKeyColumnExpressionMock2.getChildren()).thenReturn(literalExpressions);
+
+        // mock row key column PK order position
+        if (isPkOrder) {
+            expressionChildren.add(rowKeyColumnExpressionMock1);
+            expressionChildren.add(rowKeyColumnExpressionMock2);
+
+        } else {
+            expressionChildren.add(rowKeyColumnExpressionMock2);
+            expressionChildren.add(rowKeyColumnExpressionMock1);
+
+        }
+
+        RowValueConstructorExpression rvc1 = new RowValueConstructorExpression(expressionChildren, true);
+        RowValueConstructorExpression rvc2 = new RowValueConstructorExpression(literalExpressions, true);
+        expressionList.add(rvc1);
+        expressionList.add(rvc2);
+
+        if (isPkOrder) {
+            assertEquals(1, ((RowKeyColumnExpression)expressionList.get(0).getChildren().get(0)).getPosition());
+            assertEquals(2, ((RowKeyColumnExpression)expressionList.get(0).getChildren().get(1)).getPosition());
+        } else {
+            assertEquals(2, ((RowKeyColumnExpression)expressionList.get(0).getChildren().get(0)).getPosition());
+            assertEquals(1, ((RowKeyColumnExpression)expressionList.get(0).getChildren().get(1)).getPosition());
+        }
+
+        List<InListExpression.InListColumnKeyValuePair> inListColumnKeyValuePairList =
+                InListExpression.getSortedInListColumnKeyValuePair(expressionList);
+
+        assertEquals(1, inListColumnKeyValuePairList.get(0).getRowKeyColumnExpression().getPosition());
+        assertEquals(2, inListColumnKeyValuePairList.get(1).getRowKeyColumnExpression().getPosition());
+    }
+
+    @Test
+    public void testGetSortedInListColumnKeyValuePairWithLessValueThanPkColumns() {
+        List<Expression> expressionList = new ArrayList<>();
+        LiteralExpression literalChild1 = Mockito.mock(LiteralExpression.class);
+        List<Expression> literalExpressions = new ArrayList<>();
+        when(literalChild1.getDataType()).thenReturn(PInteger.INSTANCE);
+        when(literalChild1.getBytes()).thenReturn(null);
+        when(literalChild1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        literalExpressions.add(literalChild1);
+        literalExpressions.add(literalChild1);
+
+        // mock row key column
+        List<Expression> expressionChildren = new ArrayList<>();
+        RowKeyColumnExpression rowKeyColumnExpressionMock1 = Mockito.mock(RowKeyColumnExpression.class);
+
+        when(rowKeyColumnExpressionMock1.getPosition()).thenReturn(1);
+        when(rowKeyColumnExpressionMock1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        when(rowKeyColumnExpressionMock1.getChildren()).thenReturn(expressionChildren);
+
+        expressionChildren.add(rowKeyColumnExpressionMock1);
+
+        RowValueConstructorExpression rvc1 = new RowValueConstructorExpression(expressionChildren, true);
+        RowValueConstructorExpression rvc2 = new RowValueConstructorExpression(literalExpressions, true);
+        expressionList.add(rvc1);
+        expressionList.add(rvc2);
+
+        List<InListExpression.InListColumnKeyValuePair> inListColumnKeyValuePairList =
+                InListExpression.getSortedInListColumnKeyValuePair(expressionList);
+
+        assertEquals(null, inListColumnKeyValuePairList);
+    }
+
+    @Test
+    public void testGetSortedInListColumnKeyValuePairWithMoreValueThanPkColumn() {
+        List<Expression> expressionList = new ArrayList<>();
+        LiteralExpression literalChild1 = Mockito.mock(LiteralExpression.class);
+        List<Expression> literalExpressions = new ArrayList<>();
+        when(literalChild1.getDataType()).thenReturn(PInteger.INSTANCE);
+        when(literalChild1.getBytes()).thenReturn(null);
+        when(literalChild1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        literalExpressions.add(literalChild1);
+
+        // mock row key column
+        List<Expression> expressionChildren = new ArrayList<>();
+        RowKeyColumnExpression rowKeyColumnExpressionMock1 = Mockito.mock(RowKeyColumnExpression.class);
+        when(rowKeyColumnExpressionMock1.getPosition()).thenReturn(1);
+        when(rowKeyColumnExpressionMock1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        when(rowKeyColumnExpressionMock1.getChildren()).thenReturn(expressionChildren);
+
+        expressionChildren.add(rowKeyColumnExpressionMock1);
+        expressionChildren.add(rowKeyColumnExpressionMock1);
+
+        RowValueConstructorExpression rvc1 = new RowValueConstructorExpression(expressionChildren, true);
+        RowValueConstructorExpression rvc2 = new RowValueConstructorExpression(literalExpressions, true);
+        expressionList.add(rvc1);
+        expressionList.add(rvc2);
+
+        List<InListExpression.InListColumnKeyValuePair> inListColumnKeyValuePairList =
+                InListExpression.getSortedInListColumnKeyValuePair(expressionList);
+
+        assertEquals(null, inListColumnKeyValuePairList);
+    }
+
+    @Test
+    public void testInListColumnKeyValuePairClass() {
+        RowKeyColumnExpression rowKeyColumnExpression = Mockito.mock(RowKeyColumnExpression.class);
+        LiteralExpression literalChild = Mockito.mock(LiteralExpression.class);
+
+        InListExpression.InListColumnKeyValuePair inListColumnKeyValuePair =
+                new InListExpression.InListColumnKeyValuePair(rowKeyColumnExpression);
+        inListColumnKeyValuePair.addToLiteralExpressionList(literalChild);
+
+        assertEquals(rowKeyColumnExpression, inListColumnKeyValuePair.getRowKeyColumnExpression());
+        assertEquals(literalChild, inListColumnKeyValuePair.getLiteralExpressionList().get(0));
+    }
+
+    @Test
+    public void testGetSortedRowValueConstructorExpressionList() {
+        byte[] bytesValueOne = ByteBuffer.allocate(4).putInt(1).array();
+        byte[] bytesValueTwo = ByteBuffer.allocate(4).putInt(1).array();
+        // mock literal
+        List<Expression> literalExpressions = new ArrayList<>();
+        LiteralExpression literalChild1 = Mockito.mock(LiteralExpression.class);
+        when(literalChild1.getDataType()).thenReturn(PInteger.INSTANCE);
+        when(literalChild1.getBytes()).thenReturn(bytesValueOne);
+        when(literalChild1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        literalExpressions.add(literalChild1);
+
+        LiteralExpression literalChild2 = Mockito.mock(LiteralExpression.class);
+        when(literalChild2.getDataType()).thenReturn(PInteger.INSTANCE);
+        when(literalChild2.getBytes()).thenReturn(bytesValueTwo);
+        when(literalChild2.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        literalExpressions.add(literalChild2);
+
+        List<Expression> expressionChildren = new ArrayList<>();
+        RowKeyColumnExpression rowKeyColumnExpressionMock1 = Mockito.mock(RowKeyColumnExpression.class);
+        RowKeyColumnExpression rowKeyColumnExpressionMock2 = Mockito.mock(RowKeyColumnExpression.class);
+        expressionChildren.add(rowKeyColumnExpressionMock1);
+        expressionChildren.add(rowKeyColumnExpressionMock2);
+
+        when(rowKeyColumnExpressionMock1.getPosition()).thenReturn(1);
+        when(rowKeyColumnExpressionMock1.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        when(rowKeyColumnExpressionMock2.getPosition()).thenReturn(2);
+        when(rowKeyColumnExpressionMock2.getDeterminism()).thenReturn(Determinism.ALWAYS);
+        when(rowKeyColumnExpressionMock1.getChildren()).thenReturn(expressionChildren);
+        when(rowKeyColumnExpressionMock2.getChildren()).thenReturn(literalExpressions);
+
+        //construct sorted InListColumnKeyValuePair list
+        List<InListExpression.InListColumnKeyValuePair> children = new ArrayList<>();
+        InListExpression.InListColumnKeyValuePair rvc1 =
+                new InListExpression.InListColumnKeyValuePair(rowKeyColumnExpressionMock1);
+        rvc1.addToLiteralExpressionList(literalChild1);
+        children.add(rvc1);
+        InListExpression.InListColumnKeyValuePair rvc2 =
+                new InListExpression.InListColumnKeyValuePair(rowKeyColumnExpressionMock2);
+        rvc2.addToLiteralExpressionList(literalChild2);
+        children.add(rvc2);
+
+        List<Expression> result = InListExpression.getSortedRowValueConstructorExpressionList(
+                children,true, 1);
+
+        assertTrue(result.get(0).getChildren().get(0) instanceof RowKeyColumnExpression);
+        assertTrue(result.get(0).getChildren().get(1) instanceof RowKeyColumnExpression);
+        assertEquals(1, ((RowKeyColumnExpression)result.get(0).getChildren().get(0)).getPosition());
+        assertEquals(2, ((RowKeyColumnExpression)result.get(0).getChildren().get(1)).getPosition());
+
+        assertTrue(result.get(1).getChildren().get(0) instanceof LiteralExpression);
+        assertTrue(result.get(1).getChildren().get(1) instanceof LiteralExpression);
+        assertEquals(bytesValueOne, ((LiteralExpression)result.get(1).getChildren().get(0)).getBytes());
+        assertEquals(bytesValueTwo, ((LiteralExpression)result.get(1).getChildren().get(1)).getBytes());
+    }
 }