PHOENIX-5605: 4.14 Client can't add a column to a table on a 4.15 server
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 21c0823..dab77b6 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
@@ -2110,12 +2110,11 @@
         return PTableType.INDEX == tableType && parentTable.getIndexes().size() >= maxIndexesPerTable;
     }
 
-    private List<PTable> findAllChildViews(long clientTimeStamp, byte[] tenantId, byte[] schemaName, byte[] tableName) throws IOException, SQLException {
+    private List<PTable> findAllChildViews(long clientTimeStamp, int clientVersion, byte[] tenantId,
+            byte[] schemaName, byte[] tableName) throws IOException, SQLException {
         TableViewFinderResult result = new TableViewFinderResult();
-        try (Table hTable =
-                     env.getTable(SchemaUtil.getPhysicalTableName(
-                             SYSTEM_CHILD_LINK_NAME_BYTES,
-                             env.getConfiguration()))) {
+        try (Table hTable = env.getTable(
+                getSystemTableForChildLinks(clientVersion, env.getConfiguration()))) {
             ViewUtil.findAllRelatives(hTable, tenantId, schemaName, tableName,
                     LinkType.CHILD_TABLE, result);
         }
@@ -2505,7 +2504,8 @@
             List<RowLock> locks = Lists.newArrayList();
             try {
                 if (expectedType == PTableType.TABLE) {
-                    childViews = findAllChildViews(clientTimeStamp, tenantId, schemaName, tableName);
+                    childViews = findAllChildViews(clientTimeStamp, clientVersion, tenantId,
+                            schemaName, tableName);
 
                     if (!childViews.isEmpty()) {
                         // From 4.15 onwards we allow SYSTEM.CATALOG to split and no longer propagate parent
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 fe05aca..b7bbb02 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
@@ -42,6 +42,8 @@
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE_BYTES;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_CAT;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
@@ -1348,28 +1350,37 @@
             syncUpdateCacheFreqForIndexesOfTable(table, stmt);
 
             TableViewFinderResult childViewsResult = new TableViewFinderResult();
-            try (Table childLinkTable = newConn.getQueryServices()
-                    .getTable(SchemaUtil.getPhysicalName(
-                            PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES,
-                            newConn.getQueryServices().getProps())
-                            .getName())) {
-                ViewUtil.findAllRelatives(childLinkTable, tenantId,
-                        table.getSchemaName().getBytes(), table.getTableName().getBytes(),
-                        LinkType.CHILD_TABLE, childViewsResult);
+            for (int i=0; i<2; i++) {
+                try (Table sysCatOrSysChildLinkTable = newConn.getQueryServices()
+                        .getTable(SchemaUtil.getPhysicalName(
+                                i==0 ? SYSTEM_CHILD_LINK_NAME_BYTES : SYSTEM_CATALOG_TABLE_BYTES,
+                                newConn.getQueryServices().getProps())
+                                .getName())) {
+                    ViewUtil.findAllRelatives(sysCatOrSysChildLinkTable, tenantId,
+                            table.getSchemaName().getBytes(), table.getTableName().getBytes(),
+                            LinkType.CHILD_TABLE, childViewsResult);
 
-                // Iterate over the chain of child views
-                for (TableInfo tableInfo: childViewsResult.getLinks()) {
-                    PTable view;
-                    String viewName = SchemaUtil.getTableName(tableInfo.getSchemaName(),
-                            tableInfo.getTableName());
-                    try {
-                        view = PhoenixRuntime.getTable(newConn, viewName);
-                    } catch (TableNotFoundException e) {
-                        // Ignore
-                        LOGGER.warn("Error getting PTable for view: " + viewName);
-                        continue;
+                    // Iterate over the chain of child views
+                    for (TableInfo tableInfo: childViewsResult.getLinks()) {
+                        PTable view;
+                        String viewName = SchemaUtil.getTableName(tableInfo.getSchemaName(),
+                                tableInfo.getTableName());
+                        try {
+                            view = PhoenixRuntime.getTable(newConn, viewName);
+                        } catch (TableNotFoundException e) {
+                            // Ignore
+                            LOGGER.warn("Error getting PTable for view: " + viewName);
+                            continue;
+                        }
+                        syncUpdateCacheFreqForIndexesOfTable(view, stmt);
                     }
-                    syncUpdateCacheFreqForIndexesOfTable(view, stmt);
+                    break;
+                } catch (TableNotFoundException ex) {
+                    // try again with SYSTEM.CATALOG in case the schema is old
+                    if (i == 1) {
+                        // This means even SYSTEM.CATALOG was not found, so this is bad, rethrow
+                        throw ex;
+                    }
                 }
             }
             stmt.executeBatch();
@@ -2110,14 +2121,23 @@
             LOGGER.info(String.format("teanantId %s..", conn.getTenantId()));
 
             TableViewFinderResult childViewsResult = new TableViewFinderResult();
-            try (Table childLinkTable =
-                    conn.getQueryServices()
-                            .getTable(SchemaUtil.getPhysicalName(
-                                PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES, readOnlyProps)
-                                    .getName())) {
-                byte[] tenantId = conn.getTenantId() != null ? conn.getTenantId().getBytes() : null;
-                ViewUtil.findAllRelatives(childLinkTable, tenantId, schemaName.getBytes(),
-                    tableName.getBytes(), LinkType.CHILD_TABLE, childViewsResult);
+
+            for (int i=0; i<2; i++) {
+                try (Table sysCatOrSysChildLinkTable = conn.getQueryServices()
+                        .getTable(SchemaUtil.getPhysicalName(
+                                i==0 ? SYSTEM_CHILD_LINK_NAME_BYTES : SYSTEM_CATALOG_TABLE_BYTES,
+                                readOnlyProps).getName())) {
+                    byte[] tenantId = conn.getTenantId() != null ? conn.getTenantId().getBytes() : null;
+                    ViewUtil.findAllRelatives(sysCatOrSysChildLinkTable, tenantId, schemaName.getBytes(),
+                            tableName.getBytes(), LinkType.CHILD_TABLE, childViewsResult);
+                    break;
+                } catch (TableNotFoundException ex) {
+                    // try again with SYSTEM.CATALOG in case the schema is old
+                    if (i == 1) {
+                        // This means even SYSTEM.CATALOG was not found, so this is bad, rethrow
+                        throw ex;
+                    }
+                }
             }
 
             // Upgrade the data or main table
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java
index 8c81234..5757adc 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java
@@ -85,25 +85,25 @@
 
     private static final Logger logger = LoggerFactory.getLogger(ViewUtil.class);
 
-    public static void findAllRelatives(Table systemTable, byte[] tenantId, byte[] schema, byte[] table,
+    public static void findAllRelatives(Table sysCatOrsysChildLink, byte[] tenantId, byte[] schema, byte[] table,
         PTable.LinkType linkType, TableViewFinderResult result) throws IOException {
-        findAllRelatives(systemTable, tenantId, schema, table, linkType, HConstants.LATEST_TIMESTAMP, result);
+        findAllRelatives(sysCatOrsysChildLink, tenantId, schema, table, linkType, HConstants.LATEST_TIMESTAMP, result);
     }
 
-    static void findAllRelatives(Table systemCatalog, byte[] tenantId, byte[] schema, byte[] table,
+    private static void findAllRelatives(Table sysCatOrsysChildLink, byte[] tenantId, byte[] schema, byte[] table,
         PTable.LinkType linkType, long timestamp, TableViewFinderResult result) throws IOException {
         TableViewFinderResult currentResult =
-            findRelatedViews(systemCatalog, tenantId, schema, table, linkType, timestamp);
+            findRelatedViews(sysCatOrsysChildLink, tenantId, schema, table, linkType, timestamp);
         result.addResult(currentResult);
         for (TableInfo viewInfo : currentResult.getLinks()) {
-            findAllRelatives(systemCatalog, viewInfo.getTenantId(), viewInfo.getSchemaName(), viewInfo.getTableName(), linkType, timestamp, result);
+            findAllRelatives(sysCatOrsysChildLink, viewInfo.getTenantId(), viewInfo.getSchemaName(), viewInfo.getTableName(), linkType, timestamp, result);
         }
     }
 
     /**
      * Runs a scan on SYSTEM.CATALOG or SYSTEM.CHILD_LINK to get the related tables/views
      */
-    static TableViewFinderResult findRelatedViews(Table systemCatalog, byte[] tenantId, byte[] schema, byte[] table,
+    private static TableViewFinderResult findRelatedViews(Table sysCatOrsysChildLink, byte[] tenantId, byte[] schema, byte[] table,
         PTable.LinkType linkType, long timestamp) throws IOException {
         if (linkType==PTable.LinkType.INDEX_TABLE || linkType==PTable.LinkType.EXCLUDED_COLUMN) {
             throw new IllegalArgumentException("findAllRelatives does not support link type "+linkType);
@@ -121,7 +121,7 @@
         if (linkType==PTable.LinkType.PHYSICAL_TABLE)
             scan.addColumn(TABLE_FAMILY_BYTES, TABLE_TYPE_BYTES);
         List<TableInfo> tableInfoList = Lists.newArrayList();
-        try (ResultScanner scanner = systemCatalog.getScanner(scan))  {
+        try (ResultScanner scanner = sysCatOrsysChildLink.getScanner(scan))  {
             for (Result result = scanner.next(); (result != null); result = scanner.next()) {
                 byte[][] rowKeyMetaData = new byte[5][];
                 byte[] viewTenantId = null;
@@ -189,7 +189,7 @@
         }
         catch (Exception e){
         }
-        // if the SYSTEM.CHILD_LINK doesn't exist just return
+        // if the SYSTEM.CATALOG or SYSTEM.CHILD_LINK doesn't exist just return
         if (hTable==null) {
             return;
         }