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

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


The following commit(s) were added to refs/heads/master by this push:
     new ad5e61c  PHOENIX-5712 Got SYSCAT ILLEGAL_DATA exception after created 
tenant index on view
ad5e61c is described below

commit ad5e61c3427c4c91ea91e0970361f844f293b27e
Author: Xinyi Yan <[email protected]>
AuthorDate: Wed Dec 2 22:19:23 2020 -0800

    PHOENIX-5712 Got SYSCAT ILLEGAL_DATA exception after created tenant index 
on view
    
    Signed-off-by: Xinyi Yan <[email protected]>
---
 .../phoenix/end2end/BackwardCompatibilityIT.java   |  34 ++++
 .../end2end/BackwardCompatibilityTestUtil.java     |   3 +
 .../phoenix/end2end/ViewIndexIdRetrieveIT.java     | 175 +++++++++++++++++++++
 .../resources/gold_files/gold_query_view_index.txt |  20 +++
 .../src/it/resources/sql_files/add_view_index.sql  |  21 +++
 .../it/resources/sql_files/query_view_index.sql    |  19 +++
 .../coprocessor/SystemCatalogRegionObserver.java   |  58 +++++++
 .../filter/SystemCatalogViewIndexIdFilter.java     | 156 ++++++++++++++++++
 .../phoenix/query/ConnectionQueryServicesImpl.java |  22 +++
 .../phoenix/util/ViewIndexIdRetrieveUtil.java      |  66 ++++++++
 10 files changed, 574 insertions(+)

diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityIT.java
 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityIT.java
index 238c574..5158a60 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityIT.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityIT.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.end2end;
 
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.ADD_DATA;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.ADD_DELETE;
+import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.ADD_VIEW_INDEX;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.CREATE_ADD;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.CREATE_DIVERGED_VIEW;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.INDEX_REBUILD_ASYNC;
@@ -27,6 +28,7 @@ import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.QUERY_ADD
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.QUERY_CREATE_ADD;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.QUERY_CREATE_DIVERGED_VIEW;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.QUERY_INDEX_REBUILD_ASYNC;
+import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.QUERY_VIEW_INDEX;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.assertExpectedOutput;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.checkForPreConditions;
 import static 
org.apache.phoenix.end2end.BackwardCompatibilityTestUtil.computeClientVersions;
@@ -46,9 +48,11 @@ import java.util.Collection;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
+import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.phoenix.coprocessor.SystemCatalogRegionObserver;
 import org.apache.phoenix.coprocessor.TaskMetaDataEndpoint;
 import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
 import org.apache.phoenix.jdbc.PhoenixDriver;
@@ -377,4 +381,34 @@ public class BackwardCompatibilityIT {
         }
     }
 
+    @Test
+    public void testViewIndexIdCreatedWithOldClient() throws Exception {
+        executeQueryWithClientVersion(compatibleClientVersion, ADD_VIEW_INDEX, 
zkQuorum);
+        try (org.apache.hadoop.hbase.client.Connection conn =
+                     hbaseTestUtil.getConnection(); Admin admin = 
conn.getAdmin()) {
+            HTableDescriptor tableDescriptor = admin.getTableDescriptor(
+                    
TableName.valueOf(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME));
+            assertFalse("Coprocessor " + 
SystemCatalogRegionObserver.class.getName()
+                    + " has been added with compatible client version: "
+                    + compatibleClientVersion, tableDescriptor.hasCoprocessor(
+                    SystemCatalogRegionObserver.class.getName()));
+
+            executeQueriesWithCurrentVersion(QUERY_VIEW_INDEX, url, NONE);
+            assertExpectedOutput(QUERY_VIEW_INDEX);
+
+            tableDescriptor = admin.getTableDescriptor(
+                    
TableName.valueOf(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME));
+            assertTrue("Coprocessor " + 
SystemCatalogRegionObserver.class.getName()
+                    + " has been added with compatible client version: "
+                    + compatibleClientVersion, tableDescriptor.hasCoprocessor(
+                    SystemCatalogRegionObserver.class.getName()));
+        }
+    }
+
+    @Test
+    public void testViewIndexIdCreatedWithNewClient() throws Exception {
+        executeQueriesWithCurrentVersion(ADD_VIEW_INDEX, url, NONE);
+        executeQueryWithClientVersion(compatibleClientVersion, 
QUERY_VIEW_INDEX, zkQuorum);
+        assertExpectedOutput(QUERY_VIEW_INDEX);
+    }
 }
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityTestUtil.java
 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityTestUtil.java
index 300fbcc..049b6f0 100644
--- 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityTestUtil.java
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BackwardCompatibilityTestUtil.java
@@ -75,7 +75,9 @@ public final class BackwardCompatibilityTestUtil {
     public static final String CREATE_DIVERGED_VIEW = "create_diverged_view";
     public static final String ADD_DATA = "add_data";
     public static final String ADD_DELETE = "add_delete";
+    public static final String ADD_VIEW_INDEX = "add_view_index";
     public static final String DELETE = "delete";
+    public static final String VIEW_INDEX = "view_index";
     public static final String SELECT_AND_DROP_TABLE = "select_and_drop_table";
     public static final String QUERY_CREATE_ADD = QUERY_PREFIX + CREATE_ADD;
     public static final String QUERY_ADD_DATA = QUERY_PREFIX + ADD_DATA;
@@ -83,6 +85,7 @@ public final class BackwardCompatibilityTestUtil {
     public static final String QUERY_DELETE = QUERY_PREFIX + DELETE;
     public static final String QUERY_SELECT_AND_DROP_TABLE = QUERY_PREFIX + 
SELECT_AND_DROP_TABLE;
     public static final String QUERY_CREATE_DIVERGED_VIEW = QUERY_PREFIX + 
CREATE_DIVERGED_VIEW;
+    public static final String QUERY_VIEW_INDEX = QUERY_PREFIX + VIEW_INDEX;
     public static final String INDEX_REBUILD_ASYNC = "index_rebuild_async";
     public static final String QUERY_INDEX_REBUILD_ASYNC = QUERY_PREFIX
         + INDEX_REBUILD_ASYNC;
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIndexIdRetrieveIT.java
 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIndexIdRetrieveIT.java
new file mode 100644
index 0000000..486a535
--- /dev/null
+++ 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIndexIdRetrieveIT.java
@@ -0,0 +1,175 @@
+/*
+ * 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.end2end;
+
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_DATA_TYPE;
+import static 
org.apache.phoenix.query.QueryServices.LONG_VIEW_INDEX_ENABLED_ATTRIB;
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.phoenix.util.PropertiesUtil;
+import org.apache.phoenix.util.ReadOnlyProps;
+import org.apache.phoenix.util.SchemaUtil;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/*
+    After 4.15 release, Phoenix introduced VIEW_INDEX_ID_COLUMN_TYPE and 
changed VIEW_INDEX_ID data
+    type from SMALLINT to BIGINT. However, SELECT from syscat doesn't have the 
right view index id
+    because the VIEW_INDEX_ID column always assume the data type is BIGINT. 
PHOENIX-5712 introduced
+    a coproc that checks the client request version and send it back to the 
client.
+    For more information, please see PHOENIX-3547, PHOENIX-5712
+ */
+public class ViewIndexIdRetrieveIT extends BaseUniqueNamesOwnClusterIT {
+    private final String BASE_TABLE_DDL = "CREATE TABLE %s (TENANT_ID CHAR(15) 
NOT NULL, " +
+            "ID CHAR(3) NOT NULL, NUM BIGINT CONSTRAINT PK PRIMARY KEY 
(TENANT_ID, ID))" +
+            " MULTI_TENANT = true, COLUMN_ENCODED_BYTES=0 ";
+    private final String VIEW_DDL = "CREATE VIEW %s (A BIGINT PRIMARY KEY, B 
BIGINT)" +
+            " AS SELECT * FROM %s WHERE ID='ABC'";
+    private final String VIEW_INDEX_DDL =
+            "CREATE INDEX %s ON %s (B DESC) INCLUDE (NUM)";
+    private final String SELECT_ALL = "SELECT * FROM SYSTEM.CATALOG";
+    private final String SELECT_ROW = "SELECT 
VIEW_INDEX_ID,VIEW_INDEX_ID_DATA_TYPE" +
+            " FROM SYSTEM.CATALOG WHERE TABLE_NAME='%s' AND COLUMN_COUNT IS 
NOT NULL";
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        Map<String, String> props = new HashMap<>();
+        setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator()));
+    }
+
+    @Test
+    public void testSelectViewIndexIdAsLong() throws Exception {
+        testSelectViewIndexId(true);
+    }
+
+    @Test
+    public void testSelectViewIndexIdAsShort() throws Exception {
+        testSelectViewIndexId(false);
+    }
+
+    private void testSelectViewIndexId(boolean isTestingLongViewIndexId) 
throws Exception {
+        String val = isTestingLongViewIndexId ? "true" : "false";
+        int expectedDataType = isTestingLongViewIndexId ? Types.BIGINT : 
Types.SMALLINT;
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        props.setProperty(LONG_VIEW_INDEX_ENABLED_ATTRIB, val);
+        String schema = generateUniqueName();
+        String baseTable = generateUniqueName();
+        String fullTableName = SchemaUtil.getTableName(schema, baseTable);
+        String viewName = generateUniqueName();
+        String viewFullName = SchemaUtil.getTableName(schema, viewName);
+        String viewIndexName = generateUniqueName();
+        try (final Connection conn = DriverManager.getConnection(url,props);
+             final Statement stmt = conn.createStatement()) {
+            stmt.execute(String.format(BASE_TABLE_DDL, fullTableName));
+            stmt.execute(String.format(VIEW_DDL, viewFullName, fullTableName));
+            stmt.execute(String.format(VIEW_INDEX_DDL, viewIndexName, 
viewFullName));
+
+            ResultSet rs = stmt.executeQuery(String.format(SELECT_ROW, 
viewIndexName));
+            rs.next();
+            // even we enabled longViewIndex config, but the sequence always 
starts at smallest short
+            assertEquals(Short.MIN_VALUE,rs.getLong(1));
+            assertEquals(expectedDataType, rs.getInt(2));
+            assertFalse(rs.next());
+        }
+    }
+
+    @Test
+    public void testMixedCase() throws Exception {
+        // mixed case
+        Properties propsForLongType = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        propsForLongType.setProperty(LONG_VIEW_INDEX_ENABLED_ATTRIB, "true");
+        String schema = generateUniqueName();
+        String baseTable = generateUniqueName();
+        String fullTableName = SchemaUtil.getTableName(schema, baseTable);
+        String viewName = generateUniqueName();
+        String viewFullName = SchemaUtil.getTableName(schema, viewName);
+        String viewIndexName1 = generateUniqueName();
+
+        // view index id data type is long
+        try (final Connection conn = 
DriverManager.getConnection(url,propsForLongType);
+             final Statement stmt = conn.createStatement()) {
+            stmt.execute(String.format(BASE_TABLE_DDL, fullTableName));
+            stmt.execute(String.format(VIEW_DDL, viewFullName, fullTableName));
+            stmt.execute(String.format(VIEW_INDEX_DDL, viewIndexName1, 
viewFullName));
+
+            ResultSet rs = stmt.executeQuery(String.format(SELECT_ROW, 
viewIndexName1));
+            rs.next();
+            assertEquals(Short.MIN_VALUE,rs.getLong(1));
+            assertEquals(Types.BIGINT, rs.getInt(2));
+            assertFalse(rs.next());
+        }
+
+        // view index id data type is short
+        String viewIndexName2 = generateUniqueName();
+        Properties propsForShortType = 
PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        propsForShortType.setProperty(LONG_VIEW_INDEX_ENABLED_ATTRIB, "false");
+        try (final Connection conn = 
DriverManager.getConnection(url,propsForShortType);
+             final Statement stmt = conn.createStatement()) {
+            stmt.execute(String.format(VIEW_INDEX_DDL, viewIndexName2, 
viewFullName));
+
+            ResultSet rs = stmt.executeQuery(String.format(SELECT_ROW, 
viewIndexName2));
+            rs.next();
+            assertEquals(Short.MIN_VALUE + 1,rs.getLong(1));
+            assertEquals(Types.SMALLINT, rs.getInt(2));
+            assertFalse(rs.next());
+        }
+
+        // check select * from syscat
+        try (final Connection conn = DriverManager.getConnection(url);
+             final Statement stmt = conn.createStatement()) {
+            ResultSet rs = stmt.executeQuery(String.format(SELECT_ALL));
+            boolean checkShort = false;
+            boolean checkLong = false;
+            while (rs.next()) {
+
+                String schemaName = rs.getString(TABLE_SCHEM);
+                long viewIndexId = rs.getLong(VIEW_INDEX_ID);
+                if (schemaName != null && schemaName.equals(schema) && 
viewIndexId != 0) {
+                    int viewIndexIdDataType = 
rs.getInt(VIEW_INDEX_ID_DATA_TYPE);
+                    String tableName = rs.getString(TABLE_NAME);
+                    if (tableName.equals(viewIndexName1)) {
+                        assertEquals(Short.MIN_VALUE, viewIndexId);
+                        assertEquals(Types.BIGINT, viewIndexIdDataType);
+                        checkLong = true;
+                    } else if (tableName.equals(viewIndexName2)) {
+                        assertEquals(Short.MIN_VALUE + 1, viewIndexId);
+                        assertEquals(Types.SMALLINT, viewIndexIdDataType);
+                        checkShort = true;
+                    }
+                }
+            }
+            assertTrue(checkLong);
+            assertTrue(checkShort);
+        }
+    }
+}
\ No newline at end of file
diff --git a/phoenix-core/src/it/resources/gold_files/gold_query_view_index.txt 
b/phoenix-core/src/it/resources/gold_files/gold_query_view_index.txt
new file mode 100644
index 0000000..5ea0549
--- /dev/null
+++ b/phoenix-core/src/it/resources/gold_files/gold_query_view_index.txt
@@ -0,0 +1,20 @@
+ /*
+ * 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.
+ */
+
+ 'VIEW_INDEX_ID'
+'-32768'
\ No newline at end of file
diff --git a/phoenix-core/src/it/resources/sql_files/add_view_index.sql 
b/phoenix-core/src/it/resources/sql_files/add_view_index.sql
new file mode 100644
index 0000000..7cbfac2
--- /dev/null
+++ b/phoenix-core/src/it/resources/sql_files/add_view_index.sql
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+CREATE TABLE MY_SCHEMA.VIEW_INDEX_BASE_TABLE (TENANT_ID CHAR(15) NOT NULL, ID 
CHAR(3) NOT NULL, NUM BIGINT CONSTRAINT PK PRIMARY KEY (TENANT_ID, ID)) 
MULTI_TENANT = true;
+CREATE VIEW MY_SCHEMA.GLOBAL_VIEW (A BIGINT PRIMARY KEY, B BIGINT) AS SELECT * 
FROM MY_SCHEMA.VIEW_INDEX_BASE_TABLE WHERE ID='ABC';
+CREATE INDEX MY_SCHEMA_VIEW_INDEX ON MY_SCHEMA.GLOBAL_VIEW (B DESC) INCLUDE 
(NUM);
\ No newline at end of file
diff --git a/phoenix-core/src/it/resources/sql_files/query_view_index.sql 
b/phoenix-core/src/it/resources/sql_files/query_view_index.sql
new file mode 100644
index 0000000..9f30f05
--- /dev/null
+++ b/phoenix-core/src/it/resources/sql_files/query_view_index.sql
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+SELECT VIEW_INDEX_ID FROM SYSTEM.CATALOG WHERE 
TABLE_NAME='MY_SCHEMA_VIEW_INDEX' AND TABLE_SCHEM='MY_SCHEMA' AND COLUMN_COUNT 
IS NOT NULL;
\ No newline at end of file
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/SystemCatalogRegionObserver.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/SystemCatalogRegionObserver.java
new file mode 100644
index 0000000..19ebe4a
--- /dev/null
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/SystemCatalogRegionObserver.java
@@ -0,0 +1,58 @@
+/*
+ * 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.coprocessor;
+
+import org.apache.hadoop.hbase.CoprocessorEnvironment;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
+import org.apache.hadoop.hbase.coprocessor.ObserverContext;
+import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
+import org.apache.hadoop.hbase.regionserver.RegionScanner;
+import org.apache.phoenix.filter.SystemCatalogViewIndexIdFilter;
+import org.apache.phoenix.util.ScanUtil;
+
+import java.io.IOException;
+
+import static org.apache.phoenix.util.ScanUtil.UNKNOWN_CLIENT_VERSION;
+
+/**
+ * Coprocessor that checks whether the VIEW_INDEX_ID needs to retrieve.
+ */
+public class SystemCatalogRegionObserver extends BaseRegionObserver {
+    @Override public void start(CoprocessorEnvironment e) throws IOException {
+        super.start(e);
+    }
+
+    @Override public void stop(CoprocessorEnvironment e) throws IOException {
+        super.stop(e);
+    }
+
+    @Override
+    public void preScannerOpen(ObserverContext<RegionCoprocessorEnvironment> 
e, Scan scan)
+            throws IOException {
+        int clientVersion = ScanUtil.getClientVersion(scan);
+        /*
+            ScanUtil.getClientVersion returns UNKNOWN_CLIENT_VERSION if the 
phoenix client version
+            isn't set. We only want to retrieve the data based on the client 
version, and we don't
+            want to change the behavior other than Phoenix env.
+         */
+        if (clientVersion != UNKNOWN_CLIENT_VERSION) {
+            ScanUtil.andFilterAtBeginning(scan, new 
SystemCatalogViewIndexIdFilter(clientVersion));
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/filter/SystemCatalogViewIndexIdFilter.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/filter/SystemCatalogViewIndexIdFilter.java
new file mode 100644
index 0000000..dbd230c
--- /dev/null
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/filter/SystemCatalogViewIndexIdFilter.java
@@ -0,0 +1,156 @@
+/*
+ * 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.filter;
+
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.filter.FilterBase;
+import org.apache.hadoop.hbase.util.Writables;
+import org.apache.hadoop.io.Writable;
+import org.apache.phoenix.hbase.index.util.GenericKeyValueBuilder;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PInteger;
+import org.apache.phoenix.util.PhoenixKeyValueUtil;
+import org.apache.phoenix.util.ViewIndexIdRetrieveUtil;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.sql.Types;
+import java.util.Collections;
+import java.util.List;
+
+
+import static 
org.apache.phoenix.coprocessor.MetaDataProtocol.MIN_SPLITTABLE_SYSTEM_CATALOG;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_BYTES;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_DATA_TYPE_BYTES;
+import static 
org.apache.phoenix.query.QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES;
+import static 
org.apache.phoenix.util.ViewIndexIdRetrieveUtil.NULL_DATA_TYPE_VALUE;
+import static 
org.apache.phoenix.util.ViewIndexIdRetrieveUtil.VIEW_INDEX_ID_BIGINT_TYPE_PTR_LEN;
+import static 
org.apache.phoenix.util.ViewIndexIdRetrieveUtil.VIEW_INDEX_ID_SMALLINT_TYPE_VALUE_LEN;
+
+public class SystemCatalogViewIndexIdFilter extends FilterBase implements 
Writable {
+    private int clientVersion;
+
+    public SystemCatalogViewIndexIdFilter() {
+    }
+
+    public SystemCatalogViewIndexIdFilter(int clientVersion) {
+        this.clientVersion = clientVersion;
+    }
+
+    @Override
+    public ReturnCode filterKeyValue(Cell keyValue) {
+        return ReturnCode.INCLUDE_AND_NEXT_COL;
+    }
+
+    @Override
+    public boolean hasFilterRow() {
+        return true;
+    }
+
+    @Override
+    public void filterRowCells(List<Cell> kvs) throws IOException {
+        Cell viewIndexIdCell = PhoenixKeyValueUtil.getColumnLatest(
+                GenericKeyValueBuilder.INSTANCE, kvs,
+                DEFAULT_COLUMN_FAMILY_BYTES, VIEW_INDEX_ID_BYTES);
+
+        /*
+            We retrieve the VIEW_INDEX_ID cell from SMALLINT to BIGINT or 
BIGINT to SMALLINT if and
+            only if VIEW_INDEX_ID is included as part of the projected column.
+            This is combination of diff client created view index looks like:
+            client                  VIEW_INDEX_ID(Cell number of bytes)     
VIEW_INDEX_ID_DATA_TYPE
+        pre-4.15                        2 bytes                                
     NULL
+        post-4.15[config smallint]      2 bytes                                
     5(smallint)
+        post-4.15[config bigint]        8 bytes                                
     -5(bigint)
+         */
+        if (viewIndexIdCell != null) {
+            int type = NULL_DATA_TYPE_VALUE;
+            Cell viewIndexIdDataTypeCell = PhoenixKeyValueUtil.getColumnLatest(
+                    GenericKeyValueBuilder.INSTANCE, kvs,
+                    DEFAULT_COLUMN_FAMILY_BYTES, 
VIEW_INDEX_ID_DATA_TYPE_BYTES);
+            if (viewIndexIdDataTypeCell != null) {
+                type = (Integer) PInteger.INSTANCE.toObject(
+                        viewIndexIdDataTypeCell.getValueArray(),
+                        viewIndexIdDataTypeCell.getValueOffset(),
+                        viewIndexIdDataTypeCell.getValueLength(),
+                        PInteger.INSTANCE,
+                        SortOrder.ASC);
+            }
+            if (this.clientVersion < MIN_SPLITTABLE_SYSTEM_CATALOG) {
+                /*
+                    For pre-4.15 client select query cannot include 
VIEW_INDEX_ID_DATA_TYPE as part
+                    of the projected columns; for this reason, the TYPE will 
always be NULL. Since
+                    the pre-4.15 client always assume the VIEW_INDEX_ID column 
is type of SMALLINT,
+                    we need to retrieve the BIGINT cell to SMALLINT cell.
+                    VIEW_INDEX_ID_DATA_TYPE,      VIEW_INDEX_ID(Cell 
representation of the data)
+                        NULL,                         SMALLINT         -> DO 
NOT CONVERT
+                        SMALLINT,                     SMALLINT         -> DO 
NOT CONVERT
+                        BIGINT,                       BIGINT           -> 
RETRIEVE AND SEND SMALLINT BACK
+                 */
+                if (type == NULL_DATA_TYPE_VALUE && 
viewIndexIdCell.getValueLength() >
+                        VIEW_INDEX_ID_SMALLINT_TYPE_VALUE_LEN) {
+                    Cell keyValue = ViewIndexIdRetrieveUtil.
+                            getRetrievedViewIndexIdCell(viewIndexIdCell, 
false);
+                    Collections.replaceAll(kvs, viewIndexIdCell, keyValue);
+                }
+            } else {
+                /*
+                    For post-4.15 client select query needs to include 
VIEW_INDEX_ID_DATA_TYPE as
+                    part of the projected columns, and VIEW_INDEX_ID depends 
on it.
+                    VIEW_INDEX_ID_DATA_TYPE,      VIEW_INDEX_ID(Cell 
representation of the data)
+                        NULL,                         SMALLINT         -> 
RETRIEVE AND SEND BIGINT BACK
+                        SMALLINT,                     SMALLINT         -> 
RETRIEVE AND SEND BIGINT BACK
+                        BIGINT,                       BIGINT           -> DO 
NOT RETRIEVE
+                 */
+                if (type != Types.BIGINT && viewIndexIdCell.getValueLength() <
+                        VIEW_INDEX_ID_BIGINT_TYPE_PTR_LEN) {
+                    Cell keyValue = ViewIndexIdRetrieveUtil.
+                            getRetrievedViewIndexIdCell(viewIndexIdCell, true);
+                    Collections.replaceAll(kvs, viewIndexIdCell, keyValue);
+                }
+            }
+        }
+    }
+
+    public static SystemCatalogViewIndexIdFilter parseFrom(final byte [] 
pbBytes) throws DeserializationException {
+        try {
+            SystemCatalogViewIndexIdFilter writable = 
(SystemCatalogViewIndexIdFilter)
+                    Writables.getWritable(pbBytes, new 
SystemCatalogViewIndexIdFilter());
+            return writable;
+        } catch (IOException e) {
+            throw new DeserializationException(e);
+        }
+    }
+
+    @Override
+    public byte[] toByteArray() throws IOException {
+        return Writables.getBytes(this);
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        this.clientVersion = input.readInt();
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        output.writeInt(this.clientVersion);
+    }
+
+}
\ No newline at end of file
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index a3d096e..037c8d8 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -122,6 +122,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionLocation;
+import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.KeepDeletedCells;
 import org.apache.hadoop.hbase.NamespaceDescriptor;
 import org.apache.hadoop.hbase.NamespaceNotFoundException;
@@ -134,6 +135,7 @@ import 
org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
 import org.apache.hadoop.hbase.client.Connection;
 import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
 import org.apache.hadoop.hbase.client.Increment;
 import org.apache.hadoop.hbase.client.Mutation;
 import org.apache.hadoop.hbase.client.Put;
@@ -171,6 +173,7 @@ import org.apache.phoenix.coprocessor.ScanRegionObserver;
 import org.apache.phoenix.coprocessor.SequenceRegionObserver;
 import org.apache.phoenix.coprocessor.ServerCachingEndpointImpl;
 import org.apache.phoenix.coprocessor.PhoenixTTLRegionObserver;
+import org.apache.phoenix.coprocessor.SystemCatalogRegionObserver;
 import org.apache.phoenix.coprocessor.TaskMetaDataEndpoint;
 import org.apache.phoenix.coprocessor.TaskRegionObserver;
 import org.apache.phoenix.coprocessor.UngroupedAggregateRegionObserver;
@@ -1139,6 +1142,12 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
                             PhoenixTTLRegionObserver.class.getName(), null, 
priority-2, null);
                 }
             }
+            if (Arrays.equals(tableName, SYSTEM_CATALOG_NAME_BYTES)) {
+                if 
(!newDesc.hasCoprocessor(SystemCatalogRegionObserver.class.getName())) {
+                    builder.addCoprocessor(
+                            SystemCatalogRegionObserver.class.getName(), null, 
priority, null);
+                }
+            }
 
         } catch (IOException e) {
             throw ServerUtil.parseServerException(e);
@@ -3796,6 +3805,19 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
             } else {
                 LOGGER.info("Updating VIEW_INDEX_ID data type is not needed.");
             }
+            try (Admin admin = metaConnection.getQueryServices().getAdmin()) {
+                HTableDescriptor htd;
+                TableName syscatPhysicalTableName = 
SchemaUtil.getPhysicalTableName(
+                        PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME, props);
+                htd = admin.getTableDescriptor(syscatPhysicalTableName);
+                if 
(!htd.hasCoprocessor(SystemCatalogRegionObserver.class.getName())) {
+                    int priority = 
props.getInt(QueryServices.COPROCESSOR_PRIORITY_ATTRIB,
+                            QueryServicesOptions.DEFAULT_COPROCESSOR_PRIORITY);
+                    
htd.addCoprocessor(SystemCatalogRegionObserver.class.getName(), null, priority, 
null);
+                    admin.modifyTable(syscatPhysicalTableName, htd);
+                    pollForUpdatedTableDescriptor(admin, htd, 
syscatPhysicalTableName.getName());
+                }
+            }
         }
         return metaConnection;
     }
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/util/ViewIndexIdRetrieveUtil.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/util/ViewIndexIdRetrieveUtil.java
new file mode 100644
index 0000000..d5b0fea
--- /dev/null
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/util/ViewIndexIdRetrieveUtil.java
@@ -0,0 +1,66 @@
+/*
+ * 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.util;
+
+import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.schema.types.PLong;
+import org.apache.phoenix.schema.types.PSmallint;
+
+public final class ViewIndexIdRetrieveUtil {
+    public static final int VIEW_INDEX_ID_BIGINT_TYPE_PTR_LEN = 9;
+    public static final int VIEW_INDEX_ID_SMALLINT_TYPE_VALUE_LEN = 3;
+    public static final int NULL_DATA_TYPE_VALUE = 0;
+
+    private ViewIndexIdRetrieveUtil() {
+
+    }
+
+    public static Cell buildNewCell(Cell viewIndexIdCell, byte[] newVal) {
+        KeyValue keyValue = new KeyValue(
+                viewIndexIdCell.getRowArray(), viewIndexIdCell.getRowOffset(),
+                viewIndexIdCell.getRowLength(),
+                viewIndexIdCell.getFamilyArray(), 
viewIndexIdCell.getFamilyOffset(),
+                viewIndexIdCell.getFamilyLength(),
+                viewIndexIdCell.getQualifierArray(), 
viewIndexIdCell.getQualifierOffset(),
+                viewIndexIdCell.getQualifierLength(),
+                viewIndexIdCell.getTimestamp(),KeyValue.Type.Put,
+                newVal, 0,newVal.length);
+        keyValue.setSequenceId(viewIndexIdCell.getSequenceId());
+        return keyValue;
+    }
+
+    public static Cell getRetrievedViewIndexIdCell(Cell viewIndexIdCell, 
boolean isShortToLong) {
+
+        ImmutableBytesWritable columnValue =
+                new 
ImmutableBytesWritable(CellUtil.cloneValue(viewIndexIdCell));
+        ImmutableBytesWritable newValue = new ImmutableBytesWritable();
+
+        byte[] newBytes;
+
+        if (isShortToLong) {
+            newBytes = 
PLong.INSTANCE.toBytes(PSmallint.INSTANCE.toObject(columnValue.get()));
+        } else {
+            newBytes = 
PSmallint.INSTANCE.toBytes(PLong.INSTANCE.toObject(columnValue.get()));
+        }
+        newValue.set(newBytes);
+        return buildNewCell(viewIndexIdCell, newValue.get());
+    }
+}
\ No newline at end of file

Reply via email to