PHOENIX-2160 - Projection of specific array index does not work (Dumindu
Buddhika)


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

Branch: refs/heads/calcite
Commit: 7d7c21786f4c1224027aec05a9b72411a3a1c07b
Parents: ed3f3bb
Author: ramkrishna <ramkrishna.s.vasude...@gmail.com>
Authored: Wed Sep 2 14:40:49 2015 +0530
Committer: ramkrishna <ramkrishna.s.vasude...@gmail.com>
Committed: Wed Sep 2 14:40:49 2015 +0530

----------------------------------------------------------------------
 .../org/apache/phoenix/end2end/ArrayIT.java     | 441 +++++++++++++++++++
 .../phoenix/compile/ProjectionCompiler.java     | 130 ++++--
 .../apache/phoenix/compile/RowProjector.java    |   4 +-
 .../coprocessor/BaseScannerRegionObserver.java  |  15 +-
 .../expression/ProjectedColumnExpression.java   |   7 +-
 .../visitor/CloneExpressionVisitor.java         |  47 +-
 .../apache/phoenix/iterate/ExplainTable.java    |   3 +
 .../phoenix/compile/QueryCompilerTest.java      |  77 ++++
 .../expression/ArithmeticOperationTest.java     |   8 +-
 9 files changed, 660 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
index 800a7b4..b7a2ad2 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
@@ -2238,4 +2238,445 @@ public class ArrayIT extends BaseClientManagedTimeIT {
         rs = stmt.executeQuery();
         assertTrue(rs.next());
     }
+
+    @Test
+    public void testServerArrayElementProjection1() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 VARCHAR ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY['a', 'b'])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], arr2[1] FROM a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals("a", rs.getString(3));
+    }
+
+    @Test
+    public void testServerArrayElementProjection2() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 VARCHAR ARRAY, arr3 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY['a', 'b'], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], arr2[1], arr3[1] 
from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals("a", rs.getString(3));
+        assertEquals(2, rs.getInt(4));
+    }
+
+    @Test
+    public void testServerArrayElementProjection3() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 VARCHAR ARRAY, arr3 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY['a', 'b'], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], arr2[1], arr3, 
arr3[1] from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals("a", rs.getString(3));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{2, 3}), 
rs.getArray(4));
+        assertEquals(2, rs.getInt(5));
+    }
+
+    @Test
+    public void testServerArrayElementProjection4() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 VARCHAR ARRAY, arr3 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY['a', 'b'], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], arr2[1], 
ARRAY_APPEND(arr3, 4), arr3[1] from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals("a", rs.getString(3));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{2, 3, 4}), 
rs.getArray(4));
+        assertEquals(2, rs.getInt(5));
+    }
+
+    @Test
+    public void testServerArrayElementProjection5() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr3 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], ARRAY_APPEND(arr1, 
arr3[1]) from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 2}), 
rs.getArray(3));
+    }
+
+    @Test
+    public void testServerArrayElementProjection6() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], ARRAY_APPEND(arr1, 
arr2[1]), p from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 2}), 
rs.getArray(3));
+        assertEquals(1, rs.getInt(4));
+    }
+
+    @Test
+    public void testServerArrayElementProjection7() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], 
ARRAY_APPEND(ARRAY_APPEND(arr1, arr2[2]), arr2[1]), p from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 3, 2}), 
rs.getArray(3));
+        assertEquals(1, rs.getInt(4));
+    }
+
+    @Test
+    public void testServerArrayElementProjection8() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], 
ARRAY_ELEM(ARRAY_APPEND(arr1, arr2[1]), 1), p, arr2[2] from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals(1, rs.getInt(3));
+        assertEquals(1, rs.getInt(4));
+        assertEquals(3, rs.getInt(5));
+    }
+
+    @Test
+    public void testServerArrayElementProjection9() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER ARRAY PRIMARY KEY, arr1 
INTEGER ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(ARRAY[5, 6], ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1, arr1[1], 
ARRAY_ELEM(ARRAY_APPEND(arr1, arr2[1]), 1), p, arr2[2] from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2}), 
rs.getArray(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals(1, rs.getInt(3));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{5, 6}), 
rs.getArray(4));
+        assertEquals(3, rs.getInt(5));
+    }
+
+    @Test
+    public void testServerArrayElementProjection10() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT arr1[1] + 5, arr2[1] FROM a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(6, rs.getInt(1));
+        assertEquals(2, rs.getInt(2));
+    }
+
+    @Test
+    public void testServerArrayElementProjection11() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (2, ARRAY[1, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (3, ARRAY[1, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (4, ARRAY[1, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT CASE WHEN p = 1 THEN arr1[1] WHEN 
p = 2 THEN arr1[2] WHEN p = 3 THEN arr2[1] ELSE arr2[2] END FROM a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(1, rs.getInt(1));
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertTrue(rs.next());
+        assertEquals(3, rs.getInt(1));
+        assertFalse(rs.next());
+    }
+
+    @Test
+    public void testServerArrayElementProjection12() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (2, ARRAY[1, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (3, ARRAY[1, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (4, ARRAY[1, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT CASE WHEN p = 1 THEN arr1[1] WHEN 
p = 2 THEN arr1[2] WHEN p = 3 THEN arr2[1] ELSE arr2[2] END, ARRAY_APPEND(arr1, 
arr1[1]) FROM a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(1, rs.getInt(1));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 1}), 
rs.getArray(2));
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 1}), 
rs.getArray(2));
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 1}), 
rs.getArray(2));
+        assertTrue(rs.next());
+        assertEquals(3, rs.getInt(1));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{1, 2, 1}), 
rs.getArray(2));
+        assertFalse(rs.next());
+    }
+
+    @Test
+    public void testServerArrayElementProjection13() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER PRIMARY KEY, arr1 INTEGER 
ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(1, ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (2, ARRAY[3, 2], 
ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (3, ARRAY[3, 5], 
ARRAY[2, 3])");
+        stmt.execute();
+        stmt = conn.prepareStatement("UPSERT INTO a VALUES (4, ARRAY[3, 5], 
ARRAY[6, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT CASE WHEN arr1[1] = 1 THEN 1 WHEN 
arr1[2] = 2 THEN 2 WHEN arr2[1] = 2 THEN 2 ELSE arr2[2] END FROM a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(1, rs.getInt(1));
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertTrue(rs.next());
+        assertEquals(3, rs.getInt(1));
+        assertFalse(rs.next());
+    }
+
+    @Test
+    public void testServerArrayElementProjection14() throws SQLException {
+        long ts = nextTimestamp();
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        String ddl = "CREATE TABLE a (p INTEGER ARRAY PRIMARY KEY, arr1 
INTEGER ARRAY, arr2 INTEGER ARRAY)";
+        conn.createStatement().execute(ddl);
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        PreparedStatement stmt = conn.prepareStatement("UPSERT INTO a VALUES 
(ARRAY[5, 6], ARRAY[1, 2], ARRAY[2, 3])");
+        stmt.execute();
+        conn.commit();
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts 
+ 40));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs;
+        stmt = conn.prepareStatement("SELECT ARRAY_ELEM(ARRAY_PREPEND(arr2[1], 
ARRAY_CAT(arr1, ARRAY[arr2[2],3])), 1), arr1[1], ARRAY_ELEM(ARRAY_APPEND(arr1, 
arr2[1]), 1), p, arr2[2] from a");
+        rs = stmt.executeQuery();
+        assertTrue(rs.next());
+        assertEquals(2, rs.getInt(1));
+        assertEquals(1, rs.getInt(2));
+        assertEquals(1, rs.getInt(3));
+        assertEquals(conn.createArrayOf("INTEGER", new Integer[]{5, 6}), 
rs.getArray(4));
+        assertEquals(3, rs.getInt(5));
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
index 915a55d..ad02961 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -42,12 +43,14 @@ import org.apache.phoenix.expression.CoerceExpression;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.expression.KeyValueColumnExpression;
 import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.ProjectedColumnExpression;
 import org.apache.phoenix.expression.aggregator.ClientAggregators;
 import org.apache.phoenix.expression.aggregator.ServerAggregators;
 import org.apache.phoenix.expression.function.ArrayIndexFunction;
 import org.apache.phoenix.expression.function.SingleAggregateFunction;
 import org.apache.phoenix.expression.visitor.ExpressionVisitor;
-import org.apache.phoenix.expression.visitor.KeyValueExpressionVisitor;
+import org.apache.phoenix.expression.visitor.ProjectedColumnExpressionVisitor;
+import 
org.apache.phoenix.expression.visitor.ReplaceArrayFunctionExpressionVisitor;
 import org.apache.phoenix.expression.visitor.SingleAggregateFunctionVisitor;
 import org.apache.phoenix.jdbc.PhoenixConnection;
 import org.apache.phoenix.parse.AliasedNode;
@@ -104,8 +107,6 @@ import com.google.common.collect.Sets;
  * @since 0.1
  */
 public class ProjectionCompiler {
-    private static ValueBitSet arrayIndexesBitSet; 
-    private static KeyValueSchema arrayIndexesSchema;
     private ProjectionCompiler() {
     }
     
@@ -339,10 +340,13 @@ public class ProjectionCompiler {
      */
     public static RowProjector compile(StatementContext context, 
SelectStatement statement, GroupBy groupBy, List<? extends PDatum> 
targetColumns) throws SQLException {
         List<KeyValueColumnExpression> arrayKVRefs = new 
ArrayList<KeyValueColumnExpression>();
+        List<ProjectedColumnExpression> arrayProjectedColumnRefs = new 
ArrayList<ProjectedColumnExpression>();
         List<Expression> arrayKVFuncs = new ArrayList<Expression>();
+        List<Expression> arrayOldFuncs = new ArrayList<Expression>();
+        Map<Expression, Integer> arrayExpressionCounts = new HashMap<>();
         List<AliasedNode> aliasedNodes = statement.getSelect();
         // Setup projected columns in Scan
-        SelectClauseVisitor selectVisitor = new SelectClauseVisitor(context, 
groupBy, arrayKVRefs, arrayKVFuncs, statement);
+        SelectClauseVisitor selectVisitor = new SelectClauseVisitor(context, 
groupBy, arrayKVRefs, arrayKVFuncs, arrayExpressionCounts, 
arrayProjectedColumnRefs, arrayOldFuncs, statement);
         List<ExpressionProjector> projectedColumns = new 
ArrayList<ExpressionProjector>();
         ColumnResolver resolver = context.getResolver();
         TableRef tableRef = context.getCurrentTable();
@@ -409,24 +413,48 @@ public class ProjectionCompiler {
                 String name = columnAlias == null ? expression.toString() : 
columnAlias;
                 projectedColumns.add(new ExpressionProjector(name, 
tableRef.getTableAlias() == null ? (table.getName() == null ? "" : 
table.getName().getString()) : tableRef.getTableAlias(), expression, 
isCaseSensitive));
             }
-            if(arrayKVFuncs.size() > 0 && arrayKVRefs.size() > 0) {
-                serailizeArrayIndexInformationAndSetInScan(context, 
arrayKVFuncs, arrayKVRefs);
-                KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(0);
-                for (Expression expression : arrayKVRefs) {
-                    builder.addField(expression);
-                }
-                KeyValueSchema kvSchema = builder.build();
-                arrayIndexesBitSet = ValueBitSet.newInstance(kvSchema);
-                builder = new KeyValueSchemaBuilder(0);
-                for (Expression expression : arrayKVFuncs) {
-                    builder.addField(expression);
-                }
-                arrayIndexesSchema = builder.build();
-            }
+
             selectVisitor.reset();
             index++;
         }
 
+        for (int i = arrayProjectedColumnRefs.size() - 1; i >= 0; i--) {
+            Expression expression = arrayProjectedColumnRefs.get(i);
+            Integer count = arrayExpressionCounts.get(expression);
+            if (count != 0) {
+                arrayKVRefs.remove(i);
+                arrayKVFuncs.remove(i);
+                arrayOldFuncs.remove(i);
+            }
+        }
+
+        if (arrayKVFuncs.size() > 0 && arrayKVRefs.size() > 0) {
+            serailizeArrayIndexInformationAndSetInScan(context, arrayKVFuncs, 
arrayKVRefs);
+            KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(0);
+            for (Expression expression : arrayKVRefs) {
+                builder.addField(expression);
+            }
+            KeyValueSchema kvSchema = builder.build();
+            ValueBitSet arrayIndexesBitSet = ValueBitSet.newInstance(kvSchema);
+            builder = new KeyValueSchemaBuilder(0);
+            for (Expression expression : arrayKVFuncs) {
+                builder.addField(expression);
+            }
+            KeyValueSchema arrayIndexesSchema = builder.build();
+
+            Map<Expression, Expression> replacementMap = new HashMap<>();
+            for(int i = 0; i < arrayOldFuncs.size(); i++){
+                Expression function =arrayKVFuncs.get(i);
+                replacementMap.put(arrayOldFuncs.get(i), new 
ArrayIndexExpression(i, function.getDataType(), arrayIndexesBitSet, 
arrayIndexesSchema));
+            }
+
+            ReplaceArrayFunctionExpressionVisitor visitor = new 
ReplaceArrayFunctionExpressionVisitor(replacementMap);
+            for (int i = 0; i < projectedColumns.size(); i++) {
+                ExpressionProjector projector = projectedColumns.get(i);
+                projectedColumns.set(i, new 
ExpressionProjector(projector.getName(), tableRef.getTableAlias() == null ? 
(table.getName() == null ? "" : table.getName().getString()) : 
tableRef.getTableAlias(), projector.getExpression().accept(visitor), 
projector.isCaseSensitive()));
+            }
+        }
+
         // TODO make estimatedByteSize more accurate by counting the joined 
columns.
         int estimatedKeySize = 
table.getRowKeySchema().getEstimatedValueLength();
         int estimatedByteSize = 0;
@@ -473,17 +501,21 @@ public class ProjectionCompiler {
     static class ArrayIndexExpression extends BaseTerminalExpression {
         private final int position;
         private final PDataType type;
+        private final ValueBitSet arrayIndexesBitSet;
+        private final KeyValueSchema arrayIndexesSchema;
 
-        public ArrayIndexExpression(int position, PDataType type) {
+        public ArrayIndexExpression(int position, PDataType type, ValueBitSet 
arrayIndexesBitSet, KeyValueSchema arrayIndexesSchema) {
             this.position = position;
             this.type =  type;
+            this.arrayIndexesBitSet = arrayIndexesBitSet;
+            this.arrayIndexesSchema = arrayIndexesSchema;
         }
 
         @Override
         public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
             if (!tuple.getValue(QueryConstants.ARRAY_VALUE_COLUMN_FAMILY, 
QueryConstants.ARRAY_VALUE_COLUMN_QUALIFIER,
                     ptr)) { 
-              return false; 
+              return false;
             }
             int maxOffset = ptr.getOffset() + ptr.getLength();
             arrayIndexesBitSet.or(ptr);
@@ -556,13 +588,19 @@ public class ProjectionCompiler {
         private int elementCount;
         private List<KeyValueColumnExpression> arrayKVRefs;
         private List<Expression> arrayKVFuncs;
+        private List<Expression> arrayOldFuncs;
+        private List<ProjectedColumnExpression> arrayProjectedColumnRefs;
+        private Map<Expression, Integer> arrayExpressionCounts;
         private SelectStatement statement; 
         
         private SelectClauseVisitor(StatementContext context, GroupBy groupBy, 
-                List<KeyValueColumnExpression> arrayKVRefs, List<Expression> 
arrayKVFuncs, SelectStatement statement) {
+                List<KeyValueColumnExpression> arrayKVRefs, List<Expression> 
arrayKVFuncs, Map<Expression, Integer> arrayExpressionCounts, 
List<ProjectedColumnExpression> arrayProjectedColumnRefs, List<Expression> 
arrayOldFuncs, SelectStatement statement) {
             super(context, groupBy);
             this.arrayKVRefs = arrayKVRefs;
             this.arrayKVFuncs = arrayKVFuncs;
+            this.arrayOldFuncs = arrayOldFuncs;
+            this.arrayExpressionCounts = arrayExpressionCounts;
+            this.arrayProjectedColumnRefs = arrayProjectedColumnRefs;
             this.statement = statement;
             reset();
         }
@@ -614,6 +652,16 @@ public class ProjectionCompiler {
             isCaseSensitive = isCaseSensitive && node.isCaseSensitive();
             return ref;
         }
+
+        @Override
+        public Expression visit(ColumnParseNode node) throws SQLException {
+            Expression expression = super.visit(node);
+            if (expression.getDataType().isArrayType()) {
+                Integer count = arrayExpressionCounts.get(expression);
+                arrayExpressionCounts.put(expression, count != null ? (count + 
1) : 1);
+            }
+            return expression;
+        }
         
         @Override
         public void addElement(List<Expression> l, Expression element) {
@@ -633,37 +681,43 @@ public class ProjectionCompiler {
         }
         
         @Override
-        public Expression visitLeave(FunctionParseNode node, List<Expression> 
children) throws SQLException {
-            Expression func = super.visitLeave(node,children);
+        public Expression visitLeave(FunctionParseNode node, final 
List<Expression> children) throws SQLException {
+
             // this need not be done for group by clause with array. Hence the 
below check
-            if (!statement.isAggregate() && 
ArrayIndexFunction.NAME.equals(node.getName())) {
+            if (!statement.isAggregate() && 
ArrayIndexFunction.NAME.equals(node.getName()) && children.get(0) instanceof 
ProjectedColumnExpression) {
                  final List<KeyValueColumnExpression> indexKVs = 
Lists.newArrayList();
+                 final List<ProjectedColumnExpression> indexProjectedColumns = 
Lists.newArrayList();
+                 final List<Expression> copyOfChildren = new 
ArrayList<>(children);
                  // Create anon visitor to find reference to array in a 
generic way
-                 children.get(0).accept(new KeyValueExpressionVisitor() {
+                 children.get(0).accept(new ProjectedColumnExpressionVisitor() 
{
                      @Override
-                     public Void visit(KeyValueColumnExpression expression) {
+                     public Void visit(ProjectedColumnExpression expression) {
                          if (expression.getDataType().isArrayType()) {
-                             indexKVs.add(expression);
+                             indexProjectedColumns.add(expression);
+                             KeyValueColumnExpression keyValueColumnExpression 
= new KeyValueColumnExpression(expression.getColumn());
+                             indexKVs.add(keyValueColumnExpression);
+                             copyOfChildren.set(0, keyValueColumnExpression);
+                             Integer count = 
arrayExpressionCounts.get(expression);
+                             arrayExpressionCounts.put(expression, count != 
null ? (count - 1) : -1);
                          }
                          return null;
                      }
                  });
+
+                 Expression func = super.visitLeave(node,children);
                  // Add the keyvalues which is of type array
                  if (!indexKVs.isEmpty()) {
                     arrayKVRefs.addAll(indexKVs);
-                    // Track the array index function also 
-                    arrayKVFuncs.add(func);
-                    // Store the index of the array index function in the 
select query list
-                    func = replaceArrayIndexFunction(func, arrayKVFuncs.size() 
- 1);
-                    return func;
+                    arrayProjectedColumnRefs.addAll(indexProjectedColumns);
+                    Expression funcModified = super.visitLeave(node, 
copyOfChildren);
+                    // Track the array index function also
+                    arrayKVFuncs.add(funcModified);
+                    arrayOldFuncs.add(func);
                 }
+                return func;
+            } else {
+                return super.visitLeave(node,children);
             }
-            return func;
-        }
-        
-        public Expression replaceArrayIndexFunction(Expression func, int size) 
{
-            return new ArrayIndexExpression(size, func.getDataType());
         }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
index c60933e..99ab5d4 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/RowProjector.java
@@ -24,7 +24,7 @@ import java.util.List;
 
 import org.apache.phoenix.expression.Determinism;
 import org.apache.phoenix.expression.Expression;
-import org.apache.phoenix.expression.visitor.CloneExpressionVisitor;
+import 
org.apache.phoenix.expression.visitor.CloneNonDeterministicExpressionVisitor;
 import org.apache.phoenix.schema.AmbiguousColumnException;
 import org.apache.phoenix.schema.ColumnNotFoundException;
 import org.apache.phoenix.util.SchemaUtil;
@@ -118,7 +118,7 @@ public class RowProjector {
             ColumnProjector colProjector = columnProjectors.get(i);
             Expression expression = colProjector.getExpression();
             if (expression.getDeterminism() == Determinism.PER_INVOCATION) {
-                CloneExpressionVisitor visitor = new CloneExpressionVisitor();
+                CloneNonDeterministicExpressionVisitor visitor = new 
CloneNonDeterministicExpressionVisitor();
                 Expression clonedExpression = expression.accept(visitor);
                 clonedColProjectors.add(new 
ExpressionProjector(colProjector.getName(),
                         colProjector.getTableName(), 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseScannerRegionObserver.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseScannerRegionObserver.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseScannerRegionObserver.java
index c8d4926..74ea651 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseScannerRegionObserver.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseScannerRegionObserver.java
@@ -303,11 +303,13 @@ abstract public class BaseScannerRegionObserver extends 
BaseRegionObserver {
             public boolean nextRaw(List<Cell> result) throws IOException {
                 try {
                     boolean next = s.nextRaw(result);
+                    Cell arrayElementCell = null;
                     if (result.size() == 0) {
                         return next;
                     }
                     if (arrayFuncRefs != null && arrayFuncRefs.length > 0 && 
arrayKVRefs.size() > 0) {
-                        replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, 
result);
+                        int arrayElementCellPosition = 
replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, result);
+                        arrayElementCell = 
result.get(arrayElementCellPosition);
                     }
                     if (ScanUtil.isLocalIndex(scan) && 
!ScanUtil.isAnalyzeTable(scan)) {
                         IndexUtil.wrapResultUsingOffset(c, result, offset, 
dataColumns,
@@ -317,6 +319,8 @@ abstract public class BaseScannerRegionObserver extends 
BaseRegionObserver {
                         Tuple tuple = projector.projectResults(new 
ResultTuple(Result.create(result)));
                         result.clear();
                         result.add(tuple.getValue(0));
+                        if(arrayElementCell != null)
+                            result.add(arrayElementCell);
                     }
                     // There is a scanattribute set to retrieve the specific 
array element
                     return next;
@@ -331,11 +335,13 @@ abstract public class BaseScannerRegionObserver extends 
BaseRegionObserver {
                 throws IOException {
               try {
                 boolean next = s.nextRaw(result, scannerContext);
+                Cell arrayElementCell = null;
                 if (result.size() == 0) {
                     return next;
                 }
                 if (arrayFuncRefs != null && arrayFuncRefs.length > 0 && 
arrayKVRefs.size() > 0) {
-                    replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, 
result);
+                    int arrayElementCellPosition = 
replaceArrayIndexElement(arrayKVRefs, arrayFuncRefs, result);
+                    arrayElementCell = result.get(arrayElementCellPosition);
                 }
                 if ((offset > 0 || ScanUtil.isLocalIndex(scan))  && 
!ScanUtil.isAnalyzeTable(scan)) {
                     IndexUtil.wrapResultUsingOffset(c, result, offset, 
dataColumns,
@@ -345,6 +351,8 @@ abstract public class BaseScannerRegionObserver extends 
BaseRegionObserver {
                     Tuple tuple = projector.projectResults(new 
ResultTuple(Result.create(result)));
                     result.clear();
                     result.add(tuple.getValue(0));
+                    if(arrayElementCell != null)
+                        result.add(arrayElementCell);
                 }
                 // There is a scanattribute set to retrieve the specific array 
element
                 return next;
@@ -354,7 +362,7 @@ abstract public class BaseScannerRegionObserver extends 
BaseRegionObserver {
               }
             }
 
-            private void replaceArrayIndexElement(final 
Set<KeyValueColumnExpression> arrayKVRefs,
+            private int replaceArrayIndexElement(final 
Set<KeyValueColumnExpression> arrayKVRefs,
                     final Expression[] arrayFuncRefs, List<Cell> result) {
                 // make a copy of the results array here, as we're modifying 
it below
                 MultiKeyValueTuple tuple = new 
MultiKeyValueTuple(ImmutableList.copyOf(result));
@@ -385,6 +393,7 @@ abstract public class BaseScannerRegionObserver extends 
BaseRegionObserver {
                         QueryConstants.ARRAY_VALUE_COLUMN_QUALIFIER, 0,
                         QueryConstants.ARRAY_VALUE_COLUMN_QUALIFIER.length, 
HConstants.LATEST_TIMESTAMP,
                         Type.codeToType(rowKv.getTypeByte()), value, 0, 
value.length));
+                return result.size() - 1;
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/main/java/org/apache/phoenix/expression/ProjectedColumnExpression.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/ProjectedColumnExpression.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/ProjectedColumnExpression.java
index 97d1aff..89619bf 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/ProjectedColumnExpression.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/ProjectedColumnExpression.java
@@ -40,6 +40,7 @@ public class ProjectedColumnExpression extends 
ColumnExpression {
        private int position;
        private String displayName;
        private final Collection<PColumn> columns;
+    private PColumn column;
        
        public ProjectedColumnExpression() {
         this.columns = Collections.emptyList();
@@ -48,9 +49,10 @@ public class ProjectedColumnExpression extends 
ColumnExpression {
        public ProjectedColumnExpression(PColumn column, PTable table, String 
displayName) {
                this(column, table.getColumns(), column.getPosition() - 
table.getPKColumns().size(), displayName);
        }
-    
+
     public ProjectedColumnExpression(PColumn column, Collection<PColumn> 
columns, int position, String displayName) {
         super(column);
+        this.column = column;
         this.columns = columns;
         this.position = position;
         this.displayName = displayName;
@@ -143,4 +145,7 @@ public class ProjectedColumnExpression extends 
ColumnExpression {
         return visitor.visit(this);
     }
 
+    public PColumn getColumn() {
+        return column;
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
index 55f227f..18b8795 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
@@ -26,7 +26,6 @@ import 
org.apache.phoenix.expression.ArrayConstructorExpression;
 import org.apache.phoenix.expression.CaseExpression;
 import org.apache.phoenix.expression.CoerceExpression;
 import org.apache.phoenix.expression.ComparisonExpression;
-import org.apache.phoenix.expression.Determinism;
 import org.apache.phoenix.expression.DivideExpression;
 import org.apache.phoenix.expression.Expression;
 import org.apache.phoenix.expression.InListExpression;
@@ -49,7 +48,7 @@ import org.apache.phoenix.expression.function.ScalarFunction;
 import org.apache.phoenix.expression.function.SingleAggregateFunction;
 import org.apache.phoenix.expression.function.UDFExpression;
 
-public class CloneExpressionVisitor extends 
TraverseAllExpressionVisitor<Expression> {
+public abstract class CloneExpressionVisitor extends 
TraverseAllExpressionVisitor<Expression> {
 
     public CloneExpressionVisitor() {
     }
@@ -88,17 +87,17 @@ public class CloneExpressionVisitor extends 
TraverseAllExpressionVisitor<Express
 
     @Override
     public Expression visitLeave(AndExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node : new AndExpression(l);
+        return isCloneNode(node, l) ? new AndExpression(l) : node;
     }
 
     @Override
     public Expression visitLeave(OrExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  new OrExpression(l);
+        return isCloneNode(node, l) ? new OrExpression(l) : node;
     }
 
     @Override
     public Expression visitLeave(ScalarFunction node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     public Expression visitLeave(UDFExpression node, List<Expression> l) {
@@ -108,95 +107,95 @@ public class CloneExpressionVisitor extends 
TraverseAllExpressionVisitor<Express
 
     @Override
     public Expression visitLeave(ComparisonExpression node, List<Expression> 
l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(LikeExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node : node
-                .clone(l);
+        return isCloneNode(node, l) ? node.clone(l): node;
     }
 
     @Override
     public Expression visitLeave(SingleAggregateFunction node, 
List<Expression> l) {
         // Do not clone aggregate functions, as they're executed on the server 
side,
         // so any state for evaluation will live there.
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node;
+        return isCloneNode(node, l) ? node :  node;
     }
 
     @Override
     public Expression visitLeave(CaseExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  new CaseExpression(l);
+        return isCloneNode(node, l) ? new CaseExpression(l) : node;
     }
 
     @Override
     public Expression visitLeave(NotExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  new NotExpression(l);
+        return isCloneNode(node, l) ? new NotExpression(l) : node;
     }
 
     @Override
     public Expression visitLeave(InListExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(IsNullExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(SubtractExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(MultiplyExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(AddExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node : node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(DivideExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(ModulusExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(CoerceExpression node, List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(ArrayConstructorExpression node, 
List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(StringConcatExpression node, List<Expression> 
l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  new StringConcatExpression(l);
+        return isCloneNode(node, l) ? new StringConcatExpression(l) : node;
     }
 
     @Override
     public Expression visitLeave(RowValueConstructorExpression node, 
List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  node.clone(l);
+        return isCloneNode(node, l) ? node.clone(l) : node;
     }
 
     @Override
     public Expression visitLeave(ArrayAnyComparisonExpression node, 
List<Expression> l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  new ArrayAnyComparisonExpression(l);
+        return isCloneNode(node, l) ? new ArrayAnyComparisonExpression(l) : 
node;
     }
 
     @Override
     public Expression visitLeave(ArrayElemRefExpression node, List<Expression> 
l) {
-        return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 
? node :  new ArrayElemRefExpression(l);
+        return isCloneNode(node, l) ? new ArrayElemRefExpression(l) : node;
     }
 
+    public abstract boolean isCloneNode(Expression node, List<Expression> 
children);
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java 
b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
index e3eb51b..cf19a6c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
@@ -156,6 +156,9 @@ public abstract class ExplainTable {
             groupByLimit = (Integer) 
PInteger.INSTANCE.toObject(groupByLimitBytes);
         }
         groupBy.explain(planSteps, groupByLimit);
+        if (scan.getAttribute(BaseScannerRegionObserver.SPECIFIC_ARRAY_INDEX) 
!= null) {
+            planSteps.add("    SERVER ARRAY ELEMENT PROJECTION");
+        }
     }
 
     private void appendPKColumnValue(StringBuilder buf, byte[] range, Boolean 
isNull, int slotIndex) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
index 98b130e..6225c6b 100644
--- 
a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
+++ 
b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryCompilerTest.java
@@ -1989,4 +1989,81 @@ public class QueryCompilerTest extends 
BaseConnectionlessQueryTest {
          }
      }
 
+    @Test
+    public void testServerArrayElementProjection1() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t(a INTEGER PRIMARY 
KEY, arr INTEGER ARRAY)");
+            ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT 
arr[1] from t");
+            assertTrue(QueryUtil.getExplainPlan(rs).contains("    SERVER ARRAY 
ELEMENT PROJECTION"));
+        } finally {
+            conn.createStatement().execute("DROP TABLE IF EXISTS t");
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testServerArrayElementProjection2() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t(a INTEGER PRIMARY 
KEY, arr INTEGER ARRAY)");
+            ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT 
arr, arr[1] from t");
+            assertFalse(QueryUtil.getExplainPlan(rs).contains("    SERVER 
ARRAY ELEMENT PROJECTION"));
+        } finally {
+            conn.createStatement().execute("DROP TABLE IF EXISTS t");
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testServerArrayElementProjection3() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t(a INTEGER PRIMARY 
KEY, arr INTEGER ARRAY, arr2 VARCHAR ARRAY)");
+            ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT 
arr, arr[1], arr2[1] from t");
+            assertTrue(QueryUtil.getExplainPlan(rs).contains("    SERVER ARRAY 
ELEMENT PROJECTION"));
+        } finally {
+            conn.createStatement().execute("DROP TABLE IF EXISTS t");
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testServerArrayElementProjection4() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t (p INTEGER PRIMARY 
KEY, arr1 INTEGER ARRAY, arr2 INTEGER ARRAY)");
+            ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT 
arr1, arr1[1], ARRAY_APPEND(ARRAY_APPEND(arr1, arr2[2]), arr2[1]), p from t");
+            assertTrue(QueryUtil.getExplainPlan(rs).contains("    SERVER ARRAY 
ELEMENT PROJECTION"));
+        } finally {
+            conn.createStatement().execute("DROP TABLE IF EXISTS t");
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testServerArrayElementProjection5() throws SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t (p INTEGER PRIMARY 
KEY, arr1 INTEGER ARRAY, arr2 INTEGER ARRAY)");
+            ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT 
arr1, arr1[1], ARRAY_ELEM(ARRAY_APPEND(arr1, arr2[1]), 1), p, arr2[2] from t");
+            assertTrue(QueryUtil.getExplainPlan(rs).contains("    SERVER ARRAY 
ELEMENT PROJECTION"));
+        } finally {
+            conn.createStatement().execute("DROP TABLE IF EXISTS t");
+            conn.close();
+        }
+    }
+
+    @Test
+    public void testServerArrayElementProjectionWithArrayPrimaryKey() throws 
SQLException {
+        Connection conn = DriverManager.getConnection(getUrl());
+        try {
+            conn.createStatement().execute("CREATE TABLE t(arr INTEGER ARRAY 
PRIMARY KEY)");
+            ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT 
arr[1] from t");
+            assertFalse(QueryUtil.getExplainPlan(rs).contains("    SERVER 
ARRAY ELEMENT PROJECTION"));
+        } finally {
+            conn.createStatement().execute("DROP TABLE IF EXISTS t");
+            conn.close();
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/7d7c2178/phoenix-core/src/test/java/org/apache/phoenix/expression/ArithmeticOperationTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/expression/ArithmeticOperationTest.java
 
b/phoenix-core/src/test/java/org/apache/phoenix/expression/ArithmeticOperationTest.java
index 1b830f2..7876fce 100644
--- 
a/phoenix-core/src/test/java/org/apache/phoenix/expression/ArithmeticOperationTest.java
+++ 
b/phoenix-core/src/test/java/org/apache/phoenix/expression/ArithmeticOperationTest.java
@@ -30,7 +30,7 @@ import java.util.List;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
 import org.apache.phoenix.exception.DataExceedsCapacityException;
 import org.apache.phoenix.expression.function.RandomFunction;
-import org.apache.phoenix.expression.visitor.CloneExpressionVisitor;
+import 
org.apache.phoenix.expression.visitor.CloneNonDeterministicExpressionVisitor;
 import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PDecimal;
 import org.apache.phoenix.schema.types.PInteger;
@@ -273,7 +273,7 @@ public class ArithmeticOperationTest {
         e2 = new DoubleSubtractExpression(children);
         e3 = new DoubleAddExpression(Arrays.<Expression>asList(e1, e2));
         e4 = new DoubleAddExpression(Arrays.<Expression>asList(new 
RandomFunction(Arrays.<Expression>asList(LiteralExpression.newConstant(null))), 
e3));
-        CloneExpressionVisitor visitor = new CloneExpressionVisitor();
+        CloneNonDeterministicExpressionVisitor visitor = new 
CloneNonDeterministicExpressionVisitor();
         Expression clone = e4.accept(visitor);
         assertTrue(clone != e4);
         e4.evaluate(null, ptr1);
@@ -281,7 +281,7 @@ public class ArithmeticOperationTest {
         assertNotEquals(ptr1, ptr2);
         
         e4 = new DoubleAddExpression(Arrays.<Expression>asList(new 
RandomFunction(Arrays.<Expression>asList(LiteralExpression.newConstant(1))), 
e3));
-        visitor = new CloneExpressionVisitor();
+        visitor = new CloneNonDeterministicExpressionVisitor();
         clone = e4.accept(visitor);
         assertTrue(clone == e4);
         e4.evaluate(null, ptr1);
@@ -294,7 +294,7 @@ public class ArithmeticOperationTest {
         boolean evaluated = e.evaluate(null, ptr);
         assertTrue(evaluated);
         assertEquals(value, type.toObject(ptr.get()));
-        CloneExpressionVisitor visitor = new CloneExpressionVisitor();
+        CloneNonDeterministicExpressionVisitor visitor = new 
CloneNonDeterministicExpressionVisitor();
         Expression clone = e.accept(visitor);
         evaluated = clone.evaluate(null, ptr);
         assertTrue(evaluated);

Reply via email to