You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/02/10 18:13:58 UTC

[1/8] Fix failing unit test, rename tests for consistency

Updated Branches:
  refs/heads/master fe18e96ae -> 0ea954eae


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java b/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
index 2816023..a5d7d1e 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
@@ -215,8 +215,8 @@ public class TestUtil {
         return  new ComparisonExpression(op, Arrays.asList(e, LiteralExpression.newConstant(o)));
     }
 
-    public static Expression columnComparison(CompareOp op, PColumn c1, PColumn c2) {
-        return  new ComparisonExpression(op, Arrays.<Expression>asList(new KeyValueColumnExpression(c1), new KeyValueColumnExpression(c2)));
+    public static Expression columnComparison(CompareOp op, Expression c1, Expression c2) {
+        return  new ComparisonExpression(op, Arrays.<Expression>asList(c1, c2));
     }
 
     public static SingleKeyValueComparisonFilter singleKVFilter(Expression e) {


[3/8] Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java
new file mode 100644
index 0000000..82f3bcd
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereCompilerTest.java
@@ -0,0 +1,931 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.apache.phoenix.util.TestUtil.ATABLE_NAME;
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.apache.phoenix.util.TestUtil.and;
+import static org.apache.phoenix.util.TestUtil.assertDegenerate;
+import static org.apache.phoenix.util.TestUtil.columnComparison;
+import static org.apache.phoenix.util.TestUtil.constantComparison;
+import static org.apache.phoenix.util.TestUtil.in;
+import static org.apache.phoenix.util.TestUtil.multiKVFilter;
+import static org.apache.phoenix.util.TestUtil.not;
+import static org.apache.phoenix.util.TestUtil.or;
+import static org.apache.phoenix.util.TestUtil.singleKVFilter;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.text.Format;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.filter.Filter;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.function.SubstrFunction;
+import org.apache.phoenix.filter.RowKeyComparisonFilter;
+import org.apache.phoenix.filter.SkipScanFilter;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.RowKeyValueAccessor;
+import org.apache.phoenix.schema.SaltingUtil;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.DateUtil;
+import org.apache.phoenix.util.NumberUtil;
+import org.apache.phoenix.util.SchemaUtil;
+import org.apache.phoenix.util.StringUtil;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+
+public class WhereCompilerTest extends BaseConnectionlessQueryTest {
+
+    @Test
+    public void testSingleEqualFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer=0";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            singleKVFilter(constantComparison(
+                CompareOp.EQUAL,
+                BaseConnectionlessQueryTest.A_INTEGER,
+                0)),
+            filter);
+    }
+
+    @Test
+    public void testSingleFixedFullPkSalted() throws SQLException {
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        pconn.createStatement().execute("CREATE TABLE t (k bigint not null primary key, v varchar) SALT_BUCKETS=20");
+        String query = "select * from t where k=" + 1;
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertNull(filter);
+        byte[] key = new byte[PDataType.LONG.getByteSize() + 1];
+        PDataType.LONG.toBytes(1L, key, 1);
+        key[0] = SaltingUtil.getSaltingByte(key, 1, PDataType.LONG.getByteSize(), 20);
+        byte[] expectedStartKey = key;
+        byte[] expectedEndKey = ByteUtil.concat(key, QueryConstants.SEPARATOR_BYTE_ARRAY);
+        byte[] startKey = scan.getStartRow();
+        byte[] stopKey = scan.getStopRow();
+        assertTrue(Bytes.compareTo(expectedStartKey, startKey) == 0);
+        assertTrue(Bytes.compareTo(expectedEndKey, stopKey) == 0);
+    }
+
+    @Test
+    public void testSingleVariableFullPkSalted() throws SQLException {
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        pconn.createStatement().execute("CREATE TABLE t (k varchar primary key, v varchar) SALT_BUCKETS=20");
+        String query = "select * from t where k='a'";
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertNull(filter);
+        byte[] key = new byte[2];
+        PDataType.VARCHAR.toBytes("a", key, 1);
+        key[0] = SaltingUtil.getSaltingByte(key, 1, 1, 20);
+        byte[] expectedStartKey = key;
+        byte[] expectedEndKey = ByteUtil.concat(key, QueryConstants.SEPARATOR_BYTE_ARRAY);
+        byte[] startKey = scan.getStartRow();
+        byte[] stopKey = scan.getStopRow();
+        assertTrue(Bytes.compareTo(expectedStartKey, startKey) == 0);
+        assertTrue(Bytes.compareTo(expectedEndKey, stopKey) == 0);
+    }
+
+    @Test
+    public void testMultiFixedFullPkSalted() throws SQLException {
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        pconn.createStatement().execute("CREATE TABLE t (k bigint not null primary key, v varchar) SALT_BUCKETS=20");
+        String query = "select * from t where k in (1,3)";
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        byte[] key = new byte[PDataType.LONG.getByteSize() + 1];
+        PDataType.LONG.toBytes(1L, key, 1);
+        key[0] = SaltingUtil.getSaltingByte(key, 1, PDataType.LONG.getByteSize(), 20);
+        byte[] startKey1 = key;
+        
+        key = new byte[PDataType.LONG.getByteSize() + 1];
+        PDataType.LONG.toBytes(3L, key, 1);
+        key[0] = SaltingUtil.getSaltingByte(key, 1, PDataType.LONG.getByteSize(), 20);
+        byte[] startKey2 = key;
+        
+        byte[] startKey = scan.getStartRow();
+        byte[] stopKey = scan.getStopRow();
+        
+        // Due to salting byte, the 1 key may be after the 3 key
+        byte[] expectedStartKey;
+        byte[] expectedEndKey;
+        List<List<KeyRange>> expectedRanges = Collections.singletonList(
+                Arrays.asList(KeyRange.getKeyRange(startKey1),
+                              KeyRange.getKeyRange(startKey2)));
+        if (Bytes.compareTo(startKey1, startKey2) > 0) {
+            expectedStartKey = startKey2;
+            expectedEndKey = ByteUtil.concat(startKey1, QueryConstants.SEPARATOR_BYTE_ARRAY);
+            Collections.reverse(expectedRanges.get(0));
+        } else {
+            expectedStartKey = startKey1;
+            expectedEndKey = ByteUtil.concat(startKey2, QueryConstants.SEPARATOR_BYTE_ARRAY);;
+        }
+        assertTrue(Bytes.compareTo(expectedStartKey, startKey) == 0);
+        assertTrue(Bytes.compareTo(expectedEndKey, stopKey) == 0);
+
+        assertNotNull(filter);
+        assertTrue(filter instanceof SkipScanFilter);
+        StatementContext context = plan.getContext();
+        ScanRanges scanRanges = context.getScanRanges();
+        List<List<KeyRange>> ranges = scanRanges.getRanges();
+        assertEquals(expectedRanges, ranges);
+    }
+
+    @Test
+    public void testMultiColumnEqualFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_string=b_string";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            multiKVFilter(columnComparison(
+                CompareOp.EQUAL,
+                BaseConnectionlessQueryTest.A_STRING,
+                BaseConnectionlessQueryTest.B_STRING)),
+            filter);
+    }
+
+    @Test
+    public void testCollapseFunctionToNull() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,null) = 'foo'";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertNull(filter);
+
+        assertArrayEquals(scan.getStartRow(),KeyRange.EMPTY_RANGE.getLowerRange());
+        assertArrayEquals(scan.getStopRow(),KeyRange.EMPTY_RANGE.getUpperRange());
+    }
+
+    private static void bindParams(PhoenixPreparedStatement stmt, List<Object> binds) throws SQLException {
+        for (int i = 0; i < binds.size(); i++) {
+            stmt.setObject(i+1, binds.get(i));
+        }
+    }
+    
+    @Test
+    public void testAndFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id=? and a_integer=0 and a_string='foo'";
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        
+        assertEquals(
+            multiKVFilter(and(
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_INTEGER,
+                    0),
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_STRING,
+                    "foo"))),
+            filter);
+    }
+
+    @Test
+    public void testRHSLiteral() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and 0 >= a_integer";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        
+        Filter filter = scan.getFilter();
+        assertEquals(
+            singleKVFilter(constantComparison(
+                CompareOp.LESS_OR_EQUAL,
+                BaseConnectionlessQueryTest.A_INTEGER,
+                0)),
+            filter);
+    }
+
+    @Test
+    public void testToDateFilter() throws Exception {
+        String tenantId = "000000000000001";
+        String dateStr = "2012-01-01 12:00:00";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_date >= to_date('" + dateStr + "')";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+
+        Format format = DateUtil.getDateParser(DateUtil.DEFAULT_DATE_FORMAT);
+        Object date = format.parseObject(dateStr);
+
+        assertEquals(
+            singleKVFilter(constantComparison(
+                CompareOp.GREATER_OR_EQUAL,
+                BaseConnectionlessQueryTest.A_DATE,
+                date)),
+            filter);
+    }
+
+    private void helpTestToNumberFilter(String toNumberClause, BigDecimal expectedDecimal) throws Exception {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and x_decimal >= " + toNumberClause;
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+
+        assertEquals(
+            singleKVFilter(constantComparison(
+                CompareOp.GREATER_OR_EQUAL,
+                BaseConnectionlessQueryTest.X_DECIMAL,
+                expectedDecimal)),
+            filter);
+}
+
+    private void helpTestToNumberFilterWithNoPattern(String stringValue) throws Exception {
+        String toNumberClause = "to_number('" + stringValue + "')";
+        BigDecimal expectedDecimal = NumberUtil.normalize(new BigDecimal(stringValue));
+        helpTestToNumberFilter(toNumberClause, expectedDecimal);
+    }
+
+    @Test
+    public void testToNumberFilterWithInteger() throws Exception {
+        String stringValue = "123";
+        helpTestToNumberFilterWithNoPattern(stringValue);
+    }
+
+    @Test
+    public void testToNumberFilterWithDecimal() throws Exception {
+        String stringValue = "123.33";
+        helpTestToNumberFilterWithNoPattern(stringValue);
+    }
+
+    @Test
+    public void testToNumberFilterWithNegativeDecimal() throws Exception {
+        String stringValue = "-123.33";
+        helpTestToNumberFilterWithNoPattern(stringValue);
+    }
+
+    @Test
+    public void testToNumberFilterWithPatternParam() throws Exception {
+        String toNumberClause = "to_number('$1.23333E2', '\u00A40.00000E0')";
+        BigDecimal expectedDecimal = NumberUtil.normalize(new BigDecimal("123.333"));
+        helpTestToNumberFilter(toNumberClause, expectedDecimal);
+    }
+
+    @Test(expected=AssertionError.class) // compileStatement() fails because zero rows are found by to_number()
+    public void testToNumberFilterWithPatternParamNegativeTest() throws Exception {
+        String toNumberClause = "to_number('$123.33', '000.00')"; // no currency sign in pattern param
+        BigDecimal expectedDecimal = NumberUtil.normalize(new BigDecimal("123.33"));
+        helpTestToNumberFilter(toNumberClause, expectedDecimal);
+    }
+
+    @Test
+    public void testRowKeyFilter() throws SQLException {
+        String keyPrefix = "foo";
+        String query = "select * from atable where substr(entity_id,1,3)=?";
+        List<Object> binds = Arrays.<Object>asList(keyPrefix);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+
+        assertEquals(
+            new RowKeyComparisonFilter(
+                constantComparison(CompareOp.EQUAL,
+                    new SubstrFunction(
+                        Arrays.<Expression>asList(
+                            new RowKeyColumnExpression(BaseConnectionlessQueryTest.ENTITY_ID,new RowKeyValueAccessor(BaseConnectionlessQueryTest.ATABLE.getPKColumns(),1)),
+                            LiteralExpression.newConstant(1),
+                            LiteralExpression.newConstant(3))
+                        ),
+                    keyPrefix),
+                QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES),
+            filter);
+    }
+
+    @Test
+    public void testPaddedRowKeyFilter() throws SQLException {
+        String keyPrefix = "fo";
+        String query = "select * from atable where entity_id=?";
+        List<Object> binds = Arrays.<Object>asList(keyPrefix);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        assertEquals(0,scan.getStartRow().length);
+        assertEquals(0,scan.getStopRow().length);
+        assertNotNull(scan.getFilter());
+    }
+
+    @Test
+    public void testPaddedStartStopKey() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "fo";
+        String query = "select * from atable where organization_id=? AND entity_id=?";
+        List<Object> binds = Arrays.<Object>asList(tenantId,keyPrefix);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        byte[] expectedStartRow = ByteUtil.concat(Bytes.toBytes(tenantId), StringUtil.padChar(Bytes.toBytes(keyPrefix), 15));
+        assertArrayEquals(expectedStartRow,scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(expectedStartRow,QueryConstants.SEPARATOR_BYTE_ARRAY),scan.getStopRow());
+    }
+
+    @Test
+    public void testDegenerateRowKeyFilter() throws SQLException {
+        String keyPrefix = "foobar";
+        String query = "select * from atable where substr(entity_id,1,3)=?";
+        List<Object> binds = Arrays.<Object>asList(keyPrefix);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        // Degenerate b/c "foobar" is more than 3 characters
+        assertDegenerate(plan.getContext());
+    }
+
+    @Test
+    public void testDegenerateBiggerThanMaxLengthVarchar() throws SQLException {
+        byte[] tooBigValue = new byte[101];
+        Arrays.fill(tooBigValue, (byte)50);
+        String aString = (String)PDataType.VARCHAR.toObject(tooBigValue);
+        String query = "select * from atable where a_string=?";
+        List<Object> binds = Arrays.<Object>asList(aString);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        // Degenerate b/c a_string length is 100
+        assertDegenerate(plan.getContext());
+    }
+
+    @Test
+    public void testOrFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "foo";
+        int aInt = 2;
+        String query = "select * from atable where organization_id=? and (substr(entity_id,1,3)=? or a_integer=?)";
+        List<Object> binds = Arrays.<Object>asList(tenantId, keyPrefix, aInt);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        bindParams(pstmt, binds);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            singleKVFilter( // single b/c one column is a row key column
+            or(
+                constantComparison(
+                    CompareOp.EQUAL,
+                    new SubstrFunction(Arrays.<Expression> asList(
+                        new RowKeyColumnExpression(
+                            BaseConnectionlessQueryTest.ENTITY_ID,
+                            new RowKeyValueAccessor(BaseConnectionlessQueryTest.ATABLE.getPKColumns(), 1)),
+                        LiteralExpression.newConstant(1),
+                        LiteralExpression.newConstant(3))),
+                    keyPrefix),
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_INTEGER,
+                    aInt))),
+            filter);
+    }
+
+    @Test
+    public void testTypeMismatch() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer > 'foo'";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+
+        try {
+            pstmt.optimizeQuery();
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("Type mismatch"));
+        }
+    }
+
+    @Test
+    public void testAndFalseFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer=0 and 2=3";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        assertDegenerate(plan.getContext());
+    }
+
+    @Test
+    public void testFalseFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and 2=3";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        assertDegenerate(plan.getContext());
+    }
+
+    @Test
+    public void testTrueFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and 2<=2";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        assertNull(scan.getFilter());
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testAndTrueFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer=0 and 2<3";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            singleKVFilter(constantComparison(
+                CompareOp.EQUAL,
+                BaseConnectionlessQueryTest.A_INTEGER,
+                0)),
+            filter);
+
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testOrFalseFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and (a_integer=0 or 3!=3)";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            singleKVFilter(constantComparison(
+                CompareOp.EQUAL,
+                BaseConnectionlessQueryTest.A_INTEGER,
+                0)),
+            filter);
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testOrTrueFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and (a_integer=0 or 3>2)";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertNull(filter);
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testInFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_string IN ('a','b')";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+
+        Filter filter = scan.getFilter();
+        assertEquals(
+            singleKVFilter(in(
+                BaseConnectionlessQueryTest.A_STRING,
+                "a",
+                "b")),
+            filter);
+    }
+
+    @Test
+    public void testInListFilter() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String tenantId3 = "000000000000003";
+        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s')",
+                ATABLE_NAME, tenantId1, tenantId3, tenantId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId1);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = PDataType.VARCHAR.toBytes(tenantId3);
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+
+        Filter filter = scan.getFilter();
+        assertEquals(
+            new SkipScanFilter(
+                ImmutableList.of(Arrays.asList(
+                    pointRange(tenantId1),
+                    pointRange(tenantId2),
+                    pointRange(tenantId3))),
+                plan.getContext().getResolver().getTables().get(0).getTable().getRowKeySchema()),
+            filter);
+    }
+
+    @Test @Ignore("OR not yet optimized")
+    public void testOr2InFilter() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String tenantId3 = "000000000000003";
+        String query = String.format("select * from %s where organization_id='%s' OR organization_id='%s' OR organization_id='%s'",
+                ATABLE_NAME, tenantId1, tenantId3, tenantId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+
+        Filter filter = scan.getFilter();
+        assertEquals(
+            new SkipScanFilter(
+                ImmutableList.of(Arrays.asList(
+                    pointRange(tenantId1),
+                    pointRange(tenantId2),
+                    pointRange(tenantId3))),
+                plan.getContext().getResolver().getTables().get(0).getTable().getRowKeySchema()),
+            filter);
+
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId1);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = PDataType.VARCHAR.toBytes(tenantId3);
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testSecondPkColInListFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String entityId1 = "00000000000000X";
+        String entityId2 = "00000000000000Y";
+        String query = String.format("select * from %s where organization_id='%s' AND entity_id IN ('%s','%s')",
+                ATABLE_NAME, tenantId, entityId1, entityId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId + entityId1);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = PDataType.VARCHAR.toBytes(tenantId + entityId2);
+        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+
+        Filter filter = scan.getFilter();
+
+        assertEquals(
+            new SkipScanFilter(
+                ImmutableList.of(
+                    Arrays.asList(
+                        pointRange(tenantId,entityId1),
+                        pointRange(tenantId,entityId2))),
+                SchemaUtil.VAR_BINARY_SCHEMA),
+            filter);
+    }
+
+    @Test
+    public void testInListWithAnd1GTEFilter() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String tenantId3 = "000000000000003";
+        String entityId1 = "00000000000000X";
+        String entityId2 = "00000000000000Y";
+        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id>='%s' AND entity_id<='%s'",
+                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId1, entityId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            new SkipScanFilter(
+                ImmutableList.of(
+                    Arrays.asList(
+                        pointRange(tenantId1),
+                        pointRange(tenantId2),
+                        pointRange(tenantId3)),
+                    Arrays.asList(PDataType.CHAR.getKeyRange(
+                        Bytes.toBytes(entityId1),
+                        true,
+                        Bytes.toBytes(entityId2),
+                        true))),
+                plan.getContext().getResolver().getTables().get(0).getTable().getRowKeySchema()),
+            filter);
+    }
+    
+    @Test
+    public void testInListWithAnd1Filter() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String tenantId3 = "000000000000003";
+        String entityId = "00000000000000X";
+        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id='%s'",
+                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+            new SkipScanFilter(
+                ImmutableList.of(
+                    Arrays.asList(
+                        pointRange(tenantId1, entityId),
+                        pointRange(tenantId2, entityId),
+                        pointRange(tenantId3, entityId))),
+                SchemaUtil.VAR_BINARY_SCHEMA),
+            filter);
+    }
+    @Test
+    public void testInListWithAnd1FilterScankey() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String tenantId3 = "000000000000003";
+        String entityId = "00000000000000X";
+        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id='%s'",
+                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId1), PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId3), PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+        // TODO: validate scan ranges
+    }
+
+    private static KeyRange pointRange(String... ids) {
+        byte[] theKey = ByteUtil.EMPTY_BYTE_ARRAY;
+        for (String id : ids) {
+            theKey = ByteUtil.concat(theKey, Bytes.toBytes(id));
+        }
+        return pointRange(theKey);
+    }
+    private static KeyRange pointRange(byte[] bytes) {
+        return KeyRange.POINT.apply(bytes);
+    }
+
+    @Test
+    public void testInListWithAnd2Filter() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String entityId1 = "00000000000000X";
+        String entityId2 = "00000000000000Y";
+        String query = String.format("select * from %s where organization_id IN ('%s','%s') AND entity_id IN ('%s', '%s')",
+                ATABLE_NAME, tenantId1, tenantId2, entityId1, entityId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+
+        Filter filter = scan.getFilter();
+        assertEquals(
+            new SkipScanFilter(
+                    ImmutableList.<List<KeyRange>>of(ImmutableList.of(
+                        pointRange(tenantId1, entityId1),
+                        pointRange(tenantId1, entityId2),
+                        pointRange(tenantId2, entityId1),
+                        pointRange(tenantId2, entityId2))),
+                SchemaUtil.VAR_BINARY_SCHEMA),
+            filter);
+    }
+
+    @Test
+    public void testPartialRangeFilter() throws SQLException {
+        // I know these id's are ridiculous, but users can write queries that look like this
+        String tenantId1 = "001";
+        String tenantId2 = "02";
+        String query = String.format("select * from %s where organization_id > '%s' AND organization_id < '%s'",
+                ATABLE_NAME, tenantId1, tenantId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+
+        assertNull(scan.getFilter());
+        byte[] wideLower = ByteUtil.nextKey(StringUtil.padChar(Bytes.toBytes(tenantId1), 15));
+        byte[] wideUpper = StringUtil.padChar(Bytes.toBytes(tenantId2), 15);
+        assertArrayEquals(wideLower, scan.getStartRow());
+        assertArrayEquals(wideUpper, scan.getStopRow());
+    }
+
+    @Test
+    public void testInListWithAnd2FilterScanKey() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000002";
+        String tenantId3 = "000000000000003";
+        String entityId1 = "00000000000000X";
+        String entityId2 = "00000000000000Y";
+        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id IN ('%s', '%s')",
+                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId1, entityId2);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId1),PDataType.VARCHAR.toBytes(entityId1));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId3),PDataType.VARCHAR.toBytes(entityId2));
+        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+        // TODO: validate scan ranges
+    }
+    
+    @Test
+    public void testBetweenFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer between 0 and 10";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+                singleKVFilter(and(
+                    constantComparison(
+                        CompareOp.GREATER_OR_EQUAL,
+                        BaseConnectionlessQueryTest.A_INTEGER,
+                        0),
+                    constantComparison(
+                        CompareOp.LESS_OR_EQUAL,
+                        BaseConnectionlessQueryTest.A_INTEGER,
+                        10))),
+                filter);
+    }
+    
+    @Test
+    public void testNotBetweenFilter() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer not between 0 and 10";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+        assertEquals(
+                singleKVFilter(not(and(
+                    constantComparison(
+                        CompareOp.GREATER_OR_EQUAL,
+                        BaseConnectionlessQueryTest.A_INTEGER,
+                        0),
+                    constantComparison(
+                        CompareOp.LESS_OR_EQUAL,
+                        BaseConnectionlessQueryTest.A_INTEGER,
+                        10)))).toString(),
+                filter.toString());
+    }
+    
+    @Test
+    public void testTenantConstraintsAddedToScan() throws SQLException {
+        String tenantTypeId = "5678";
+        String tenantId = "000000000000123";
+        String url = getUrl(tenantId);
+        createTestTable(getUrl(), "create table base_table_for_tenant_filter_test (tenant_id char(15) not null, type_id char(4) not null, " +
+        		"id char(5) not null, a_integer integer, a_string varchar(100) constraint pk primary key (tenant_id, type_id, id)) multi_tenant=true");
+        createTestTable(url, "create view tenant_filter_test (tenant_col integer) AS SELECT * FROM BASE_TABLE_FOR_TENANT_FILTER_TEST WHERE type_id= '" + tenantTypeId + "'");
+        
+        String query = "select * from tenant_filter_test where a_integer=0 and a_string='foo'";
+        PhoenixConnection pconn = DriverManager.getConnection(url, TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+
+        assertEquals(
+            multiKVFilter(and(
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_INTEGER,
+                    0),
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_STRING,
+                    "foo"))),
+            filter);
+        
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId + tenantTypeId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+    
+    @Test
+    public void testTenantConstraintsAddedToScanWithNullTenantTypeId() throws SQLException {
+        String tenantId = "000000000000123";
+        createTestTable(getUrl(), "create table base_table_for_tenant_filter_test (tenant_id char(15) not null, " +
+                "id char(5) not null, a_integer integer, a_string varchar(100) constraint pk primary key (tenant_id, id)) multi_tenant=true");
+        createTestTable(getUrl(tenantId), "create view tenant_filter_test (tenant_col integer) AS SELECT * FROM BASE_TABLE_FOR_TENANT_FILTER_TEST");
+        
+        String query = "select * from tenant_filter_test where a_integer=0 and a_string='foo'";
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(tenantId), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
+        QueryPlan plan = pstmt.optimizeQuery();
+        Scan scan = plan.getContext().getScan();
+        Filter filter = scan.getFilter();
+
+        assertEquals(
+            multiKVFilter(and(
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_INTEGER,
+                    0),
+                constantComparison(
+                    CompareOp.EQUAL,
+                    BaseConnectionlessQueryTest.A_STRING,
+                    "foo"))),
+            filter);
+        
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = startRow;
+        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
+    }
+}


[5/8] Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseCompileTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseCompileTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseCompileTest.java
deleted file mode 100644
index 50854a2..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseCompileTest.java
+++ /dev/null
@@ -1,932 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.apache.phoenix.util.TestUtil.ATABLE_NAME;
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
-import static org.apache.phoenix.util.TestUtil.and;
-import static org.apache.phoenix.util.TestUtil.assertDegenerate;
-import static org.apache.phoenix.util.TestUtil.columnComparison;
-import static org.apache.phoenix.util.TestUtil.constantComparison;
-import static org.apache.phoenix.util.TestUtil.in;
-import static org.apache.phoenix.util.TestUtil.kvColumn;
-import static org.apache.phoenix.util.TestUtil.multiKVFilter;
-import static org.apache.phoenix.util.TestUtil.not;
-import static org.apache.phoenix.util.TestUtil.or;
-import static org.apache.phoenix.util.TestUtil.singleKVFilter;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.math.BigDecimal;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.text.Format;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
-import org.apache.hadoop.hbase.filter.Filter;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.phoenix.expression.Expression;
-import org.apache.phoenix.expression.LiteralExpression;
-import org.apache.phoenix.expression.RowKeyColumnExpression;
-import org.apache.phoenix.expression.function.SubstrFunction;
-import org.apache.phoenix.filter.RowKeyComparisonFilter;
-import org.apache.phoenix.filter.SkipScanFilter;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-import org.apache.phoenix.query.KeyRange;
-import org.apache.phoenix.query.QueryConstants;
-import org.apache.phoenix.schema.PDataType;
-import org.apache.phoenix.schema.RowKeyValueAccessor;
-import org.apache.phoenix.schema.SaltingUtil;
-import org.apache.phoenix.util.ByteUtil;
-import org.apache.phoenix.util.DateUtil;
-import org.apache.phoenix.util.NumberUtil;
-import org.apache.phoenix.util.SchemaUtil;
-import org.apache.phoenix.util.StringUtil;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import com.google.common.collect.ImmutableList;
-
-
-public class WhereClauseCompileTest extends BaseConnectionlessQueryTest {
-
-    @Test
-    public void testSingleEqualFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer=0";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            singleKVFilter(constantComparison(
-                CompareOp.EQUAL,
-                BaseConnectionlessQueryTest.A_INTEGER,
-                0)),
-            filter);
-    }
-
-    @Test
-    public void testSingleFixedFullPkSalted() throws SQLException {
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        pconn.createStatement().execute("CREATE TABLE t (k bigint not null primary key, v varchar) SALT_BUCKETS=20");
-        String query = "select * from t where k=" + 1;
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertNull(filter);
-        byte[] key = new byte[PDataType.LONG.getByteSize() + 1];
-        PDataType.LONG.toBytes(1L, key, 1);
-        key[0] = SaltingUtil.getSaltingByte(key, 1, PDataType.LONG.getByteSize(), 20);
-        byte[] expectedStartKey = key;
-        byte[] expectedEndKey = ByteUtil.concat(key, QueryConstants.SEPARATOR_BYTE_ARRAY);
-        byte[] startKey = scan.getStartRow();
-        byte[] stopKey = scan.getStopRow();
-        assertTrue(Bytes.compareTo(expectedStartKey, startKey) == 0);
-        assertTrue(Bytes.compareTo(expectedEndKey, stopKey) == 0);
-    }
-
-    @Test
-    public void testSingleVariableFullPkSalted() throws SQLException {
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        pconn.createStatement().execute("CREATE TABLE t (k varchar primary key, v varchar) SALT_BUCKETS=20");
-        String query = "select * from t where k='a'";
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertNull(filter);
-        byte[] key = new byte[2];
-        PDataType.VARCHAR.toBytes("a", key, 1);
-        key[0] = SaltingUtil.getSaltingByte(key, 1, 1, 20);
-        byte[] expectedStartKey = key;
-        byte[] expectedEndKey = ByteUtil.concat(key, QueryConstants.SEPARATOR_BYTE_ARRAY);
-        byte[] startKey = scan.getStartRow();
-        byte[] stopKey = scan.getStopRow();
-        assertTrue(Bytes.compareTo(expectedStartKey, startKey) == 0);
-        assertTrue(Bytes.compareTo(expectedEndKey, stopKey) == 0);
-    }
-
-    @Test
-    public void testMultiFixedFullPkSalted() throws SQLException {
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        pconn.createStatement().execute("CREATE TABLE t (k bigint not null primary key, v varchar) SALT_BUCKETS=20");
-        String query = "select * from t where k in (1,3)";
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        byte[] key = new byte[PDataType.LONG.getByteSize() + 1];
-        PDataType.LONG.toBytes(1L, key, 1);
-        key[0] = SaltingUtil.getSaltingByte(key, 1, PDataType.LONG.getByteSize(), 20);
-        byte[] startKey1 = key;
-        
-        key = new byte[PDataType.LONG.getByteSize() + 1];
-        PDataType.LONG.toBytes(3L, key, 1);
-        key[0] = SaltingUtil.getSaltingByte(key, 1, PDataType.LONG.getByteSize(), 20);
-        byte[] startKey2 = key;
-        
-        byte[] startKey = scan.getStartRow();
-        byte[] stopKey = scan.getStopRow();
-        
-        // Due to salting byte, the 1 key may be after the 3 key
-        byte[] expectedStartKey;
-        byte[] expectedEndKey;
-        List<List<KeyRange>> expectedRanges = Collections.singletonList(
-                Arrays.asList(KeyRange.getKeyRange(startKey1),
-                              KeyRange.getKeyRange(startKey2)));
-        if (Bytes.compareTo(startKey1, startKey2) > 0) {
-            expectedStartKey = startKey2;
-            expectedEndKey = ByteUtil.concat(startKey1, QueryConstants.SEPARATOR_BYTE_ARRAY);
-            Collections.reverse(expectedRanges.get(0));
-        } else {
-            expectedStartKey = startKey1;
-            expectedEndKey = ByteUtil.concat(startKey2, QueryConstants.SEPARATOR_BYTE_ARRAY);;
-        }
-        assertTrue(Bytes.compareTo(expectedStartKey, startKey) == 0);
-        assertTrue(Bytes.compareTo(expectedEndKey, stopKey) == 0);
-
-        assertNotNull(filter);
-        assertTrue(filter instanceof SkipScanFilter);
-        StatementContext context = plan.getContext();
-        ScanRanges scanRanges = context.getScanRanges();
-        List<List<KeyRange>> ranges = scanRanges.getRanges();
-        assertEquals(expectedRanges, ranges);
-    }
-
-    @Test
-    public void testMultiColumnEqualFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_string=b_string";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            multiKVFilter(columnComparison(
-                CompareOp.EQUAL,
-                BaseConnectionlessQueryTest.A_STRING,
-                BaseConnectionlessQueryTest.B_STRING)),
-            filter);
-    }
-
-    @Test
-    public void testCollapseFunctionToNull() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,null) = 'foo'";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertNull(filter);
-
-        assertArrayEquals(scan.getStartRow(),KeyRange.EMPTY_RANGE.getLowerRange());
-        assertArrayEquals(scan.getStopRow(),KeyRange.EMPTY_RANGE.getUpperRange());
-    }
-
-    private static void bindParams(PhoenixPreparedStatement stmt, List<Object> binds) throws SQLException {
-        for (int i = 0; i < binds.size(); i++) {
-            stmt.setObject(i+1, binds.get(i));
-        }
-    }
-    
-    @Test
-    public void testAndFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id=? and a_integer=0 and a_string='foo'";
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        
-        assertEquals(
-            multiKVFilter(and(
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_INTEGER,
-                    0),
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_STRING,
-                    "foo"))),
-            filter);
-    }
-
-    @Test
-    public void testRHSLiteral() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and 0 >= a_integer";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        
-        Filter filter = scan.getFilter();
-        assertEquals(
-            singleKVFilter(constantComparison(
-                CompareOp.LESS_OR_EQUAL,
-                BaseConnectionlessQueryTest.A_INTEGER,
-                0)),
-            filter);
-    }
-
-    @Test
-    public void testToDateFilter() throws Exception {
-        String tenantId = "000000000000001";
-        String dateStr = "2012-01-01 12:00:00";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_date >= to_date('" + dateStr + "')";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-
-        Format format = DateUtil.getDateParser(DateUtil.DEFAULT_DATE_FORMAT);
-        Object date = format.parseObject(dateStr);
-
-        assertEquals(
-            singleKVFilter(constantComparison(
-                CompareOp.GREATER_OR_EQUAL,
-                BaseConnectionlessQueryTest.A_DATE,
-                date)),
-            filter);
-    }
-
-    private void helpTestToNumberFilter(String toNumberClause, BigDecimal expectedDecimal) throws Exception {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and x_decimal >= " + toNumberClause;
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-
-        assertEquals(
-            singleKVFilter(constantComparison(
-                CompareOp.GREATER_OR_EQUAL,
-                BaseConnectionlessQueryTest.X_DECIMAL,
-                expectedDecimal)),
-            filter);
-}
-
-    private void helpTestToNumberFilterWithNoPattern(String stringValue) throws Exception {
-        String toNumberClause = "to_number('" + stringValue + "')";
-        BigDecimal expectedDecimal = NumberUtil.normalize(new BigDecimal(stringValue));
-        helpTestToNumberFilter(toNumberClause, expectedDecimal);
-    }
-
-    @Test
-    public void testToNumberFilterWithInteger() throws Exception {
-        String stringValue = "123";
-        helpTestToNumberFilterWithNoPattern(stringValue);
-    }
-
-    @Test
-    public void testToNumberFilterWithDecimal() throws Exception {
-        String stringValue = "123.33";
-        helpTestToNumberFilterWithNoPattern(stringValue);
-    }
-
-    @Test
-    public void testToNumberFilterWithNegativeDecimal() throws Exception {
-        String stringValue = "-123.33";
-        helpTestToNumberFilterWithNoPattern(stringValue);
-    }
-
-    @Test
-    public void testToNumberFilterWithPatternParam() throws Exception {
-        String toNumberClause = "to_number('$1.23333E2', '\u00A40.00000E0')";
-        BigDecimal expectedDecimal = NumberUtil.normalize(new BigDecimal("123.333"));
-        helpTestToNumberFilter(toNumberClause, expectedDecimal);
-    }
-
-    @Test(expected=AssertionError.class) // compileStatement() fails because zero rows are found by to_number()
-    public void testToNumberFilterWithPatternParamNegativeTest() throws Exception {
-        String toNumberClause = "to_number('$123.33', '000.00')"; // no currency sign in pattern param
-        BigDecimal expectedDecimal = NumberUtil.normalize(new BigDecimal("123.33"));
-        helpTestToNumberFilter(toNumberClause, expectedDecimal);
-    }
-
-    @Test
-    public void testRowKeyFilter() throws SQLException {
-        String keyPrefix = "foo";
-        String query = "select * from atable where substr(entity_id,1,3)=?";
-        List<Object> binds = Arrays.<Object>asList(keyPrefix);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-
-        assertEquals(
-            new RowKeyComparisonFilter(
-                constantComparison(CompareOp.EQUAL,
-                    new SubstrFunction(
-                        Arrays.<Expression>asList(
-                            new RowKeyColumnExpression(BaseConnectionlessQueryTest.ENTITY_ID,new RowKeyValueAccessor(BaseConnectionlessQueryTest.ATABLE.getPKColumns(),1)),
-                            LiteralExpression.newConstant(1),
-                            LiteralExpression.newConstant(3))
-                        ),
-                    keyPrefix),
-                QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES),
-            filter);
-    }
-
-    @Test
-    public void testPaddedRowKeyFilter() throws SQLException {
-        String keyPrefix = "fo";
-        String query = "select * from atable where entity_id=?";
-        List<Object> binds = Arrays.<Object>asList(keyPrefix);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        assertEquals(0,scan.getStartRow().length);
-        assertEquals(0,scan.getStopRow().length);
-        assertNotNull(scan.getFilter());
-    }
-
-    @Test
-    public void testPaddedStartStopKey() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "fo";
-        String query = "select * from atable where organization_id=? AND entity_id=?";
-        List<Object> binds = Arrays.<Object>asList(tenantId,keyPrefix);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        byte[] expectedStartRow = ByteUtil.concat(Bytes.toBytes(tenantId), StringUtil.padChar(Bytes.toBytes(keyPrefix), 15));
-        assertArrayEquals(expectedStartRow,scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(expectedStartRow,QueryConstants.SEPARATOR_BYTE_ARRAY),scan.getStopRow());
-    }
-
-    @Test
-    public void testDegenerateRowKeyFilter() throws SQLException {
-        String keyPrefix = "foobar";
-        String query = "select * from atable where substr(entity_id,1,3)=?";
-        List<Object> binds = Arrays.<Object>asList(keyPrefix);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        // Degenerate b/c "foobar" is more than 3 characters
-        assertDegenerate(plan.getContext());
-    }
-
-    @Test
-    public void testDegenerateBiggerThanMaxLengthVarchar() throws SQLException {
-        byte[] tooBigValue = new byte[101];
-        Arrays.fill(tooBigValue, (byte)50);
-        String aString = (String)PDataType.VARCHAR.toObject(tooBigValue);
-        String query = "select * from atable where a_string=?";
-        List<Object> binds = Arrays.<Object>asList(aString);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        // Degenerate b/c a_string length is 100
-        assertDegenerate(plan.getContext());
-    }
-
-    @Test
-    public void testOrFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "foo";
-        int aInt = 2;
-        String query = "select * from atable where organization_id=? and (substr(entity_id,1,3)=? or a_integer=?)";
-        List<Object> binds = Arrays.<Object>asList(tenantId, keyPrefix, aInt);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        bindParams(pstmt, binds);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            singleKVFilter( // single b/c one column is a row key column
-            or(
-                constantComparison(
-                    CompareOp.EQUAL,
-                    new SubstrFunction(Arrays.<Expression> asList(
-                        new RowKeyColumnExpression(
-                            BaseConnectionlessQueryTest.ENTITY_ID,
-                            new RowKeyValueAccessor(BaseConnectionlessQueryTest.ATABLE.getPKColumns(), 1)),
-                        LiteralExpression.newConstant(1),
-                        LiteralExpression.newConstant(3))),
-                    keyPrefix),
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_INTEGER,
-                    aInt))),
-            filter);
-    }
-
-    @Test
-    public void testTypeMismatch() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer > 'foo'";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-
-        try {
-            pstmt.optimizeQuery();
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("Type mismatch"));
-        }
-    }
-
-    @Test
-    public void testAndFalseFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer=0 and 2=3";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        assertDegenerate(plan.getContext());
-    }
-
-    @Test
-    public void testFalseFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and 2=3";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        assertDegenerate(plan.getContext());
-    }
-
-    @Test
-    public void testTrueFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and 2<=2";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        assertNull(scan.getFilter());
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testAndTrueFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer=0 and 2<3";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            singleKVFilter(constantComparison(
-                CompareOp.EQUAL,
-                BaseConnectionlessQueryTest.A_INTEGER,
-                0)),
-            filter);
-
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testOrFalseFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and (a_integer=0 or 3!=3)";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            singleKVFilter(constantComparison(
-                CompareOp.EQUAL,
-                BaseConnectionlessQueryTest.A_INTEGER,
-                0)),
-            filter);
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testOrTrueFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and (a_integer=0 or 3>2)";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertNull(filter);
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testInFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_string IN ('a','b')";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-
-        Filter filter = scan.getFilter();
-        assertEquals(
-            singleKVFilter(in(
-                kvColumn(BaseConnectionlessQueryTest.A_STRING),
-                "a",
-                "b")),
-            filter);
-    }
-
-    @Test
-    public void testInListFilter() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String tenantId3 = "000000000000003";
-        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s')",
-                ATABLE_NAME, tenantId1, tenantId3, tenantId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId1);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = PDataType.VARCHAR.toBytes(tenantId3);
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-
-        Filter filter = scan.getFilter();
-        assertEquals(
-            new SkipScanFilter(
-                ImmutableList.of(Arrays.asList(
-                    pointRange(tenantId1),
-                    pointRange(tenantId2),
-                    pointRange(tenantId3))),
-                plan.getContext().getResolver().getTables().get(0).getTable().getRowKeySchema()),
-            filter);
-    }
-
-    @Test @Ignore("OR not yet optimized")
-    public void testOr2InFilter() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String tenantId3 = "000000000000003";
-        String query = String.format("select * from %s where organization_id='%s' OR organization_id='%s' OR organization_id='%s'",
-                ATABLE_NAME, tenantId1, tenantId3, tenantId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-
-        Filter filter = scan.getFilter();
-        assertEquals(
-            new SkipScanFilter(
-                ImmutableList.of(Arrays.asList(
-                    pointRange(tenantId1),
-                    pointRange(tenantId2),
-                    pointRange(tenantId3))),
-                plan.getContext().getResolver().getTables().get(0).getTable().getRowKeySchema()),
-            filter);
-
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId1);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = PDataType.VARCHAR.toBytes(tenantId3);
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testSecondPkColInListFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String entityId1 = "00000000000000X";
-        String entityId2 = "00000000000000Y";
-        String query = String.format("select * from %s where organization_id='%s' AND entity_id IN ('%s','%s')",
-                ATABLE_NAME, tenantId, entityId1, entityId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId + entityId1);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = PDataType.VARCHAR.toBytes(tenantId + entityId2);
-        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-
-        Filter filter = scan.getFilter();
-
-        assertEquals(
-            new SkipScanFilter(
-                ImmutableList.of(
-                    Arrays.asList(
-                        pointRange(tenantId,entityId1),
-                        pointRange(tenantId,entityId2))),
-                SchemaUtil.VAR_BINARY_SCHEMA),
-            filter);
-    }
-
-    @Test
-    public void testInListWithAnd1GTEFilter() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String tenantId3 = "000000000000003";
-        String entityId1 = "00000000000000X";
-        String entityId2 = "00000000000000Y";
-        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id>='%s' AND entity_id<='%s'",
-                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId1, entityId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            new SkipScanFilter(
-                ImmutableList.of(
-                    Arrays.asList(
-                        pointRange(tenantId1),
-                        pointRange(tenantId2),
-                        pointRange(tenantId3)),
-                    Arrays.asList(PDataType.CHAR.getKeyRange(
-                        Bytes.toBytes(entityId1),
-                        true,
-                        Bytes.toBytes(entityId2),
-                        true))),
-                plan.getContext().getResolver().getTables().get(0).getTable().getRowKeySchema()),
-            filter);
-    }
-    
-    @Test
-    public void testInListWithAnd1Filter() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String tenantId3 = "000000000000003";
-        String entityId = "00000000000000X";
-        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id='%s'",
-                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-            new SkipScanFilter(
-                ImmutableList.of(
-                    Arrays.asList(
-                        pointRange(tenantId1, entityId),
-                        pointRange(tenantId2, entityId),
-                        pointRange(tenantId3, entityId))),
-                SchemaUtil.VAR_BINARY_SCHEMA),
-            filter);
-    }
-    @Test
-    public void testInListWithAnd1FilterScankey() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String tenantId3 = "000000000000003";
-        String entityId = "00000000000000X";
-        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id='%s'",
-                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId1), PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId3), PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-        // TODO: validate scan ranges
-    }
-
-    private static KeyRange pointRange(String... ids) {
-        byte[] theKey = ByteUtil.EMPTY_BYTE_ARRAY;
-        for (String id : ids) {
-            theKey = ByteUtil.concat(theKey, Bytes.toBytes(id));
-        }
-        return pointRange(theKey);
-    }
-    private static KeyRange pointRange(byte[] bytes) {
-        return KeyRange.POINT.apply(bytes);
-    }
-
-    @Test
-    public void testInListWithAnd2Filter() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String entityId1 = "00000000000000X";
-        String entityId2 = "00000000000000Y";
-        String query = String.format("select * from %s where organization_id IN ('%s','%s') AND entity_id IN ('%s', '%s')",
-                ATABLE_NAME, tenantId1, tenantId2, entityId1, entityId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-
-        Filter filter = scan.getFilter();
-        assertEquals(
-            new SkipScanFilter(
-                    ImmutableList.<List<KeyRange>>of(ImmutableList.of(
-                        pointRange(tenantId1, entityId1),
-                        pointRange(tenantId1, entityId2),
-                        pointRange(tenantId2, entityId1),
-                        pointRange(tenantId2, entityId2))),
-                SchemaUtil.VAR_BINARY_SCHEMA),
-            filter);
-    }
-
-    @Test
-    public void testPartialRangeFilter() throws SQLException {
-        // I know these id's are ridiculous, but users can write queries that look like this
-        String tenantId1 = "001";
-        String tenantId2 = "02";
-        String query = String.format("select * from %s where organization_id > '%s' AND organization_id < '%s'",
-                ATABLE_NAME, tenantId1, tenantId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-
-        assertNull(scan.getFilter());
-        byte[] wideLower = ByteUtil.nextKey(StringUtil.padChar(Bytes.toBytes(tenantId1), 15));
-        byte[] wideUpper = StringUtil.padChar(Bytes.toBytes(tenantId2), 15);
-        assertArrayEquals(wideLower, scan.getStartRow());
-        assertArrayEquals(wideUpper, scan.getStopRow());
-    }
-
-    @Test
-    public void testInListWithAnd2FilterScanKey() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000002";
-        String tenantId3 = "000000000000003";
-        String entityId1 = "00000000000000X";
-        String entityId2 = "00000000000000Y";
-        String query = String.format("select * from %s where organization_id IN ('%s','%s','%s') AND entity_id IN ('%s', '%s')",
-                ATABLE_NAME, tenantId1, tenantId3, tenantId2, entityId1, entityId2);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId1),PDataType.VARCHAR.toBytes(entityId1));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId3),PDataType.VARCHAR.toBytes(entityId2));
-        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-        // TODO: validate scan ranges
-    }
-    
-    @Test
-    public void testBetweenFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer between 0 and 10";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-                singleKVFilter(and(
-                    constantComparison(
-                        CompareOp.GREATER_OR_EQUAL,
-                        BaseConnectionlessQueryTest.A_INTEGER,
-                        0),
-                    constantComparison(
-                        CompareOp.LESS_OR_EQUAL,
-                        BaseConnectionlessQueryTest.A_INTEGER,
-                        10))),
-                filter);
-    }
-    
-    @Test
-    public void testNotBetweenFilter() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and a_integer not between 0 and 10";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-        assertEquals(
-                singleKVFilter(not(and(
-                    constantComparison(
-                        CompareOp.GREATER_OR_EQUAL,
-                        BaseConnectionlessQueryTest.A_INTEGER,
-                        0),
-                    constantComparison(
-                        CompareOp.LESS_OR_EQUAL,
-                        BaseConnectionlessQueryTest.A_INTEGER,
-                        10)))).toString(),
-                filter.toString());
-    }
-    
-    @Test
-    public void testTenantConstraintsAddedToScan() throws SQLException {
-        String tenantTypeId = "5678";
-        String tenantId = "000000000000123";
-        String url = getUrl(tenantId);
-        createTestTable(getUrl(), "create table base_table_for_tenant_filter_test (tenant_id char(15) not null, type_id char(4) not null, " +
-        		"id char(5) not null, a_integer integer, a_string varchar(100) constraint pk primary key (tenant_id, type_id, id)) multi_tenant=true");
-        createTestTable(url, "create view tenant_filter_test (tenant_col integer) AS SELECT * FROM BASE_TABLE_FOR_TENANT_FILTER_TEST WHERE type_id= '" + tenantTypeId + "'");
-        
-        String query = "select * from tenant_filter_test where a_integer=0 and a_string='foo'";
-        PhoenixConnection pconn = DriverManager.getConnection(url, TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-
-        assertEquals(
-            multiKVFilter(and(
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_INTEGER,
-                    0),
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_STRING,
-                    "foo"))),
-            filter);
-        
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId + tenantTypeId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-    
-    @Test
-    public void testTenantConstraintsAddedToScanWithNullTenantTypeId() throws SQLException {
-        String tenantId = "000000000000123";
-        createTestTable(getUrl(), "create table base_table_for_tenant_filter_test (tenant_id char(15) not null, " +
-                "id char(5) not null, a_integer integer, a_string varchar(100) constraint pk primary key (tenant_id, id)) multi_tenant=true");
-        createTestTable(getUrl(tenantId), "create view tenant_filter_test (tenant_col integer) AS SELECT * FROM BASE_TABLE_FOR_TENANT_FILTER_TEST");
-        
-        String query = "select * from tenant_filter_test where a_integer=0 and a_string='foo'";
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(tenantId), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(pconn, query);
-        QueryPlan plan = pstmt.optimizeQuery();
-        Scan scan = plan.getContext().getScan();
-        Filter filter = scan.getFilter();
-
-        assertEquals(
-            multiKVFilter(and(
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_INTEGER,
-                    0),
-                constantComparison(
-                    CompareOp.EQUAL,
-                    BaseConnectionlessQueryTest.A_STRING,
-                    "foo"))),
-            filter);
-        
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = startRow;
-        assertArrayEquals(ByteUtil.nextKey(stopRow), scan.getStopRow());
-    }
-}


[4/8] Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseOptimizerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseOptimizerTest.java
deleted file mode 100644
index 925bcc2..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereClauseOptimizerTest.java
+++ /dev/null
@@ -1,1620 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
-import static org.apache.phoenix.util.TestUtil.assertDegenerate;
-import static org.apache.phoenix.util.TestUtil.assertEmptyScanKey;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.sql.Connection;
-import java.sql.Date;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.filter.Filter;
-import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
-import org.apache.phoenix.expression.Expression;
-import org.apache.phoenix.expression.OrExpression;
-import org.apache.phoenix.filter.RowKeyComparisonFilter;
-import org.apache.phoenix.filter.SkipScanFilter;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.jdbc.PhoenixStatement;
-import org.apache.phoenix.parse.SQLParser;
-import org.apache.phoenix.parse.SelectStatement;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-import org.apache.phoenix.query.KeyRange;
-import org.apache.phoenix.query.QueryConstants;
-import org.apache.phoenix.schema.ColumnNotFoundException;
-import org.apache.phoenix.schema.PDataType;
-import org.apache.phoenix.util.ByteUtil;
-import org.apache.phoenix.util.DateUtil;
-import org.apache.phoenix.util.TestUtil;
-import org.junit.Test;
-
-import com.google.common.collect.Sets;
-
-
-
-public class WhereClauseOptimizerTest extends BaseConnectionlessQueryTest {
-    
-    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds) throws SQLException {
-        return compileStatement(query, scan, binds, null, null);
-    }
-
-    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds, Integer limit) throws SQLException {
-        return compileStatement(query, scan, binds, limit, null);
-    }
-
-    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds, Set<Expression> extractedNodes) throws SQLException {
-        return compileStatement(query, scan, binds, null, extractedNodes);
-    }
-
-    // TODO: remove this and replace checks on extractedNodes with tests for the scan filter
-    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds, Integer limit, Set<Expression> extractedNodes) throws SQLException {
-        SQLParser parser = new SQLParser(query);
-        SelectStatement statement = parser.parseQuery();
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
-        statement = StatementNormalizer.normalize(statement, resolver);
-        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
-
-        Integer actualLimit = LimitCompiler.compile(context, statement);
-        assertEquals(limit, actualLimit);
-        GroupBy groupBy = GroupByCompiler.compile(context, statement);
-        statement = HavingCompiler.rewrite(context, statement, groupBy);
-        WhereCompiler.compileWhereClause(context, statement, extractedNodes);
-        return context;
-    }
-
-    @Test
-    public void testSingleKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        compileStatement(query, scan, binds);
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-
-    @Test
-    public void testReverseSingleKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where '" + tenantId + "' = organization_id";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        compileStatement(query, scan, binds);
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-
-    @Test
-    public void testStartKeyStopKey() throws SQLException {
-        Connection conn = DriverManager.getConnection(getUrl());
-        conn.createStatement().execute("CREATE TABLE start_stop_test (pk char(2) not null primary key)");
-        conn.close();
-
-        String query = "select * from start_stop_test where pk >= 'EA' and pk < 'EZ'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        assertArrayEquals(PDataType.VARCHAR.toBytes("EA"), scan.getStartRow());
-        assertArrayEquals(PDataType.VARCHAR.toBytes("EZ"), scan.getStopRow());
-    }
-
-    @Test
-    public void testConcatSingleKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id || 'foo' ='" + tenantId + "'||'foo'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        // The || operator cannot currently be used to form the start/stop key
-        assertNotNull(scan.getFilter());
-        assertEquals(0, scan.getStartRow().length);
-        assertEquals(0, scan.getStopRow().length);
-    }
-
-    @Test
-    public void testLiteralConcatExpression() throws SQLException {
-        String query = "select * from atable where null||'foo'||'bar' = 'foobar'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        assertEquals(0, scan.getStartRow().length);
-        assertEquals(0, scan.getStopRow().length);
-    }
-
-    @Test
-    public void testSingleKeyNotExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where not organization_id='" + tenantId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertNotNull(scan.getFilter());
-
-        assertEquals(0, scan.getStartRow().length);
-        assertEquals(0, scan.getStopRow().length);
-    }
-
-    @Test
-    public void testMultiKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3)='" + keyPrefix + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)), 15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testMultiKeyBindExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id=? and substr(entity_id,1,3)=?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId,keyPrefix);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testEqualRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')=?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(startDate));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testDegenerateRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')=?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testBoundaryGreaterThanRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testBoundaryGreaterThanOrEqualRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>=?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testGreaterThanRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testLessThanRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testBoundaryLessThanRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testLessThanOrEqualRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testBoundaryLessThanOrEqualRound() throws Exception {
-        String inst = "a";
-        String host = "b";
-        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
-        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
-        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
-        compileStatement(query, scan, binds);
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
-                PDataType.DATE.toBytes(endDate));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testOverlappingKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String entityId = "002333333333333";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3)='" + keyPrefix + "' and entity_id='" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(startRow, scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(startRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-    }
-
-    @Test
-    public void testTrailingSubstrExpression() throws SQLException {
-        String tenantId = "0xD000000000001";
-        String entityId = "002333333333333";
-        String query = "select * from atable where substr(organization_id,1,3)='" + tenantId.substring(0, 3) + "' and entity_id='" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertNotNull(scan.getFilter());
-
-        byte[] startRow = ByteUtil.concat(ByteUtil.fillKey(PDataType.VARCHAR.toBytes(tenantId.substring(0,3)),15),PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(startRow, scan.getStartRow());
-        // Even though the first slot is a non inclusive range, we need to do a next key
-        // on the second slot because of the algorithm we use to seek to and terminate the
-        // loop during skip scan. We could end up having a first slot just under the upper
-        // limit of slot one and a value equal to the value in slot two and we need this to
-        // be less than the upper range that would get formed.
-        byte[] stopRow = ByteUtil.concat(ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId.substring(0,3))),15),ByteUtil.nextKey(PDataType.VARCHAR.toBytes(entityId)));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testBasicRangeExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id <= '" + tenantId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertNull(scan.getFilter());
-
-        assertTrue(scan.getStartRow().length == 0);
-        byte[] stopRow = ByteUtil.concat(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression1() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String keyPrefix2= "004";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) >= '" + keyPrefix1 + "' and substr(entity_id,1,3) < '" + keyPrefix2 + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertNull(scan.getFilter());
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix1),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix2),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression2() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String keyPrefix2= "004";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) >= '" + keyPrefix1 + "' and substr(entity_id,1,3) <= '" + keyPrefix2 + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertNull(scan.getFilter());
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix1),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix2)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression3() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String keyPrefix2= "004";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) > '" + keyPrefix1 + "' and substr(entity_id,1,3) <= '" + keyPrefix2 + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix1)),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix2)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression4() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String entityId= "002000000000002";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) > '" + keyPrefix1 + "' and substr(entity_id,1,3) = '" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testKeyRangeExpression5() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String entityId= "002000000000002";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) <= '" + keyPrefix1 + "' and entity_id = '" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression6() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String entityId= "002000000000002";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) < '" + keyPrefix1 + "' and entity_id = '" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testKeyRangeExpression7() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String entityId= "002000000000002";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) < '" + keyPrefix1 + "' and entity_id < '" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertNull(scan.getFilter());
-
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(keyPrefix1),new byte[entityId.length() - keyPrefix1.length()]);
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression8() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "001";
-        String entityId= "002000000000002";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) > '" + keyPrefix1 + "' and entity_id = '" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
-        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-    }
-
-    @Test
-    public void testKeyRangeExpression9() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix1 = "002";
-        String keyPrefix2 = "0033";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) >= '" + keyPrefix1 + "' and substr(entity_id,1,4) <= '" + keyPrefix2 + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix1),15)); // extra byte is due to implicit internal padding
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix2)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    /**
-     * This is testing the degenerate case where nothing will match because the overlapping keys (keyPrefix and entityId) don't match.
-     * @throws SQLException
-     */
-    @Test
-    public void testUnequalOverlappingKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String entityId = "001333333333333";
-        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3)='" + keyPrefix + "' and entity_id='" + entityId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testTopLevelOrKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' or a_integer=2";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(0, scan.getStartRow().length);
-        assertEquals(0, scan.getStopRow().length);
-    }
-
-    @Test
-    public void testSiblingOrKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and (a_integer = 2 or a_integer = 3)";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNotNull(scan.getFilter());
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-
-    @Test
-    public void testColumnNotFound() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where bar='" + tenantId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileStatement(query, scan, binds);
-            fail();
-        } catch (ColumnNotFoundException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void testNotContiguousPkColumn() throws SQLException {
-        String keyPrefix = "002";
-        String query = "select * from atable where substr(entity_id,1,3)='" + keyPrefix + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(0, scan.getStartRow().length);
-        assertEquals(0, scan.getStopRow().length);
-    }
-
-    @Test
-    public void testMultipleNonEqualitiesPkColumn() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id >= '" + tenantId + "' AND substr(entity_id,1,3) > '" + keyPrefix + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds);
-
-        assertNotNull(scan.getFilter());
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-
-    @Test
-    public void testRHSLiteral() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' and 0 >= a_integer limit 1000";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        compileStatement(query, scan, binds, 1000);
-
-        assertNotNull(scan.getFilter());
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-
-
-    @Test
-    public void testKeyTypeMismatch() {
-        String query = "select * from atable where organization_id=5";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileStatement(query, scan, binds);
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("Type mismatch"));
-        }
-    }
-
-    @Test
-    public void testLikeExtractAllKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id = ? and entity_id  LIKE '" + keyPrefix + "%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testLikeExtractAllAsEqKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id LIKE ? and entity_id  LIKE '" + keyPrefix + "%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        compileStatement(query, scan, binds);
-
-        assertNull(scan.getFilter());
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testDegenerateLikeNoWildcard() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id LIKE ? and entity_id  LIKE '" + keyPrefix + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        compileStatement(query, scan, binds);
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testLikeExtractKeyExpression2() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        // TODO: verify that _ at end of like doesn't go to equals
-        String query = "select * from atable where organization_id = ? and entity_id  LIKE '" + keyPrefix + "_'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        compileStatement(query, scan, binds);
-
-        assertNotNull(scan.getFilter());
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testLikeOptKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id = ? and entity_id  LIKE '" + keyPrefix + "%003%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(1, extractedNodes.size());
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testLikeOptKeyExpression2() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id = ? and substr(entity_id,1,10)  LIKE '" + keyPrefix + "%003%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(1, extractedNodes.size());
-
-
-        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
-        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
-        assertArrayEquals(startRow, scan.getStartRow());
-        assertArrayEquals(stopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testLikeNoOptKeyExpression3() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id = ? and substr(entity_id,4,10)  LIKE '" + keyPrefix + "%003%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(1, extractedNodes.size());
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(startRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testLikeDegenerate() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id = ? and entity_id  LIKE '0000000000000012%003%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateDivision1() throws SQLException {
-        String query = "select * from atable where a_integer = 3 / null";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateDivision2() throws SQLException {
-        String query = "select * from atable where a_integer / null = 3";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateMult1() throws SQLException {
-        String query = "select * from atable where a_integer = 3 * null";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateMult2() throws SQLException {
-        String query = "select * from atable where a_integer * null = 3";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateAdd1() throws SQLException {
-        String query = "select * from atable where a_integer = 3 + null";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateAdd2() throws SQLException {
-        String query = "select * from atable where a_integer + null = 3";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateSub1() throws SQLException {
-        String query = "select * from atable where a_integer = 3 - null";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testDegenerateSub2() throws SQLException {
-        String query = "select * from atable where a_integer - null = 3";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testLikeNoOptKeyExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id = ? and entity_id  LIKE '%001%" + keyPrefix + "%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(1, extractedNodes.size());
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(startRow), scan.getStopRow());
-    }
-
-    @Test
-    public void testLikeNoOptKeyExpression2() throws SQLException {
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select * from atable where organization_id = ? and entity_id  NOT LIKE '" + keyPrefix + "%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-
-        assertNotNull(scan.getFilter());
-        assertEquals(1, extractedNodes.size());
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
-        assertArrayEquals(startRow, scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(startRow), scan.getStopRow());
-    }
-    /*
-     * The following 5 tests are testing the comparison in where clauses under the case when the rhs
-     * cannot be coerced into the lhs. We need to confirm the decision make by expression compilation
-     * returns correct decisions.
-     */
-    @Test
-    public void testValueComparisonInt() throws SQLException {
-        ensureTableCreated(getUrl(),"PKIntValueTest");
-        String query;
-        // int <-> long
-        // Case 1: int = long, comparison always false, key is degenerated.
-        query = "SELECT * FROM PKintValueTest where pk = " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysFalse(query);
-        // Case 2: int != long, comparison always true, no key set since we need to do a full
-        // scan all the time.
-        query = "SELECT * FROM PKintValueTest where pk != " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysTrue(query);
-        // Case 3: int > positive long, comparison always false;
-        query = "SELECT * FROM PKintValueTest where pk >= " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysFalse(query);
-        // Case 4: int <= Integer.MAX_VALUE < positive long, always true;
-        query = "SELECT * FROM PKintValueTest where pk <= " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysTrue(query);
-        // Case 5: int >= Integer.MIN_VALUE > negative long, always true;
-        query = "SELECT * FROM PKintValueTest where pk >= " + (Long.MIN_VALUE + 1);
-        assertQueryConditionAlwaysTrue(query);
-        // Case 6: int < negative long, comparison always false;
-        query = "SELECT * FROM PKintValueTest where pk <= " + (Long.MIN_VALUE + 1);
-        assertQueryConditionAlwaysFalse(query);
-    }
-
-    @Test
-    public void testValueComparisonUnsignedInt() throws SQLException {
-        ensureTableCreated(getUrl(), "PKUnsignedIntValueTest");
-        String query;
-        // unsigned_int <-> negative int/long
-        // Case 1: unsigned_int = negative int, always false;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk = -1";
-        assertQueryConditionAlwaysFalse(query);
-        // Case 2: unsigned_int != negative int, always true;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk != -1";
-        assertQueryConditionAlwaysTrue(query);
-        // Case 3: unsigned_int > negative int, always true;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk > " + (Long.MIN_VALUE + 1);
-        assertQueryConditionAlwaysTrue(query);
-        // Case 4: unsigned_int < negative int, always false;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk < " + + (Long.MIN_VALUE + 1);
-        assertQueryConditionAlwaysFalse(query);
-        // unsigned_int <-> big positive long
-        // Case 1: unsigned_int = big positive long, always false;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk = " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysFalse(query);
-        // Case 2: unsigned_int != big positive long, always true;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk != " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysTrue(query);
-        // Case 3: unsigned_int > big positive long, always false;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk >= " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysFalse(query);
-        // Case 4: unsigned_int < big positive long, always true;
-        query = "SELECT * FROM PKUnsignedIntValueTest where pk <= " + Long.MAX_VALUE;
-        assertQueryConditionAlwaysTrue(query);
-    }
-
-    @Test
-    public void testValueComparisonUnsignedLong() throws SQLException {
-        ensureTableCreated(getUrl(), "PKUnsignedLongValueTest");
-        String query;
-        // unsigned_long <-> positive int/long
-        // Case 1: unsigned_long = negative int/long, always false;
-        query = "SELECT * FROM PKUnsignedLongValueTest where pk = -1";
-        assertQueryConditionAlwaysFalse(query);
-        // Case 2: unsigned_long = negative int/long, always true;
-        query = "SELECT * FROM PKUnsignedLongValueTest where pk != " + (Long.MIN_VALUE + 1);
-        assertQueryConditionAlwaysTrue(query);
-        // Case 3: unsigned_long > negative int/long, always true;
-        query = "SELECT * FROM PKUnsignedLongValueTest where pk > -1";
-        assertQueryConditionAlwaysTrue(query);
-        // Case 4: unsigned_long < negative int/long, always false;
-        query = "SELECT * FROM PKUnsignedLongValueTest where pk < " + (Long.MIN_VALUE + 1);
-        assertQueryConditionAlwaysFalse(query);
-    }
-
-    private void assertQueryConditionAlwaysTrue(String query) throws SQLException {
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression> extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-        assertEmptyScanKey(scan);
-    }
-
-    private void assertQueryConditionAlwaysFalse(String query) throws SQLException {
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList();
-        Set<Expression> extractedNodes = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedNodes);
-        assertDegenerate(scan);
-    }
-    
-    @Test
-    public void testOrSameColExpression() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000003";
-        String query = "select * from atable where organization_id = ? or organization_id  = ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId1,tenantId2);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
-
-        Filter filter = scan.getFilter();
-        assertNotNull(filter);
-        assertTrue(filter instanceof SkipScanFilter);
-        ScanRanges scanRanges = context.getScanRanges();
-        assertNotNull(scanRanges);
-        List<List<KeyRange>> ranges = scanRanges.getRanges();
-        assertEquals(1,ranges.size());
-        List<List<KeyRange>> expectedRanges = Collections.singletonList(Arrays.asList(
-                PDataType.CHAR.getKeyRange(PDataType.CHAR.toBytes(tenantId1), true, PDataType.CHAR.toBytes(tenantId1), true), 
-                PDataType.CHAR.getKeyRange(PDataType.CHAR.toBytes(tenantId2), true, PDataType.CHAR.toBytes(tenantId2), true)));
-        assertEquals(expectedRanges, ranges);
-        assertEquals(1, extractedNodes.size());
-        assertTrue(extractedNodes.iterator().next() instanceof OrExpression);
-        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId1);
-        assertArrayEquals(startRow, scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId2)), scan.getStopRow());
-    }
-    
-    @Test
-    public void testAndOrExpression() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String tenantId2 = "000000000000003";
-        String entityId1 = "002333333333331";
-        String entityId2 = "002333333333333";
-        String query = "select * from atable where (organization_id = ? and entity_id  = ?) or (organization_id = ? and entity_id  = ?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId1,entityId1,tenantId2,entityId2);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
-
-        Filter filter = scan.getFilter();
-        assertNotNull(filter);
-        assertTrue(filter instanceof RowKeyComparisonFilter);
-        ScanRanges scanRanges = context.getScanRanges();
-        assertEquals(ScanRanges.EVERYTHING,scanRanges);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testOrDiffColExpression() throws SQLException {
-        String tenantId1 = "000000000000001";
-        String entityId1 = "002333333333331";
-        String query = "select * from atable where organization_id = ? or entity_id  = ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId1,entityId1);
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
-
-        Filter filter = scan.getFilter();
-        assertNotNull(filter);
-        assertTrue(filter instanceof RowKeyComparisonFilter);
-        ScanRanges scanRanges = context.getScanRanges();
-        assertEquals(ScanRanges.EVERYTHING,scanRanges);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testOrSameColRangeExpression() throws SQLException {
-        String query = "select * from atable where substr(organization_id,1,3) = ? or organization_id LIKE 'foo%'";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList("00D");
-        Set<Expression>extractedNodes = new HashSet<Expression>();
-        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
-
-        Filter filter = scan.getFilter();
-        assertNotNull(filter);
-        assertTrue(filter instanceof SkipScanFilter);
-        ScanRanges scanRanges = context.getScanRanges();
-        assertNotNull(scanRanges);
-        List<List<KeyRange>> ranges = scanRanges.getRanges();
-        assertEquals(1,ranges.size());
-        List<List<KeyRange>> expectedRanges = Collections.singletonList(Arrays.asList(
-                PDataType.CHAR.getKeyRange(
-                        ByteUtil.fillKey(PDataType.CHAR.toBytes("00D"),15), true, 
-                        ByteUtil.fillKey(ByteUtil.nextKey(PDataType.CHAR.toBytes("00D")),15), false), 
-                PDataType.CHAR.getKeyRange(
-                        ByteUtil.fillKey(PDataType.CHAR.toBytes("foo"),15), true, 
-                        ByteUtil.fillKey(ByteUtil.nextKey(PDataType.CHAR.toBytes("foo")),15), false)));
-        assertEquals(expectedRanges, ranges);
-        assertEquals(1, extractedNodes.size());
-        assertTrue(extractedNodes.iterator().next() instanceof OrExpression);
-    }
-    
-    @Test
-    public void testForceSkipScanOnSaltedTable() throws SQLException {
-        Connection conn = DriverManager.getConnection(getUrl());
-        conn.createStatement().execute("CREATE TABLE IF NOT EXISTS user_messages (\n" + 
-                "        SENDER_ID UNSIGNED_LONG NOT NULL,\n" + 
-                "        RECIPIENT_ID UNSIGNED_LONG NOT NULL,\n" + 
-                "        SENDER_IP VARCHAR,\n" + 
-                "        IS_READ VARCHAR,\n" + 
-                "        IS_DELETED VARCHAR,\n" + 
-                "        M_TEXT VARCHAR,\n" + 
-                "        M_TIMESTAMP timestamp  NOT NULL,\n" + 
-                "        ROW_ID UNSIGNED_LONG NOT NULL\n" + 
-                "        constraint rowkey primary key (SENDER_ID,RECIPIENT_ID,M_TIMESTAMP DESC,ROW_ID))\n" + 
-                "SALT_BUCKETS=12\n");
-        String query = "select /*+ SKIP_SCAN */ count(*) from user_messages where is_read='N' and recipient_id=5399179882";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        Set<Expression> extractedNodes = Sets.newHashSet();
-        StatementContext context = compileStatement(query, scan, binds, null, extractedNodes);
-        ScanRanges scanRanges = context.getScanRanges();
-        assertNotNull(scanRanges);
-        assertEquals(3,scanRanges.getRanges().size());
-        assertEquals(1,scanRanges.getRanges().get(1).size());
-        assertEquals(KeyRange.EVERYTHING_RANGE,scanRanges.getRanges().get(1).get(0));
-        assertEquals(1,scanRanges.getRanges().get(2).size());
-        assertTrue(scanRanges.getRanges().get(2).get(0).isSingleKey());
-        assertEquals(Long.valueOf(5399179882L), PDataType.UNSIGNED_LONG.toObject(scanRanges.getRanges().get(2).get(0).getLowerRange()));
-        assertEquals(1, extractedNodes.size());
-        assertNotNull(scan.getFilter());
-    }
-    
-    @Test
-    public void testForceRangeScanKeepsFilters() throws SQLException {
-        ensureTableCreated(getUrl(), TestUtil.ENTITY_HISTORY_TABLE_NAME);
-        String tenantId = "000000000000001";
-        String keyPrefix = "002";
-        String query = "select /*+ RANGE_SCAN */ ORGANIZATION_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID from " + TestUtil.ENTITY_HISTORY_TABLE_NAME + 
-                " where ORGANIZATION_ID=? and SUBSTR(PARENT_ID, 1, 3) = ? and  CREATED_DATE >= ? and CREATED_DATE < ? order by ORGANIZATION_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID limit 6";
-        Scan scan = new Scan();
-        Date startTime = new Date(System.currentTimeMillis());
-        Date stopTime = new Date(startTime.getTime() + TestUtil.MILLIS_IN_DAY);
-        List<Object> binds = Arrays.<Object>asList(tenantId, keyPrefix, startTime, stopTime);
-        Set<Expression> extractedNodes = Sets.newHashSet();
-        compileStatement(query, scan, binds, 6, extractedNodes);
-        assertEquals(2, extractedNodes.size());
-        assertNotNull(scan.getFilter());
-
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15), PDataType.DATE.toBytes(startTime));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        byte[] expectedStopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15), PDataType.DATE.toBytes(stopTime));
-        assertArrayEquals(expectedStopRow, scan.getStopRow());
-    }
-
-    @Test
-    public void testBasicRVCExpression() throws SQLException {
-        String tenantId = "000000000000001";
-        String entityId = "002333333333331";
-        String query = "select * from atable where (organization_id,entity_id) >= (?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, entityId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.CHAR.toBytes(tenantId), PDataType.CHAR.toBytes(entityId));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-
-    
-    @Test
-    public void testRVCExpressionThroughOr() throws SQLException {
-        String tenantId = "000000000000001";
-        String entityId = "002333333333331";
-        String entityId1 = "002333333333330";
-        String entityId2 = "002333333333332";
-        String query = "select * from atable where (organization_id,entity_id) >= (?,?) and organization_id = ? and  (entity_id = ? or entity_id = ?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, entityId, tenantId, entityId1, entityId2);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 3);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(entityId));
-        byte[] expectedStopRow = ByteUtil.concat(ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(entityId2)), QueryConstants.SEPARATOR_BYTE_ARRAY);
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(expectedStopRow, scan.getStopRow());
-    }
-    
-    /**
-     * With only a subset of row key cols present (which includes the leading key), 
-     * Phoenix should have optimized the start row for the scan to include the 
-     * row keys cols that occur contiguously in the RVC.
-     * 
-     * Table entity_history has the row key defined as (organization_id, parent_id, created_date, entity_history_id). 
-     * This test uses (organization_id, parent_id, entity_id) in RVC. So the start row should be comprised of
-     * organization_id and parent_id.
-     * @throws SQLException
-     */
-    @Test
-    public void testRVCExpressionWithSubsetOfPKCols() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000002";
-        String entityHistId = "000000000000003";
-        
-        String query = "select * from entity_history where (organization_id, parent_id, entity_history_id) >= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, entityHistId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 0);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(parentId));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    /**
-     * With the leading row key col missing Phoenix won't be able to optimize
-     * and provide the start row for the scan.
-     * 
-     * Table entity_history has the row key defined as (organization_id, parent_id, created_date, entity_history_id). 
-     * This test uses (parent_id, entity_id) in RVC. Start row should be empty.
-     * @throws SQLException
-     */
-    
-    @Test
-    public void testRVCExpressionWithoutLeadingColOfRowKey() throws SQLException {
-        
-        String parentId = "000000000000002";
-        String entityHistId = "000000000000003";
-        
-        String query = "select * from entity_history where (parent_id, entity_history_id) >= (?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(parentId, entityHistId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 0);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testMultiRVCExpressionsCombinedWithAnd() throws SQLException {
-        String lowerTenantId = "000000000000001";
-        String lowerParentId = "000000000000002";
-        Date lowerCreatedDate = new Date(System.currentTimeMillis());
-        String upperTenantId = "000000000000008";
-        String upperParentId = "000000000000009";
-        
-        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?, ?, ?) AND (organization_id, parent_id) <= (?, ?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(lowerTenantId, lowerParentId, lowerCreatedDate, upperTenantId, upperParentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 2);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(lowerTenantId), PDataType.VARCHAR.toBytes(lowerParentId), PDataType.DATE.toBytes(lowerCreatedDate));
-        byte[] expectedStopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(upperTenantId), PDataType.VARCHAR.toBytes(upperParentId)));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(expectedStopRow, scan.getStopRow());
-    }
-    
-    @Test
-    public void testMultiRVCExpressionsCombinedUsingLiteralExpressions() throws SQLException {
-        String lowerTenantId = "000000000000001";
-        String lowerParentId = "000000000000002";
-        Date lowerCreatedDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?, ?, ?) AND (organization_id, parent_id) <= ('7', '7')";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(lowerTenantId, lowerParentId, lowerCreatedDate);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 2);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(lowerTenantId), PDataType.VARCHAR.toBytes(lowerParentId), PDataType.DATE.toBytes(lowerCreatedDate));
-        byte[] expectedStopRow = ByteUtil.nextKey(ByteUtil.concat(ByteUtil.fillKey(PDataType.VARCHAR.toBytes("7"),15), ByteUtil.fillKey(PDataType.VARCHAR.toBytes("7"), 15)));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(expectedStopRow, scan.getStopRow());
-    }
-    
-    @Test
-    public void testUseOfFunctionOnLHSInRVC() throws SQLException {
-        String tenantId = "000000000000001";
-        String subStringTenantId = tenantId.substring(0, 3);
-        String parentId = "000000000000002";
-        Date createdDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (substr(organization_id, 1, 3), parent_id, created_date) >= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(subStringTenantId, parentId, createdDate);
-        Set<Expression> extractedFilters = new HashSet<Expression>(2);
-        compileStatement(query, scan, binds, extractedFilters);
-        byte[] expectedStartRow = PDataType.VARCHAR.toBytes(subStringTenantId);
-        assertTrue(extractedFilters.size() == 0);
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testUseOfFunctionOnLHSInMiddleOfRVC() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000002";
-        String subStringParentId = parentId.substring(0, 3);
-        Date createdDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (organization_id, substr(parent_id, 1, 3), created_date) >= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, subStringParentId, createdDate);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 0);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(subStringParentId));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testUseOfFunctionOnLHSInMiddleOfRVCForLTE() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000002";
-        String subStringParentId = parentId.substring(0, 3);
-        Date createdDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (organization_id, substr(parent_id, 1, 3), created_date) <= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, subStringParentId, createdDate);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 0);
-        byte[] expectedStopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), ByteUtil.nextKey(PDataType.VARCHAR.toBytes(subStringParentId)));
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStartRow());
-        assertArrayEquals(expectedStopRow, scan.getStopRow());
-    }
-    
-    @Test
-    public void testNullAtEndOfRVC() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000002";
-        Date createdDate = null;
-        
-        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, createdDate);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(parentId));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testNullInMiddleOfRVC() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = null;
-        Date createdDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, createdDate);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        byte[] expectedStartRow = ByteUtil.concat(PDataType.CHAR.toBytes(tenantId), new byte[15], ByteUtil.previousKey(PDataType.DATE.toBytes(createdDate)));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testNullAtStartOfRVC() throws SQLException {
-        String tenantId = null;
-        String parentId = "000000000000002";
-        Date createdDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, createdDate);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        byte[] expectedStartRow = ByteUtil.concat(new byte[15], ByteUtil.previousKey(PDataType.CHAR.toBytes(parentId)), PDataType.DATE.toBytes(createdDate));
-        assertArrayEquals(expectedStartRow, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testRVCInCombinationWithOtherNonRVC() throws SQLException {
-        String firstOrgId = "000000000000001";
-        String secondOrgId = "000000000000008";
-        
-        String parentId = "000000000000002";
-        Date createdDate = new Date(System.currentTimeMillis());
-        
-        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?) AND organization_id <= ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstOrgId, parentId, createdDate, secondOrgId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 2);
-        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstOrgId), PDataType.VARCHAR.toBytes(parentId), PDataType.DATE.toBytes(createdDate)), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(secondOrgId)), scan.getStopRow());
-    }
-    
-    @Test
-    public void testGreaterThanEqualTo_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000008";
-        
-        String query = "select * from entity_history where organization_id >= (?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testGreaterThan_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000008";
-        
-        String query = "select * from entity_history where organization_id > (?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testGreaterThan() throws SQLException {
-        String tenantId = "000000000000001";
-        
-        String query = "select * from entity_history where organization_id >?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testLessThanEqualTo_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000008";
-        
-        String query = "select * from entity_history where organization_id <= (?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-    
-    @Test
-    public void testLessThan_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
-        String tenantId = "000000000000001";
-        String parentId = "000000000000008";
-        
-        String query = "select * from entity_history where organization_id < (?,?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-    
-    @Test
-    public void testCombiningRVCUsingOr() throws SQLException {
-        String firstTenantId = "000000000000001";
-        String secondTenantId = "000000000000005";
-        String firstParentId = "000000000000011";
-        String secondParentId = "000000000000015";
-        
-        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR (organization_id, parent_id) <= (?, ?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId, secondParentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1); // extracts the entire OR
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testCombiningRVCUsingOr2() throws SQLException {
-        String firstTenantId = "000000000000001";
-        String secondTenantId = "000000000000005";
-        String firstParentId = "000000000000011";
-        String secondParentId = "000000000000015";
-        
-        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR (organization_id, parent_id) >= (?, ?)";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId, secondParentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstTenantId), PDataType.VARCHAR.toBytes(firstParentId)), scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testCombiningRVCWithNonRVCUsingOr() throws SQLException {
-        String firstTenantId = "000000000000001";
-        String secondTenantId = "000000000000005";
-        String firstParentId = "000000000000011";
-        
-        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR organization_id  >= ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstTenantId), PDataType.VARCHAR.toBytes(firstParentId)), scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testCombiningRVCWithNonRVCUsingOr2() throws SQLException {
-        String firstTenantId = "000000000000001";
-        String secondTenantId = "000000000000005";
-        String firstParentId = "000000000000011";
-        
-        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR organization_id  <= ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testCombiningRVCWithNonRVCUsingOr3() throws SQLException {
-        String firstTenantId = "000000000000005";
-        String secondTenantId = "000000000000001";
-        String firstParentId = "000000000000011";
-        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR organization_id  <= ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 0);
-        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
-        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
-    }
-    
-    @Test
-    public void testUsingRVCNonFullyQualifiedInClause() throws Exception {
-        String firstOrgId = "000000000000001";
-        String secondOrgId = "000000000000009";
-        String firstParentId = "000000000000011";
-        String secondParentId = "000000000000021";
-        String query = "select * from entity_history where (organization_id, parent_id) IN ((?, ?), (?, ?))";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstOrgId, firstParentId, secondOrgId, secondParentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 0);
-        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstOrgId), PDataType.VARCHAR.toBytes(firstParentId)), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(secondOrgId), PDataType.VARCHAR.toBytes(secondParentId))), scan.getStopRow());
-    }
-    
-    @Test
-    public void testUsingRVCFullyQualifiedInClause() throws Exception {
-        String firstOrgId = "000000000000001";
-        String secondOrgId = "000000000000009";
-        String firstParentId = "000000000000011";
-        String secondParentId = "000000000000021";
-        String query = "select * from atable where (organization_id, entity_id) IN ((?, ?), (?, ?))";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(firstOrgId, firstParentId, secondOrgId, secondParentId);
-        HashSet<Expression> extractedFilters = new HashSet<Expression>();
-        StatementContext context = compileStatement(query, scan, binds, extractedFilters);
-        assertTrue(extractedFilters.size() == 1);
-        List<List<KeyRange>> skipScanRanges = Collections.singletonList(Arrays.asList(
-                KeyRange.getKeyRange(ByteUtil.concat(PDataType.CHAR.toBytes(firstOrgId), PDataType.CHAR.toBytes(firstParentId))), 
-                KeyRange.getKeyRange(ByteUtil.concat(PDataType.CHAR.toBytes(secondOrgId), PDataType.CHAR.toBytes(secondParentId)))));
-        assertEquals(skipScanRanges, context.getScanRanges().getRanges());
-        assertArrayEquals(ByteUtil.concat(PDataType.CHAR.toBytes(firstOrgId), PDataType.CHAR.toBytes(firstParentId)), scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(PDataType.CHAR.toBytes(secondOrgId), PDataType.CHAR.toBytes(secondParentId), QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-    }
-}


[6/8] Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
new file mode 100644
index 0000000..ac2c458
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
@@ -0,0 +1,1313 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.apache.phoenix.util.TestUtil.assertDegenerate;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.coprocessor.GroupedAggregateRegionObserver;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.expression.aggregator.Aggregator;
+import org.apache.phoenix.expression.aggregator.CountAggregator;
+import org.apache.phoenix.expression.aggregator.ServerAggregators;
+import org.apache.phoenix.expression.function.TimeUnit;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.AmbiguousColumnException;
+import org.apache.phoenix.schema.ColumnAlreadyExistsException;
+import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.PhoenixRuntime;
+import org.apache.phoenix.util.SchemaUtil;
+import org.apache.phoenix.util.TestUtil;
+import org.junit.Test;
+
+
+
+/**
+ * 
+ * Tests for compiling a query
+ * The compilation stage finds additional errors that can't be found at parse
+ * time so this is a good place for negative tests (since the mini-cluster
+ * is not necessary enabling the tests to run faster).
+ *
+ * 
+ * @since 0.1
+ */
+@edu.umd.cs.findbugs.annotations.SuppressWarnings(
+        value="RV_RETURN_VALUE_IGNORED",
+        justification="Test code.")
+public class QueryCompilerTest extends BaseConnectionlessQueryTest {
+
+    @Test
+    public void testParameterUnbound() throws Exception {
+        try {
+            String query = "SELECT a_string, b_string FROM atable WHERE organization_id=? and a_integer = ?";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("Parameter 2 is unbound"));
+        }
+    }
+
+    @Test
+    public void testMultiPKDef() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (pk1 integer not null primary key, pk2 bigint not null primary key)";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 510 (42889): The table already has a primary key. columnName=PK2"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testPKDefAndPKConstraint() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (pk integer not null primary key, col1 decimal, col2 decimal constraint my_pk primary key (col1,col2))";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 510 (42889): The table already has a primary key. columnName=PK"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testFamilyNameInPK() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (a.pk integer not null primary key, col1 decimal, col2 decimal)";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertEquals(e.getErrorCode(), SQLExceptionCode.PRIMARY_KEY_WITH_FAMILY_NAME.getErrorCode());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testSameColumnNameInPKAndNonPK() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE t1 (k integer not null primary key, a.k decimal, b.k decimal)";
+            conn.createStatement().execute(query);
+            PColumn c = conn.unwrap(PhoenixConnection.class).getPMetaData().getTable("T1").getColumn("K");
+            assertTrue(SchemaUtil.isPKColumn(c));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testVarBinaryInMultipartPK() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        // When the VARBINARY key is the last column, it is allowed.
+        String query = "CREATE TABLE foo (a_string varchar not null, b_string varchar not null, a_binary varbinary not null, " +
+                "col1 decimal, col2 decimal CONSTRAINT pk PRIMARY KEY (a_string, b_string, a_binary))";
+        PreparedStatement statement = conn.prepareStatement(query);
+        statement.execute();
+        try {
+            // VARBINARY key is not allowed in the middle of the key.
+            query = "CREATE TABLE foo (a_binary varbinary not null, a_string varchar not null, col1 decimal, col2 decimal CONSTRAINT pk PRIMARY KEY (a_binary, a_string))";
+            statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1005 (42J03): The VARBINARY type can only be used as the last part of a multi-part row key. columnName=FOO.A_BINARY"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testNoPK() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (pk integer not null, col1 decimal, col2 decimal)";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 509 (42888): The table does not have a primary key. tableName=FOO"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testUnknownFamilyNameInTableOption() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (pk integer not null primary key, a.col1 decimal, b.col2 decimal) c.my_property='foo'";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("Properties may not be defined for an unused family name"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testInvalidGroupedAggregation() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT count(1),a_integer FROM atable WHERE organization_id=? GROUP BY a_string";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER"));
+        }
+    }
+
+    @Test
+    public void testInvalidGroupExpressionAggregation() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT sum(a_integer) + a_integer FROM atable WHERE organization_id=? GROUP BY a_string";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER"));
+        }
+    }
+
+    @Test
+    public void testAggInWhereClause() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT a_integer FROM atable WHERE organization_id=? AND count(1) > 2";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1017 (42Y26): Aggregate may not be used in WHERE."));
+        }
+    }
+
+    @Test
+    public void testHavingAggregateQuery() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT a_integer FROM atable WHERE organization_id=? HAVING count(1) > 2";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER"));
+        }
+    }
+
+    @Test
+    public void testNonAggInHavingClause() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT a_integer FROM atable WHERE organization_id=? HAVING a_integer = 5";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1019 (42Y26): Only aggregate maybe used in the HAVING clause."));
+        }
+    }
+
+    @Test
+    public void testTypeMismatchInCase() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT a_integer FROM atable WHERE organization_id=? HAVING CASE WHEN a_integer <= 2 THEN 'foo' WHEN a_integer = 3 THEN 2 WHEN a_integer <= 5 THEN 5 ELSE 5 END  = 5";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("Case expressions must have common type"));
+        }
+    }
+
+    @Test
+    public void testNonBooleanWhereExpression() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "SELECT a_integer FROM atable WHERE organization_id=? and CASE WHEN a_integer <= 2 THEN 'foo' WHEN a_integer = 3 THEN 'bar' WHEN a_integer <= 5 THEN 'bas' ELSE 'blah' END";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("ERROR 203 (22005): Type mismatch. BOOLEAN and VARCHAR for CASE WHEN A_INTEGER <= 2 THEN 'foo'WHEN A_INTEGER = 3 THEN 'bar'WHEN A_INTEGER <= 5 THEN 'bas' ELSE 'blah' END"));
+        }
+    }
+
+    @Test
+    public void testNoSCNInConnectionProps() throws Exception {
+        Properties props = new Properties();
+        DriverManager.getConnection(getUrl(), props);
+    }
+    
+
+    @Test
+    public void testPercentileWrongQueryWithMixOfAggrAndNonAggrExps() throws Exception {
+        String query = "select a_integer, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
+        try {
+            compileQuery(query, Collections.emptyList());
+            fail();
+        } catch (SQLException e) {
+            assertEquals("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER",
+                    e.getMessage());
+        }
+    }
+
+    @Test
+    public void testPercentileWrongQuery1() throws Exception {
+        String query = "select PERCENTILE_CONT('*') WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
+        try {
+            compileQuery(query, Collections.emptyList());
+            fail();
+        } catch (SQLException e) {
+            assertEquals(
+                    "ERROR 203 (22005): Type mismatch. expected: [DECIMAL] but was: VARCHAR at PERCENTILE_CONT argument 3",
+                    e.getMessage());
+        }
+    }
+
+    @Test
+    public void testPercentileWrongQuery2() throws Exception {
+        String query = "select PERCENTILE_CONT(1.1) WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
+        try {
+            compileQuery(query, Collections.emptyList());
+            fail();
+        } catch (SQLException e) {
+            assertEquals(
+                    "ERROR 213 (22003): Value outside range. expected: [0 , 1] but was: 1.1 at PERCENTILE_CONT argument 3",
+                    e.getMessage());
+        }
+    }
+
+    @Test
+    public void testPercentileWrongQuery3() throws Exception {
+        String query = "select PERCENTILE_CONT(-1) WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
+        try {
+            compileQuery(query, Collections.emptyList());
+            fail();
+        } catch (Exception e) {
+            assertEquals(
+                    "ERROR 213 (22003): Value outside range. expected: [0 , 1] but was: -1 at PERCENTILE_CONT argument 3",
+                    e.getMessage());
+        }
+    }
+
+    private Scan compileQuery(String query, List<Object> binds) throws SQLException {
+        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            PhoenixPreparedStatement statement = conn.prepareStatement(query).unwrap(PhoenixPreparedStatement.class);
+            for (Object bind : binds) {
+                statement.setObject(1, bind);
+            }
+            QueryPlan plan = statement.compileQuery(query);
+            return plan.getContext().getScan();
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testKeyOrderedGroupByOptimization() throws Exception {
+        // Select columns in PK
+        String[] queries = new String[] {
+            "SELECT count(1) FROM atable GROUP BY organization_id,entity_id",
+            "SELECT count(1) FROM atable GROUP BY organization_id,substr(entity_id,1,3),entity_id",
+            "SELECT count(1) FROM atable GROUP BY entity_id,organization_id",
+            "SELECT count(1) FROM atable GROUP BY substr(entity_id,1,3),organization_id",
+            "SELECT count(1) FROM ptsdb GROUP BY host,inst,round(date,'HOUR')",
+            "SELECT count(1) FROM atable GROUP BY organization_id",
+        };
+        List<Object> binds = Collections.emptyList();
+        for (String query : queries) {
+            Scan scan = compileQuery(query, binds);
+            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.KEY_ORDERED_GROUP_BY_EXPRESSIONS) != null);
+            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.UNORDERED_GROUP_BY_EXPRESSIONS) == null);
+        }
+    }
+
+    @Test
+    public void testNullInScanKey() throws Exception {
+        // Select columns in PK
+        String query = "select val from ptsdb where inst is null and host='a'";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        // Projects column family with not null column
+        assertNull(scan.getFilter());
+        assertEquals(1,scan.getFamilyMap().keySet().size());
+        assertArrayEquals(Bytes.toBytes(SchemaUtil.normalizeIdentifier(QueryConstants.DEFAULT_COLUMN_FAMILY)), scan.getFamilyMap().keySet().iterator().next());
+    }
+
+    @Test
+    public void testOnlyNullInScanKey() throws Exception {
+        // Select columns in PK
+        String query = "select val from ptsdb where inst is null";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        // Projects column family with not null column
+        assertEquals(1,scan.getFamilyMap().keySet().size());
+        assertArrayEquals(Bytes.toBytes(SchemaUtil.normalizeIdentifier(QueryConstants.DEFAULT_COLUMN_FAMILY)), scan.getFamilyMap().keySet().iterator().next());
+    }
+
+    @Test
+    public void testIsNullOnNotNullable() throws Exception {
+        // Select columns in PK
+        String query = "select a_string from atable where entity_id is null";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testIsNotNullOnNotNullable() throws Exception {
+        // Select columns in PK
+        String query = "select a_string from atable where entity_id is not null";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        assertNull(scan.getFilter());
+        assertTrue(scan.getStartRow().length == 0);
+        assertTrue(scan.getStopRow().length == 0);
+    }
+
+    @Test
+    public void testUpsertTypeMismatch() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "upsert into ATABLE VALUES (?, ?, ?)";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.setString(2, "00D300000000XHP");
+                statement.setInt(3, 1);
+                statement.executeUpdate();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) { // TODO: use error codes
+            assertTrue(e.getMessage().contains("Type mismatch"));
+        }
+    }
+
+    @Test
+    public void testUpsertMultiByteIntoChar() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "upsert into ATABLE VALUES (?, ?, ?)";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.setString(1, "00D300000000XHP");
+                statement.setString(2, "繰り返し曜日マスク");
+                statement.setInt(3, 1);
+                statement.executeUpdate();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 201 (22000): Illegal data."));
+            assertTrue(e.getCause().getMessage().contains("CHAR types may only contain single byte characters"));
+        }
+    }
+
+    @Test
+    public void testSelectStarOnGroupBy() throws Exception {
+        try {
+            // Select non agg column in aggregate query
+            String query = "select * from ATABLE group by a_string";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY."));
+        }
+    }
+
+    @Test
+    public void testOrderByAggSelectNonAgg() throws Exception {
+        try {
+            // Order by in select with no limit or group by
+            String query = "select a_string from ATABLE order by max(b_string)";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_STRING"));
+        }
+    }
+
+    @Test
+    public void testOrderByAggAndNonAgg() throws Exception {
+        try {
+            // Order by in select with no limit or group by
+            String query = "select max(a_string) from ATABLE order by max(b_string),a_string";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_STRING"));
+        }
+    }
+
+    @Test
+    public void testOrderByNonAggSelectAgg() throws Exception {
+        try {
+            // Order by in select with no limit or group by
+            String query = "select max(a_string) from ATABLE order by b_string LIMIT 5";
+            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+            Connection conn = DriverManager.getConnection(getUrl(), props);
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.executeQuery();
+                fail();
+            } finally {
+                conn.close();
+            }
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. B_STRING"));
+        }
+    }
+
+    @Test
+    public void testNotKeyOrderedGroupByOptimization() throws Exception {
+        // Select columns in PK
+        String[] queries = new String[] {
+            "SELECT count(1) FROM atable GROUP BY entity_id",
+            "SELECT count(1) FROM atable GROUP BY substr(organization_id,2,3)",
+            "SELECT count(1) FROM atable GROUP BY substr(entity_id,1,3)",
+            "SELECT count(1) FROM atable GROUP BY to_date(organization_id)",
+            "SELECT count(1) FROM atable GROUP BY regexp_substr(organization_id, '.*foo.*'),entity_id",
+            "SELECT count(1) FROM atable GROUP BY substr(organization_id,1),entity_id",
+        };
+        List<Object> binds = Collections.emptyList();
+        for (String query : queries) {
+            Scan scan = compileQuery(query, binds);
+            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.KEY_ORDERED_GROUP_BY_EXPRESSIONS) == null);
+            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.UNORDERED_GROUP_BY_EXPRESSIONS) != null);
+        }
+    }
+    
+    @Test
+    public void testFunkyColumnNames() throws Exception {
+        // Select columns in PK
+        String[] queries = new String[] {
+            "SELECT \"foo!\",\"foo.bar-bas\",\"#@$\",\"_blah^\" FROM FUNKY_NAMES",
+            "SELECT count(\"foo!\"),\"_blah^\" FROM FUNKY_NAMES WHERE \"foo.bar-bas\"='x' GROUP BY \"#@$\",\"_blah^\"",
+        };
+        List<Object> binds = Collections.emptyList();
+        for (String query : queries) {
+            compileQuery(query, binds);
+        }
+    }
+    
+    @Test
+    public void testCountAggregatorFirst() throws Exception {
+        String[] queries = new String[] {
+            "SELECT sum(2.5),organization_id FROM atable GROUP BY organization_id,entity_id",
+            "SELECT avg(a_integer) FROM atable GROUP BY organization_id,substr(entity_id,1,3),entity_id",
+            "SELECT count(a_string) FROM atable GROUP BY substr(organization_id,1),entity_id",
+            "SELECT min('foo') FROM atable GROUP BY entity_id,organization_id",
+            "SELECT min('foo'),sum(a_integer),avg(2.5),4.5,max(b_string) FROM atable GROUP BY substr(organization_id,1),entity_id",
+            "SELECT sum(2.5) FROM atable",
+            "SELECT avg(a_integer) FROM atable",
+            "SELECT count(a_string) FROM atable",
+            "SELECT min('foo') FROM atable LIMIT 5",
+            "SELECT min('foo'),sum(a_integer),avg(2.5),4.5,max(b_string) FROM atable",
+        };
+        List<Object> binds = Collections.emptyList();
+        String query = null;
+        try {
+            for (int i = 0; i < queries.length; i++) {
+                query = queries[i];
+                Scan scan = compileQuery(query, binds);
+                ServerAggregators aggregators = ServerAggregators.deserialize(scan.getAttribute(GroupedAggregateRegionObserver.AGGREGATORS), null);
+                Aggregator aggregator = aggregators.getAggregators()[0];
+                assertTrue(aggregator instanceof CountAggregator);
+            }
+        } catch (Exception e) {
+            throw new Exception(query, e);
+        }
+    }
+
+    @Test
+    public void testInvalidArithmetic() throws Exception {
+        String[] queries = new String[] { 
+                "SELECT entity_id,organization_id FROM atable where A_STRING - 5.5 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_DATE - 'transaction' < 0",
+                "SELECT entity_id,organization_id FROM atable where A_DATE * 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_DATE / 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where 45 - A_DATE < 0",
+                "SELECT entity_id,organization_id FROM atable where A_DATE - to_date('2000-01-01 12:00:00') < to_date('2000-02-01 12:00:00')", // RHS must be number
+                "SELECT entity_id,organization_id FROM atable where A_DATE - A_DATE + 1 < A_DATE", // RHS must be number
+                "SELECT entity_id,organization_id FROM atable where A_DATE + 2 < 0", // RHS must be date
+                "SELECT entity_id,organization_id FROM atable where 45.5 - A_DATE < 0",
+                "SELECT entity_id,organization_id FROM atable where 1 + A_DATE + A_DATE < A_DATE",
+                "SELECT entity_id,organization_id FROM atable where A_STRING - 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_STRING / 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_STRING * 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_STRING + 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_STRING - 45 < 0",
+                "SELECT entity_id,organization_id FROM atable where A_STRING - 'transaction' < 0", };
+
+        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        for (String query : queries) {
+            try {
+                PreparedStatement statement = conn.prepareStatement(query);
+                statement.executeQuery();
+                fail(query);
+            } catch (SQLException e) {
+                if (e.getMessage().contains("ERROR 203 (22005): Type mismatch.")) {
+                    continue;
+                }
+                throw new IllegalStateException("Didn't find type mismatch: " + query, e);
+            }
+        }
+    }
+    
+    
+    @Test
+    public void testAmbiguousColumn() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT * from multi_cf G where RESPONSE_TIME = 2222";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (AmbiguousColumnException e) { // expected
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testTableAliasMatchesCFName() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT F.RESPONSE_TIME,G.RESPONSE_TIME from multi_cf G where G.RESPONSE_TIME-1 = F.RESPONSE_TIME";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (AmbiguousColumnException e) { // expected
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testCoelesceFunctionTypeMismatch() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT coalesce(x_integer,'foo') from atable";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 507 (42846): Cannot convert type. COALESCE expected INTEGER, but got VARCHAR"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testOrderByNotInSelectDistinct() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT distinct a_string,b_string from atable order by x_integer";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertEquals(SQLExceptionCode.ORDER_BY_NOT_IN_SELECT_DISTINCT.getErrorCode(), e.getErrorCode());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testSelectDistinctAndAll() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT all distinct a_string,b_string from atable order by x_integer";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertEquals(SQLExceptionCode.PARSER_ERROR.getErrorCode(), e.getErrorCode());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testOrderByNotInSelectDistinctAgg() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT distinct count(1) from atable order by x_integer";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertEquals(SQLExceptionCode.ORDER_BY_NOT_IN_SELECT_DISTINCT.getErrorCode(), e.getErrorCode());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testSelectDistinctWithAggregation() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT distinct a_string,count(*) from atable";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertEquals(SQLExceptionCode.AGGREGATE_WITH_NOT_GROUP_BY_COLUMN.getErrorCode(), e.getErrorCode());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test 
+    public void testRegexpSubstrSetScanKeys() throws Exception {
+        // First test scan keys are set when the offset is 0 or 1. 
+        String query = "SELECT host FROM ptsdb WHERE regexp_substr(inst, '[a-zA-Z]+') = 'abc'";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(ByteUtil.nextKey(Bytes.toBytes("abc")),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+        assertTrue(scan.getFilter() != null);
+
+        query = "SELECT host FROM ptsdb WHERE regexp_substr(inst, '[a-zA-Z]+', 0) = 'abc'";
+        binds = Collections.emptyList();
+        scan = compileQuery(query, binds);
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(ByteUtil.nextKey(Bytes.toBytes("abc")),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+        assertTrue(scan.getFilter() != null);
+
+        // Test scan keys are not set when the offset is not 0 or 1.
+        query = "SELECT host FROM ptsdb WHERE regexp_substr(inst, '[a-zA-Z]+', 3) = 'abc'";
+        binds = Collections.emptyList();
+        scan = compileQuery(query, binds);
+        assertTrue(scan.getStartRow().length == 0);
+        assertTrue(scan.getStopRow().length == 0);
+        assertTrue(scan.getFilter() != null);
+    }
+    
+    @Test
+    public void testStringConcatExpression() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT entity_id,a_string FROM atable where 2 || a_integer || ? like '2%'";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Properties props = new Properties(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(url, props);
+        byte []x=new byte[]{127,127,0,0};//Binary data
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.setBytes(1, x);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertTrue(e.getMessage().contains("Concatenation does not support"));
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    public void testDivideByBigDecimalZero() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT a_integer/x_integer/0.0 FROM atable";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Connection conn = DriverManager.getConnection(url);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertTrue(e.getMessage().contains("Divide by zero"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testDivideByIntegerZero() throws Exception {
+        long ts = nextTimestamp();
+        String query = "SELECT a_integer/0 FROM atable";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Connection conn = DriverManager.getConnection(url);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.executeQuery();
+            fail();
+        } catch (SQLException e) { // expected
+            assertTrue(e.getMessage().contains("Divide by zero"));
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testCreateNullableInPKMiddle() throws Exception {
+        long ts = nextTimestamp();
+        String query = "CREATE TABLE foo(i integer not null, j integer null, k integer not null CONSTRAINT pk PRIMARY KEY(i,j,k))";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Connection conn = DriverManager.getConnection(url);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) { // expected
+            assertTrue(e.getMessage().contains("PK columns may not be both fixed width and nullable"));
+        }
+    }
+
+    @Test
+    public void testSetSaltBucketOnAlterTable() throws Exception {
+        long ts = nextTimestamp();
+        String query = "ALTER TABLE atable ADD xyz INTEGER SALT_BUCKETS=4";
+        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
+        Connection conn = DriverManager.getConnection(url);
+        try {
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) { // expected
+            assertTrue(e.getErrorCode() == SQLExceptionCode.SALT_ONLY_ON_CREATE_TABLE.getErrorCode());
+        }
+    }
+
+    @Test
+    public void testSubstrSetScanKey() throws Exception {
+        String query = "SELECT inst FROM ptsdb WHERE substr(inst, 0, 3) = 'abc'";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abd"),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+        assertTrue(scan.getFilter() == null); // Extracted.
+    }
+
+    @Test
+    public void testRTrimSetScanKey() throws Exception {
+        String query = "SELECT inst FROM ptsdb WHERE rtrim(inst) = 'abc'";
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery(query, binds);
+        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(ByteUtil.nextKey(Bytes.toBytes("abc ")),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+        assertNotNull(scan.getFilter());
+    }
+    
+    @Test
+    public void testCastingIntegerToDecimalInSelect() throws Exception {
+        String query = "SELECT CAST a_integer AS DECIMAL/2 FROM aTable WHERE 5=a_integer";
+        List<Object> binds = Collections.emptyList();
+        compileQuery(query, binds);
+    }
+    
+    @Test
+    public void testCastingStringToDecimalInSelect() throws Exception {
+        String query = "SELECT CAST b_string AS DECIMAL/2 FROM aTable WHERE 5=a_integer";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a string to decimal isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testCastingStringToDecimalInWhere() throws Exception {
+        String query = "SELECT a_integer FROM aTable WHERE 2.5=CAST b_string AS DECIMAL/2 ";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a string to decimal isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }  
+    }
+    
+    @Test
+    public void testUsingNonComparableDataTypesInRowValueConstructorFails() throws Exception {
+        String query = "SELECT a_integer, x_integer FROM aTable WHERE (a_integer, x_integer) > (2, 'abc')";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a integer to string isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testUsingNonComparableDataTypesOfColumnRefOnLHSAndRowValueConstructorFails() throws Exception {
+        String query = "SELECT a_integer, x_integer FROM aTable WHERE a_integer > ('abc', 2)";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a integer to string isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testUsingNonComparableDataTypesOfLiteralOnLHSAndRowValueConstructorFails() throws Exception {
+        String query = "SELECT a_integer, x_integer FROM aTable WHERE 'abc' > (a_integer, x_integer)";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a integer to string isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testUsingNonComparableDataTypesOfColumnRefOnRHSAndRowValueConstructorFails() throws Exception {
+        String query = "SELECT a_integer, x_integer FROM aTable WHERE ('abc', 2) < a_integer ";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a integer to string isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testUsingNonComparableDataTypesOfLiteralOnRHSAndRowValueConstructorFails() throws Exception {
+        String query = "SELECT a_integer, x_integer FROM aTable WHERE (a_integer, x_integer) < 'abc'";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since casting a integer to string isn't supported");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testNonConstantInList() throws Exception {
+        String query = "SELECT a_integer, x_integer FROM aTable WHERE a_integer IN (x_integer)";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since non constants in IN is not valid");
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.VALUE_IN_LIST_NOT_CONSTANT.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testKeyValueColumnInPKConstraint() throws Exception {
+        String ddl = "CREATE TABLE t (a.k VARCHAR, b.v VARCHAR CONSTRAINT pk PRIMARY KEY(k))";
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(ddl);
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getErrorCode() == SQLExceptionCode.PRIMARY_KEY_WITH_FAMILY_NAME.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testUnknownColumnInPKConstraint() throws Exception {
+        String ddl = "CREATE TABLE t (k1 VARCHAR, b.v VARCHAR CONSTRAINT pk PRIMARY KEY(k1, k2))";
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(ddl);
+            fail();
+        } catch (ColumnNotFoundException e) {
+            assertEquals("K2",e.getColumnName());
+        }
+    }
+    
+    
+    @Test
+    public void testDuplicatePKColumn() throws Exception {
+        String ddl = "CREATE TABLE t (k1 VARCHAR, k1 VARCHAR CONSTRAINT pk PRIMARY KEY(k1))";
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(ddl);
+            fail();
+        } catch (ColumnAlreadyExistsException e) {
+            assertEquals("K1",e.getColumnName());
+        }
+    }
+    
+    
+    @Test
+    public void testDuplicateKVColumn() throws Exception {
+        String ddl = "CREATE TABLE t (k1 VARCHAR, v1 VARCHAR, v2 VARCHAR, v1 INTEGER CONSTRAINT pk PRIMARY KEY(k1))";
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(ddl);
+            fail();
+        } catch (ColumnAlreadyExistsException e) {
+            assertEquals("V1",e.getColumnName());
+        }
+    }
+    
+    @Test
+    public void testDeleteFromImmutableWithKV() throws Exception {
+        String ddl = "CREATE TABLE t (k1 VARCHAR, v1 VARCHAR, v2 VARCHAR CONSTRAINT pk PRIMARY KEY(k1)) immutable_rows=true";
+        String indexDDL = "CREATE INDEX i ON t (v1)";
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(ddl);
+            conn.createStatement().execute(indexDDL);
+            conn.createStatement().execute("DELETE FROM t");
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.NO_DELETE_IF_IMMUTABLE_INDEX.getErrorCode(), e.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testInvalidNegativeArrayIndex() throws Exception {
+    	String query = "SELECT a_double_array[-20] FROM table_with_array";
+    	Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(query);
+            fail();
+        } catch (Exception e) {
+        	
+        }
+    }
+    @Test
+    public void testWrongDataTypeInRoundFunction() throws Exception {
+        String query = "SELECT ROUND(a_string, 'day', 1) FROM aTable";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since VARCHAR is not a valid data type for ROUND");
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testNonArrayColumnWithIndex() throws Exception {
+    	String query = "SELECT a_float[1] FROM table_with_array";
+    	Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute(query);
+            fail();
+        } catch (Exception e) {
+        }
+    }
+
+    public void testWrongTimeUnitInRoundDateFunction() throws Exception {
+        String query = "SELECT ROUND(a_date, 'dayss', 1) FROM aTable";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since dayss is not a valid time unit type");
+        } catch (IllegalArgumentException e) {
+            assertTrue(e.getMessage().contains(TimeUnit.VALID_VALUES));
+        }
+    }
+    
+    @Test
+    public void testWrongMultiplierInRoundDateFunction() throws Exception {
+        String query = "SELECT ROUND(a_date, 'days', 1.23) FROM aTable";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since multiplier can be an INTEGER only");
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testTypeMismatchForArrayElem() throws Exception {
+        String query = "SELECT (a_string,a_date)[1] FROM aTable";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since a row value constructor is not an array");
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testTypeMismatch2ForArrayElem() throws Exception {
+        String query = "SELECT ROUND(a_date, 'days', 1.23)[1] FROM aTable";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileQuery(query, binds);
+            fail("Compilation should have failed since ROUND does not return an array");
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
+        }
+    }
+    
+    @Test
+    public void testInvalidArrayTypeAsPK () throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (col1 INTEGER[10] NOT NULL PRIMARY KEY)";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+                assertEquals(SQLExceptionCode.ARRAY_NOT_ALLOWED_IN_PRIMARY_KEY.getErrorCode(), e.getErrorCode());
+        } finally {
+                conn.close();
+        }
+
+        conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (col1 VARCHAR, col2 INTEGER ARRAY[10] CONSTRAINT pk PRIMARY KEY (col1, col2))";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.ARRAY_NOT_ALLOWED_IN_PRIMARY_KEY.getErrorCode(), e.getErrorCode());
+        } finally {
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testInvalidArraySize() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            String query = "CREATE TABLE foo (col1 INTEGER[-1] NOT NULL PRIMARY KEY)";
+            PreparedStatement statement = conn.prepareStatement(query);
+            statement.execute();
+            fail();
+        } catch (SQLException e) {
+                assertEquals(SQLExceptionCode.MISMATCHED_TOKEN.getErrorCode(), e.getErrorCode());
+        } finally {
+                conn.close();
+        }
+    }
+
+    @Test
+    public void testInvalidArrayInQuery () throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute("CREATE TABLE t (k VARCHAR PRIMARY KEY, a INTEGER[10], B INTEGER[10])");
+        try {
+            conn.createStatement().execute("SELECT * FROM t ORDER BY a");
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.ORDER_BY_ARRAY_NOT_SUPPORTED.getErrorCode(), e.getErrorCode());
+        }
+        try {
+            conn.createStatement().execute("SELECT * FROM t WHERE a < b");
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.NON_EQUALITY_ARRAY_COMPARISON.getErrorCode(), e.getErrorCode());
+        }
+        conn.close();
+    }
+
+    @Test
+    public void testInvalidArrayElemRefInUpsert() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute("CREATE TABLE t (k VARCHAR PRIMARY KEY, a INTEGER[10], B INTEGER[10])");
+        try {
+            conn.createStatement().execute("UPSERT INTO t(k,a[2]) VALUES('A', 5)");
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.PARSER_ERROR.getErrorCode(), e.getErrorCode());
+        }
+        conn.close();
+    }
+
+    @Test
+    public void testInvalidNextValueFor() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute("CREATE SEQUENCE alpha.zeta");
+        String[] queries = {
+                "SELECT * FROM aTable WHERE a_integer < next value for alpha.zeta",
+                "SELECT * FROM aTable GROUP BY a_string,next value for alpha.zeta",
+                "SELECT * FROM aTable GROUP BY 1 + next value for alpha.zeta",
+                "SELECT * FROM aTable GROUP BY a_integer HAVING a_integer < next value for alpha.zeta",
+                "SELECT * FROM aTable WHERE a_integer < 3 GROUP BY a_integer HAVING a_integer < next value for alpha.zeta",
+                "SELECT * FROM aTable ORDER BY next value for alpha.zeta",
+                "SELECT max(next value for alpha.zeta) FROM aTable",
+        };
+        for (String query : queries) {
+            List<Object> binds = Collections.emptyList();
+            try {
+                compileQuery(query, binds);
+                fail("Compilation should have failed since this is an invalid usage of NEXT VALUE FOR: " + query);
+            } catch (SQLException e) {
+                assertEquals(SQLExceptionCode.INVALID_USE_OF_NEXT_VALUE_FOR.getErrorCode(), e.getErrorCode());
+            }
+        }
+    }
+
+    @Test
+    public void testNoCachingHint() throws Exception {
+        List<Object> binds = Collections.emptyList();
+        Scan scan = compileQuery("select val from ptsdb", binds);
+        assertTrue(scan.getCacheBlocks());
+        scan = compileQuery("select /*+ NO_CACHE */ val from ptsdb", binds);
+        assertFalse(scan.getCacheBlocks());
+        scan = compileQuery("select /*+ NO_CACHE */ p1.val from ptsdb p1 inner join ptsdb p2 on p1.inst = p2.inst", binds);
+        assertFalse(scan.getCacheBlocks());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompileTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompileTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompileTest.java
deleted file mode 100644
index 58db078..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompileTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Properties;
-
-import org.junit.Test;
-
-import org.apache.phoenix.exception.SQLExceptionCode;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-import org.apache.phoenix.schema.ColumnNotFoundException;
-import org.apache.phoenix.schema.PTable;
-import org.apache.phoenix.schema.PTable.ViewType;
-import org.apache.phoenix.schema.PTableType;
-import org.apache.phoenix.util.TestUtil;
-
-public class ViewCompileTest extends BaseConnectionlessQueryTest {
-    @Test
-    public void testViewTypeCalculation() throws Exception {
-        assertViewType(new String[] {
-            "CREATE VIEW v1 AS SELECT * FROM t WHERE k1 = 1 AND k2 = 'foo'",
-            "CREATE VIEW v2 AS SELECT * FROM t WHERE k2 = 'foo'",
-            "CREATE VIEW v3 AS SELECT * FROM t WHERE v = 'bar'||'bas'",
-            "CREATE VIEW v4 AS SELECT * FROM t WHERE 'bar'=v and 5+3/2 = k1",
-        }, ViewType.UPDATABLE);
-        assertViewType(new String[] {
-                "CREATE VIEW v1 AS SELECT * FROM t WHERE k1 < 1 AND k2 = 'foo'",
-                "CREATE VIEW v2 AS SELECT * FROM t WHERE substr(k2,0,3) = 'foo'",
-                "CREATE VIEW v3 AS SELECT * FROM t WHERE v = TO_CHAR(CURRENT_DATE())",
-                "CREATE VIEW v4 AS SELECT * FROM t WHERE 'bar'=v or 3 = k1",
-            }, ViewType.READ_ONLY);
-    }
-    
-    public void assertViewType(String[] views, ViewType viewType) throws Exception {
-        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-        PhoenixConnection conn = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class);
-        String ct = "CREATE TABLE t (k1 INTEGER NOT NULL, k2 VARCHAR, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k1,k2))";
-        conn.createStatement().execute(ct);
-        
-        for (String view : views) {
-            conn.createStatement().execute(view);
-        }
-        
-        int count = 0;
-        for (PTable table : conn.getPMetaData().getTables().values()) {
-            if (table.getType() == PTableType.VIEW) {
-                assertEquals(viewType, table.getViewType());
-                conn.createStatement().execute("DROP VIEW " + table.getName().getString());
-                count++;
-            }
-        }
-        assertEquals(views.length, count);
-    }
-
-    @Test
-    public void testViewInvalidation() throws Exception {
-        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-        PhoenixConnection conn = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class);
-        String ct = "CREATE TABLE t (k1 INTEGER NOT NULL, k2 VARCHAR, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k1,k2))";
-        conn.createStatement().execute(ct);
-        conn.createStatement().execute("CREATE VIEW v3 AS SELECT * FROM t WHERE v = 'bar'");
-        
-        // TODO: should it be an error to remove columns from a VIEW that we're defined there?
-        // TOOD: should we require an ALTER VIEW instead of ALTER TABLE?
-        conn.createStatement().execute("ALTER VIEW v3 DROP COLUMN v");
-        try {
-            conn.createStatement().executeQuery("SELECT * FROM v3");
-            fail();
-        } catch (ColumnNotFoundException e) {
-            
-        }
-        
-        // No error, as v still exists in t
-        conn.createStatement().execute("CREATE VIEW v4 AS SELECT * FROM t WHERE v = 'bas'");
-
-        // No error, even though view is invalid
-        conn.createStatement().execute("DROP VIEW v3");
-    }
-
-
-    @Test
-    public void testInvalidUpsertSelect() throws Exception {
-        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-        PhoenixConnection conn = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class);
-        conn.createStatement().execute("CREATE TABLE t1 (k1 INTEGER NOT NULL, k2 VARCHAR, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k1,k2))");
-        conn.createStatement().execute("CREATE TABLE t2 (k3 INTEGER NOT NULL, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k3))");
-        conn.createStatement().execute("CREATE VIEW v1 AS SELECT * FROM t1 WHERE k1 = 1");
-        
-        try {
-            conn.createStatement().executeUpdate("UPSERT INTO v1 SELECT k3,'foo',v FROM t2");
-            fail();
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.CANNOT_UPDATE_VIEW_COLUMN.getErrorCode(), e.getErrorCode());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompilerTest.java
new file mode 100644
index 0000000..8af9f28
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/ViewCompilerTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.junit.Test;
+
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTable.ViewType;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.util.TestUtil;
+
+public class ViewCompilerTest extends BaseConnectionlessQueryTest {
+    @Test
+    public void testViewTypeCalculation() throws Exception {
+        assertViewType(new String[] {
+            "CREATE VIEW v1 AS SELECT * FROM t WHERE k1 = 1 AND k2 = 'foo'",
+            "CREATE VIEW v2 AS SELECT * FROM t WHERE k2 = 'foo'",
+            "CREATE VIEW v3 AS SELECT * FROM t WHERE v = 'bar'||'bas'",
+            "CREATE VIEW v4 AS SELECT * FROM t WHERE 'bar'=v and 5+3/2 = k1",
+        }, ViewType.UPDATABLE);
+        assertViewType(new String[] {
+                "CREATE VIEW v1 AS SELECT * FROM t WHERE k1 < 1 AND k2 = 'foo'",
+                "CREATE VIEW v2 AS SELECT * FROM t WHERE substr(k2,0,3) = 'foo'",
+                "CREATE VIEW v3 AS SELECT * FROM t WHERE v = TO_CHAR(CURRENT_DATE())",
+                "CREATE VIEW v4 AS SELECT * FROM t WHERE 'bar'=v or 3 = k1",
+            }, ViewType.READ_ONLY);
+    }
+    
+    public void assertViewType(String[] views, ViewType viewType) throws Exception {
+        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+        PhoenixConnection conn = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class);
+        String ct = "CREATE TABLE t (k1 INTEGER NOT NULL, k2 VARCHAR, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k1,k2))";
+        conn.createStatement().execute(ct);
+        
+        for (String view : views) {
+            conn.createStatement().execute(view);
+        }
+        
+        int count = 0;
+        for (PTable table : conn.getPMetaData().getTables().values()) {
+            if (table.getType() == PTableType.VIEW) {
+                assertEquals(viewType, table.getViewType());
+                conn.createStatement().execute("DROP VIEW " + table.getName().getString());
+                count++;
+            }
+        }
+        assertEquals(views.length, count);
+    }
+
+    @Test
+    public void testViewInvalidation() throws Exception {
+        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+        PhoenixConnection conn = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class);
+        String ct = "CREATE TABLE t (k1 INTEGER NOT NULL, k2 VARCHAR, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k1,k2))";
+        conn.createStatement().execute(ct);
+        conn.createStatement().execute("CREATE VIEW v3 AS SELECT * FROM t WHERE v = 'bar'");
+        
+        // TODO: should it be an error to remove columns from a VIEW that we're defined there?
+        // TOOD: should we require an ALTER VIEW instead of ALTER TABLE?
+        conn.createStatement().execute("ALTER VIEW v3 DROP COLUMN v");
+        try {
+            conn.createStatement().executeQuery("SELECT * FROM v3");
+            fail();
+        } catch (ColumnNotFoundException e) {
+            
+        }
+        
+        // No error, as v still exists in t
+        conn.createStatement().execute("CREATE VIEW v4 AS SELECT * FROM t WHERE v = 'bas'");
+
+        // No error, even though view is invalid
+        conn.createStatement().execute("DROP VIEW v3");
+    }
+
+
+    @Test
+    public void testInvalidUpsertSelect() throws Exception {
+        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
+        PhoenixConnection conn = DriverManager.getConnection(getUrl(), props).unwrap(PhoenixConnection.class);
+        conn.createStatement().execute("CREATE TABLE t1 (k1 INTEGER NOT NULL, k2 VARCHAR, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k1,k2))");
+        conn.createStatement().execute("CREATE TABLE t2 (k3 INTEGER NOT NULL, v VARCHAR, CONSTRAINT pk PRIMARY KEY (k3))");
+        conn.createStatement().execute("CREATE VIEW v1 AS SELECT * FROM t1 WHERE k1 = 1");
+        
+        try {
+            conn.createStatement().executeUpdate("UPSERT INTO v1 SELECT k3,'foo',v FROM t2");
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.CANNOT_UPDATE_VIEW_COLUMN.getErrorCode(), e.getErrorCode());
+        }
+    }
+}


[2/8] Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
new file mode 100644
index 0000000..96a8cef
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
@@ -0,0 +1,1620 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.apache.phoenix.util.TestUtil.assertDegenerate;
+import static org.apache.phoenix.util.TestUtil.assertEmptyScanKey;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.filter.Filter;
+import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.OrExpression;
+import org.apache.phoenix.filter.RowKeyComparisonFilter;
+import org.apache.phoenix.filter.SkipScanFilter;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixStatement;
+import org.apache.phoenix.parse.SQLParser;
+import org.apache.phoenix.parse.SelectStatement;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.DateUtil;
+import org.apache.phoenix.util.TestUtil;
+import org.junit.Test;
+
+import com.google.common.collect.Sets;
+
+
+
+public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
+    
+    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds) throws SQLException {
+        return compileStatement(query, scan, binds, null, null);
+    }
+
+    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds, Integer limit) throws SQLException {
+        return compileStatement(query, scan, binds, limit, null);
+    }
+
+    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds, Set<Expression> extractedNodes) throws SQLException {
+        return compileStatement(query, scan, binds, null, extractedNodes);
+    }
+
+    // TODO: remove this and replace checks on extractedNodes with tests for the scan filter
+    private static StatementContext compileStatement(String query, Scan scan, List<Object> binds, Integer limit, Set<Expression> extractedNodes) throws SQLException {
+        SQLParser parser = new SQLParser(query);
+        SelectStatement statement = parser.parseQuery();
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
+        statement = StatementNormalizer.normalize(statement, resolver);
+        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
+
+        Integer actualLimit = LimitCompiler.compile(context, statement);
+        assertEquals(limit, actualLimit);
+        GroupBy groupBy = GroupByCompiler.compile(context, statement);
+        statement = HavingCompiler.rewrite(context, statement, groupBy);
+        WhereCompiler.compileWhereClause(context, statement, extractedNodes);
+        return context;
+    }
+
+    @Test
+    public void testSingleKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        compileStatement(query, scan, binds);
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+
+    @Test
+    public void testReverseSingleKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where '" + tenantId + "' = organization_id";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        compileStatement(query, scan, binds);
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+
+    @Test
+    public void testStartKeyStopKey() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute("CREATE TABLE start_stop_test (pk char(2) not null primary key)");
+        conn.close();
+
+        String query = "select * from start_stop_test where pk >= 'EA' and pk < 'EZ'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        assertArrayEquals(PDataType.VARCHAR.toBytes("EA"), scan.getStartRow());
+        assertArrayEquals(PDataType.VARCHAR.toBytes("EZ"), scan.getStopRow());
+    }
+
+    @Test
+    public void testConcatSingleKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id || 'foo' ='" + tenantId + "'||'foo'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        // The || operator cannot currently be used to form the start/stop key
+        assertNotNull(scan.getFilter());
+        assertEquals(0, scan.getStartRow().length);
+        assertEquals(0, scan.getStopRow().length);
+    }
+
+    @Test
+    public void testLiteralConcatExpression() throws SQLException {
+        String query = "select * from atable where null||'foo'||'bar' = 'foobar'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        assertEquals(0, scan.getStartRow().length);
+        assertEquals(0, scan.getStopRow().length);
+    }
+
+    @Test
+    public void testSingleKeyNotExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where not organization_id='" + tenantId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertNotNull(scan.getFilter());
+
+        assertEquals(0, scan.getStartRow().length);
+        assertEquals(0, scan.getStopRow().length);
+    }
+
+    @Test
+    public void testMultiKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3)='" + keyPrefix + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)), 15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testMultiKeyBindExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id=? and substr(entity_id,1,3)=?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId,keyPrefix);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testEqualRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')=?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(startDate));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testDegenerateRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')=?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testBoundaryGreaterThanRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testBoundaryGreaterThanOrEqualRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>=?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testGreaterThanRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')>?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testLessThanRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testBoundaryLessThanRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testLessThanOrEqualRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 01:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testBoundaryLessThanOrEqualRound() throws Exception {
+        String inst = "a";
+        String host = "b";
+        Date startDate = DateUtil.parseDate("2012-01-01 00:00:00");
+        Date endDate = DateUtil.parseDate("2012-01-02 00:00:00");
+        String query = "select * from ptsdb where inst=? and host=? and round(date,'DAY')<=?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(inst,host,startDate);
+        compileStatement(query, scan, binds);
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(inst),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.VARCHAR.toBytes(host),QueryConstants.SEPARATOR_BYTE_ARRAY,
+                PDataType.DATE.toBytes(endDate));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testOverlappingKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String entityId = "002333333333333";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3)='" + keyPrefix + "' and entity_id='" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(startRow, scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(startRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+    }
+
+    @Test
+    public void testTrailingSubstrExpression() throws SQLException {
+        String tenantId = "0xD000000000001";
+        String entityId = "002333333333333";
+        String query = "select * from atable where substr(organization_id,1,3)='" + tenantId.substring(0, 3) + "' and entity_id='" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertNotNull(scan.getFilter());
+
+        byte[] startRow = ByteUtil.concat(ByteUtil.fillKey(PDataType.VARCHAR.toBytes(tenantId.substring(0,3)),15),PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(startRow, scan.getStartRow());
+        // Even though the first slot is a non inclusive range, we need to do a next key
+        // on the second slot because of the algorithm we use to seek to and terminate the
+        // loop during skip scan. We could end up having a first slot just under the upper
+        // limit of slot one and a value equal to the value in slot two and we need this to
+        // be less than the upper range that would get formed.
+        byte[] stopRow = ByteUtil.concat(ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId.substring(0,3))),15),ByteUtil.nextKey(PDataType.VARCHAR.toBytes(entityId)));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testBasicRangeExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id <= '" + tenantId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertNull(scan.getFilter());
+
+        assertTrue(scan.getStartRow().length == 0);
+        byte[] stopRow = ByteUtil.concat(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression1() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String keyPrefix2= "004";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) >= '" + keyPrefix1 + "' and substr(entity_id,1,3) < '" + keyPrefix2 + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertNull(scan.getFilter());
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix1),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix2),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression2() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String keyPrefix2= "004";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) >= '" + keyPrefix1 + "' and substr(entity_id,1,3) <= '" + keyPrefix2 + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertNull(scan.getFilter());
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix1),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix2)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression3() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String keyPrefix2= "004";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) > '" + keyPrefix1 + "' and substr(entity_id,1,3) <= '" + keyPrefix2 + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix1)),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix2)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression4() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String entityId= "002000000000002";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) > '" + keyPrefix1 + "' and substr(entity_id,1,3) = '" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testKeyRangeExpression5() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String entityId= "002000000000002";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) <= '" + keyPrefix1 + "' and entity_id = '" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression6() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String entityId= "002000000000002";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) < '" + keyPrefix1 + "' and entity_id = '" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testKeyRangeExpression7() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String entityId= "002000000000002";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) < '" + keyPrefix1 + "' and entity_id < '" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertNull(scan.getFilter());
+
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(keyPrefix1),new byte[entityId.length() - keyPrefix1.length()]);
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression8() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "001";
+        String entityId= "002000000000002";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) > '" + keyPrefix1 + "' and entity_id = '" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),PDataType.VARCHAR.toBytes(entityId));
+        assertArrayEquals(ByteUtil.concat(stopRow, QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+    }
+
+    @Test
+    public void testKeyRangeExpression9() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix1 = "002";
+        String keyPrefix2 = "0033";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3) >= '" + keyPrefix1 + "' and substr(entity_id,1,4) <= '" + keyPrefix2 + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix1),15)); // extra byte is due to implicit internal padding
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix2)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    /**
+     * This is testing the degenerate case where nothing will match because the overlapping keys (keyPrefix and entityId) don't match.
+     * @throws SQLException
+     */
+    @Test
+    public void testUnequalOverlappingKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String entityId = "001333333333333";
+        String query = "select * from atable where organization_id='" + tenantId + "' and substr(entity_id,1,3)='" + keyPrefix + "' and entity_id='" + entityId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testTopLevelOrKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' or a_integer=2";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(0, scan.getStartRow().length);
+        assertEquals(0, scan.getStopRow().length);
+    }
+
+    @Test
+    public void testSiblingOrKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and (a_integer = 2 or a_integer = 3)";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNotNull(scan.getFilter());
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+
+    @Test
+    public void testColumnNotFound() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where bar='" + tenantId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileStatement(query, scan, binds);
+            fail();
+        } catch (ColumnNotFoundException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testNotContiguousPkColumn() throws SQLException {
+        String keyPrefix = "002";
+        String query = "select * from atable where substr(entity_id,1,3)='" + keyPrefix + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(0, scan.getStartRow().length);
+        assertEquals(0, scan.getStopRow().length);
+    }
+
+    @Test
+    public void testMultipleNonEqualitiesPkColumn() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id >= '" + tenantId + "' AND substr(entity_id,1,3) > '" + keyPrefix + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds);
+
+        assertNotNull(scan.getFilter());
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+
+    @Test
+    public void testRHSLiteral() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' and 0 >= a_integer limit 1000";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        compileStatement(query, scan, binds, 1000);
+
+        assertNotNull(scan.getFilter());
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+
+
+    @Test
+    public void testKeyTypeMismatch() {
+        String query = "select * from atable where organization_id=5";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileStatement(query, scan, binds);
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("Type mismatch"));
+        }
+    }
+
+    @Test
+    public void testLikeExtractAllKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id = ? and entity_id  LIKE '" + keyPrefix + "%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testLikeExtractAllAsEqKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id LIKE ? and entity_id  LIKE '" + keyPrefix + "%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        compileStatement(query, scan, binds);
+
+        assertNull(scan.getFilter());
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testDegenerateLikeNoWildcard() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id LIKE ? and entity_id  LIKE '" + keyPrefix + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        compileStatement(query, scan, binds);
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testLikeExtractKeyExpression2() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        // TODO: verify that _ at end of like doesn't go to equals
+        String query = "select * from atable where organization_id = ? and entity_id  LIKE '" + keyPrefix + "_'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        compileStatement(query, scan, binds);
+
+        assertNotNull(scan.getFilter());
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testLikeOptKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id = ? and entity_id  LIKE '" + keyPrefix + "%003%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(1, extractedNodes.size());
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testLikeOptKeyExpression2() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id = ? and substr(entity_id,1,10)  LIKE '" + keyPrefix + "%003%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(1, extractedNodes.size());
+
+
+        byte[] startRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15));
+        byte[] stopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId),ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15));
+        assertArrayEquals(startRow, scan.getStartRow());
+        assertArrayEquals(stopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testLikeNoOptKeyExpression3() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id = ? and substr(entity_id,4,10)  LIKE '" + keyPrefix + "%003%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(1, extractedNodes.size());
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(startRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testLikeDegenerate() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id = ? and entity_id  LIKE '0000000000000012%003%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateDivision1() throws SQLException {
+        String query = "select * from atable where a_integer = 3 / null";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateDivision2() throws SQLException {
+        String query = "select * from atable where a_integer / null = 3";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateMult1() throws SQLException {
+        String query = "select * from atable where a_integer = 3 * null";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateMult2() throws SQLException {
+        String query = "select * from atable where a_integer * null = 3";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateAdd1() throws SQLException {
+        String query = "select * from atable where a_integer = 3 + null";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateAdd2() throws SQLException {
+        String query = "select * from atable where a_integer + null = 3";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateSub1() throws SQLException {
+        String query = "select * from atable where a_integer = 3 - null";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testDegenerateSub2() throws SQLException {
+        String query = "select * from atable where a_integer - null = 3";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertDegenerate(scan);
+    }
+
+    @Test
+    public void testLikeNoOptKeyExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id = ? and entity_id  LIKE '%001%" + keyPrefix + "%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(1, extractedNodes.size());
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(startRow), scan.getStopRow());
+    }
+
+    @Test
+    public void testLikeNoOptKeyExpression2() throws SQLException {
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select * from atable where organization_id = ? and entity_id  NOT LIKE '" + keyPrefix + "%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+
+        assertNotNull(scan.getFilter());
+        assertEquals(1, extractedNodes.size());
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId);
+        assertArrayEquals(startRow, scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(startRow), scan.getStopRow());
+    }
+    /*
+     * The following 5 tests are testing the comparison in where clauses under the case when the rhs
+     * cannot be coerced into the lhs. We need to confirm the decision make by expression compilation
+     * returns correct decisions.
+     */
+    @Test
+    public void testValueComparisonInt() throws SQLException {
+        ensureTableCreated(getUrl(),"PKIntValueTest");
+        String query;
+        // int <-> long
+        // Case 1: int = long, comparison always false, key is degenerated.
+        query = "SELECT * FROM PKintValueTest where pk = " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysFalse(query);
+        // Case 2: int != long, comparison always true, no key set since we need to do a full
+        // scan all the time.
+        query = "SELECT * FROM PKintValueTest where pk != " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysTrue(query);
+        // Case 3: int > positive long, comparison always false;
+        query = "SELECT * FROM PKintValueTest where pk >= " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysFalse(query);
+        // Case 4: int <= Integer.MAX_VALUE < positive long, always true;
+        query = "SELECT * FROM PKintValueTest where pk <= " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysTrue(query);
+        // Case 5: int >= Integer.MIN_VALUE > negative long, always true;
+        query = "SELECT * FROM PKintValueTest where pk >= " + (Long.MIN_VALUE + 1);
+        assertQueryConditionAlwaysTrue(query);
+        // Case 6: int < negative long, comparison always false;
+        query = "SELECT * FROM PKintValueTest where pk <= " + (Long.MIN_VALUE + 1);
+        assertQueryConditionAlwaysFalse(query);
+    }
+
+    @Test
+    public void testValueComparisonUnsignedInt() throws SQLException {
+        ensureTableCreated(getUrl(), "PKUnsignedIntValueTest");
+        String query;
+        // unsigned_int <-> negative int/long
+        // Case 1: unsigned_int = negative int, always false;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk = -1";
+        assertQueryConditionAlwaysFalse(query);
+        // Case 2: unsigned_int != negative int, always true;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk != -1";
+        assertQueryConditionAlwaysTrue(query);
+        // Case 3: unsigned_int > negative int, always true;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk > " + (Long.MIN_VALUE + 1);
+        assertQueryConditionAlwaysTrue(query);
+        // Case 4: unsigned_int < negative int, always false;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk < " + + (Long.MIN_VALUE + 1);
+        assertQueryConditionAlwaysFalse(query);
+        // unsigned_int <-> big positive long
+        // Case 1: unsigned_int = big positive long, always false;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk = " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysFalse(query);
+        // Case 2: unsigned_int != big positive long, always true;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk != " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysTrue(query);
+        // Case 3: unsigned_int > big positive long, always false;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk >= " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysFalse(query);
+        // Case 4: unsigned_int < big positive long, always true;
+        query = "SELECT * FROM PKUnsignedIntValueTest where pk <= " + Long.MAX_VALUE;
+        assertQueryConditionAlwaysTrue(query);
+    }
+
+    @Test
+    public void testValueComparisonUnsignedLong() throws SQLException {
+        ensureTableCreated(getUrl(), "PKUnsignedLongValueTest");
+        String query;
+        // unsigned_long <-> positive int/long
+        // Case 1: unsigned_long = negative int/long, always false;
+        query = "SELECT * FROM PKUnsignedLongValueTest where pk = -1";
+        assertQueryConditionAlwaysFalse(query);
+        // Case 2: unsigned_long = negative int/long, always true;
+        query = "SELECT * FROM PKUnsignedLongValueTest where pk != " + (Long.MIN_VALUE + 1);
+        assertQueryConditionAlwaysTrue(query);
+        // Case 3: unsigned_long > negative int/long, always true;
+        query = "SELECT * FROM PKUnsignedLongValueTest where pk > -1";
+        assertQueryConditionAlwaysTrue(query);
+        // Case 4: unsigned_long < negative int/long, always false;
+        query = "SELECT * FROM PKUnsignedLongValueTest where pk < " + (Long.MIN_VALUE + 1);
+        assertQueryConditionAlwaysFalse(query);
+    }
+
+    private void assertQueryConditionAlwaysTrue(String query) throws SQLException {
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression> extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+        assertEmptyScanKey(scan);
+    }
+
+    private void assertQueryConditionAlwaysFalse(String query) throws SQLException {
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList();
+        Set<Expression> extractedNodes = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedNodes);
+        assertDegenerate(scan);
+    }
+    
+    @Test
+    public void testOrSameColExpression() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000003";
+        String query = "select * from atable where organization_id = ? or organization_id  = ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId1,tenantId2);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
+
+        Filter filter = scan.getFilter();
+        assertNotNull(filter);
+        assertTrue(filter instanceof SkipScanFilter);
+        ScanRanges scanRanges = context.getScanRanges();
+        assertNotNull(scanRanges);
+        List<List<KeyRange>> ranges = scanRanges.getRanges();
+        assertEquals(1,ranges.size());
+        List<List<KeyRange>> expectedRanges = Collections.singletonList(Arrays.asList(
+                PDataType.CHAR.getKeyRange(PDataType.CHAR.toBytes(tenantId1), true, PDataType.CHAR.toBytes(tenantId1), true), 
+                PDataType.CHAR.getKeyRange(PDataType.CHAR.toBytes(tenantId2), true, PDataType.CHAR.toBytes(tenantId2), true)));
+        assertEquals(expectedRanges, ranges);
+        assertEquals(1, extractedNodes.size());
+        assertTrue(extractedNodes.iterator().next() instanceof OrExpression);
+        byte[] startRow = PDataType.VARCHAR.toBytes(tenantId1);
+        assertArrayEquals(startRow, scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId2)), scan.getStopRow());
+    }
+    
+    @Test
+    public void testAndOrExpression() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String tenantId2 = "000000000000003";
+        String entityId1 = "002333333333331";
+        String entityId2 = "002333333333333";
+        String query = "select * from atable where (organization_id = ? and entity_id  = ?) or (organization_id = ? and entity_id  = ?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId1,entityId1,tenantId2,entityId2);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
+
+        Filter filter = scan.getFilter();
+        assertNotNull(filter);
+        assertTrue(filter instanceof RowKeyComparisonFilter);
+        ScanRanges scanRanges = context.getScanRanges();
+        assertEquals(ScanRanges.EVERYTHING,scanRanges);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testOrDiffColExpression() throws SQLException {
+        String tenantId1 = "000000000000001";
+        String entityId1 = "002333333333331";
+        String query = "select * from atable where organization_id = ? or entity_id  = ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId1,entityId1);
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
+
+        Filter filter = scan.getFilter();
+        assertNotNull(filter);
+        assertTrue(filter instanceof RowKeyComparisonFilter);
+        ScanRanges scanRanges = context.getScanRanges();
+        assertEquals(ScanRanges.EVERYTHING,scanRanges);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testOrSameColRangeExpression() throws SQLException {
+        String query = "select * from atable where substr(organization_id,1,3) = ? or organization_id LIKE 'foo%'";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList("00D");
+        Set<Expression>extractedNodes = new HashSet<Expression>();
+        StatementContext context = compileStatement(query, scan, binds, extractedNodes);
+
+        Filter filter = scan.getFilter();
+        assertNotNull(filter);
+        assertTrue(filter instanceof SkipScanFilter);
+        ScanRanges scanRanges = context.getScanRanges();
+        assertNotNull(scanRanges);
+        List<List<KeyRange>> ranges = scanRanges.getRanges();
+        assertEquals(1,ranges.size());
+        List<List<KeyRange>> expectedRanges = Collections.singletonList(Arrays.asList(
+                PDataType.CHAR.getKeyRange(
+                        ByteUtil.fillKey(PDataType.CHAR.toBytes("00D"),15), true, 
+                        ByteUtil.fillKey(ByteUtil.nextKey(PDataType.CHAR.toBytes("00D")),15), false), 
+                PDataType.CHAR.getKeyRange(
+                        ByteUtil.fillKey(PDataType.CHAR.toBytes("foo"),15), true, 
+                        ByteUtil.fillKey(ByteUtil.nextKey(PDataType.CHAR.toBytes("foo")),15), false)));
+        assertEquals(expectedRanges, ranges);
+        assertEquals(1, extractedNodes.size());
+        assertTrue(extractedNodes.iterator().next() instanceof OrExpression);
+    }
+    
+    @Test
+    public void testForceSkipScanOnSaltedTable() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute("CREATE TABLE IF NOT EXISTS user_messages (\n" + 
+                "        SENDER_ID UNSIGNED_LONG NOT NULL,\n" + 
+                "        RECIPIENT_ID UNSIGNED_LONG NOT NULL,\n" + 
+                "        SENDER_IP VARCHAR,\n" + 
+                "        IS_READ VARCHAR,\n" + 
+                "        IS_DELETED VARCHAR,\n" + 
+                "        M_TEXT VARCHAR,\n" + 
+                "        M_TIMESTAMP timestamp  NOT NULL,\n" + 
+                "        ROW_ID UNSIGNED_LONG NOT NULL\n" + 
+                "        constraint rowkey primary key (SENDER_ID,RECIPIENT_ID,M_TIMESTAMP DESC,ROW_ID))\n" + 
+                "SALT_BUCKETS=12\n");
+        String query = "select /*+ SKIP_SCAN */ count(*) from user_messages where is_read='N' and recipient_id=5399179882";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        Set<Expression> extractedNodes = Sets.newHashSet();
+        StatementContext context = compileStatement(query, scan, binds, null, extractedNodes);
+        ScanRanges scanRanges = context.getScanRanges();
+        assertNotNull(scanRanges);
+        assertEquals(3,scanRanges.getRanges().size());
+        assertEquals(1,scanRanges.getRanges().get(1).size());
+        assertEquals(KeyRange.EVERYTHING_RANGE,scanRanges.getRanges().get(1).get(0));
+        assertEquals(1,scanRanges.getRanges().get(2).size());
+        assertTrue(scanRanges.getRanges().get(2).get(0).isSingleKey());
+        assertEquals(Long.valueOf(5399179882L), PDataType.UNSIGNED_LONG.toObject(scanRanges.getRanges().get(2).get(0).getLowerRange()));
+        assertEquals(1, extractedNodes.size());
+        assertNotNull(scan.getFilter());
+    }
+    
+    @Test
+    public void testForceRangeScanKeepsFilters() throws SQLException {
+        ensureTableCreated(getUrl(), TestUtil.ENTITY_HISTORY_TABLE_NAME);
+        String tenantId = "000000000000001";
+        String keyPrefix = "002";
+        String query = "select /*+ RANGE_SCAN */ ORGANIZATION_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID from " + TestUtil.ENTITY_HISTORY_TABLE_NAME + 
+                " where ORGANIZATION_ID=? and SUBSTR(PARENT_ID, 1, 3) = ? and  CREATED_DATE >= ? and CREATED_DATE < ? order by ORGANIZATION_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID limit 6";
+        Scan scan = new Scan();
+        Date startTime = new Date(System.currentTimeMillis());
+        Date stopTime = new Date(startTime.getTime() + TestUtil.MILLIS_IN_DAY);
+        List<Object> binds = Arrays.<Object>asList(tenantId, keyPrefix, startTime, stopTime);
+        Set<Expression> extractedNodes = Sets.newHashSet();
+        compileStatement(query, scan, binds, 6, extractedNodes);
+        assertEquals(2, extractedNodes.size());
+        assertNotNull(scan.getFilter());
+
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), ByteUtil.fillKey(PDataType.VARCHAR.toBytes(keyPrefix),15), PDataType.DATE.toBytes(startTime));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        byte[] expectedStopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), ByteUtil.fillKey(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(keyPrefix)),15), PDataType.DATE.toBytes(stopTime));
+        assertArrayEquals(expectedStopRow, scan.getStopRow());
+    }
+
+    @Test
+    public void testBasicRVCExpression() throws SQLException {
+        String tenantId = "000000000000001";
+        String entityId = "002333333333331";
+        String query = "select * from atable where (organization_id,entity_id) >= (?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, entityId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.CHAR.toBytes(tenantId), PDataType.CHAR.toBytes(entityId));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+
+    
+    @Test
+    public void testRVCExpressionThroughOr() throws SQLException {
+        String tenantId = "000000000000001";
+        String entityId = "002333333333331";
+        String entityId1 = "002333333333330";
+        String entityId2 = "002333333333332";
+        String query = "select * from atable where (organization_id,entity_id) >= (?,?) and organization_id = ? and  (entity_id = ? or entity_id = ?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, entityId, tenantId, entityId1, entityId2);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 3);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(entityId));
+        byte[] expectedStopRow = ByteUtil.concat(ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(entityId2)), QueryConstants.SEPARATOR_BYTE_ARRAY);
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(expectedStopRow, scan.getStopRow());
+    }
+    
+    /**
+     * With only a subset of row key cols present (which includes the leading key), 
+     * Phoenix should have optimized the start row for the scan to include the 
+     * row keys cols that occur contiguously in the RVC.
+     * 
+     * Table entity_history has the row key defined as (organization_id, parent_id, created_date, entity_history_id). 
+     * This test uses (organization_id, parent_id, entity_id) in RVC. So the start row should be comprised of
+     * organization_id and parent_id.
+     * @throws SQLException
+     */
+    @Test
+    public void testRVCExpressionWithSubsetOfPKCols() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000002";
+        String entityHistId = "000000000000003";
+        
+        String query = "select * from entity_history where (organization_id, parent_id, entity_history_id) >= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, entityHistId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 0);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(parentId));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    /**
+     * With the leading row key col missing Phoenix won't be able to optimize
+     * and provide the start row for the scan.
+     * 
+     * Table entity_history has the row key defined as (organization_id, parent_id, created_date, entity_history_id). 
+     * This test uses (parent_id, entity_id) in RVC. Start row should be empty.
+     * @throws SQLException
+     */
+    
+    @Test
+    public void testRVCExpressionWithoutLeadingColOfRowKey() throws SQLException {
+        
+        String parentId = "000000000000002";
+        String entityHistId = "000000000000003";
+        
+        String query = "select * from entity_history where (parent_id, entity_history_id) >= (?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(parentId, entityHistId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 0);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testMultiRVCExpressionsCombinedWithAnd() throws SQLException {
+        String lowerTenantId = "000000000000001";
+        String lowerParentId = "000000000000002";
+        Date lowerCreatedDate = new Date(System.currentTimeMillis());
+        String upperTenantId = "000000000000008";
+        String upperParentId = "000000000000009";
+        
+        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?, ?, ?) AND (organization_id, parent_id) <= (?, ?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(lowerTenantId, lowerParentId, lowerCreatedDate, upperTenantId, upperParentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 2);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(lowerTenantId), PDataType.VARCHAR.toBytes(lowerParentId), PDataType.DATE.toBytes(lowerCreatedDate));
+        byte[] expectedStopRow = ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(upperTenantId), PDataType.VARCHAR.toBytes(upperParentId)));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(expectedStopRow, scan.getStopRow());
+    }
+    
+    @Test
+    public void testMultiRVCExpressionsCombinedUsingLiteralExpressions() throws SQLException {
+        String lowerTenantId = "000000000000001";
+        String lowerParentId = "000000000000002";
+        Date lowerCreatedDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?, ?, ?) AND (organization_id, parent_id) <= ('7', '7')";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(lowerTenantId, lowerParentId, lowerCreatedDate);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 2);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(lowerTenantId), PDataType.VARCHAR.toBytes(lowerParentId), PDataType.DATE.toBytes(lowerCreatedDate));
+        byte[] expectedStopRow = ByteUtil.nextKey(ByteUtil.concat(ByteUtil.fillKey(PDataType.VARCHAR.toBytes("7"),15), ByteUtil.fillKey(PDataType.VARCHAR.toBytes("7"), 15)));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(expectedStopRow, scan.getStopRow());
+    }
+    
+    @Test
+    public void testUseOfFunctionOnLHSInRVC() throws SQLException {
+        String tenantId = "000000000000001";
+        String subStringTenantId = tenantId.substring(0, 3);
+        String parentId = "000000000000002";
+        Date createdDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (substr(organization_id, 1, 3), parent_id, created_date) >= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(subStringTenantId, parentId, createdDate);
+        Set<Expression> extractedFilters = new HashSet<Expression>(2);
+        compileStatement(query, scan, binds, extractedFilters);
+        byte[] expectedStartRow = PDataType.VARCHAR.toBytes(subStringTenantId);
+        assertTrue(extractedFilters.size() == 0);
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testUseOfFunctionOnLHSInMiddleOfRVC() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000002";
+        String subStringParentId = parentId.substring(0, 3);
+        Date createdDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (organization_id, substr(parent_id, 1, 3), created_date) >= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, subStringParentId, createdDate);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 0);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(subStringParentId));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testUseOfFunctionOnLHSInMiddleOfRVCForLTE() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000002";
+        String subStringParentId = parentId.substring(0, 3);
+        Date createdDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (organization_id, substr(parent_id, 1, 3), created_date) <= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, subStringParentId, createdDate);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 0);
+        byte[] expectedStopRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), ByteUtil.nextKey(PDataType.VARCHAR.toBytes(subStringParentId)));
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStartRow());
+        assertArrayEquals(expectedStopRow, scan.getStopRow());
+    }
+    
+    @Test
+    public void testNullAtEndOfRVC() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000002";
+        Date createdDate = null;
+        
+        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, createdDate);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.VARCHAR.toBytes(tenantId), PDataType.VARCHAR.toBytes(parentId));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testNullInMiddleOfRVC() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = null;
+        Date createdDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, createdDate);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        byte[] expectedStartRow = ByteUtil.concat(PDataType.CHAR.toBytes(tenantId), new byte[15], ByteUtil.previousKey(PDataType.DATE.toBytes(createdDate)));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testNullAtStartOfRVC() throws SQLException {
+        String tenantId = null;
+        String parentId = "000000000000002";
+        Date createdDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId, createdDate);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        byte[] expectedStartRow = ByteUtil.concat(new byte[15], ByteUtil.previousKey(PDataType.CHAR.toBytes(parentId)), PDataType.DATE.toBytes(createdDate));
+        assertArrayEquals(expectedStartRow, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testRVCInCombinationWithOtherNonRVC() throws SQLException {
+        String firstOrgId = "000000000000001";
+        String secondOrgId = "000000000000008";
+        
+        String parentId = "000000000000002";
+        Date createdDate = new Date(System.currentTimeMillis());
+        
+        String query = "select * from entity_history where (organization_id, parent_id, created_date) >= (?,?,?) AND organization_id <= ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstOrgId, parentId, createdDate, secondOrgId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 2);
+        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstOrgId), PDataType.VARCHAR.toBytes(parentId), PDataType.DATE.toBytes(createdDate)), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(secondOrgId)), scan.getStopRow());
+    }
+    
+    @Test
+    public void testGreaterThanEqualTo_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000008";
+        
+        String query = "select * from entity_history where organization_id >= (?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testGreaterThan_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000008";
+        
+        String query = "select * from entity_history where organization_id > (?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testGreaterThan() throws SQLException {
+        String tenantId = "000000000000001";
+        
+        String query = "select * from entity_history where organization_id >?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testLessThanEqualTo_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000008";
+        
+        String query = "select * from entity_history where organization_id <= (?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+    
+    @Test
+    public void testLessThan_NonRVCOnLHSAndRVCOnRHS_WithNonNullBindParams() throws SQLException {
+        String tenantId = "000000000000001";
+        String parentId = "000000000000008";
+        
+        String query = "select * from entity_history where organization_id < (?,?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(tenantId, parentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+    
+    @Test
+    public void testCombiningRVCUsingOr() throws SQLException {
+        String firstTenantId = "000000000000001";
+        String secondTenantId = "000000000000005";
+        String firstParentId = "000000000000011";
+        String secondParentId = "000000000000015";
+        
+        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR (organization_id, parent_id) <= (?, ?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId, secondParentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1); // extracts the entire OR
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testCombiningRVCUsingOr2() throws SQLException {
+        String firstTenantId = "000000000000001";
+        String secondTenantId = "000000000000005";
+        String firstParentId = "000000000000011";
+        String secondParentId = "000000000000015";
+        
+        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR (organization_id, parent_id) >= (?, ?)";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId, secondParentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstTenantId), PDataType.VARCHAR.toBytes(firstParentId)), scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testCombiningRVCWithNonRVCUsingOr() throws SQLException {
+        String firstTenantId = "000000000000001";
+        String secondTenantId = "000000000000005";
+        String firstParentId = "000000000000011";
+        
+        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR organization_id  >= ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstTenantId), PDataType.VARCHAR.toBytes(firstParentId)), scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testCombiningRVCWithNonRVCUsingOr2() throws SQLException {
+        String firstTenantId = "000000000000001";
+        String secondTenantId = "000000000000005";
+        String firstParentId = "000000000000011";
+        
+        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR organization_id  <= ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testCombiningRVCWithNonRVCUsingOr3() throws SQLException {
+        String firstTenantId = "000000000000005";
+        String secondTenantId = "000000000000001";
+        String firstParentId = "000000000000011";
+        String query = "select * from entity_history where (organization_id, parent_id) >= (?,?) OR organization_id  <= ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstTenantId, firstParentId, secondTenantId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 0);
+        assertArrayEquals(HConstants.EMPTY_START_ROW, scan.getStartRow());
+        assertArrayEquals(HConstants.EMPTY_END_ROW, scan.getStopRow());
+    }
+    
+    @Test
+    public void testUsingRVCNonFullyQualifiedInClause() throws Exception {
+        String firstOrgId = "000000000000001";
+        String secondOrgId = "000000000000009";
+        String firstParentId = "000000000000011";
+        String secondParentId = "000000000000021";
+        String query = "select * from entity_history where (organization_id, parent_id) IN ((?, ?), (?, ?))";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstOrgId, firstParentId, secondOrgId, secondParentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 0);
+        assertArrayEquals(ByteUtil.concat(PDataType.VARCHAR.toBytes(firstOrgId), PDataType.VARCHAR.toBytes(firstParentId)), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(ByteUtil.concat(PDataType.VARCHAR.toBytes(secondOrgId), PDataType.VARCHAR.toBytes(secondParentId))), scan.getStopRow());
+    }
+    
+    @Test
+    public void testUsingRVCFullyQualifiedInClause() throws Exception {
+        String firstOrgId = "000000000000001";
+        String secondOrgId = "000000000000009";
+        String firstParentId = "000000000000011";
+        String secondParentId = "000000000000021";
+        String query = "select * from atable where (organization_id, entity_id) IN ((?, ?), (?, ?))";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(firstOrgId, firstParentId, secondOrgId, secondParentId);
+        HashSet<Expression> extractedFilters = new HashSet<Expression>();
+        StatementContext context = compileStatement(query, scan, binds, extractedFilters);
+        assertTrue(extractedFilters.size() == 1);
+        List<List<KeyRange>> skipScanRanges = Collections.singletonList(Arrays.asList(
+                KeyRange.getKeyRange(ByteUtil.concat(PDataType.CHAR.toBytes(firstOrgId), PDataType.CHAR.toBytes(firstParentId))), 
+                KeyRange.getKeyRange(ByteUtil.concat(PDataType.CHAR.toBytes(secondOrgId), PDataType.CHAR.toBytes(secondParentId)))));
+        assertEquals(skipScanRanges, context.getScanRanges().getRanges());
+        assertArrayEquals(ByteUtil.concat(PDataType.CHAR.toBytes(firstOrgId), PDataType.CHAR.toBytes(firstParentId)), scan.getStartRow());
+        assertArrayEquals(ByteUtil.concat(PDataType.CHAR.toBytes(secondOrgId), PDataType.CHAR.toBytes(secondParentId), QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/query/BaseConnectionlessQueryTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/BaseConnectionlessQueryTest.java b/phoenix-core/src/test/java/org/apache/phoenix/query/BaseConnectionlessQueryTest.java
index 41c4716..f5f7928 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/query/BaseConnectionlessQueryTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/query/BaseConnectionlessQueryTest.java
@@ -35,29 +35,30 @@ import static org.apache.phoenix.util.TestUtil.TABLE_WITH_ARRAY;
 import java.sql.DriverManager;
 import java.util.Properties;
 
-import org.junit.BeforeClass;
-
 import org.apache.phoenix.coprocessor.MetaDataProtocol;
+import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.ColumnRef;
 import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.TableRef;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.TestUtil;
+import org.junit.BeforeClass;
 
 
 
 public class BaseConnectionlessQueryTest extends BaseTest {
 
     public static PTable ATABLE;
-    public static PColumn ORGANIZATION_ID;
-    public static PColumn ENTITY_ID;
-    public static PColumn A_INTEGER;
-    public static PColumn A_STRING;
-    public static PColumn B_STRING;
-    public static PColumn A_DATE;
-    public static PColumn A_TIME;
-    public static PColumn A_TIMESTAMP;
-    public static PColumn X_DECIMAL;
+    public static Expression ORGANIZATION_ID;
+    public static Expression ENTITY_ID;
+    public static Expression A_INTEGER;
+    public static Expression A_STRING;
+    public static Expression B_STRING;
+    public static Expression A_DATE;
+    public static Expression A_TIME;
+    public static Expression A_TIMESTAMP;
+    public static Expression X_DECIMAL;
     
     protected static String getUrl() {
         return TestUtil.PHOENIX_CONNECTIONLESS_JDBC_URL;
@@ -86,16 +87,15 @@ public class BaseConnectionlessQueryTest extends BaseTest {
         try {
             PTable table = conn.getPMetaData().getTable(ATABLE_NAME);
             ATABLE = table;
-            ORGANIZATION_ID = table.getColumn("ORGANIZATION_ID");
-            ENTITY_ID = table.getColumn("ENTITY_ID");
-            A_INTEGER = table.getColumn("A_INTEGER");
-            A_STRING = table.getColumn("A_STRING");
-            B_STRING = table.getColumn("B_STRING");
-            ENTITY_ID = table.getColumn("ENTITY_ID");
-            A_DATE = table.getColumn("A_DATE");
-            A_TIME = table.getColumn("A_TIME");
-            A_TIMESTAMP = table.getColumn("A_TIMESTAMP");
-            X_DECIMAL = table.getColumn("X_DECIMAL");
+            ORGANIZATION_ID = new ColumnRef(new TableRef(table), table.getColumn("ORGANIZATION_ID").getPosition()).newColumnExpression();
+            ENTITY_ID = new ColumnRef(new TableRef(table), table.getColumn("ENTITY_ID").getPosition()).newColumnExpression();
+            A_INTEGER = new ColumnRef(new TableRef(table), table.getColumn("A_INTEGER").getPosition()).newColumnExpression();
+            A_STRING = new ColumnRef(new TableRef(table), table.getColumn("A_STRING").getPosition()).newColumnExpression();
+            B_STRING = new ColumnRef(new TableRef(table), table.getColumn("B_STRING").getPosition()).newColumnExpression();
+            A_DATE = new ColumnRef(new TableRef(table), table.getColumn("A_DATE").getPosition()).newColumnExpression();
+            A_TIME = new ColumnRef(new TableRef(table), table.getColumn("A_TIME").getPosition()).newColumnExpression();
+            A_TIMESTAMP = new ColumnRef(new TableRef(table), table.getColumn("A_TIMESTAMP").getPosition()).newColumnExpression();
+            X_DECIMAL = new ColumnRef(new TableRef(table), table.getColumn("X_DECIMAL").getPosition()).newColumnExpression();
         } finally {
             conn.close();
         }


[7/8] Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompileTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompileTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompileTest.java
deleted file mode 100644
index e9c34e0..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompileTest.java
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
-import static org.apache.phoenix.util.TestUtil.assertDegenerate;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.phoenix.coprocessor.GroupedAggregateRegionObserver;
-import org.apache.phoenix.exception.SQLExceptionCode;
-import org.apache.phoenix.expression.aggregator.Aggregator;
-import org.apache.phoenix.expression.aggregator.CountAggregator;
-import org.apache.phoenix.expression.aggregator.ServerAggregators;
-import org.apache.phoenix.expression.function.TimeUnit;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-import org.apache.phoenix.query.QueryConstants;
-import org.apache.phoenix.schema.AmbiguousColumnException;
-import org.apache.phoenix.schema.ColumnAlreadyExistsException;
-import org.apache.phoenix.schema.ColumnNotFoundException;
-import org.apache.phoenix.schema.PColumn;
-import org.apache.phoenix.util.ByteUtil;
-import org.apache.phoenix.util.PhoenixRuntime;
-import org.apache.phoenix.util.SchemaUtil;
-import org.apache.phoenix.util.TestUtil;
-import org.junit.Test;
-
-
-
-/**
- * 
- * Tests for compiling a query
- * The compilation stage finds additional errors that can't be found at parse
- * time so this is a good place for negative tests (since the mini-cluster
- * is not necessary enabling the tests to run faster).
- *
- * 
- * @since 0.1
- */
-@edu.umd.cs.findbugs.annotations.SuppressWarnings(
-        value="RV_RETURN_VALUE_IGNORED",
-        justification="Test code.")
-public class QueryCompileTest extends BaseConnectionlessQueryTest {
-
-    @Test
-    public void testParameterUnbound() throws Exception {
-        try {
-            String query = "SELECT a_string, b_string FROM atable WHERE organization_id=? and a_integer = ?";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("Parameter 2 is unbound"));
-        }
-    }
-
-    @Test
-    public void testMultiPKDef() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (pk1 integer not null primary key, pk2 bigint not null primary key)";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 510 (42889): The table already has a primary key. columnName=PK2"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testPKDefAndPKConstraint() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (pk integer not null primary key, col1 decimal, col2 decimal constraint my_pk primary key (col1,col2))";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 510 (42889): The table already has a primary key. columnName=PK"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testFamilyNameInPK() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (a.pk integer not null primary key, col1 decimal, col2 decimal)";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertEquals(e.getErrorCode(), SQLExceptionCode.PRIMARY_KEY_WITH_FAMILY_NAME.getErrorCode());
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testSameColumnNameInPKAndNonPK() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE t1 (k integer not null primary key, a.k decimal, b.k decimal)";
-            conn.createStatement().execute(query);
-            PColumn c = conn.unwrap(PhoenixConnection.class).getPMetaData().getTable("T1").getColumn("K");
-            assertTrue(SchemaUtil.isPKColumn(c));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testVarBinaryInMultipartPK() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        // When the VARBINARY key is the last column, it is allowed.
-        String query = "CREATE TABLE foo (a_string varchar not null, b_string varchar not null, a_binary varbinary not null, " +
-                "col1 decimal, col2 decimal CONSTRAINT pk PRIMARY KEY (a_string, b_string, a_binary))";
-        PreparedStatement statement = conn.prepareStatement(query);
-        statement.execute();
-        try {
-            // VARBINARY key is not allowed in the middle of the key.
-            query = "CREATE TABLE foo (a_binary varbinary not null, a_string varchar not null, col1 decimal, col2 decimal CONSTRAINT pk PRIMARY KEY (a_binary, a_string))";
-            statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1005 (42J03): The VARBINARY type can only be used as the last part of a multi-part row key. columnName=FOO.A_BINARY"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testNoPK() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (pk integer not null, col1 decimal, col2 decimal)";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 509 (42888): The table does not have a primary key. tableName=FOO"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testUnknownFamilyNameInTableOption() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (pk integer not null primary key, a.col1 decimal, b.col2 decimal) c.my_property='foo'";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("Properties may not be defined for an unused family name"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testInvalidGroupedAggregation() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT count(1),a_integer FROM atable WHERE organization_id=? GROUP BY a_string";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER"));
-        }
-    }
-
-    @Test
-    public void testInvalidGroupExpressionAggregation() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT sum(a_integer) + a_integer FROM atable WHERE organization_id=? GROUP BY a_string";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER"));
-        }
-    }
-
-    @Test
-    public void testAggInWhereClause() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT a_integer FROM atable WHERE organization_id=? AND count(1) > 2";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1017 (42Y26): Aggregate may not be used in WHERE."));
-        }
-    }
-
-    @Test
-    public void testHavingAggregateQuery() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT a_integer FROM atable WHERE organization_id=? HAVING count(1) > 2";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER"));
-        }
-    }
-
-    @Test
-    public void testNonAggInHavingClause() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT a_integer FROM atable WHERE organization_id=? HAVING a_integer = 5";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1019 (42Y26): Only aggregate maybe used in the HAVING clause."));
-        }
-    }
-
-    @Test
-    public void testTypeMismatchInCase() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT a_integer FROM atable WHERE organization_id=? HAVING CASE WHEN a_integer <= 2 THEN 'foo' WHEN a_integer = 3 THEN 2 WHEN a_integer <= 5 THEN 5 ELSE 5 END  = 5";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("Case expressions must have common type"));
-        }
-    }
-
-    @Test
-    public void testNonBooleanWhereExpression() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "SELECT a_integer FROM atable WHERE organization_id=? and CASE WHEN a_integer <= 2 THEN 'foo' WHEN a_integer = 3 THEN 'bar' WHEN a_integer <= 5 THEN 'bas' ELSE 'blah' END";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("ERROR 203 (22005): Type mismatch. BOOLEAN and VARCHAR for CASE WHEN A_INTEGER <= 2 THEN 'foo'WHEN A_INTEGER = 3 THEN 'bar'WHEN A_INTEGER <= 5 THEN 'bas' ELSE 'blah' END"));
-        }
-    }
-
-    @Test
-    public void testNoSCNInConnectionProps() throws Exception {
-        Properties props = new Properties();
-        DriverManager.getConnection(getUrl(), props);
-    }
-    
-
-    @Test
-    public void testPercentileWrongQueryWithMixOfAggrAndNonAggrExps() throws Exception {
-        String query = "select a_integer, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
-        try {
-            compileQuery(query, Collections.emptyList());
-            fail();
-        } catch (SQLException e) {
-            assertEquals("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_INTEGER",
-                    e.getMessage());
-        }
-    }
-
-    @Test
-    public void testPercentileWrongQuery1() throws Exception {
-        String query = "select PERCENTILE_CONT('*') WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
-        try {
-            compileQuery(query, Collections.emptyList());
-            fail();
-        } catch (SQLException e) {
-            assertEquals(
-                    "ERROR 203 (22005): Type mismatch. expected: [DECIMAL] but was: VARCHAR at PERCENTILE_CONT argument 3",
-                    e.getMessage());
-        }
-    }
-
-    @Test
-    public void testPercentileWrongQuery2() throws Exception {
-        String query = "select PERCENTILE_CONT(1.1) WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
-        try {
-            compileQuery(query, Collections.emptyList());
-            fail();
-        } catch (SQLException e) {
-            assertEquals(
-                    "ERROR 213 (22003): Value outside range. expected: [0 , 1] but was: 1.1 at PERCENTILE_CONT argument 3",
-                    e.getMessage());
-        }
-    }
-
-    @Test
-    public void testPercentileWrongQuery3() throws Exception {
-        String query = "select PERCENTILE_CONT(-1) WITHIN GROUP (ORDER BY a_integer ASC) from ATABLE";
-        try {
-            compileQuery(query, Collections.emptyList());
-            fail();
-        } catch (Exception e) {
-            assertEquals(
-                    "ERROR 213 (22003): Value outside range. expected: [0 , 1] but was: -1 at PERCENTILE_CONT argument 3",
-                    e.getMessage());
-        }
-    }
-
-    private Scan compileQuery(String query, List<Object> binds) throws SQLException {
-        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(getUrl(), props);
-        try {
-            PhoenixPreparedStatement statement = conn.prepareStatement(query).unwrap(PhoenixPreparedStatement.class);
-            for (Object bind : binds) {
-                statement.setObject(1, bind);
-            }
-            QueryPlan plan = statement.compileQuery(query);
-            return plan.getContext().getScan();
-        } finally {
-            conn.close();
-        }
-    }
-    
-    @Test
-    public void testKeyOrderedGroupByOptimization() throws Exception {
-        // Select columns in PK
-        String[] queries = new String[] {
-            "SELECT count(1) FROM atable GROUP BY organization_id,entity_id",
-            "SELECT count(1) FROM atable GROUP BY organization_id,substr(entity_id,1,3),entity_id",
-            "SELECT count(1) FROM atable GROUP BY entity_id,organization_id",
-            "SELECT count(1) FROM atable GROUP BY substr(entity_id,1,3),organization_id",
-            "SELECT count(1) FROM ptsdb GROUP BY host,inst,round(date,'HOUR')",
-            "SELECT count(1) FROM atable GROUP BY organization_id",
-        };
-        List<Object> binds = Collections.emptyList();
-        for (String query : queries) {
-            Scan scan = compileQuery(query, binds);
-            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.KEY_ORDERED_GROUP_BY_EXPRESSIONS) != null);
-            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.UNORDERED_GROUP_BY_EXPRESSIONS) == null);
-        }
-    }
-
-    @Test
-    public void testNullInScanKey() throws Exception {
-        // Select columns in PK
-        String query = "select val from ptsdb where inst is null and host='a'";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        // Projects column family with not null column
-        assertNull(scan.getFilter());
-        assertEquals(1,scan.getFamilyMap().keySet().size());
-        assertArrayEquals(Bytes.toBytes(SchemaUtil.normalizeIdentifier(QueryConstants.DEFAULT_COLUMN_FAMILY)), scan.getFamilyMap().keySet().iterator().next());
-    }
-
-    @Test
-    public void testOnlyNullInScanKey() throws Exception {
-        // Select columns in PK
-        String query = "select val from ptsdb where inst is null";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        // Projects column family with not null column
-        assertEquals(1,scan.getFamilyMap().keySet().size());
-        assertArrayEquals(Bytes.toBytes(SchemaUtil.normalizeIdentifier(QueryConstants.DEFAULT_COLUMN_FAMILY)), scan.getFamilyMap().keySet().iterator().next());
-    }
-
-    @Test
-    public void testIsNullOnNotNullable() throws Exception {
-        // Select columns in PK
-        String query = "select a_string from atable where entity_id is null";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        assertDegenerate(scan);
-    }
-
-    @Test
-    public void testIsNotNullOnNotNullable() throws Exception {
-        // Select columns in PK
-        String query = "select a_string from atable where entity_id is not null";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        assertNull(scan.getFilter());
-        assertTrue(scan.getStartRow().length == 0);
-        assertTrue(scan.getStopRow().length == 0);
-    }
-
-    @Test
-    public void testUpsertTypeMismatch() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "upsert into ATABLE VALUES (?, ?, ?)";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.setString(2, "00D300000000XHP");
-                statement.setInt(3, 1);
-                statement.executeUpdate();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) { // TODO: use error codes
-            assertTrue(e.getMessage().contains("Type mismatch"));
-        }
-    }
-
-    @Test
-    public void testUpsertMultiByteIntoChar() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "upsert into ATABLE VALUES (?, ?, ?)";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.setString(1, "00D300000000XHP");
-                statement.setString(2, "繰り返し曜日マスク");
-                statement.setInt(3, 1);
-                statement.executeUpdate();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 201 (22000): Illegal data."));
-            assertTrue(e.getCause().getMessage().contains("CHAR types may only contain single byte characters"));
-        }
-    }
-
-    @Test
-    public void testSelectStarOnGroupBy() throws Exception {
-        try {
-            // Select non agg column in aggregate query
-            String query = "select * from ATABLE group by a_string";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY."));
-        }
-    }
-
-    @Test
-    public void testOrderByAggSelectNonAgg() throws Exception {
-        try {
-            // Order by in select with no limit or group by
-            String query = "select a_string from ATABLE order by max(b_string)";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_STRING"));
-        }
-    }
-
-    @Test
-    public void testOrderByAggAndNonAgg() throws Exception {
-        try {
-            // Order by in select with no limit or group by
-            String query = "select max(a_string) from ATABLE order by max(b_string),a_string";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. A_STRING"));
-        }
-    }
-
-    @Test
-    public void testOrderByNonAggSelectAgg() throws Exception {
-        try {
-            // Order by in select with no limit or group by
-            String query = "select max(a_string) from ATABLE order by b_string LIMIT 5";
-            Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-            Connection conn = DriverManager.getConnection(getUrl(), props);
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.executeQuery();
-                fail();
-            } finally {
-                conn.close();
-            }
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1018 (42Y27): Aggregate may not contain columns not in GROUP BY. B_STRING"));
-        }
-    }
-
-    @Test
-    public void testNotKeyOrderedGroupByOptimization() throws Exception {
-        // Select columns in PK
-        String[] queries = new String[] {
-            "SELECT count(1) FROM atable GROUP BY entity_id",
-            "SELECT count(1) FROM atable GROUP BY substr(organization_id,2,3)",
-            "SELECT count(1) FROM atable GROUP BY substr(entity_id,1,3)",
-            "SELECT count(1) FROM atable GROUP BY to_date(organization_id)",
-            "SELECT count(1) FROM atable GROUP BY regexp_substr(organization_id, '.*foo.*'),entity_id",
-            "SELECT count(1) FROM atable GROUP BY substr(organization_id,1),entity_id",
-        };
-        List<Object> binds = Collections.emptyList();
-        for (String query : queries) {
-            Scan scan = compileQuery(query, binds);
-            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.KEY_ORDERED_GROUP_BY_EXPRESSIONS) == null);
-            assertTrue(query, scan.getAttribute(GroupedAggregateRegionObserver.UNORDERED_GROUP_BY_EXPRESSIONS) != null);
-        }
-    }
-    
-    @Test
-    public void testFunkyColumnNames() throws Exception {
-        // Select columns in PK
-        String[] queries = new String[] {
-            "SELECT \"foo!\",\"foo.bar-bas\",\"#@$\",\"_blah^\" FROM FUNKY_NAMES",
-            "SELECT count(\"foo!\"),\"_blah^\" FROM FUNKY_NAMES WHERE \"foo.bar-bas\"='x' GROUP BY \"#@$\",\"_blah^\"",
-        };
-        List<Object> binds = Collections.emptyList();
-        for (String query : queries) {
-            compileQuery(query, binds);
-        }
-    }
-    
-    @Test
-    public void testCountAggregatorFirst() throws Exception {
-        String[] queries = new String[] {
-            "SELECT sum(2.5),organization_id FROM atable GROUP BY organization_id,entity_id",
-            "SELECT avg(a_integer) FROM atable GROUP BY organization_id,substr(entity_id,1,3),entity_id",
-            "SELECT count(a_string) FROM atable GROUP BY substr(organization_id,1),entity_id",
-            "SELECT min('foo') FROM atable GROUP BY entity_id,organization_id",
-            "SELECT min('foo'),sum(a_integer),avg(2.5),4.5,max(b_string) FROM atable GROUP BY substr(organization_id,1),entity_id",
-            "SELECT sum(2.5) FROM atable",
-            "SELECT avg(a_integer) FROM atable",
-            "SELECT count(a_string) FROM atable",
-            "SELECT min('foo') FROM atable LIMIT 5",
-            "SELECT min('foo'),sum(a_integer),avg(2.5),4.5,max(b_string) FROM atable",
-        };
-        List<Object> binds = Collections.emptyList();
-        String query = null;
-        try {
-            for (int i = 0; i < queries.length; i++) {
-                query = queries[i];
-                Scan scan = compileQuery(query, binds);
-                ServerAggregators aggregators = ServerAggregators.deserialize(scan.getAttribute(GroupedAggregateRegionObserver.AGGREGATORS), null);
-                Aggregator aggregator = aggregators.getAggregators()[0];
-                assertTrue(aggregator instanceof CountAggregator);
-            }
-        } catch (Exception e) {
-            throw new Exception(query, e);
-        }
-    }
-
-    @Test
-    public void testInvalidArithmetic() throws Exception {
-        String[] queries = new String[] { 
-                "SELECT entity_id,organization_id FROM atable where A_STRING - 5.5 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_DATE - 'transaction' < 0",
-                "SELECT entity_id,organization_id FROM atable where A_DATE * 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_DATE / 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where 45 - A_DATE < 0",
-                "SELECT entity_id,organization_id FROM atable where A_DATE - to_date('2000-01-01 12:00:00') < to_date('2000-02-01 12:00:00')", // RHS must be number
-                "SELECT entity_id,organization_id FROM atable where A_DATE - A_DATE + 1 < A_DATE", // RHS must be number
-                "SELECT entity_id,organization_id FROM atable where A_DATE + 2 < 0", // RHS must be date
-                "SELECT entity_id,organization_id FROM atable where 45.5 - A_DATE < 0",
-                "SELECT entity_id,organization_id FROM atable where 1 + A_DATE + A_DATE < A_DATE",
-                "SELECT entity_id,organization_id FROM atable where A_STRING - 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_STRING / 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_STRING * 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_STRING + 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_STRING - 45 < 0",
-                "SELECT entity_id,organization_id FROM atable where A_STRING - 'transaction' < 0", };
-
-        Properties props = new Properties(TestUtil.TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(getUrl(), props);
-        for (String query : queries) {
-            try {
-                PreparedStatement statement = conn.prepareStatement(query);
-                statement.executeQuery();
-                fail(query);
-            } catch (SQLException e) {
-                if (e.getMessage().contains("ERROR 203 (22005): Type mismatch.")) {
-                    continue;
-                }
-                throw new IllegalStateException("Didn't find type mismatch: " + query, e);
-            }
-        }
-    }
-    
-    
-    @Test
-    public void testAmbiguousColumn() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT * from multi_cf G where RESPONSE_TIME = 2222";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (AmbiguousColumnException e) { // expected
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testTableAliasMatchesCFName() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT F.RESPONSE_TIME,G.RESPONSE_TIME from multi_cf G where G.RESPONSE_TIME-1 = F.RESPONSE_TIME";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (AmbiguousColumnException e) { // expected
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testCoelesceFunctionTypeMismatch() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT coalesce(x_integer,'foo') from atable";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 507 (42846): Cannot convert type. COALESCE expected INTEGER, but got VARCHAR"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testOrderByNotInSelectDistinct() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT distinct a_string,b_string from atable order by x_integer";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertEquals(SQLExceptionCode.ORDER_BY_NOT_IN_SELECT_DISTINCT.getErrorCode(), e.getErrorCode());
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testSelectDistinctAndAll() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT all distinct a_string,b_string from atable order by x_integer";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertEquals(SQLExceptionCode.PARSER_ERROR.getErrorCode(), e.getErrorCode());
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testOrderByNotInSelectDistinctAgg() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT distinct count(1) from atable order by x_integer";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertEquals(SQLExceptionCode.ORDER_BY_NOT_IN_SELECT_DISTINCT.getErrorCode(), e.getErrorCode());
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testSelectDistinctWithAggregation() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT distinct a_string,count(*) from atable";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertEquals(SQLExceptionCode.AGGREGATE_WITH_NOT_GROUP_BY_COLUMN.getErrorCode(), e.getErrorCode());
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test 
-    public void testRegexpSubstrSetScanKeys() throws Exception {
-        // First test scan keys are set when the offset is 0 or 1. 
-        String query = "SELECT host FROM ptsdb WHERE regexp_substr(inst, '[a-zA-Z]+') = 'abc'";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(ByteUtil.nextKey(Bytes.toBytes("abc")),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-        assertTrue(scan.getFilter() != null);
-
-        query = "SELECT host FROM ptsdb WHERE regexp_substr(inst, '[a-zA-Z]+', 0) = 'abc'";
-        binds = Collections.emptyList();
-        scan = compileQuery(query, binds);
-        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(ByteUtil.nextKey(Bytes.toBytes("abc")),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-        assertTrue(scan.getFilter() != null);
-
-        // Test scan keys are not set when the offset is not 0 or 1.
-        query = "SELECT host FROM ptsdb WHERE regexp_substr(inst, '[a-zA-Z]+', 3) = 'abc'";
-        binds = Collections.emptyList();
-        scan = compileQuery(query, binds);
-        assertTrue(scan.getStartRow().length == 0);
-        assertTrue(scan.getStopRow().length == 0);
-        assertTrue(scan.getFilter() != null);
-    }
-    
-    @Test
-    public void testStringConcatExpression() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT entity_id,a_string FROM atable where 2 || a_integer || ? like '2%'";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Properties props = new Properties(TEST_PROPERTIES);
-        Connection conn = DriverManager.getConnection(url, props);
-        byte []x=new byte[]{127,127,0,0};//Binary data
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.setBytes(1, x);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertTrue(e.getMessage().contains("Concatenation does not support"));
-        } finally {
-            conn.close();
-        }
-    }
-    
-    @Test
-    public void testDivideByBigDecimalZero() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT a_integer/x_integer/0.0 FROM atable";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Connection conn = DriverManager.getConnection(url);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertTrue(e.getMessage().contains("Divide by zero"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testDivideByIntegerZero() throws Exception {
-        long ts = nextTimestamp();
-        String query = "SELECT a_integer/0 FROM atable";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Connection conn = DriverManager.getConnection(url);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.executeQuery();
-            fail();
-        } catch (SQLException e) { // expected
-            assertTrue(e.getMessage().contains("Divide by zero"));
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testCreateNullableInPKMiddle() throws Exception {
-        long ts = nextTimestamp();
-        String query = "CREATE TABLE foo(i integer not null, j integer null, k integer not null CONSTRAINT pk PRIMARY KEY(i,j,k))";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Connection conn = DriverManager.getConnection(url);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) { // expected
-            assertTrue(e.getMessage().contains("PK columns may not be both fixed width and nullable"));
-        }
-    }
-
-    @Test
-    public void testSetSaltBucketOnAlterTable() throws Exception {
-        long ts = nextTimestamp();
-        String query = "ALTER TABLE atable ADD xyz INTEGER SALT_BUCKETS=4";
-        String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 5); // Run query at timestamp 5
-        Connection conn = DriverManager.getConnection(url);
-        try {
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) { // expected
-            assertTrue(e.getErrorCode() == SQLExceptionCode.SALT_ONLY_ON_CREATE_TABLE.getErrorCode());
-        }
-    }
-
-    @Test
-    public void testSubstrSetScanKey() throws Exception {
-        String query = "SELECT inst FROM ptsdb WHERE substr(inst, 0, 3) = 'abc'";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abd"),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-        assertTrue(scan.getFilter() == null); // Extracted.
-    }
-
-    @Test
-    public void testRTrimSetScanKey() throws Exception {
-        String query = "SELECT inst FROM ptsdb WHERE rtrim(inst) = 'abc'";
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery(query, binds);
-        assertArrayEquals(ByteUtil.concat(Bytes.toBytes("abc")), scan.getStartRow());
-        assertArrayEquals(ByteUtil.concat(ByteUtil.nextKey(Bytes.toBytes("abc ")),QueryConstants.SEPARATOR_BYTE_ARRAY), scan.getStopRow());
-        assertNotNull(scan.getFilter());
-    }
-    
-    @Test
-    public void testCastingIntegerToDecimalInSelect() throws Exception {
-        String query = "SELECT CAST a_integer AS DECIMAL/2 FROM aTable WHERE 5=a_integer";
-        List<Object> binds = Collections.emptyList();
-        compileQuery(query, binds);
-    }
-    
-    @Test
-    public void testCastingStringToDecimalInSelect() throws Exception {
-        String query = "SELECT CAST b_string AS DECIMAL/2 FROM aTable WHERE 5=a_integer";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a string to decimal isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testCastingStringToDecimalInWhere() throws Exception {
-        String query = "SELECT a_integer FROM aTable WHERE 2.5=CAST b_string AS DECIMAL/2 ";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a string to decimal isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }  
-    }
-    
-    @Test
-    public void testUsingNonComparableDataTypesInRowValueConstructorFails() throws Exception {
-        String query = "SELECT a_integer, x_integer FROM aTable WHERE (a_integer, x_integer) > (2, 'abc')";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a integer to string isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testUsingNonComparableDataTypesOfColumnRefOnLHSAndRowValueConstructorFails() throws Exception {
-        String query = "SELECT a_integer, x_integer FROM aTable WHERE a_integer > ('abc', 2)";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a integer to string isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testUsingNonComparableDataTypesOfLiteralOnLHSAndRowValueConstructorFails() throws Exception {
-        String query = "SELECT a_integer, x_integer FROM aTable WHERE 'abc' > (a_integer, x_integer)";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a integer to string isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testUsingNonComparableDataTypesOfColumnRefOnRHSAndRowValueConstructorFails() throws Exception {
-        String query = "SELECT a_integer, x_integer FROM aTable WHERE ('abc', 2) < a_integer ";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a integer to string isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testUsingNonComparableDataTypesOfLiteralOnRHSAndRowValueConstructorFails() throws Exception {
-        String query = "SELECT a_integer, x_integer FROM aTable WHERE (a_integer, x_integer) < 'abc'";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since casting a integer to string isn't supported");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.TYPE_MISMATCH.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testNonConstantInList() throws Exception {
-        String query = "SELECT a_integer, x_integer FROM aTable WHERE a_integer IN (x_integer)";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since non constants in IN is not valid");
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.VALUE_IN_LIST_NOT_CONSTANT.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testKeyValueColumnInPKConstraint() throws Exception {
-        String ddl = "CREATE TABLE t (a.k VARCHAR, b.v VARCHAR CONSTRAINT pk PRIMARY KEY(k))";
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(ddl);
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getErrorCode() == SQLExceptionCode.PRIMARY_KEY_WITH_FAMILY_NAME.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testUnknownColumnInPKConstraint() throws Exception {
-        String ddl = "CREATE TABLE t (k1 VARCHAR, b.v VARCHAR CONSTRAINT pk PRIMARY KEY(k1, k2))";
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(ddl);
-            fail();
-        } catch (ColumnNotFoundException e) {
-            assertEquals("K2",e.getColumnName());
-        }
-    }
-    
-    
-    @Test
-    public void testDuplicatePKColumn() throws Exception {
-        String ddl = "CREATE TABLE t (k1 VARCHAR, k1 VARCHAR CONSTRAINT pk PRIMARY KEY(k1))";
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(ddl);
-            fail();
-        } catch (ColumnAlreadyExistsException e) {
-            assertEquals("K1",e.getColumnName());
-        }
-    }
-    
-    
-    @Test
-    public void testDuplicateKVColumn() throws Exception {
-        String ddl = "CREATE TABLE t (k1 VARCHAR, v1 VARCHAR, v2 VARCHAR, v1 INTEGER CONSTRAINT pk PRIMARY KEY(k1))";
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(ddl);
-            fail();
-        } catch (ColumnAlreadyExistsException e) {
-            assertEquals("V1",e.getColumnName());
-        }
-    }
-    
-    @Test
-    public void testDeleteFromImmutableWithKV() throws Exception {
-        String ddl = "CREATE TABLE t (k1 VARCHAR, v1 VARCHAR, v2 VARCHAR CONSTRAINT pk PRIMARY KEY(k1)) immutable_rows=true";
-        String indexDDL = "CREATE INDEX i ON t (v1)";
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(ddl);
-            conn.createStatement().execute(indexDDL);
-            conn.createStatement().execute("DELETE FROM t");
-            fail();
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.NO_DELETE_IF_IMMUTABLE_INDEX.getErrorCode(), e.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testInvalidNegativeArrayIndex() throws Exception {
-    	String query = "SELECT a_double_array[-20] FROM table_with_array";
-    	Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(query);
-            fail();
-        } catch (Exception e) {
-        	
-        }
-    }
-    @Test
-    public void testWrongDataTypeInRoundFunction() throws Exception {
-        String query = "SELECT ROUND(a_string, 'day', 1) FROM aTable";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since VARCHAR is not a valid data type for ROUND");
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testNonArrayColumnWithIndex() throws Exception {
-    	String query = "SELECT a_float[1] FROM table_with_array";
-    	Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            conn.createStatement().execute(query);
-            fail();
-        } catch (Exception e) {
-        }
-    }
-
-    public void testWrongTimeUnitInRoundDateFunction() throws Exception {
-        String query = "SELECT ROUND(a_date, 'dayss', 1) FROM aTable";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since dayss is not a valid time unit type");
-        } catch (IllegalArgumentException e) {
-            assertTrue(e.getMessage().contains(TimeUnit.VALID_VALUES));
-        }
-    }
-    
-    @Test
-    public void testWrongMultiplierInRoundDateFunction() throws Exception {
-        String query = "SELECT ROUND(a_date, 'days', 1.23) FROM aTable";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since multiplier can be an INTEGER only");
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testTypeMismatchForArrayElem() throws Exception {
-        String query = "SELECT (a_string,a_date)[1] FROM aTable";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since a row value constructor is not an array");
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testTypeMismatch2ForArrayElem() throws Exception {
-        String query = "SELECT ROUND(a_date, 'days', 1.23)[1] FROM aTable";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileQuery(query, binds);
-            fail("Compilation should have failed since ROUND does not return an array");
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.TYPE_MISMATCH.getErrorCode(), e.getErrorCode());
-        }
-    }
-    
-    @Test
-    public void testInvalidArrayTypeAsPK () throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (col1 INTEGER[10] NOT NULL PRIMARY KEY)";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-                assertEquals(SQLExceptionCode.ARRAY_NOT_ALLOWED_IN_PRIMARY_KEY.getErrorCode(), e.getErrorCode());
-        } finally {
-                conn.close();
-        }
-
-        conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (col1 VARCHAR, col2 INTEGER ARRAY[10] CONSTRAINT pk PRIMARY KEY (col1, col2))";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.ARRAY_NOT_ALLOWED_IN_PRIMARY_KEY.getErrorCode(), e.getErrorCode());
-        } finally {
-            conn.close();
-        }
-    }
-
-    @Test
-    public void testInvalidArraySize() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        try {
-            String query = "CREATE TABLE foo (col1 INTEGER[-1] NOT NULL PRIMARY KEY)";
-            PreparedStatement statement = conn.prepareStatement(query);
-            statement.execute();
-            fail();
-        } catch (SQLException e) {
-                assertEquals(SQLExceptionCode.MISMATCHED_TOKEN.getErrorCode(), e.getErrorCode());
-        } finally {
-                conn.close();
-        }
-    }
-
-    @Test
-    public void testInvalidArrayInQuery () throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        conn.createStatement().execute("CREATE TABLE t (k VARCHAR PRIMARY KEY, a INTEGER[10], B INTEGER[10])");
-        try {
-            conn.createStatement().execute("SELECT * FROM t ORDER BY a");
-            fail();
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.ORDER_BY_ARRAY_NOT_SUPPORTED.getErrorCode(), e.getErrorCode());
-        }
-        try {
-            conn.createStatement().execute("SELECT * FROM t WHERE a < b");
-            fail();
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.NON_EQUALITY_ARRAY_COMPARISON.getErrorCode(), e.getErrorCode());
-        }
-        conn.close();
-    }
-
-    @Test
-    public void testInvalidArrayElemRefInUpsert() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        conn.createStatement().execute("CREATE TABLE t (k VARCHAR PRIMARY KEY, a INTEGER[10], B INTEGER[10])");
-        try {
-            conn.createStatement().execute("UPSERT INTO t(k,a[2]) VALUES('A', 5)");
-            fail();
-        } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.PARSER_ERROR.getErrorCode(), e.getErrorCode());
-        }
-        conn.close();
-    }
-
-    @Test
-    public void testInvalidNextValueFor() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        conn.createStatement().execute("CREATE SEQUENCE alpha.zeta");
-        String[] queries = {
-                "SELECT * FROM aTable WHERE a_integer < next value for alpha.zeta",
-                "SELECT * FROM aTable GROUP BY a_string,next value for alpha.zeta",
-                "SELECT * FROM aTable GROUP BY 1 + next value for alpha.zeta",
-                "SELECT * FROM aTable GROUP BY a_integer HAVING a_integer < next value for alpha.zeta",
-                "SELECT * FROM aTable WHERE a_integer < 3 GROUP BY a_integer HAVING a_integer < next value for alpha.zeta",
-                "SELECT * FROM aTable ORDER BY next value for alpha.zeta",
-                "SELECT max(next value for alpha.zeta) FROM aTable",
-        };
-        for (String query : queries) {
-            List<Object> binds = Collections.emptyList();
-            try {
-                compileQuery(query, binds);
-                fail("Compilation should have failed since this is an invalid usage of NEXT VALUE FOR: " + query);
-            } catch (SQLException e) {
-                assertEquals(SQLExceptionCode.INVALID_USE_OF_NEXT_VALUE_FOR.getErrorCode(), e.getErrorCode());
-            }
-        }
-    }
-
-    @Test
-    public void testNoCachingHint() throws Exception {
-        List<Object> binds = Collections.emptyList();
-        Scan scan = compileQuery("select val from ptsdb", binds);
-        assertTrue(scan.getCacheBlocks());
-        scan = compileQuery("select /*+ NO_CACHE */ val from ptsdb", binds);
-        assertFalse(scan.getCacheBlocks());
-        scan = compileQuery("select /*+ NO_CACHE */ p1.val from ptsdb p1 inner join ptsdb p2 on p1.inst = p2.inst", binds);
-        assertFalse(scan.getCacheBlocks());
-    }
-
-}


[8/8] git commit: Fix failing unit test, rename tests for consistency

Posted by ja...@apache.org.
Fix failing unit test, rename tests for consistency


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

Branch: refs/heads/master
Commit: 0ea954eaeaf8a5543ea2c5bae6baa61cbb508381
Parents: fe18e96
Author: James Taylor <ja...@apache.org>
Authored: Mon Feb 10 09:13:55 2014 -0800
Committer: James Taylor <ja...@apache.org>
Committed: Mon Feb 10 09:13:55 2014 -0800

----------------------------------------------------------------------
 .../TrackOrderPreservingExpressionCompiler.java |    6 +-
 .../phoenix/expression/InListExpression.java    |    6 +-
 .../org/apache/phoenix/schema/PDataType.java    |   10 +-
 .../phoenix/compile/HavingClauseTest.java       |  194 ---
 .../phoenix/compile/HavingCompilerTest.java     |  191 +++
 .../phoenix/compile/JoinQueryCompileTest.java   |  146 --
 .../phoenix/compile/JoinQueryCompilerTest.java  |  146 ++
 .../apache/phoenix/compile/LimitClauseTest.java |  157 --
 .../phoenix/compile/LimitCompilerTest.java      |  157 ++
 .../phoenix/compile/QueryCompileTest.java       | 1313 --------------
 .../phoenix/compile/QueryCompilerTest.java      | 1313 ++++++++++++++
 .../apache/phoenix/compile/ViewCompileTest.java |  119 --
 .../phoenix/compile/ViewCompilerTest.java       |  119 ++
 .../phoenix/compile/WhereClauseCompileTest.java |  932 ----------
 .../compile/WhereClauseOptimizerTest.java       | 1620 ------------------
 .../phoenix/compile/WhereCompilerTest.java      |  931 ++++++++++
 .../phoenix/compile/WhereOptimizerTest.java     | 1620 ++++++++++++++++++
 .../query/BaseConnectionlessQueryTest.java      |   44 +-
 .../java/org/apache/phoenix/util/TestUtil.java  |    4 +-
 19 files changed, 4506 insertions(+), 4522 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
index 9600e55..a167fe6 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
@@ -5,8 +5,6 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
 import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.expression.LiteralExpression;
@@ -17,10 +15,12 @@ import org.apache.phoenix.parse.ColumnParseNode;
 import org.apache.phoenix.parse.DivideParseNode;
 import org.apache.phoenix.parse.MultiplyParseNode;
 import org.apache.phoenix.parse.SubtractParseNode;
-import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.ColumnRef;
+import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.util.SchemaUtil;
 
+import com.google.common.collect.Lists;
+
 /**
  * Visitor that builds the expressions of a GROUP BY and ORDER BY clause. While traversing
  * the parse node tree, the visitor also determines if the natural key order of the scan

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
index dfd073a..8a49999 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
@@ -33,11 +33,6 @@ import org.apache.hadoop.hbase.index.util.ImmutableBytesPtr;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.io.WritableUtils;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import org.apache.hadoop.hbase.index.util.ImmutableBytesPtr;
 import org.apache.phoenix.expression.visitor.ExpressionVisitor;
 import org.apache.phoenix.schema.ConstraintViolationException;
 import org.apache.phoenix.schema.PDataType;
@@ -48,6 +43,7 @@ import org.apache.phoenix.util.ByteUtil;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
+
 /*
  * Implementation of a SQL foo IN (a,b,c) expression. Other than the first
  * expression, child expressions must be constants.

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
index b2b4af6..fd21e09 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
@@ -33,14 +33,6 @@ import java.util.Map;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.hadoop.hbase.util.Base64;
 import org.apache.hadoop.hbase.util.Bytes;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.math.LongMath;
-import com.google.common.primitives.Booleans;
-import com.google.common.primitives.Doubles;
-import com.google.common.primitives.Longs;
-
 import org.apache.phoenix.query.KeyRange;
 import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.util.ByteUtil;
@@ -48,13 +40,13 @@ import org.apache.phoenix.util.DateUtil;
 import org.apache.phoenix.util.NumberUtil;
 import org.apache.phoenix.util.StringUtil;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.math.LongMath;
 import com.google.common.primitives.Booleans;
 import com.google.common.primitives.Doubles;
 import com.google.common.primitives.Longs;
 
-
 /**
  * The data types of PColumns
  *

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingClauseTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingClauseTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingClauseTest.java
deleted file mode 100644
index 0a36e8b..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingClauseTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
-import static org.apache.phoenix.util.TestUtil.and;
-import static org.apache.phoenix.util.TestUtil.constantComparison;
-import static org.apache.phoenix.util.TestUtil.kvColumn;
-import static org.apache.phoenix.util.TestUtil.or;
-import static org.apache.phoenix.util.TestUtil.pkColumn;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.sql.Date;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
-import org.junit.Test;
-
-import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
-import org.apache.phoenix.expression.Expression;
-import org.apache.phoenix.expression.LiteralExpression;
-import org.apache.phoenix.expression.function.CountAggregateFunction;
-import org.apache.phoenix.expression.function.RoundDateExpression;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.jdbc.PhoenixStatement;
-import org.apache.phoenix.parse.SQLParser;
-import org.apache.phoenix.parse.SelectStatement;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-
-
-public class HavingClauseTest extends BaseConnectionlessQueryTest {
-    private static StatementContext context;
-    
-    private static class Expressions {
-        private Expression whereClause;
-        private Expression havingClause;
-        
-        private Expressions(Expression whereClause, Expression havingClause) {
-            this.whereClause = whereClause;
-            this.havingClause = havingClause;
-        }
-    }
-    
-    private static Expressions compileStatement(String query, List<Object> binds) throws SQLException {
-        SQLParser parser = new SQLParser(query);
-        SelectStatement statement = parser.parseQuery();
-        Scan scan = new Scan();
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
-        statement = StatementNormalizer.normalize(statement, resolver);
-        context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
-
-        GroupBy groupBy = GroupByCompiler.compile(context, statement);
-        // Optimize the HAVING clause by finding any group by expressions that can be moved
-        // to the WHERE clause
-        statement = HavingCompiler.rewrite(context, statement, groupBy);
-        Expression having = HavingCompiler.compile(context, statement, groupBy);
-        Expression where = WhereCompiler.compile(context, statement);
-        where = WhereOptimizer.pushKeyExpressionsToScan(context, statement, where);
-        return new Expressions(where,having);
-    }
-    
-    @Test
-    public void testHavingToWhere() throws SQLException {
-        String query = "select count(1) from atable group by a_string having a_string = 'foo'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression w = constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo");
-        assertEquals(w, expressions.whereClause);
-        assertNull(expressions.havingClause);
-    }
-    
-    @Test
-    public void testHavingFuncToWhere() throws SQLException {
-        // TODO: confirm that this is a valid optimization
-        String query = "select count(1) from atable group by a_date having round(a_date, 'hour') > ?";
-        Date date = new Date(System.currentTimeMillis());
-        List<Object> binds = Arrays.<Object>asList(date);
-        Expressions expressions = compileStatement(query,binds);
-        Expression w = constantComparison(CompareOp.GREATER, RoundDateExpression.create(Arrays.asList(kvColumn(BaseConnectionlessQueryTest.A_DATE),LiteralExpression.newConstant("hour"),LiteralExpression.newConstant(1))), date);
-        assertEquals(w, expressions.whereClause);
-        assertNull(expressions.havingClause);
-    }
-    
-    @Test
-    public void testHavingToAndWhere() throws SQLException {
-        String query = "select count(1) from atable where b_string > 'bar' group by a_string having a_string = 'foo'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression w = and(constantComparison(CompareOp.GREATER, BaseConnectionlessQueryTest.B_STRING,"bar"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo"));
-        assertEquals(w, expressions.whereClause);
-        assertNull(expressions.havingClause);
-    }
-
-    
-    @Test
-    public void testAndHavingToAndWhere() throws SQLException {
-        String query = "select count(1) from atable where b_string > 'bar' group by a_string having count(1) >= 1 and a_string = 'foo'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L);
-        Expression w = and(constantComparison(CompareOp.GREATER, BaseConnectionlessQueryTest.B_STRING,"bar"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo"));
-        assertEquals(w, expressions.whereClause);
-        assertEquals(h, expressions.havingClause);
-    }
-    
-    @Test
-    public void testAndHavingToWhere() throws SQLException {
-        String query = "select count(1) from atable group by a_string having count(1) >= 1 and a_string = 'foo'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L);
-        Expression w = constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo");
-        assertEquals(w, expressions.whereClause);
-        assertEquals(h, expressions.havingClause);
-    }
-    
-    @Test
-    public void testAggFuncInHaving() throws SQLException {
-        String query = "select count(1) from atable group by a_string having count(a_string) >= 1";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(Arrays.asList(kvColumn(BaseConnectionlessQueryTest.A_STRING))),1L);
-        assertTrue(LiteralExpression.isTrue(expressions.whereClause));
-        assertEquals(h, expressions.havingClause);
-    }
-    
-    @Test
-    public void testOrAggFuncInHaving() throws SQLException {
-        String query = "select count(1) from atable group by a_string having count(1) >= 1 or a_string = 'foo'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression h = or(constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L),constantComparison(CompareOp.EQUAL, pkColumn(BaseConnectionlessQueryTest.A_STRING,Arrays.asList(BaseConnectionlessQueryTest.A_STRING)),"foo"));
-        assertTrue(LiteralExpression.isTrue(expressions.whereClause));
-        assertEquals(h, expressions.havingClause);
-    }
-    
-    @Test
-    public void testAndAggColsInHaving() throws SQLException {
-        String query = "select count(1) from atable group by a_string,b_string having a_string = 'a' and b_string = 'b'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression w = and(constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"a"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.B_STRING,"b"));
-        assertEquals(w, expressions.whereClause);
-        assertNull(expressions.havingClause);
-    }
-    
-    @Test
-    public void testOrAggColsInHaving() throws SQLException {
-        String query = "select count(1) from atable group by a_string,b_string having a_string = 'a' or b_string = 'b'";
-        List<Object> binds = Collections.emptyList();
-        Expressions expressions = compileStatement(query,binds);
-        Expression w = or(constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"a"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.B_STRING,"b"));
-        assertEquals(w, expressions.whereClause);
-        assertNull(expressions.havingClause);
-    }
-    
-    @Test
-    public void testNonAggColInHaving() throws SQLException {
-        String query = "select count(1) from atable group by a_string having b_string = 'bar'";
-        List<Object> binds = Collections.emptyList();
-        try {
-            compileStatement(query,binds);
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1019 (42Y26): Only aggregate maybe used in the HAVING clause."));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingCompilerTest.java
new file mode 100644
index 0000000..65e13ab
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/HavingCompilerTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.apache.phoenix.util.TestUtil.and;
+import static org.apache.phoenix.util.TestUtil.constantComparison;
+import static org.apache.phoenix.util.TestUtil.or;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.function.CountAggregateFunction;
+import org.apache.phoenix.expression.function.RoundDateExpression;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixStatement;
+import org.apache.phoenix.parse.SQLParser;
+import org.apache.phoenix.parse.SelectStatement;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.junit.Test;
+
+
+public class HavingCompilerTest extends BaseConnectionlessQueryTest {
+    private static StatementContext context;
+    
+    private static class Expressions {
+        private Expression whereClause;
+        private Expression havingClause;
+        
+        private Expressions(Expression whereClause, Expression havingClause) {
+            this.whereClause = whereClause;
+            this.havingClause = havingClause;
+        }
+    }
+    
+    private static Expressions compileStatement(String query, List<Object> binds) throws SQLException {
+        SQLParser parser = new SQLParser(query);
+        SelectStatement statement = parser.parseQuery();
+        Scan scan = new Scan();
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
+        statement = StatementNormalizer.normalize(statement, resolver);
+        context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
+
+        GroupBy groupBy = GroupByCompiler.compile(context, statement);
+        // Optimize the HAVING clause by finding any group by expressions that can be moved
+        // to the WHERE clause
+        statement = HavingCompiler.rewrite(context, statement, groupBy);
+        Expression having = HavingCompiler.compile(context, statement, groupBy);
+        Expression where = WhereCompiler.compile(context, statement);
+        where = WhereOptimizer.pushKeyExpressionsToScan(context, statement, where);
+        return new Expressions(where,having);
+    }
+    
+    @Test
+    public void testHavingToWhere() throws SQLException {
+        String query = "select count(1) from atable group by a_string having a_string = 'foo'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression w = constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo");
+        assertEquals(w, expressions.whereClause);
+        assertNull(expressions.havingClause);
+    }
+    
+    @Test
+    public void testHavingFuncToWhere() throws SQLException {
+        // TODO: confirm that this is a valid optimization
+        String query = "select count(1) from atable group by a_date having round(a_date, 'hour') > ?";
+        Date date = new Date(System.currentTimeMillis());
+        List<Object> binds = Arrays.<Object>asList(date);
+        Expressions expressions = compileStatement(query,binds);
+        Expression w = constantComparison(CompareOp.GREATER, RoundDateExpression.create(Arrays.asList(BaseConnectionlessQueryTest.A_DATE,LiteralExpression.newConstant("hour"),LiteralExpression.newConstant(1))), date);
+        assertEquals(w, expressions.whereClause);
+        assertNull(expressions.havingClause);
+    }
+    
+    @Test
+    public void testHavingToAndWhere() throws SQLException {
+        String query = "select count(1) from atable where b_string > 'bar' group by a_string having a_string = 'foo'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression w = and(constantComparison(CompareOp.GREATER, BaseConnectionlessQueryTest.B_STRING,"bar"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo"));
+        assertEquals(w, expressions.whereClause);
+        assertNull(expressions.havingClause);
+    }
+
+    
+    @Test
+    public void testAndHavingToAndWhere() throws SQLException {
+        String query = "select count(1) from atable where b_string > 'bar' group by a_string having count(1) >= 1 and a_string = 'foo'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L);
+        Expression w = and(constantComparison(CompareOp.GREATER, BaseConnectionlessQueryTest.B_STRING,"bar"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo"));
+        assertEquals(w, expressions.whereClause);
+        assertEquals(h, expressions.havingClause);
+    }
+    
+    @Test
+    public void testAndHavingToWhere() throws SQLException {
+        String query = "select count(1) from atable group by a_string having count(1) >= 1 and a_string = 'foo'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L);
+        Expression w = constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo");
+        assertEquals(w, expressions.whereClause);
+        assertEquals(h, expressions.havingClause);
+    }
+    
+    @Test
+    public void testAggFuncInHaving() throws SQLException {
+        String query = "select count(1) from atable group by a_string having count(a_string) >= 1";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression h = constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(Arrays.asList(BaseConnectionlessQueryTest.A_STRING)),1L);
+        assertTrue(LiteralExpression.isTrue(expressions.whereClause));
+        assertEquals(h, expressions.havingClause);
+    }
+    
+    @Test
+    public void testOrAggFuncInHaving() throws SQLException {
+        String query = "select count(1) from atable group by a_string having count(1) >= 1 or a_string = 'foo'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression h = or(constantComparison(CompareOp.GREATER_OR_EQUAL, new CountAggregateFunction(),1L),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"foo"));
+        assertTrue(LiteralExpression.isTrue(expressions.whereClause));
+        assertEquals(h, expressions.havingClause);
+    }
+    
+    @Test
+    public void testAndAggColsInHaving() throws SQLException {
+        String query = "select count(1) from atable group by a_string,b_string having a_string = 'a' and b_string = 'b'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression w = and(constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"a"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.B_STRING,"b"));
+        assertEquals(w, expressions.whereClause);
+        assertNull(expressions.havingClause);
+    }
+    
+    @Test
+    public void testOrAggColsInHaving() throws SQLException {
+        String query = "select count(1) from atable group by a_string,b_string having a_string = 'a' or b_string = 'b'";
+        List<Object> binds = Collections.emptyList();
+        Expressions expressions = compileStatement(query,binds);
+        Expression w = or(constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.A_STRING,"a"),constantComparison(CompareOp.EQUAL, BaseConnectionlessQueryTest.B_STRING,"b"));
+        assertEquals(w, expressions.whereClause);
+        assertNull(expressions.havingClause);
+    }
+    
+    @Test
+    public void testNonAggColInHaving() throws SQLException {
+        String query = "select count(1) from atable group by a_string having b_string = 'bar'";
+        List<Object> binds = Collections.emptyList();
+        try {
+            compileStatement(query,binds);
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 1019 (42Y26): Only aggregate maybe used in the HAVING clause."));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompileTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompileTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompileTest.java
deleted file mode 100644
index b515697..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompileTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE;
-import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_NORMALIZED;
-import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE;
-import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_NORMALIZED;
-import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE;
-import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE_NORMALIZED;
-import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE;
-import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE_NORMALIZED;
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
-import static org.junit.Assert.assertEquals;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-
-import org.junit.Test;
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.phoenix.compile.JoinCompiler.JoinSpec;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.jdbc.PhoenixStatement;
-import org.apache.phoenix.parse.SQLParser;
-import org.apache.phoenix.parse.SelectStatement;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-import org.apache.phoenix.util.QueryUtil;
-
-/**
- * Test compilation of queries containing joins.
- */
-public class JoinQueryCompileTest extends BaseConnectionlessQueryTest {
-    
-    @Test
-    public void testExplainPlan() throws Exception {
-        Connection conn = DriverManager.getConnection(getUrl());
-        String query = "EXPLAIN SELECT s.\"supplier_id\", \"order_id\", c.name, i.name, quantity, o.date FROM " + JOIN_ORDER_TABLE + " o LEFT JOIN " 
-    	+ JOIN_CUSTOMER_TABLE + " c ON o.\"customer_id\" = c.\"customer_id\" AND c.name LIKE 'C%' LEFT JOIN " 
-    	+ JOIN_ITEM_TABLE + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN " 
-    	+ JOIN_SUPPLIER_TABLE + " s ON s.\"supplier_id\" = i.\"supplier_id\" WHERE i.name LIKE 'T%'";
-        ResultSet rs = conn.createStatement().executeQuery(query);
-        assertEquals(
-        		"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_NORMALIZED + "\n" +
-        		"    SERVER FILTER BY FIRST KEY ONLY\n" +
-        		"    PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
-        		"    BUILD HASH TABLE 0\n" +
-        		"        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_NORMALIZED + "\n" +
-        		"            PARALLEL EQUI-JOIN 2 HASH TABLES:\n" +
-        		"            BUILD HASH TABLE 0\n" +
-        		"                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_CUSTOMER_TABLE_NORMALIZED + "\n" +
-        		"                    SERVER FILTER BY NAME LIKE 'C%'\n" +
-        		"            BUILD HASH TABLE 1\n" +
-        		"                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_NORMALIZED + "\n" +
-        		"    AFTER-JOIN SERVER FILTER BY I.NAME LIKE 'T%'", QueryUtil.getExplainPlan(rs));
-    }
-
-    @Test
-    public void testWhereClauseOptimization() throws Exception {
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        String queryTemplate = "SELECT t1.\"item_id\", t2.\"item_id\", t3.\"item_id\" FROM " + JOIN_ITEM_TABLE + " t1 " 
-                + "%s JOIN " + JOIN_ITEM_TABLE + " t2 ON t1.\"item_id\" = t2.\"item_id\" " 
-                + "%s JOIN " + JOIN_ITEM_TABLE + " t3 ON t1.\"item_id\" = t3.\"item_id\" " 
-                + "WHERE t1.\"item_id\" = '0000000001' AND t2.\"item_id\" = '0000000002' AND t3.\"item_id\" = '0000000003'";
-
-        String query = String.format(queryTemplate, "INNER", "INNER");
-        JoinSpec joinSpec = getJoinSpec(query, pconn);
-        assertEquals(1, joinSpec.getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "INNER", "LEFT");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(1, joinSpec.getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "INNER", "RIGHT");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(0, joinSpec.getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "LEFT", "INNER");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(1, joinSpec.getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "LEFT", "LEFT");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(1, joinSpec.getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "LEFT", "RIGHT");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(0, joinSpec.getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "RIGHT", "INNER");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(0, joinSpec.getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
-
-        query = String.format(queryTemplate, "RIGHT", "RIGHT");
-        joinSpec = getJoinSpec(query, pconn);
-        assertEquals(0, joinSpec.getPreFilters().size());
-        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
-        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
-    }
-    
-    private static JoinSpec getJoinSpec(String query, PhoenixConnection connection) throws SQLException {
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        SQLParser parser = new SQLParser(query);
-        SelectStatement select = parser.parseQuery();
-        ColumnResolver resolver = FromCompiler.getResolver(select, connection);
-        select = StatementNormalizer.normalize(select, resolver);
-        StatementContext context = new StatementContext(new PhoenixStatement(connection), resolver, binds, scan);
-        return JoinCompiler.getJoinSpec(context, select);        
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
new file mode 100644
index 0000000..2c1d1ab
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/JoinQueryCompilerTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE;
+import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_NORMALIZED;
+import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE;
+import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_NORMALIZED;
+import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE;
+import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE_NORMALIZED;
+import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE;
+import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE_NORMALIZED;
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.phoenix.compile.JoinCompiler.JoinSpec;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixStatement;
+import org.apache.phoenix.parse.SQLParser;
+import org.apache.phoenix.parse.SelectStatement;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.util.QueryUtil;
+
+/**
+ * Test compilation of queries containing joins.
+ */
+public class JoinQueryCompilerTest extends BaseConnectionlessQueryTest {
+    
+    @Test
+    public void testExplainPlan() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        String query = "EXPLAIN SELECT s.\"supplier_id\", \"order_id\", c.name, i.name, quantity, o.date FROM " + JOIN_ORDER_TABLE + " o LEFT JOIN " 
+    	+ JOIN_CUSTOMER_TABLE + " c ON o.\"customer_id\" = c.\"customer_id\" AND c.name LIKE 'C%' LEFT JOIN " 
+    	+ JOIN_ITEM_TABLE + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN " 
+    	+ JOIN_SUPPLIER_TABLE + " s ON s.\"supplier_id\" = i.\"supplier_id\" WHERE i.name LIKE 'T%'";
+        ResultSet rs = conn.createStatement().executeQuery(query);
+        assertEquals(
+        		"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_NORMALIZED + "\n" +
+        		"    SERVER FILTER BY FIRST KEY ONLY\n" +
+        		"    PARALLEL EQUI-JOIN 1 HASH TABLES:\n" +
+        		"    BUILD HASH TABLE 0\n" +
+        		"        CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_NORMALIZED + "\n" +
+        		"            PARALLEL EQUI-JOIN 2 HASH TABLES:\n" +
+        		"            BUILD HASH TABLE 0\n" +
+        		"                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_CUSTOMER_TABLE_NORMALIZED + "\n" +
+        		"                    SERVER FILTER BY NAME LIKE 'C%'\n" +
+        		"            BUILD HASH TABLE 1\n" +
+        		"                CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_NORMALIZED + "\n" +
+        		"    AFTER-JOIN SERVER FILTER BY I.NAME LIKE 'T%'", QueryUtil.getExplainPlan(rs));
+    }
+
+    @Test
+    public void testWhereClauseOptimization() throws Exception {
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        String queryTemplate = "SELECT t1.\"item_id\", t2.\"item_id\", t3.\"item_id\" FROM " + JOIN_ITEM_TABLE + " t1 " 
+                + "%s JOIN " + JOIN_ITEM_TABLE + " t2 ON t1.\"item_id\" = t2.\"item_id\" " 
+                + "%s JOIN " + JOIN_ITEM_TABLE + " t3 ON t1.\"item_id\" = t3.\"item_id\" " 
+                + "WHERE t1.\"item_id\" = '0000000001' AND t2.\"item_id\" = '0000000002' AND t3.\"item_id\" = '0000000003'";
+
+        String query = String.format(queryTemplate, "INNER", "INNER");
+        JoinSpec joinSpec = getJoinSpec(query, pconn);
+        assertEquals(1, joinSpec.getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "INNER", "LEFT");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(1, joinSpec.getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "INNER", "RIGHT");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(0, joinSpec.getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "LEFT", "INNER");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(1, joinSpec.getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "LEFT", "LEFT");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(1, joinSpec.getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "LEFT", "RIGHT");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(0, joinSpec.getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "RIGHT", "INNER");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(0, joinSpec.getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
+
+        query = String.format(queryTemplate, "RIGHT", "RIGHT");
+        joinSpec = getJoinSpec(query, pconn);
+        assertEquals(0, joinSpec.getPreFilters().size());
+        assertEquals(0, joinSpec.getJoinTables().get(0).getPreFilters().size());
+        assertEquals(1, joinSpec.getJoinTables().get(1).getPreFilters().size());
+    }
+    
+    private static JoinSpec getJoinSpec(String query, PhoenixConnection connection) throws SQLException {
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        SQLParser parser = new SQLParser(query);
+        SelectStatement select = parser.parseQuery();
+        ColumnResolver resolver = FromCompiler.getResolver(select, connection);
+        select = StatementNormalizer.normalize(select, resolver);
+        StatementContext context = new StatementContext(new PhoenixStatement(connection), resolver, binds, scan);
+        return JoinCompiler.getJoinSpec(context, select);        
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitClauseTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitClauseTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitClauseTest.java
deleted file mode 100644
index 9aa3249..0000000
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitClauseTest.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2014 The Apache Software Foundation
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.compile;
-
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.hadoop.hbase.client.Scan;
-import org.junit.Test;
-
-import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
-import org.apache.phoenix.expression.Expression;
-import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.jdbc.PhoenixStatement;
-import org.apache.phoenix.parse.SQLParser;
-import org.apache.phoenix.parse.SelectStatement;
-import org.apache.phoenix.query.BaseConnectionlessQueryTest;
-import org.apache.phoenix.schema.PDataType;
-import org.apache.phoenix.util.ByteUtil;
-
-
-public class LimitClauseTest extends BaseConnectionlessQueryTest {
-    
-    private static Integer compileStatement(String query, List<Object> binds, Scan scan) throws SQLException {
-        SQLParser parser = new SQLParser(query);
-        SelectStatement statement = parser.parseQuery();
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
-        statement = StatementNormalizer.normalize(statement, resolver);
-        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
-
-        Integer limit = LimitCompiler.compile(context, statement);
-        GroupBy groupBy = GroupByCompiler.compile(context, statement);
-        statement = HavingCompiler.rewrite(context, statement, groupBy);
-        HavingCompiler.compile(context, statement, groupBy);
-        Expression where = WhereCompiler.compile(context, statement);
-        assertNull(where);
-        return limit;
-    }
-    
-    @Test
-    public void testLimit() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' limit 5";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        Integer limit = compileStatement(query, binds, scan);
-
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-        assertEquals(limit,Integer.valueOf(5));
-    }
-
-    @Test
-    public void testNoLimit() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "'";
-        Scan scan = new Scan();
-        List<Object> binds = Collections.emptyList();
-        Integer limit = compileStatement(query, binds, scan);
-
-        assertNull(limit);
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-    }
-    
-    @Test
-    public void testBoundLimit() throws SQLException {
-        String tenantId = "000000000000001";
-        String query = "select * from atable where organization_id='" + tenantId + "' limit ?";
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(5);
-        Integer limit = compileStatement(query, binds, scan);
-
-        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
-        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
-        assertEquals(limit,Integer.valueOf(5));
-    }
-
-    @Test
-    public void testTypeMismatchBoundLimit() throws SQLException {
-        String query = "select * from atable limit ?";
-        SQLParser parser = new SQLParser(query);
-        SelectStatement statement = parser.parseQuery();
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList("foo");
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
-        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
-        try {
-            LimitCompiler.compile(context, statement);
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage().contains("Type mismatch"));
-        }
-    }
-
-    @Test
-    public void testNegativeBoundLimit() throws SQLException {
-        String query = "select * from atable limit ?";
-        SQLParser parser = new SQLParser(query);
-        SelectStatement statement = parser.parseQuery();
-        Scan scan = new Scan();
-        List<Object> binds = Arrays.<Object>asList(-1);
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
-        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
-        assertNull(LimitCompiler.compile(context, statement));
-    }
-
-    @Test
-    public void testBindTypeMismatch() throws SQLException {
-        Long tenantId = Long.valueOf(0);
-        String keyPrefix = "002";
-        List<Object> binds = Arrays.<Object>asList(tenantId,keyPrefix);
-        String query = "select * from atable where organization_id=? and substr(entity_id,1,3)=?";
-        SQLParser parser = new SQLParser(query);
-        SelectStatement statement = parser.parseQuery();
-        Scan scan = new Scan();
-        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
-        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
-        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
-        try {
-            WhereCompiler.compile(context, statement);
-            fail();
-        } catch (SQLException e) {
-            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 203 (22005): Type mismatch."));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/0ea954ea/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitCompilerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitCompilerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitCompilerTest.java
new file mode 100644
index 0000000..ff7e690
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/LimitCompilerTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2014 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.compile;
+
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.client.Scan;
+import org.junit.Test;
+
+import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixStatement;
+import org.apache.phoenix.parse.SQLParser;
+import org.apache.phoenix.parse.SelectStatement;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.util.ByteUtil;
+
+
+public class LimitCompilerTest extends BaseConnectionlessQueryTest {
+    
+    private static Integer compileStatement(String query, List<Object> binds, Scan scan) throws SQLException {
+        SQLParser parser = new SQLParser(query);
+        SelectStatement statement = parser.parseQuery();
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
+        statement = StatementNormalizer.normalize(statement, resolver);
+        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
+
+        Integer limit = LimitCompiler.compile(context, statement);
+        GroupBy groupBy = GroupByCompiler.compile(context, statement);
+        statement = HavingCompiler.rewrite(context, statement, groupBy);
+        HavingCompiler.compile(context, statement, groupBy);
+        Expression where = WhereCompiler.compile(context, statement);
+        assertNull(where);
+        return limit;
+    }
+    
+    @Test
+    public void testLimit() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' limit 5";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        Integer limit = compileStatement(query, binds, scan);
+
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+        assertEquals(limit,Integer.valueOf(5));
+    }
+
+    @Test
+    public void testNoLimit() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "'";
+        Scan scan = new Scan();
+        List<Object> binds = Collections.emptyList();
+        Integer limit = compileStatement(query, binds, scan);
+
+        assertNull(limit);
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+    }
+    
+    @Test
+    public void testBoundLimit() throws SQLException {
+        String tenantId = "000000000000001";
+        String query = "select * from atable where organization_id='" + tenantId + "' limit ?";
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(5);
+        Integer limit = compileStatement(query, binds, scan);
+
+        assertArrayEquals(PDataType.VARCHAR.toBytes(tenantId), scan.getStartRow());
+        assertArrayEquals(ByteUtil.nextKey(PDataType.VARCHAR.toBytes(tenantId)), scan.getStopRow());
+        assertEquals(limit,Integer.valueOf(5));
+    }
+
+    @Test
+    public void testTypeMismatchBoundLimit() throws SQLException {
+        String query = "select * from atable limit ?";
+        SQLParser parser = new SQLParser(query);
+        SelectStatement statement = parser.parseQuery();
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList("foo");
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
+        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
+        try {
+            LimitCompiler.compile(context, statement);
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage().contains("Type mismatch"));
+        }
+    }
+
+    @Test
+    public void testNegativeBoundLimit() throws SQLException {
+        String query = "select * from atable limit ?";
+        SQLParser parser = new SQLParser(query);
+        SelectStatement statement = parser.parseQuery();
+        Scan scan = new Scan();
+        List<Object> binds = Arrays.<Object>asList(-1);
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
+        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
+        assertNull(LimitCompiler.compile(context, statement));
+    }
+
+    @Test
+    public void testBindTypeMismatch() throws SQLException {
+        Long tenantId = Long.valueOf(0);
+        String keyPrefix = "002";
+        List<Object> binds = Arrays.<Object>asList(tenantId,keyPrefix);
+        String query = "select * from atable where organization_id=? and substr(entity_id,1,3)=?";
+        SQLParser parser = new SQLParser(query);
+        SelectStatement statement = parser.parseQuery();
+        Scan scan = new Scan();
+        PhoenixConnection pconn = DriverManager.getConnection(getUrl(), TEST_PROPERTIES).unwrap(PhoenixConnection.class);
+        ColumnResolver resolver = FromCompiler.getResolver(statement, pconn);
+        StatementContext context = new StatementContext(new PhoenixStatement(pconn), resolver, binds, scan);
+        try {
+            WhereCompiler.compile(context, statement);
+            fail();
+        } catch (SQLException e) {
+            assertTrue(e.getMessage(), e.getMessage().contains("ERROR 203 (22005): Type mismatch."));
+        }
+    }
+}