PHOENIX-2099 Backward Compatibility - Concurrent modification error on connect


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

Branch: refs/heads/calcite
Commit: 39afa9f18cad132a8a5c49b0e2e31671c85a3c7e
Parents: 997de5e
Author: Samarth <samarth.j...@salesforce.com>
Authored: Fri Jul 10 11:04:44 2015 -0700
Committer: Samarth <samarth.j...@salesforce.com>
Committed: Fri Jul 10 11:04:44 2015 -0700

----------------------------------------------------------------------
 .../coprocessor/MetaDataEndpointImpl.java       |  24 +-
 .../query/ConnectionQueryServicesImpl.java      |   8 +-
 .../org/apache/phoenix/util/UpgradeUtil.java    | 416 ++++++++++---------
 phoenix-protocol/src/main/PTable.proto          |   1 +
 4 files changed, 237 insertions(+), 212 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/39afa9f1/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
index f786768..399d56e 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
@@ -39,7 +39,6 @@ import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_ARRAY_BYTES;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_CONSTANT_BYTES;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_VIEW_REFERENCED_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.JAR_PATH_BYTES;
-import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.KEY_SEQ_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MAX_VALUE_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_VALUE_BYTES;
@@ -1567,12 +1566,6 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                     // We said to drop a table, but found a view or visa versa
                     if (type != expectedType) { return new 
MetaDataMutationResult(MutationCode.TABLE_NOT_FOUND,
                             EnvironmentEdgeManager.currentTimeMillis(), null); 
}
-                    if (table.getBaseColumnCount() == 0) {
-                        // If the base column count hasn't been set, then it 
means that the upgrade
-                        // to 4.5.0 is in progress. Have the client retry the 
mutation operation.
-                        return new 
MetaDataMutationResult(MutationCode.CONCURRENT_TABLE_MUTATION,
-                                EnvironmentEdgeManager.currentTimeMillis(), 
table);
-                    }
                 }
                 result = mutator.updateMutation(table, rowKeyMetaData, 
tableMetadata, region,
                             invalidateList, locks, clientTimeStamp);
@@ -1658,7 +1651,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                     }
                     
                     // if there is already a view column with the same name as 
the base table column we are trying to add
-                       if (existingViewColumn!=null) {
+                       if (existingViewColumn != null) {
                                List<Cell> dataTypes = viewColumnDefinitionPut
                                 
.get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES,
                                         
PhoenixDatabaseMetaData.DATA_TYPE_BYTES);
@@ -1684,7 +1677,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                                }
                         }
                                // if there is an existing view column that 
matches the column being added to the base table and if the column being added 
has a null
-                       // scale or maxLength, we need to explicity do a put to 
set the scale or maxLength to null (in case the view column has the scale or 
+                       // scale or maxLength, we need to explicitly do a put 
to set the scale or maxLength to null (in case the view column has the scale or 
                        // max length set)
                                List<Cell> columnSizes = 
viewColumnDefinitionPut.get(
                                 PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES,
@@ -1714,7 +1707,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                         }
                        }
                        else {
-                       // if we are adding a column that already exists in the 
view, no need to updates the base table or view table column count
+                       // if we are adding a column that already exists in the 
view, no need to update the base table or view table column count
                        numColsAddedToView++;
                     } 
                        
@@ -1914,9 +1907,14 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                     if (type == PTableType.TABLE || type == PTableType.SYSTEM) 
{
                         TableViewFinderResult childViewsResult = 
findChildViews(region, tenantId, table, PHYSICAL_TABLE_BYTES);
                         if (childViewsResult.hasViews()) {
-                            // Adding a column is not allowed if the meta-data 
for child view/s spans over
-                            // more than one region (since the changes cannot 
be done in a transactional fashion)
-                            if (!childViewsResult.allViewsInSingleRegion()) {
+                           /* 
+                            * Adding a column is not allowed if the meta-data 
for child view/s spans over
+                            * more than one region (since the changes cannot 
be made in a transactional fashion)
+                            * A base column count of 0 means that the metadata 
hasn't been upgraded yet or
+                            * the upgrade is currently in progress. If that is 
the case, disallow adding columns
+                            *  for tables with views.
+                            */
+                            if (!childViewsResult.allViewsInSingleRegion() || 
table.getBaseColumnCount() == 0) {
                                 return new 
MetaDataMutationResult(MutationCode.UNALLOWED_TABLE_MUTATION,
                                         
EnvironmentEdgeManager.currentTimeMillis(), null);
                             } else {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/39afa9f1/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
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 a9f455a..9cd32e8 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
@@ -1826,7 +1826,10 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
         return result;
 
     }
-
+    
+    /**
+     * This closes the passed connection.
+     */
     private PhoenixConnection addColumn(PhoenixConnection oldMetaConnection, 
String tableName, long timestamp, String columns, boolean addIfNotExists) 
throws SQLException {
         Properties props = new Properties(oldMetaConnection.getClientInfo());
         props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, 
Long.toString(timestamp));
@@ -1956,7 +1959,7 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
                                     columnsToAdd = 
PhoenixDatabaseMetaData.BASE_COLUMN_COUNT + " "
                                             + 
PInteger.INSTANCE.getSqlTypeName();
                                     try {
-                                        addColumn(metaConnection, 
PhoenixDatabaseMetaData.SYSTEM_CATALOG,
+                                        metaConnection = 
addColumn(metaConnection, PhoenixDatabaseMetaData.SYSTEM_CATALOG,
                                                 
MetaDataProtocol.MIN_SYSTEM_TABLE_TIMESTAMP, columnsToAdd, false);
                                         upgradeTo4_5_0(metaConnection);
                                     } catch (ColumnAlreadyExistsException 
ignored) {
@@ -1965,6 +1968,7 @@ public class ConnectionQueryServicesImpl extends 
DelegateQueryServices implement
                                          * BASE_COLUMN_COUNT is already part 
of the meta-data schema as the signal that
                                          * the server side upgrade has 
finished or is in progress.
                                          */
+                                        logger.debug("No need to run 4.5 
upgrade");
                                     }
                                 }
                             }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/39afa9f1/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java 
b/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
index 8d574ce..c829799 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
@@ -443,216 +443,238 @@ public class UpgradeUtil {
                 buf, keyValue.getValueOffset(), keyValue.getValueLength());
     }
     
-    public static void upgradeTo4_5_0(PhoenixConnection metaConnection) throws 
SQLException {
-        String getBaseTableAndViews = "SELECT "
-                + COLUMN_FAMILY + " AS BASE_PHYSICAL_TABLE, "
-                + TENANT_ID + ", "
-                + TABLE_SCHEM + " AS VIEW_SCHEMA, "
-                + TABLE_NAME + " AS VIEW_NAME "
-                + "FROM " + SYSTEM_CATALOG_NAME 
-                + " WHERE " + COLUMN_FAMILY + " IS NOT NULL " // column_family 
column points to the physical table name.
-                + " AND " + COLUMN_NAME + " IS NULL "
-                + " AND " + LINK_TYPE + " = ? ";
-        // Build a map of base table name -> list of views on the table. 
-        Map<String, List<ViewKey>> parentTableViewsMap = new HashMap<>();
-        try (PreparedStatement stmt = 
metaConnection.prepareStatement(getBaseTableAndViews)) {
-            // Get back view rows that have links back to the base physical 
table. This takes care
-            // of cases when we have a hierarchy of views too.
-            stmt.setByte(1, LinkType.PHYSICAL_TABLE.getSerializedValue());
-            try (ResultSet rs = stmt.executeQuery()) {
-                while (rs.next()) {
-                    // this is actually SCHEMANAME.TABLENAME
-                    String parentTable = rs.getString("BASE_PHYSICAL_TABLE");
-                    String tenantId = rs.getString(TENANT_ID);
-                    String viewSchema = rs.getString("VIEW_SCHEMA");
-                    String viewName = rs.getString("VIEW_NAME");
-                    List<ViewKey> viewKeysList = 
parentTableViewsMap.get(parentTable);
-                    if (viewKeysList == null) {
-                        viewKeysList = new ArrayList<>();
-                        parentTableViewsMap.put(parentTable, viewKeysList);
+    /**
+     * Upgrade the metadata in the catalog table to enable adding columns to 
tables with views
+     * @param oldMetaConnection caller should take care of closing the passed 
connection appropriately
+     * @throws SQLException
+     */
+    public static void upgradeTo4_5_0(PhoenixConnection oldMetaConnection) 
throws SQLException {
+        PhoenixConnection metaConnection = null;
+        try {
+            // Need to use own connection without any SCN to be able to read 
all data from SYSTEM.CATALOG 
+            metaConnection = new PhoenixConnection(oldMetaConnection);
+            logger.info("Upgrading metadata to support adding columns to 
tables with views");
+            String getBaseTableAndViews = "SELECT "
+                    + COLUMN_FAMILY + " AS BASE_PHYSICAL_TABLE, "
+                    + TENANT_ID + ", "
+                    + TABLE_SCHEM + " AS VIEW_SCHEMA, "
+                    + TABLE_NAME + " AS VIEW_NAME "
+                    + "FROM " + SYSTEM_CATALOG_NAME 
+                    + " WHERE " + COLUMN_FAMILY + " IS NOT NULL " // 
column_family column points to the physical table name.
+                    + " AND " + COLUMN_NAME + " IS NULL "
+                    + " AND " + LINK_TYPE + " = ? ";
+            // Build a map of base table name -> list of views on the table. 
+            Map<String, List<ViewKey>> parentTableViewsMap = new HashMap<>();
+            try (PreparedStatement stmt = 
metaConnection.prepareStatement(getBaseTableAndViews)) {
+                // Get back view rows that have links back to the base 
physical table. This takes care
+                // of cases when we have a hierarchy of views too.
+                stmt.setByte(1, LinkType.PHYSICAL_TABLE.getSerializedValue());
+                try (ResultSet rs = stmt.executeQuery()) {
+                    while (rs.next()) {
+                        // this is actually SCHEMANAME.TABLENAME
+                        String parentTable = 
rs.getString("BASE_PHYSICAL_TABLE");
+                        String tenantId = rs.getString(TENANT_ID);
+                        String viewSchema = rs.getString("VIEW_SCHEMA");
+                        String viewName = rs.getString("VIEW_NAME");
+                        List<ViewKey> viewKeysList = 
parentTableViewsMap.get(parentTable);
+                        if (viewKeysList == null) {
+                            viewKeysList = new ArrayList<>();
+                            parentTableViewsMap.put(parentTable, viewKeysList);
+                        }
+                        viewKeysList.add(new ViewKey(tenantId, viewSchema, 
viewName));
                     }
-                    viewKeysList.add(new ViewKey(tenantId, viewSchema, 
viewName));
                 }
             }
-        }
-        
-        for (Entry<String, List<ViewKey>> entry : 
parentTableViewsMap.entrySet()) {
-            // Fetch column information for the base physical table
-            String physicalTable = entry.getKey();
-            String baseTableSchemaName = 
SchemaUtil.getSchemaNameFromFullName(physicalTable).equals(StringUtil.EMPTY_STRING)
 ? null : SchemaUtil.getSchemaNameFromFullName(physicalTable);
-            String baseTableName = 
SchemaUtil.getTableNameFromFullName(physicalTable);
-            List<ColumnDetails> basePhysicalTableColumns = new ArrayList<>(); 
-            
-            // Columns fetched in order of ordinal position
-            String fetchColumnInfoForBasePhysicalTable = "SELECT " +
-                    COLUMN_NAME + "," +
-                    COLUMN_FAMILY + "," +
-                    DATA_TYPE + "," +
-                    COLUMN_SIZE + "," +
-                    DECIMAL_DIGITS + "," +
-                    ORDINAL_POSITION + "," +
-                    SORT_ORDER + "," +
-                    ARRAY_SIZE + " " +
-                    "FROM SYSTEM.CATALOG " +
-                    "WHERE " +
-                    "TABLE_SCHEM %s " +
-                    "AND TABLE_NAME = ? " +
-                    "AND COLUMN_NAME IS NOT NULL " +
-                    "ORDER BY " + 
-                    ORDINAL_POSITION;
-           
-            PreparedStatement stmt = null;
-            if (baseTableSchemaName == null) {
-                fetchColumnInfoForBasePhysicalTable =
-                        String.format(fetchColumnInfoForBasePhysicalTable, "IS 
NULL ");
-                stmt = 
metaConnection.prepareStatement(fetchColumnInfoForBasePhysicalTable);
-                stmt.setString(1, baseTableName);
-            } else {
-                fetchColumnInfoForBasePhysicalTable =
-                        String.format(fetchColumnInfoForBasePhysicalTable, " = 
? ");
-                stmt = 
metaConnection.prepareStatement(fetchColumnInfoForBasePhysicalTable);
-                stmt.setString(1, baseTableSchemaName);
-                stmt.setString(2, baseTableName);
-            }
+            boolean clearCache = false;
+            for (Entry<String, List<ViewKey>> entry : 
parentTableViewsMap.entrySet()) {
+                // Fetch column information for the base physical table
+                String physicalTable = entry.getKey();
+                String baseTableSchemaName = 
SchemaUtil.getSchemaNameFromFullName(physicalTable).equals(StringUtil.EMPTY_STRING)
 ? null : SchemaUtil.getSchemaNameFromFullName(physicalTable);
+                String baseTableName = 
SchemaUtil.getTableNameFromFullName(physicalTable);
+                List<ColumnDetails> basePhysicalTableColumns = new 
ArrayList<>(); 
+
+                // Columns fetched in order of ordinal position
+                String fetchColumnInfoForBasePhysicalTable = "SELECT " +
+                        COLUMN_NAME + "," +
+                        COLUMN_FAMILY + "," +
+                        DATA_TYPE + "," +
+                        COLUMN_SIZE + "," +
+                        DECIMAL_DIGITS + "," +
+                        ORDINAL_POSITION + "," +
+                        SORT_ORDER + "," +
+                        ARRAY_SIZE + " " +
+                        "FROM SYSTEM.CATALOG " +
+                        "WHERE " +
+                        "TABLE_SCHEM %s " +
+                        "AND TABLE_NAME = ? " +
+                        "AND COLUMN_NAME IS NOT NULL " +
+                        "ORDER BY " + 
+                        ORDINAL_POSITION;
+
+                PreparedStatement stmt = null;
+                if (baseTableSchemaName == null) {
+                    fetchColumnInfoForBasePhysicalTable =
+                            String.format(fetchColumnInfoForBasePhysicalTable, 
"IS NULL ");
+                    stmt = 
metaConnection.prepareStatement(fetchColumnInfoForBasePhysicalTable);
+                    stmt.setString(1, baseTableName);
+                } else {
+                    fetchColumnInfoForBasePhysicalTable =
+                            String.format(fetchColumnInfoForBasePhysicalTable, 
" = ? ");
+                    stmt = 
metaConnection.prepareStatement(fetchColumnInfoForBasePhysicalTable);
+                    stmt.setString(1, baseTableSchemaName);
+                    stmt.setString(2, baseTableName);
+                }
 
-            try (ResultSet rs = stmt.executeQuery()) {
-                while (rs.next()) {
-                    basePhysicalTableColumns.add(new 
ColumnDetails(rs.getString(COLUMN_FAMILY), rs
-                            .getString(COLUMN_NAME), 
rs.getInt(ORDINAL_POSITION), rs
-                            .getInt(DATA_TYPE), rs.getInt(COLUMN_SIZE), 
rs.getInt(DECIMAL_DIGITS),
-                            rs.getInt(SORT_ORDER), rs.getInt(ARRAY_SIZE)));
+                try (ResultSet rs = stmt.executeQuery()) {
+                    while (rs.next()) {
+                        basePhysicalTableColumns.add(new 
ColumnDetails(rs.getString(COLUMN_FAMILY), rs
+                                .getString(COLUMN_NAME), 
rs.getInt(ORDINAL_POSITION), rs
+                                .getInt(DATA_TYPE), rs.getInt(COLUMN_SIZE), 
rs.getInt(DECIMAL_DIGITS),
+                                rs.getInt(SORT_ORDER), rs.getInt(ARRAY_SIZE)));
+                    }
                 }
-            }
-            
-            // Fetch column information for all the views on the base physical 
table ordered by ordinal position.
-            List<ViewKey> viewKeys = entry.getValue();
-            StringBuilder sb = new StringBuilder();
-            sb.append("SELECT " + 
-                    TENANT_ID + "," +
-                    TABLE_SCHEM + "," +
-                    TABLE_NAME + "," +
-                    COLUMN_NAME + "," +
-                    COLUMN_FAMILY + "," +
-                    DATA_TYPE + "," +
-                    COLUMN_SIZE + "," +
-                    DECIMAL_DIGITS + "," +
-                    ORDINAL_POSITION + "," +
-                    SORT_ORDER + "," +
-                    ARRAY_SIZE + " " + 
-                    "FROM SYSTEM.CATALOG " +
-                    "WHERE " +
-                    COLUMN_NAME + " IS NOT NULL " +
-                    "AND " +
-                    ORDINAL_POSITION + " <= ? " + // fetch only those columns 
that would impact setting of base column count
-                    "AND " +
-                    "(" + TENANT_ID+ ", " + TABLE_SCHEM + ", " + TABLE_NAME + 
") IN (");
-            
-            int numViews = viewKeys.size();
-            for (int i = 0; i < numViews; i++) {
-                sb.append(" (?, ?, ?) ");
-                if (i < numViews - 1) {
-                    sb.append(", ");
+
+                // Fetch column information for all the views on the base 
physical table ordered by ordinal position.
+                List<ViewKey> viewKeys = entry.getValue();
+                StringBuilder sb = new StringBuilder();
+                sb.append("SELECT " + 
+                        TENANT_ID + "," +
+                        TABLE_SCHEM + "," +
+                        TABLE_NAME + "," +
+                        COLUMN_NAME + "," +
+                        COLUMN_FAMILY + "," +
+                        DATA_TYPE + "," +
+                        COLUMN_SIZE + "," +
+                        DECIMAL_DIGITS + "," +
+                        ORDINAL_POSITION + "," +
+                        SORT_ORDER + "," +
+                        ARRAY_SIZE + " " + 
+                        "FROM SYSTEM.CATALOG " +
+                        "WHERE " +
+                        COLUMN_NAME + " IS NOT NULL " +
+                        "AND " +
+                        ORDINAL_POSITION + " <= ? " + // fetch only those 
columns that would impact setting of base column count
+                        "AND " +
+                        "(" + TENANT_ID+ ", " + TABLE_SCHEM + ", " + 
TABLE_NAME + ") IN (");
+
+                int numViews = viewKeys.size();
+                for (int i = 0; i < numViews; i++) {
+                    sb.append(" (?, ?, ?) ");
+                    if (i < numViews - 1) {
+                        sb.append(", ");
+                    }
                 }
-            }
-            sb.append(" ) ");
-            sb.append(" GROUP BY " +
-                    TENANT_ID + "," +
-                    TABLE_SCHEM + "," +
-                    TABLE_NAME + "," +
-                    COLUMN_NAME + "," +
-                    COLUMN_FAMILY + "," +
-                    DATA_TYPE + "," +
-                    COLUMN_SIZE + "," +
-                    DECIMAL_DIGITS + "," +
-                    ORDINAL_POSITION + "," +
-                    SORT_ORDER + "," +
-                    ARRAY_SIZE + " " + 
-                    "ORDER BY " + 
-                    TENANT_ID + "," + TABLE_SCHEM + ", " + TABLE_NAME + ", " + 
ORDINAL_POSITION);
-            String fetchViewColumnsSql = sb.toString();
-            stmt = metaConnection.prepareStatement(fetchViewColumnsSql);
-            int numColsInBaseTable = basePhysicalTableColumns.size();
-            stmt.setInt(1, numColsInBaseTable);
-            int paramIndex = 1;
-            stmt.setInt(paramIndex++, numColsInBaseTable);
-            for (ViewKey view : viewKeys) {
-                stmt.setString(paramIndex++, view.tenantId);
-                stmt.setString(paramIndex++, view.schema);
-                stmt.setString(paramIndex++, view.name);
-            }
-            String currentTenantId = null;
-            String currentViewSchema = null;
-            String currentViewName = null;
-            try (ResultSet rs = stmt.executeQuery()) {
-                int numBaseTableColsMatched = 0;
-                boolean ignore = false;
-                boolean baseColumnCountUpserted = false;
-                while (rs.next()) {
-                    String viewTenantId = rs.getString(TENANT_ID);
-                    String viewSchema = rs.getString(TABLE_SCHEM);
-                    String viewName = rs.getString(TABLE_NAME);
-                    if (!(Objects.equal(viewTenantId, currentTenantId) && 
Objects.equal(viewSchema, currentViewSchema) && Objects.equal(viewName, 
currentViewName))) {
-                        // We are about to iterate through columns of a 
different view. Check whether base column count was upserted.
-                        // If it wasn't then it is likely the case that a 
column inherited from the base table was dropped from view.
-                        if (currentViewName != null && 
!baseColumnCountUpserted && numBaseTableColsMatched < numColsInBaseTable) {
-                            upsertBaseColumnCountInHeaderRow(metaConnection, 
currentTenantId, currentViewSchema, currentViewName, 
DIVERGED_VIEW_BASE_COLUMN_COUNT);
+                sb.append(" ) ");
+                sb.append(" GROUP BY " +
+                        TENANT_ID + "," +
+                        TABLE_SCHEM + "," +
+                        TABLE_NAME + "," +
+                        COLUMN_NAME + "," +
+                        COLUMN_FAMILY + "," +
+                        DATA_TYPE + "," +
+                        COLUMN_SIZE + "," +
+                        DECIMAL_DIGITS + "," +
+                        ORDINAL_POSITION + "," +
+                        SORT_ORDER + "," +
+                        ARRAY_SIZE + " " + 
+                        "ORDER BY " + 
+                        TENANT_ID + "," + TABLE_SCHEM + ", " + TABLE_NAME + ", 
" + ORDINAL_POSITION);
+                String fetchViewColumnsSql = sb.toString();
+                stmt = metaConnection.prepareStatement(fetchViewColumnsSql);
+                int numColsInBaseTable = basePhysicalTableColumns.size();
+                stmt.setInt(1, numColsInBaseTable);
+                int paramIndex = 1;
+                stmt.setInt(paramIndex++, numColsInBaseTable);
+                for (ViewKey view : viewKeys) {
+                    stmt.setString(paramIndex++, view.tenantId);
+                    stmt.setString(paramIndex++, view.schema);
+                    stmt.setString(paramIndex++, view.name);
+                }
+                String currentTenantId = null;
+                String currentViewSchema = null;
+                String currentViewName = null;
+                try (ResultSet rs = stmt.executeQuery()) {
+                    int numBaseTableColsMatched = 0;
+                    boolean ignore = false;
+                    boolean baseColumnCountUpserted = false;
+                    while (rs.next()) {
+                        String viewTenantId = rs.getString(TENANT_ID);
+                        String viewSchema = rs.getString(TABLE_SCHEM);
+                        String viewName = rs.getString(TABLE_NAME);
+                        if (!(Objects.equal(viewTenantId, currentTenantId) && 
Objects.equal(viewSchema, currentViewSchema) && Objects.equal(viewName, 
currentViewName))) {
+                            // We are about to iterate through columns of a 
different view. Check whether base column count was upserted.
+                            // If it wasn't then it is likely the case that a 
column inherited from the base table was dropped from view.
+                            if (currentViewName != null && 
!baseColumnCountUpserted && numBaseTableColsMatched < numColsInBaseTable) {
+                                
upsertBaseColumnCountInHeaderRow(metaConnection, currentTenantId, 
currentViewSchema, currentViewName, DIVERGED_VIEW_BASE_COLUMN_COUNT);
+                                clearCache = true;
+                            }
+                            // reset the values as we are now going to iterate 
over columns of a new view.
+                            numBaseTableColsMatched = 0;
+                            currentTenantId = viewTenantId;
+                            currentViewSchema = viewSchema;
+                            currentViewName = viewName;
+                            ignore = false;
+                            baseColumnCountUpserted = false;
                         }
-                        // reset the values as we are now going to iterate 
over columns of a new view.
-                        numBaseTableColsMatched = 0;
-                        currentTenantId = viewTenantId;
-                        currentViewSchema = viewSchema;
-                        currentViewName = viewName;
-                        ignore = false;
-                        baseColumnCountUpserted = false;
-                    }
-                    if (!ignore) {
-                        /*
-                         * Iterate over all the columns of the base physical 
table and the columns of the view. Compare the
-                         * two till one of the following happens: 
-                         * 
-                         * 1) We run into a view column which is different 
from column in the base physical table.
-                         * This means that the view has divorced itself from 
the base physical table. In such a case
-                         * we will set a special value for the base column 
count. That special value will also be used
-                         * on the server side to filter out the divorced view 
so that meta-data changes on the base 
-                         * physical table are not propagated to it.
-                         * 
-                         * 2) Every physical table column is present in the 
view. In that case we set the base column count
-                         * as the number of columns in the base physical 
table. At that point we ignore rest of the columns
-                         * of the view.
-                         * 
-                         */
-                        ColumnDetails baseTableColumn = 
basePhysicalTableColumns.get(numBaseTableColsMatched);
-                        String columName = rs.getString(COLUMN_NAME);
-                        String columnFamily = rs.getString(COLUMN_FAMILY);
-                        int ordinalPos = rs.getInt(ORDINAL_POSITION);
-                        int dataType = rs.getInt(DATA_TYPE);
-                        int columnSize = rs.getInt(COLUMN_SIZE);
-                        int decimalDigits = rs.getInt(DECIMAL_DIGITS);
-                        int sortOrder = rs.getInt(SORT_ORDER);
-                        int arraySize = rs.getInt(ARRAY_SIZE);
-                        ColumnDetails viewColumn = new 
ColumnDetails(columnFamily, columName, ordinalPos, dataType, columnSize, 
decimalDigits, sortOrder, arraySize);
-                        if (baseTableColumn.equals(viewColumn)) {
-                            numBaseTableColsMatched++;
-                            if (numBaseTableColsMatched == numColsInBaseTable) 
{
-                                
upsertBaseColumnCountInHeaderRow(metaConnection, viewTenantId, viewSchema, 
viewName, numColsInBaseTable);
-                                // No need to ignore the rest of the columns 
of the view here since the
-                                // query retrieved only those columns that had 
ordinal position <= numColsInBaseTable
+                        if (!ignore) {
+                            /*
+                             * Iterate over all the columns of the base 
physical table and the columns of the view. Compare the
+                             * two till one of the following happens: 
+                             * 
+                             * 1) We run into a view column which is different 
from column in the base physical table.
+                             * This means that the view has divorced itself 
from the base physical table. In such a case
+                             * we will set a special value for the base column 
count. That special value will also be used
+                             * on the server side to filter out the divorced 
view so that meta-data changes on the base 
+                             * physical table are not propagated to it.
+                             * 
+                             * 2) Every physical table column is present in 
the view. In that case we set the base column count
+                             * as the number of columns in the base physical 
table. At that point we ignore rest of the columns
+                             * of the view.
+                             * 
+                             */
+                            ColumnDetails baseTableColumn = 
basePhysicalTableColumns.get(numBaseTableColsMatched);
+                            String columName = rs.getString(COLUMN_NAME);
+                            String columnFamily = rs.getString(COLUMN_FAMILY);
+                            int ordinalPos = rs.getInt(ORDINAL_POSITION);
+                            int dataType = rs.getInt(DATA_TYPE);
+                            int columnSize = rs.getInt(COLUMN_SIZE);
+                            int decimalDigits = rs.getInt(DECIMAL_DIGITS);
+                            int sortOrder = rs.getInt(SORT_ORDER);
+                            int arraySize = rs.getInt(ARRAY_SIZE);
+                            ColumnDetails viewColumn = new 
ColumnDetails(columnFamily, columName, ordinalPos, dataType, columnSize, 
decimalDigits, sortOrder, arraySize);
+                            if (baseTableColumn.equals(viewColumn)) {
+                                numBaseTableColsMatched++;
+                                if (numBaseTableColsMatched == 
numColsInBaseTable) {
+                                    
upsertBaseColumnCountInHeaderRow(metaConnection, viewTenantId, viewSchema, 
viewName, numColsInBaseTable);
+                                    // No need to ignore the rest of the 
columns of the view here since the
+                                    // query retrieved only those columns that 
had ordinal position <= numColsInBaseTable
+                                    baseColumnCountUpserted = true;
+                                    clearCache = true;
+                                }
+                            } else {
+                                // special value to denote that the view has 
divorced itself from the base physical table.
+                                
upsertBaseColumnCountInHeaderRow(metaConnection, viewTenantId, viewSchema, 
viewName, DIVERGED_VIEW_BASE_COLUMN_COUNT);
                                 baseColumnCountUpserted = true;
+                                clearCache = true;
+                                // ignore rest of the rows for the view.
+                                ignore = true;
                             }
-                        } else {
-                            // special value to denote that the view has 
divorced itself from the base physical table.
-                            upsertBaseColumnCountInHeaderRow(metaConnection, 
viewTenantId, viewSchema, viewName, DIVERGED_VIEW_BASE_COLUMN_COUNT);
-                            baseColumnCountUpserted = true;
-                            // ignore rest of the rows for the view.
-                            ignore = true;
                         }
                     }
                 }
+                // set base column count for the header row of the base table 
too. We use this information
+                // to figure out whether the upgrade is in progress or hasn't 
started.
+                upsertBaseColumnCountInHeaderRow(metaConnection, null, 
baseTableSchemaName, baseTableName, BASE_TABLE_BASE_COLUMN_COUNT);
+                metaConnection.commit();
+            }
+            // clear metadata cache on region servers to force loading of the 
latest metadata
+            if (clearCache) {
+                metaConnection.getQueryServices().clearCache();
+            }
+        } finally {
+            if (metaConnection != null) {
+                metaConnection.close();
             }
-            // set base column count for the header row of the base table too. 
We use this information
-            // to figure out whether the upgrade is in progress or hasn't 
started.
-            upsertBaseColumnCountInHeaderRow(metaConnection, null, 
baseTableSchemaName, baseTableName, BASE_TABLE_BASE_COLUMN_COUNT);
-            metaConnection.commit();
         }
     }
     

http://git-wip-us.apache.org/repos/asf/phoenix/blob/39afa9f1/phoenix-protocol/src/main/PTable.proto
----------------------------------------------------------------------
diff --git a/phoenix-protocol/src/main/PTable.proto 
b/phoenix-protocol/src/main/PTable.proto
index 348631f..cbbbdd6 100644
--- a/phoenix-protocol/src/main/PTable.proto
+++ b/phoenix-protocol/src/main/PTable.proto
@@ -83,4 +83,5 @@ message PTable {
   optional bytes indexType = 22;
   optional int64 statsTimeStamp = 23;
   optional bool storeNulls = 24;
+  optional int32 baseColumnCount = 25;
 }

Reply via email to