PHOENIX-3534 Support multi region SYSTEM.CATALOG table (Thomas D'Silva and Rahul Gidwani)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/d56fd3c9 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/d56fd3c9 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/d56fd3c9 Branch: refs/heads/master Commit: d56fd3c991b0295aaa91ab916a0fdaed9c044402 Parents: 0af8b1e Author: Thomas D'Silva <tdsi...@apache.org> Authored: Sat Jul 14 11:34:47 2018 -0700 Committer: Thomas D'Silva <tdsi...@apache.org> Committed: Wed Jul 18 11:23:26 2018 -0700 ---------------------------------------------------------------------- .../coprocessor/MetaDataEndpointImplIT.java | 294 ++ .../StatisticsCollectionRunTrackerIT.java | 2 +- .../AlterMultiTenantTableWithViewsIT.java | 284 +- .../apache/phoenix/end2end/AlterTableIT.java | 45 +- .../phoenix/end2end/AlterTableWithViewsIT.java | 541 ++-- .../phoenix/end2end/AppendOnlySchemaIT.java | 4 +- .../end2end/BaseTenantSpecificViewIndexIT.java | 38 +- .../end2end/ExplainPlanWithStatsEnabledIT.java | 69 +- .../MigrateSystemTablesToSystemNamespaceIT.java | 38 +- .../apache/phoenix/end2end/PhoenixDriverIT.java | 37 +- .../end2end/QueryDatabaseMetaDataIT.java | 9 +- .../apache/phoenix/end2end/SaltedViewIT.java | 45 - .../phoenix/end2end/SplitSystemCatalogIT.java | 80 + .../end2end/SplitSystemCatalogTests.java | 11 + .../StatsEnabledSplitSystemCatalogIT.java | 244 ++ .../SystemCatalogCreationOnConnectionIT.java | 34 +- .../apache/phoenix/end2end/SystemCatalogIT.java | 50 +- .../end2end/TenantSpecificTablesDDLIT.java | 13 +- .../end2end/TenantSpecificViewIndexIT.java | 68 +- .../org/apache/phoenix/end2end/UpgradeIT.java | 322 +-- .../java/org/apache/phoenix/end2end/ViewIT.java | 844 ++++-- .../phoenix/end2end/index/BaseIndexIT.java | 43 +- .../index/ChildViewsUseParentViewIndexIT.java | 7 +- .../phoenix/end2end/index/DropColumnIT.java | 117 - .../phoenix/end2end/index/IndexMetadataIT.java | 4 +- .../phoenix/end2end/index/MutableIndexIT.java | 876 +++--- .../phoenix/end2end/index/ViewIndexIT.java | 68 +- .../apache/phoenix/execute/PartialCommitIT.java | 4 +- .../SystemCatalogWALEntryFilterIT.java | 78 +- .../org/apache/phoenix/rpc/UpdateCacheIT.java | 9 +- .../ColumnNameTrackingExpressionCompiler.java | 46 + .../phoenix/compile/CreateTableCompiler.java | 2 +- .../apache/phoenix/compile/FromCompiler.java | 15 +- .../phoenix/compile/ListJarsQueryPlan.java | 2 +- .../apache/phoenix/compile/TraceQueryPlan.java | 2 +- .../apache/phoenix/compile/UnionCompiler.java | 2 +- .../apache/phoenix/compile/UpsertCompiler.java | 2 +- .../coprocessor/MetaDataEndpointImpl.java | 2672 +++++++++--------- .../phoenix/coprocessor/MetaDataProtocol.java | 4 +- .../apache/phoenix/coprocessor/TableInfo.java | 79 + .../coprocessor/TableViewFinderResult.java | 48 + .../apache/phoenix/coprocessor/ViewFinder.java | 144 + .../coprocessor/WhereConstantParser.java | 106 + .../coprocessor/generated/MetaDataProtos.java | 626 +++- .../coprocessor/generated/PTableProtos.java | 323 ++- .../phoenix/expression/LikeExpression.java | 2 +- .../apache/phoenix/jdbc/PhoenixConnection.java | 8 +- .../phoenix/jdbc/PhoenixDatabaseMetaData.java | 531 ++-- .../apache/phoenix/jdbc/PhoenixStatement.java | 8 +- .../phoenix/parse/DropTableStatement.java | 8 +- .../apache/phoenix/parse/ParseNodeFactory.java | 2 +- .../phoenix/query/ConnectionQueryServices.java | 17 +- .../query/ConnectionQueryServicesImpl.java | 43 +- .../query/ConnectionlessQueryServicesImpl.java | 13 +- .../query/DelegateConnectionQueryServices.java | 8 +- .../apache/phoenix/query/QueryConstants.java | 15 +- .../org/apache/phoenix/query/QueryServices.java | 2 + .../phoenix/query/QueryServicesOptions.java | 2 + .../SystemCatalogWALEntryFilter.java | 47 +- .../apache/phoenix/schema/DelegateColumn.java | 15 + .../apache/phoenix/schema/MetaDataClient.java | 57 +- .../phoenix/schema/MetaDataSplitPolicy.java | 26 +- .../java/org/apache/phoenix/schema/PColumn.java | 12 + .../org/apache/phoenix/schema/PColumnImpl.java | 113 +- .../apache/phoenix/schema/PMetaDataImpl.java | 3 +- .../java/org/apache/phoenix/schema/PTable.java | 17 +- .../org/apache/phoenix/schema/PTableImpl.java | 279 +- .../org/apache/phoenix/schema/PTableKey.java | 4 +- .../schema/ParentTableNotFoundException.java | 30 + .../org/apache/phoenix/schema/SaltingUtil.java | 4 +- .../SplitOnLeadingVarCharColumnsPolicy.java | 3 + .../apache/phoenix/schema/TableProperty.java | 22 +- .../java/org/apache/phoenix/util/IndexUtil.java | 16 +- .../org/apache/phoenix/util/MetaDataUtil.java | 171 +- .../org/apache/phoenix/util/PhoenixRuntime.java | 1 - .../org/apache/phoenix/util/SchemaUtil.java | 43 +- .../org/apache/phoenix/util/UpgradeUtil.java | 168 +- .../phoenix/compile/QueryCompilerTest.java | 2 +- .../phoenix/execute/CorrelatePlanTest.java | 3 +- .../execute/LiteralResultIteratorPlanTest.java | 4 +- .../phoenix/execute/UnnestArrayPlanTest.java | 8 +- .../expression/ColumnExpressionTest.java | 9 +- .../java/org/apache/phoenix/query/BaseTest.java | 299 +- .../apache/phoenix/util/MetaDataUtilTest.java | 22 +- .../java/org/apache/phoenix/util/TestUtil.java | 18 +- phoenix-protocol/src/main/MetaDataService.proto | 6 + phoenix-protocol/src/main/PTable.proto | 6 +- pom.xml | 18 + 88 files changed, 6578 insertions(+), 3858 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/d56fd3c9/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/MetaDataEndpointImplIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/MetaDataEndpointImplIT.java b/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/MetaDataEndpointImplIT.java new file mode 100644 index 0000000..3b7686d --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/MetaDataEndpointImplIT.java @@ -0,0 +1,294 @@ +package org.apache.phoenix.coprocessor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.TableName; +import org.apache.phoenix.end2end.ParallelStatsDisabledIT; +import org.apache.phoenix.exception.SQLExceptionCode; +import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.schema.PColumn; +import org.apache.phoenix.schema.PTable; +import org.apache.phoenix.schema.TableNotFoundException; +import org.apache.phoenix.util.PhoenixRuntime; +import org.junit.Test; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +/** + * 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. + */ +public class MetaDataEndpointImplIT extends ParallelStatsDisabledIT { + private final TableName catalogTable = TableName.valueOf(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES); + private final TableName linkTable = TableName.valueOf(PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES); + + /* + The tree structure is as follows: Where ParentTable is the Base Table + and all children are views and child views respectively. + + ParentTable + / \ + leftChild rightChild + / + leftGrandChild + */ + + @Test + public void testGettingChildrenAndParentViews() throws Exception { + String baseTable = generateUniqueName(); + String leftChild = generateUniqueName(); + String rightChild = generateUniqueName(); + String leftGrandChild = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = + "CREATE TABLE IF NOT EXISTS " + baseTable + " (" + " PK2 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR " + + " CONSTRAINT NAME_PK PRIMARY KEY (PK2)" + " )"; + conn.createStatement().execute(ddlFormat); + + conn.createStatement().execute("CREATE VIEW " + rightChild + " AS SELECT * FROM " + baseTable); + conn.createStatement().execute("CREATE VIEW " + leftChild + " (carrier VARCHAR) AS SELECT * FROM " + baseTable); + conn.createStatement().execute("CREATE VIEW " + leftGrandChild + " (dropped_calls BIGINT) AS SELECT * FROM " + leftChild); + + PTable table = PhoenixRuntime.getTable(conn, baseTable.toUpperCase()); + PTable rightChildTable = PhoenixRuntime.getTable(conn, rightChild.toUpperCase()); + System.err.println(rightChildTable); + + TableViewFinderResult childViews = new TableViewFinderResult(); + ViewFinder.findAllRelatives(getUtility().getConnection().getTable(linkTable), + HConstants.EMPTY_BYTE_ARRAY, table.getSchemaName().getBytes(), + table.getTableName().getBytes(), PTable.LinkType.CHILD_TABLE, childViews); + assertEquals(3, childViews.getLinks().size()); + + PTable childMostView = PhoenixRuntime.getTable(conn , leftGrandChild.toUpperCase()); + TableViewFinderResult parentViews = new TableViewFinderResult(); + ViewFinder.findAllRelatives(getUtility().getConnection().getTable(catalogTable), + HConstants.EMPTY_BYTE_ARRAY, childMostView.getSchemaName().getBytes(), + childMostView.getTableName().getBytes(), PTable.LinkType.PARENT_TABLE, parentViews); + // returns back everything but the parent table - should only return back the left_child and not the right child + assertEquals(1, parentViews.getLinks().size()); + // now lets check and make sure the columns are correct + assertColumnNamesEqual(PhoenixRuntime.getTable(conn, childMostView.getName().getString()), "PK2", "V1", "V2", "CARRIER", "DROPPED_CALLS"); + + } + + @Test + public void testGettingOneChild() throws Exception { + String baseTable = generateUniqueName(); + String leftChild = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = + "CREATE TABLE IF NOT EXISTS " + baseTable + " (" + " PK2 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR " + + " CONSTRAINT NAME_PK PRIMARY KEY (PK2)" + " )"; + conn.createStatement().execute(ddlFormat); + conn.createStatement().execute("CREATE VIEW " + leftChild + " (carrier VARCHAR) AS SELECT * FROM " + baseTable); + + + // now lets check and make sure the columns are correct + assertColumnNamesEqual(PhoenixRuntime.getTable(conn, leftChild.toUpperCase()), "PK2", "V1", "V2", "CARRIER"); + } + + @Test + public void testDroppingADerivedColumn() throws Exception { + String baseTable = generateUniqueName(); + String childView = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = "CREATE TABLE " + baseTable + " (A VARCHAR PRIMARY KEY, B VARCHAR, C VARCHAR)"; + conn.createStatement().execute(ddlFormat); + conn.createStatement().execute("CREATE VIEW " + childView + " (D VARCHAR) AS SELECT * FROM " + baseTable); + assertColumnNamesEqual(PhoenixRuntime.getTable(conn, childView.toUpperCase()), "A", "B", "C", "D"); + conn.createStatement().execute("ALTER VIEW " + childView + " DROP COLUMN C"); + + // now lets check and make sure the columns are correct + assertColumnNamesEqual(PhoenixRuntime.getTableNoCache(conn, childView.toUpperCase()), "A", "B", "D"); + + } + + @Test + public void testDroppingAColumn() throws Exception { + String baseTable = generateUniqueName(); + String childView = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = "CREATE TABLE " + baseTable + " (A VARCHAR PRIMARY KEY, B VARCHAR, C VARCHAR)"; + conn.createStatement().execute(ddlFormat); + conn.createStatement().execute("CREATE VIEW " + childView + " (D VARCHAR) AS SELECT * FROM " + baseTable); + assertColumnNamesEqual(PhoenixRuntime.getTable(conn, childView.toUpperCase()), "A", "B", "C", "D"); + conn.createStatement().execute("ALTER TABLE " + baseTable + " DROP COLUMN C"); + + // now lets check and make sure the columns are correct + assertColumnNamesEqual(PhoenixRuntime.getTableNoCache(conn, childView.toUpperCase()), "A", "B", "D"); + } + + @Test + public void testAlteringBaseColumns() throws Exception { + String baseTable = generateUniqueName(); + String leftChild = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = + "CREATE TABLE IF NOT EXISTS " + baseTable + " (" + " PK2 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR " + + " CONSTRAINT NAME_PK PRIMARY KEY (PK2)" + " )"; + conn.createStatement().execute(ddlFormat); + conn.createStatement().execute("CREATE VIEW " + leftChild + " (carrier VARCHAR) AS SELECT * FROM " + baseTable); + + // now lets check and make sure the columns are correct + PTable childPTable = PhoenixRuntime.getTable(conn, leftChild.toUpperCase()); + assertColumnNamesEqual(childPTable, "PK2", "V1", "V2", "CARRIER"); + + // now lets alter the base table by adding a column + conn.createStatement().execute("ALTER TABLE " + baseTable + " ADD V3 integer"); + + // make sure that column was added to the base table + PTable table = PhoenixRuntime.getTableNoCache(conn, baseTable.toUpperCase()); + assertColumnNamesEqual(table, "PK2", "V1", "V2", "V3"); + + + childPTable = PhoenixRuntime.getTableNoCache(conn, leftChild.toUpperCase()); + assertColumnNamesEqual(childPTable, "PK2", "V1", "V2", "V3", "CARRIER"); + } + + @Test + public void testAddingAColumnWithADifferentDefinition() throws Exception { + String baseTable = generateUniqueName(); + String view = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = + "CREATE TABLE IF NOT EXISTS " + baseTable + " (" + " PK2 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR " + + " CONSTRAINT NAME_PK PRIMARY KEY (PK2)" + " )"; + conn.createStatement().execute(ddlFormat); + conn.createStatement().execute("CREATE VIEW " + view + " (carrier BIGINT) AS SELECT * FROM " + baseTable); + Map<String, String> expected = new ImmutableMap.Builder<String, String>() + .put("PK2", "VARCHAR") + .put("V1", "VARCHAR") + .put("V2", "VARCHAR") + .put("CARRIER", "BIGINT") + .build(); + + assertColumnNamesAndDefinitionsEqual(PhoenixRuntime.getTable(conn , view.toUpperCase()), expected); + try { + conn.createStatement().execute("ALTER TABLE " + baseTable + " ADD carrier VARCHAR"); + } + catch(SQLException e) { + assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode()); + } + + Map<String, String> expectedBaseTableColumns = new ImmutableMap.Builder<String, String>() + .put("PK2", "VARCHAR") + .put("V1", "VARCHAR") + .put("V2", "VARCHAR") + .build(); + + assertColumnNamesAndDefinitionsEqual(PhoenixRuntime.getTable(conn , baseTable.toUpperCase()), expectedBaseTableColumns); + + // the view column "CARRIER" should still be unchanged + Map<String, String> expectedViewColumnDefinition = new ImmutableMap.Builder<String, String>() + .put("PK2", "VARCHAR") + .put("V1", "VARCHAR") + .put("V2", "VARCHAR") + .put("CARRIER", "BIGINT") + .build(); + + assertColumnNamesAndDefinitionsEqual(PhoenixRuntime.getTable(conn , view.toUpperCase()), expectedViewColumnDefinition); + } + + public void testDropCascade() throws Exception { + String baseTable = generateUniqueName(); + String child = generateUniqueName(); + String grandChild = generateUniqueName(); + Connection conn = DriverManager.getConnection(getUrl()); + String ddlFormat = + "CREATE TABLE IF NOT EXISTS " + baseTable + " (" + " PK2 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR " + + " CONSTRAINT NAME_PK PRIMARY KEY (PK2)" + " )"; + conn.createStatement().execute(ddlFormat); + conn.createStatement().execute("CREATE VIEW " + child + " (A VARCHAR) AS SELECT * FROM " + baseTable); + conn.createStatement().execute("CREATE VIEW " + grandChild + " (B VARCHAR) AS SELECT * FROM " + child); + + PTable childMostView = PhoenixRuntime.getTable(conn , child.toUpperCase()); + // now lets check and make sure the columns are correct + PTable grandChildPTable = PhoenixRuntime.getTable(conn, childMostView.getName().getString()); + assertColumnNamesEqual(grandChildPTable, "PK2", "V1", "V2", "A"); + + // now lets drop the parent table + conn.createStatement().execute("DROP TABLE " + baseTable + " CASCADE"); + + // the tables should no longer exist + try { + PhoenixRuntime.getTableNoCache(conn, baseTable); + fail(); + } + catch(TableNotFoundException e){} + try { + PhoenixRuntime.getTableNoCache(conn, child); + fail(); + } + catch(TableNotFoundException e){} + try { + PhoenixRuntime.getTableNoCache(conn, grandChild); + fail(); + } + catch(TableNotFoundException e){} + } + + @Test + public void testWhereClause() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + String baseTableName = generateUniqueName(); + String childViewName = generateUniqueName(); + String grandChildViewName = generateUniqueName(); + String baseTableDdl = "CREATE TABLE " + baseTableName + " (" + + "A0 CHAR(1) NOT NULL PRIMARY KEY," + + "A1 CHAR(1), A2 CHAR (1))"; + conn.createStatement().execute(baseTableDdl); + conn.createStatement().execute( + "CREATE VIEW " + childViewName + " AS SELECT * FROM " + baseTableName + " WHERE A1 = 'X'"); + conn.createStatement().execute( + "CREATE VIEW " + grandChildViewName + " AS SELECT * FROM " + childViewName + " WHERE A2 = 'Y'"); + + PTable childViewTable = PhoenixRuntime.getTableNoCache(conn, childViewName); + PTable grandChildViewTable = PhoenixRuntime.getTableNoCache(conn, grandChildViewName); + + assertNotNull(childViewTable.getColumnForColumnName("A1").getViewConstant()); + assertNotNull(grandChildViewTable.getColumnForColumnName("A1").getViewConstant()); + assertNotNull(grandChildViewTable.getColumnForColumnName("A2").getViewConstant()); + } + + private void assertColumnNamesEqual(PTable table, String... cols) { + List<String> actual = Lists.newArrayList(); + for (PColumn column : table.getColumns()) { + actual.add(column.getName().getString().trim()); + } + List<String> expected = Arrays.asList(cols); + assertEquals(Joiner.on(", ").join(expected), Joiner.on(", ").join(actual)); + } + + private void assertColumnNamesAndDefinitionsEqual(PTable table, Map<String, String> expected) { + Map<String, String> actual = Maps.newHashMap(); + for (PColumn column : table.getColumns()) { + actual.put(column.getName().getString().trim(), column.getDataType().getSqlTypeName()); + } + assertEquals(expected, actual); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/d56fd3c9/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/StatisticsCollectionRunTrackerIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/StatisticsCollectionRunTrackerIT.java b/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/StatisticsCollectionRunTrackerIT.java index cdf1fde..0ca38e4 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/StatisticsCollectionRunTrackerIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/coprocessor/StatisticsCollectionRunTrackerIT.java @@ -149,7 +149,7 @@ public class StatisticsCollectionRunTrackerIT extends ParallelStatsEnabledIT { String ddl = "CREATE TABLE " + tableName + " (PK1 VARCHAR PRIMARY KEY, KV1 VARCHAR)"; try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - conn.createStatement().execute("CREATE LOCAL INDEX " + tableName + "_IDX ON " + tableName + "(KV1)"); + conn.createStatement().execute("CREATE LOCAL INDEX " + generateUniqueName() + " ON " + tableName + "(KV1)"); PhoenixConnection phxConn = conn.unwrap(PhoenixConnection.class); try (Admin admin = phxConn.getQueryServices().getAdmin()) { List<RegionInfo> tableRegions = admin.getRegions(tn); http://git-wip-us.apache.org/repos/asf/phoenix/blob/d56fd3c9/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterMultiTenantTableWithViewsIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterMultiTenantTableWithViewsIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterMultiTenantTableWithViewsIT.java index 60dbb44..7a5f4a6 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterMultiTenantTableWithViewsIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterMultiTenantTableWithViewsIT.java @@ -55,7 +55,7 @@ import org.junit.Test; import com.google.common.base.Objects; -public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { +public class AlterMultiTenantTableWithViewsIT extends SplitSystemCatalogIT { private Connection getTenantConnection(String tenantId) throws Exception { Properties tenantProps = new Properties(); @@ -85,12 +85,13 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testAddDropColumnToBaseTablePropagatesToEntireViewHierarchy() throws Exception { - String baseTable = "testViewHierarchy"; - String baseViewName = generateUniqueName(); - String view1 = baseViewName + "_VIEW1"; - String view2 = baseViewName + "_VIEW2"; - String view3 = baseViewName + "_VIEW3"; - String view4 = baseViewName + "_VIEW4"; + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String view2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); + String view3 = SchemaUtil.getTableName(SCHEMA4, generateUniqueName()); + String view4 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenant1 = TENANT1; + String tenant2 = TENANT2; /* baseTable / | \ view1(tenant1) view3(tenant2) view4(global) @@ -101,7 +102,8 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { String baseTableDDL = "CREATE TABLE " + baseTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true "; conn.createStatement().execute(baseTableDDL); - try (Connection tenant1Conn = getTenantConnection("tenant1")) { + + try (Connection tenant1Conn = getTenantConnection(tenant1)) { String view1DDL = "CREATE VIEW " + view1 + " AS SELECT * FROM " + baseTable; tenant1Conn.createStatement().execute(view1DDL); @@ -109,7 +111,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { tenant1Conn.createStatement().execute(view2DDL); } - try (Connection tenant2Conn = getTenantConnection("tenant2")) { + try (Connection tenant2Conn = getTenantConnection(tenant2)) { String view3DDL = "CREATE VIEW " + view3 + " AS SELECT * FROM " + baseTable; tenant2Conn.createStatement().execute(view3DDL); } @@ -124,13 +126,13 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { conn.createStatement().execute("SELECT V3 FROM " + view4); // verify that the column is visible to view1 and view2 - try (Connection tenant1Conn = getTenantConnection("tenant1")) { + try (Connection tenant1Conn = getTenantConnection(tenant1)) { tenant1Conn.createStatement().execute("SELECT V3 from " + view1); tenant1Conn.createStatement().execute("SELECT V3 from " + view2); } // verify that the column is visible to view3 - try (Connection tenant2Conn = getTenantConnection("tenant2")) { + try (Connection tenant2Conn = getTenantConnection(tenant2)) { tenant2Conn.createStatement().execute("SELECT V3 from " + view3); } @@ -144,7 +146,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { } catch (ColumnNotFoundException e) { } // verify that the column is not visible to view1 and view2 - try (Connection tenant1Conn = getTenantConnection("tenant1")) { + try (Connection tenant1Conn = getTenantConnection(tenant1)) { try { tenant1Conn.createStatement().execute("SELECT V1 from " + view1); fail(); @@ -158,7 +160,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { } // verify that the column is not visible to view3 - try (Connection tenant2Conn = getTenantConnection("tenant2")) { + try (Connection tenant2Conn = getTenantConnection(tenant2)) { try { tenant2Conn.createStatement().execute("SELECT V1 from " + view3); fail(); @@ -171,12 +173,13 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testChangingPKOfBaseTableChangesPKForAllViews() throws Exception { - String baseTable = "testChangePKOfBaseTable"; - String baseViewName = generateUniqueName(); - String view1 = baseViewName + "_VIEW1"; - String view2 = baseViewName + "_VIEW2"; - String view3 = baseViewName + "_VIEW3"; - String view4 = baseViewName + "_VIEW4"; + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String view2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); + String view3 = SchemaUtil.getTableName(SCHEMA4, generateUniqueName()); + String view4 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenant1 = TENANT1; + String tenant2 = TENANT2; /* baseTable / | \ view1(tenant1) view3(tenant2) view4(global) @@ -190,14 +193,14 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true "; globalConn.createStatement().execute(baseTableDDL); - tenant1Conn = getTenantConnection("tenant1"); + tenant1Conn = getTenantConnection(tenant1); String view1DDL = "CREATE VIEW " + view1 + " AS SELECT * FROM " + baseTable; tenant1Conn.createStatement().execute(view1DDL); String view2DDL = "CREATE VIEW " + view2 + " AS SELECT * FROM " + view1; tenant1Conn.createStatement().execute(view2DDL); - tenant2Conn = getTenantConnection("tenant2"); + tenant2Conn = getTenantConnection(tenant2); String view3DDL = "CREATE VIEW " + view3 + " AS SELECT * FROM " + baseTable; tenant2Conn.createStatement().execute(view3DDL); @@ -269,15 +272,16 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testAddPKColumnToBaseTableWhoseViewsHaveIndices() throws Exception { - String baseTable = "testAddPKColumnToBaseTableWhoseViewsHaveIndices"; - String baseViewName = generateUniqueName(); - String view1 = baseViewName + "_VIEW1"; - String view2 = baseViewName + "_VIEW2"; - String view3 = baseViewName + "_VIEW3"; - String tenant1 = baseViewName + "_T1"; - String tenant2 = baseViewName + "_T2"; - String view2Index = view2 + "_IDX"; - String view3Index = view3 + "_IDX"; + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String view2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); + String view3 = SchemaUtil.getTableName(SCHEMA4, generateUniqueName()); + String view2Schema = SCHEMA3; + String view3Schema = SCHEMA4; + String tenant1 = TENANT1; + String tenant2 = TENANT2; + String view2Index = generateUniqueName() + "_IDX"; + String view3Index = generateUniqueName() + "_IDX"; /* baseTable(mutli-tenant) / \ view1(tenant1) view3(tenant2, index) @@ -294,6 +298,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { + " (TENANT_ID VARCHAR NOT NULL, K1 varchar not null, V1 VARCHAR, V2 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, K1)) MULTI_TENANT = true "); } + String fullView2IndexName = SchemaUtil.getTableName(view2Schema, view2Index); try (Connection viewConn = getTenantConnection(tenant1)) { // create tenant specific view for tenant1 - view1 viewConn.createStatement().execute("CREATE VIEW " + view1 + " AS SELECT * FROM " + baseTable); @@ -309,9 +314,10 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { // create an index on view2 viewConn.createStatement().execute("CREATE INDEX " + view2Index + " ON " + view2 + " (v1) include (v2)"); - assertEquals(0, getTableSequenceNumber(phxConn, view2Index)); - assertEquals(4, getMaxKeySequenceNumber(phxConn, view2Index)); + assertEquals(0, getTableSequenceNumber(phxConn, fullView2IndexName)); + assertEquals(4, getMaxKeySequenceNumber(phxConn, fullView2IndexName)); } + String fullView3IndexName = SchemaUtil.getTableName(view3Schema, view3Index); try (Connection viewConn = getTenantConnection(tenant2)) { // create tenant specific view for tenant2 - view3 viewConn.createStatement().execute("CREATE VIEW " + view3 + " AS SELECT * FROM " + baseTable); @@ -322,10 +328,8 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { // create an index on view3 viewConn.createStatement().execute("CREATE INDEX " + view3Index + " ON " + view3 + " (v1) include (v2)"); - assertEquals(0, getTableSequenceNumber(phxConn, view3Index)); - assertEquals(4, getMaxKeySequenceNumber(phxConn, view3Index)); - - + assertEquals(0, getTableSequenceNumber(phxConn, fullView3IndexName)); + assertEquals(4, getMaxKeySequenceNumber(phxConn, fullView3IndexName)); } // alter the base table by adding 1 non-pk and 2 pk columns @@ -355,7 +359,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { globalConn.commit(); } - // Verify now that the sequence number of data table, indexes and views have changed. + // Verify now that the sequence number of data table, indexes and views have *not* changed. // Also verify that the newly added pk columns show up as pk columns of data table, indexes and views. try (Connection viewConn = getTenantConnection(tenant1)) { @@ -363,7 +367,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { PhoenixConnection phxConn = viewConn.unwrap(PhoenixConnection.class); assertEquals(2, getIndexOfPkColumn(phxConn, "k2", view1)); assertEquals(3, getIndexOfPkColumn(phxConn, "k3", view1)); - assertEquals(1, getTableSequenceNumber(phxConn, view1)); + assertEquals(0, getTableSequenceNumber(phxConn, view1)); assertEquals(4, getMaxKeySequenceNumber(phxConn, view1)); verifyNewColumns(rs, "K2", "K3", "V3"); @@ -371,27 +375,27 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { rs = viewConn.createStatement().executeQuery("SELECT K2, K3, V3 FROM " + view2); assertEquals(2, getIndexOfPkColumn(phxConn, "k2", view2)); assertEquals(3, getIndexOfPkColumn(phxConn, "k3", view2)); - assertEquals(1, getTableSequenceNumber(phxConn, view2)); + assertEquals(0, getTableSequenceNumber(phxConn, view2)); assertEquals(4, getMaxKeySequenceNumber(phxConn, view2)); verifyNewColumns(rs, "K2", "K3", "V3"); - assertEquals(4, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k2"), view2Index)); - assertEquals(5, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k3"), view2Index)); - assertEquals(1, getTableSequenceNumber(phxConn, view2Index)); - assertEquals(6, getMaxKeySequenceNumber(phxConn, view2Index)); + assertEquals(4, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k2"), fullView2IndexName)); + assertEquals(5, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k3"), fullView2IndexName)); + assertEquals(0, getTableSequenceNumber(phxConn, fullView2IndexName)); + assertEquals(6, getMaxKeySequenceNumber(phxConn, fullView2IndexName)); } try (Connection viewConn = getTenantConnection(tenant2)) { ResultSet rs = viewConn.createStatement().executeQuery("SELECT K2, K3, V3 FROM " + view3); PhoenixConnection phxConn = viewConn.unwrap(PhoenixConnection.class); assertEquals(2, getIndexOfPkColumn(phxConn, "k2", view3)); assertEquals(3, getIndexOfPkColumn(phxConn, "k3", view3)); - assertEquals(1, getTableSequenceNumber(phxConn, view3)); + assertEquals(0, getTableSequenceNumber(phxConn, view3)); verifyNewColumns(rs, "K22", "K33", "V33"); - assertEquals(4, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k2"), view3Index)); - assertEquals(5, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k3"), view3Index)); - assertEquals(1, getTableSequenceNumber(phxConn, view3Index)); - assertEquals(6, getMaxKeySequenceNumber(phxConn, view3Index)); + assertEquals(4, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k2"), fullView3IndexName)); + assertEquals(5, getIndexOfPkColumn(phxConn, IndexUtil.getIndexColumnName(null, "k3"), fullView3IndexName)); + assertEquals(0, getTableSequenceNumber(phxConn, fullView3IndexName)); + assertEquals(6, getMaxKeySequenceNumber(phxConn, fullView3IndexName)); } // Verify that the index is actually being used when using newly added pk col try (Connection viewConn = getTenantConnection(tenant1)) { @@ -401,7 +405,7 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { Statement stmt = viewConn.createStatement(); String sql = "SELECT V2 FROM " + view2 + " WHERE V1 = 'value1' AND K3 = 'key3'"; QueryPlan plan = stmt.unwrap(PhoenixStatement.class).optimizeQuery(sql); - assertTrue(plan.getTableRef().getTable().getName().getString().equals(SchemaUtil.normalizeIdentifier(view2Index))); + assertEquals(fullView2IndexName, plan.getTableRef().getTable().getName().getString()); ResultSet rs = viewConn.createStatement().executeQuery(sql); verifyNewColumns(rs, "value2"); } @@ -410,72 +414,71 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testAddingPkAndKeyValueColumnsToBaseTableWithDivergedView() throws Exception { - String baseTable = "testAlteringPkOfBaseTableWithDivergedView".toUpperCase(); - String view1 = generateUniqueName(); - String divergedView = generateUniqueName(); - String divergedViewIndex = divergedView + "_IDX"; + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String divergedView = SchemaUtil.getTableName(SCHEMA4, generateUniqueName()); + String divergedViewSchemaName = SchemaUtil.getSchemaNameFromFullName(divergedView); + String divergedViewIndex = generateUniqueName() + "_IDX"; + String tenant1 = TENANT1; + String tenant2 = TENANT2; + /* baseTable / | view1(tenant1) divergedView(tenant2) */ - try (Connection conn = DriverManager.getConnection(getUrl())) { + try (Connection conn = DriverManager.getConnection(getUrl()); + Connection tenant1Conn = getTenantConnection(tenant1); + Connection tenant2Conn = getTenantConnection(tenant2)) { String baseTableDDL = "CREATE TABLE " + baseTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR, V3 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true "; conn.createStatement().execute(baseTableDDL); - try (Connection tenant1Conn = getTenantConnection("tenant1")) { - String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; - tenant1Conn.createStatement().execute(view1DDL); - } + String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; + tenant1Conn.createStatement().execute(view1DDL); - try (Connection tenant2Conn = getTenantConnection("tenant2")) { - String divergedViewDDL = "CREATE VIEW " + divergedView + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; - tenant2Conn.createStatement().execute(divergedViewDDL); - // Drop column V2 from the view to have it diverge from the base table - tenant2Conn.createStatement().execute("ALTER VIEW " + divergedView + " DROP COLUMN V2"); - - // create an index on the diverged view - String indexDDL = "CREATE INDEX " + divergedViewIndex + " ON " + divergedView + " (V1) include (V3)"; - tenant2Conn.createStatement().execute(indexDDL); - } + String divergedViewDDL = "CREATE VIEW " + divergedView + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; + tenant2Conn.createStatement().execute(divergedViewDDL); + // Drop column V2 from the view to have it diverge from the base table + tenant2Conn.createStatement().execute("ALTER VIEW " + divergedView + " DROP COLUMN V2"); + + // create an index on the diverged view + String indexDDL = "CREATE INDEX " + divergedViewIndex + " ON " + divergedView + " (V1) include (V3)"; + tenant2Conn.createStatement().execute(indexDDL); String alterBaseTable = "ALTER TABLE " + baseTable + " ADD KV VARCHAR, PK2 VARCHAR PRIMARY KEY"; conn.createStatement().execute(alterBaseTable); // verify that the both columns were added to view1 - try (Connection tenant1Conn = getTenantConnection("tenant1")) { - tenant1Conn.createStatement().execute("SELECT KV from " + view1); - tenant1Conn.createStatement().execute("SELECT PK2 from " + view1); - } + tenant1Conn.createStatement().execute("SELECT KV from " + view1); + tenant1Conn.createStatement().execute("SELECT PK2 from " + view1); // verify that only the primary key column PK2 was added to diverged view - try (Connection tenant2Conn = getTenantConnection("tenant2")) { - tenant2Conn.createStatement().execute("SELECT PK2 from " + divergedView); - try { - tenant2Conn.createStatement().execute("SELECT KV FROM " + divergedView); - } catch (SQLException e) { - assertEquals(SQLExceptionCode.COLUMN_NOT_FOUND.getErrorCode(), e.getErrorCode()); - } + tenant2Conn.createStatement().execute("SELECT PK2 from " + divergedView); + try { + tenant2Conn.createStatement().execute("SELECT KV FROM " + divergedView); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.COLUMN_NOT_FOUND.getErrorCode(), e.getErrorCode()); } // Upsert records in diverged view. Verify that the PK column was added to the index on it. String upsert = "UPSERT INTO " + divergedView + " (PK1, PK2, V1, V3) VALUES ('PK1', 'PK2', 'V1', 'V3')"; - try (Connection viewConn = getTenantConnection("tenant2")) { + try (Connection viewConn = getTenantConnection(tenant2)) { viewConn.createStatement().executeUpdate(upsert); viewConn.commit(); Statement stmt = viewConn.createStatement(); String sql = "SELECT V3 FROM " + divergedView + " WHERE V1 = 'V1' AND PK2 = 'PK2'"; QueryPlan plan = stmt.unwrap(PhoenixStatement.class).optimizeQuery(sql); - assertTrue(plan.getTableRef().getTable().getName().getString().equals(SchemaUtil.normalizeIdentifier(divergedViewIndex))); + assertEquals(SchemaUtil.getTableName(divergedViewSchemaName, divergedViewIndex), + plan.getTableRef().getTable().getName().getString()); ResultSet rs = viewConn.createStatement().executeQuery(sql); verifyNewColumns(rs, "V3"); } // For non-diverged view, base table columns will be added at the same position as base table - assertTableDefinition(conn, view1, PTableType.VIEW, baseTable, 1, 9, 7, "TENANT_ID", "PK1", "V1", "V2", "V3", "KV", "PK2", "VIEW_COL1", "VIEW_COL2"); + assertTableDefinition(tenant1Conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "PK1", "V1", "V2", "V3", "KV", "PK2", "VIEW_COL1", "VIEW_COL2"); // For a diverged view, only base table's pk column will be added and that too at the end. - assertTableDefinition(conn, divergedView, PTableType.VIEW, baseTable, 2, 7, DIVERGED_VIEW_BASE_COLUMN_COUNT, "TENANT_ID", "PK1", "V1", "V3", "VIEW_COL1", "VIEW_COL2", "PK2"); + assertTableDefinition(tenant2Conn, divergedView, PTableType.VIEW, baseTable, 1, 6, DIVERGED_VIEW_BASE_COLUMN_COUNT, "PK1", "V1", "V3", "PK2", "VIEW_COL1", "VIEW_COL2"); // Adding existing column VIEW_COL2 to the base table isn't allowed. try { @@ -491,83 +494,81 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testAddColumnsToSaltedBaseTableWithViews() throws Exception { - String baseTable = "testAddColumnsToSaltedBaseTableWithViews".toUpperCase(); - String view1 = generateUniqueName(); - try (Connection conn = DriverManager.getConnection(getUrl())) { + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenant = TENANT1; + try (Connection conn = DriverManager.getConnection(getUrl()); + Connection tenant1Conn = getTenantConnection(tenant)) { String baseTableDDL = "CREATE TABLE " + baseTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR, V3 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true "; conn.createStatement().execute(baseTableDDL); - try (Connection tenant1Conn = getTenantConnection("tenant1")) { - String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; - tenant1Conn.createStatement().execute(view1DDL); - } + String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; + tenant1Conn.createStatement().execute(view1DDL); assertTableDefinition(conn, baseTable, PTableType.TABLE, null, 1, 5, BASE_TABLE_BASE_COLUMN_COUNT, "TENANT_ID", "PK1", "V1", "V2", "V3"); - assertTableDefinition(conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "TENANT_ID", "PK1", "V1", "V2", "V3", "VIEW_COL1", "VIEW_COL2"); + assertTableDefinition(tenant1Conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "PK1", "V1", "V2", "V3", "VIEW_COL1", "VIEW_COL2"); String alterBaseTable = "ALTER TABLE " + baseTable + " ADD KV VARCHAR, PK2 VARCHAR PRIMARY KEY"; conn.createStatement().execute(alterBaseTable); assertTableDefinition(conn, baseTable, PTableType.TABLE, null, 2, 7, BASE_TABLE_BASE_COLUMN_COUNT, "TENANT_ID", "PK1", "V1", "V2", "V3", "KV", "PK2"); - assertTableDefinition(conn, view1, PTableType.VIEW, baseTable, 1, 9, 7, "TENANT_ID", "PK1", "V1", "V2", "V3", "KV", "PK2", "VIEW_COL1", "VIEW_COL2"); + assertTableDefinition(tenant1Conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "PK1", "V1", "V2", "V3", "VIEW_COL1", "VIEW_COL2"); // verify that the both columns were added to view1 - try (Connection tenant1Conn = getTenantConnection("tenant1")) { - tenant1Conn.createStatement().execute("SELECT KV from " + view1); - tenant1Conn.createStatement().execute("SELECT PK2 from " + view1); - } + tenant1Conn.createStatement().execute("SELECT KV from " + view1); + tenant1Conn.createStatement().execute("SELECT PK2 from " + view1); } } @Test public void testDropColumnsFromSaltedBaseTableWithViews() throws Exception { - String baseTable = "testDropColumnsFromSaltedBaseTableWithViews".toUpperCase(); - String view1 = generateUniqueName(); - try (Connection conn = DriverManager.getConnection(getUrl())) { + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenant = TENANT1; + try (Connection conn = DriverManager.getConnection(getUrl()); + Connection tenant1Conn = getTenantConnection(tenant)) { String baseTableDDL = "CREATE TABLE " + baseTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR, V3 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true "; conn.createStatement().execute(baseTableDDL); - try (Connection tenant1Conn = getTenantConnection("tenant1")) { - String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; - tenant1Conn.createStatement().execute(view1DDL); - } + String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; + tenant1Conn.createStatement().execute(view1DDL); assertTableDefinition(conn, baseTable, PTableType.TABLE, null, 1, 5, BASE_TABLE_BASE_COLUMN_COUNT, "TENANT_ID", "PK1", "V1", "V2", "V3"); - assertTableDefinition(conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "TENANT_ID", "PK1", "V1", "V2", "V3", "VIEW_COL1", "VIEW_COL2"); + assertTableDefinition(tenant1Conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "PK1", "V1", "V2", "V3", "VIEW_COL1", "VIEW_COL2"); String alterBaseTable = "ALTER TABLE " + baseTable + " DROP COLUMN V2"; conn.createStatement().execute(alterBaseTable); assertTableDefinition(conn, baseTable, PTableType.TABLE, null, 2, 4, BASE_TABLE_BASE_COLUMN_COUNT, "TENANT_ID", "PK1", "V1", "V3"); - assertTableDefinition(conn, view1, PTableType.VIEW, baseTable, 1, 6, 4, "TENANT_ID", "PK1", "V1", "V3", "VIEW_COL1", "VIEW_COL2"); + // column adds and drops are no longer propagated to child views, when the parent view is resolved the dropped column is excluded + assertTableDefinition(tenant1Conn, view1, PTableType.VIEW, baseTable, 0, 7, 5, "PK1", "V1", "V2", "V3", "VIEW_COL1", "VIEW_COL2"); // verify that the dropped columns aren't visible - try (Connection tenant1Conn = getTenantConnection("tenant1")) { - try { - tenant1Conn.createStatement().execute("SELECT KV from " + view1); - fail(); - } catch (SQLException e) { - assertEquals(SQLExceptionCode.COLUMN_NOT_FOUND.getErrorCode(), e.getErrorCode()); - } - try { - tenant1Conn.createStatement().execute("SELECT PK2 from " + view1); - fail(); - } catch (SQLException e) { - assertEquals(SQLExceptionCode.COLUMN_NOT_FOUND.getErrorCode(), e.getErrorCode()); - } + try { + conn.createStatement().execute("SELECT V2 from " + baseTable); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.COLUMN_NOT_FOUND.getErrorCode(), e.getErrorCode()); + } + try { + tenant1Conn.createStatement().execute("SELECT V2 from " + view1); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.COLUMN_NOT_FOUND.getErrorCode(), e.getErrorCode()); } } } @Test public void testAlteringViewConditionallyModifiesHTableMetadata() throws Exception { - String baseTable = "testAlteringViewConditionallyModifiesBaseTable".toUpperCase(); - String view1 = generateUniqueName(); + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String view1 = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenant = TENANT1; try (Connection conn = DriverManager.getConnection(getUrl())) { String baseTableDDL = "CREATE TABLE " + baseTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR, V3 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true "; conn.createStatement().execute(baseTableDDL); TableDescriptor tableDesc1 = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin().getDescriptor(TableName.valueOf(baseTable)); - try (Connection tenant1Conn = getTenantConnection("tenant1")) { + try (Connection tenant1Conn = getTenantConnection(tenant)) { String view1DDL = "CREATE VIEW " + view1 + " ( VIEW_COL1 DECIMAL(10,2), VIEW_COL2 CHAR(256)) AS SELECT * FROM " + baseTable; tenant1Conn.createStatement().execute(view1DDL); // This should not modify the base table @@ -597,9 +598,9 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testCacheInvalidatedAfterAddingColumnToBaseTableWithViews() throws Exception { - String baseTable = "testCacheInvalidatedAfterAddingColumnToBaseTableWithViews"; - String viewName = baseTable + "_view"; - String tenantId = "tenantId"; + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String viewName = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenantId = TENANT1; try (Connection globalConn = DriverManager.getConnection(getUrl())) { String tableDDL = "CREATE TABLE " + baseTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) MULTI_TENANT = true" ; globalConn.createStatement().execute(tableDDL); @@ -622,9 +623,9 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { @Test public void testCacheInvalidatedAfterDroppingColumnFromBaseTableWithViews() throws Exception { - String baseTable = "testCacheInvalidatedAfterDroppingColumnFromBaseTableWithViews"; - String viewName = baseTable + "_view"; - String tenantId = "tenantId"; + String baseTable = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String viewName = SchemaUtil.getTableName(SCHEMA2, generateUniqueName()); + String tenantId = TENANT1; try (Connection globalConn = DriverManager.getConnection(getUrl())) { String tableDDL = "CREATE TABLE " @@ -657,15 +658,18 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { } } - public static void assertTableDefinition(Connection conn, String tableName, PTableType tableType, String parentTableName, int sequenceNumber, int columnCount, int baseColumnCount, String... columnName) throws Exception { - PreparedStatement p = conn.prepareStatement("SELECT * FROM \"SYSTEM\".\"CATALOG\" WHERE TABLE_NAME=? AND TABLE_TYPE=?"); - p.setString(1, tableName); - p.setString(2, tableType.getSerializedValue()); + public static void assertTableDefinition(Connection conn, String fullTableName, PTableType tableType, String parentTableName, int sequenceNumber, int columnCount, int baseColumnCount, String... columnName) throws Exception { + String schemaName = SchemaUtil.getSchemaNameFromFullName(fullTableName); + String tableName = SchemaUtil.getTableNameFromFullName(fullTableName); + PreparedStatement p = conn.prepareStatement("SELECT * FROM \"SYSTEM\".\"CATALOG\" WHERE TABLE_SCHEM=? AND TABLE_NAME=? AND TABLE_TYPE=?"); + p.setString(1, schemaName); + p.setString(2, tableName); + p.setString(3, tableType.getSerializedValue()); ResultSet rs = p.executeQuery(); assertTrue(rs.next()); - assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, "Mismatch in BaseColumnCount"), baseColumnCount, rs.getInt("BASE_COLUMN_COUNT")); - assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, "Mismatch in columnCount"), columnCount, rs.getInt("COLUMN_COUNT")); - assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, "Mismatch in sequenceNumber"), sequenceNumber, rs.getInt("TABLE_SEQ_NUM")); + assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, "Mismatch in BaseColumnCount"), baseColumnCount, rs.getInt("BASE_COLUMN_COUNT")); + assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, "Mismatch in columnCount"), columnCount, rs.getInt("COLUMN_COUNT")); + assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, "Mismatch in sequenceNumber"), sequenceNumber, rs.getInt("TABLE_SEQ_NUM")); rs.close(); ResultSet parentTableColumnsRs = null; @@ -674,26 +678,26 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { parentTableColumnsRs.next(); } - ResultSet viewColumnsRs = conn.getMetaData().getColumns(null, null, tableName, null); + ResultSet viewColumnsRs = conn.getMetaData().getColumns(null, schemaName, tableName, null); for (int i = 0; i < columnName.length; i++) { if (columnName[i] != null) { assertTrue(viewColumnsRs.next()); - assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, "Mismatch in columnName: i=" + i), columnName[i], viewColumnsRs.getString(PhoenixDatabaseMetaData.COLUMN_NAME)); + assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, "Mismatch in columnName: i=" + i), columnName[i], viewColumnsRs.getString(PhoenixDatabaseMetaData.COLUMN_NAME)); int viewColOrdinalPos = viewColumnsRs.getInt(PhoenixDatabaseMetaData.ORDINAL_POSITION); - assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, "Mismatch in ordinalPosition: i=" + i), i+1, viewColOrdinalPos); + assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, "Mismatch in ordinalPosition: i=" + i), i+1, viewColOrdinalPos); // validate that all the columns in the base table are present in the view if (parentTableColumnsRs != null && !parentTableColumnsRs.isAfterLast()) { ResultSetMetaData parentTableColumnsMetadata = parentTableColumnsRs.getMetaData(); assertEquals(parentTableColumnsMetadata.getColumnCount(), viewColumnsRs.getMetaData().getColumnCount()); int parentTableColOrdinalRs = parentTableColumnsRs.getInt(PhoenixDatabaseMetaData.ORDINAL_POSITION); - assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, "Mismatch in ordinalPosition of view and base table for i=" + i), parentTableColOrdinalRs, viewColOrdinalPos); + assertEquals(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, "Mismatch in ordinalPosition of view and base table for i=" + i), parentTableColOrdinalRs, viewColOrdinalPos); for (int columnIndex = 1; columnIndex < parentTableColumnsMetadata.getColumnCount(); columnIndex++) { String viewColumnValue = viewColumnsRs.getString(columnIndex); String parentTableColumnValue = parentTableColumnsRs.getString(columnIndex); if (!Objects.equal(viewColumnValue, parentTableColumnValue)) { if (parentTableColumnsMetadata.getColumnName(columnIndex).equals(PhoenixDatabaseMetaData.TABLE_NAME)) { assertEquals(parentTableName, parentTableColumnValue); - assertEquals(tableName, viewColumnValue); + assertEquals(fullTableName, viewColumnValue); } } } @@ -701,6 +705,6 @@ public class AlterMultiTenantTableWithViewsIT extends ParallelStatsDisabledIT { } } } - assertFalse(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, tableName, ""), viewColumnsRs.next()); + assertFalse(AlterTableWithViewsIT.getSystemCatalogEntriesForTable(conn, fullTableName, ""), viewColumnsRs.next()); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/d56fd3c9/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java index db46663..d5153dd 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java @@ -65,6 +65,7 @@ import org.apache.phoenix.schema.TableNotFoundException; import org.apache.phoenix.util.IndexUtil; import org.apache.phoenix.util.PropertiesUtil; import org.apache.phoenix.util.SchemaUtil; +import org.apache.phoenix.util.TestUtil; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -811,7 +812,7 @@ public class AlterTableIT extends ParallelStatsDisabledIT { conn1.createStatement().execute("CREATE INDEX " + indexTableName + " ON " + dataTableFullName + "(COL1) INCLUDE (COL2,COL3,COL4)"); ddl = "ALTER TABLE " + dataTableFullName + " DROP COLUMN COL2, COL3"; - conn1.createStatement().execute(ddl); + conn1.createStatement().execute(ddl); ResultSet rs = conn1.getMetaData().getColumns("", "", dataTableFullName, null); assertTrue(rs.next()); assertEquals("ID",rs.getString(4)); @@ -1286,10 +1287,11 @@ public class AlterTableIT extends ParallelStatsDisabledIT { // assert that the server side metadata for the base table and the view is also updated correctly. assertEncodedCQCounter(DEFAULT_COLUMN_FAMILY, schemaName, baseTableName, (ENCODED_CQ_COUNTER_INITIAL_VALUE + 10)); - assertEncodedCQValue(DEFAULT_COLUMN_FAMILY, "COL10", schemaName, viewName, (ENCODED_CQ_COUNTER_INITIAL_VALUE + 8)); - assertEncodedCQValue("A", "COL11", schemaName, viewName, ENCODED_CQ_COUNTER_INITIAL_VALUE + 9); + assertEncodedCQValue(DEFAULT_COLUMN_FAMILY, "COL10", schemaName, baseTableName, (ENCODED_CQ_COUNTER_INITIAL_VALUE + 8)); + assertEncodedCQValue("A", "COL11", schemaName, baseTableName, ENCODED_CQ_COUNTER_INITIAL_VALUE + 9); assertSequenceNumber(schemaName, baseTableName, columnEncoded ? initBaseTableSeqNumber + 4 : initBaseTableSeqNumber + 2 ); - assertSequenceNumber(schemaName, viewName, PTable.INITIAL_SEQ_NUM + 2); + // view sequence number does not change as base table column changes are not propagated to views + assertSequenceNumber(schemaName, viewName, PTable.INITIAL_SEQ_NUM + 1); } } @@ -1347,5 +1349,40 @@ public class AlterTableIT extends ParallelStatsDisabledIT { } } + @Test + public void testAlterTableWithIndexesExtendPk() throws Exception { + Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + conn.setAutoCommit(false); + String tableName = generateUniqueName(); + String indexName1 = "I_" + generateUniqueName(); + String indexName2 = "I_" + generateUniqueName(); + + try { + String ddl = "CREATE TABLE " + tableName + " (ORG_ID CHAR(15) NOT NULL," + + " PARTITION_KEY CHAR(3) NOT NULL, " + " ACTIVITY_DATE DATE NOT NULL, " + + " FK1_ID CHAR(15) NOT NULL, " + " FK2_ID CHAR(15) NOT NULL, " + " TYPE VARCHAR NOT NULL, " + + " IS_OPEN BOOLEAN " + " CONSTRAINT PKVIEW PRIMARY KEY " + "(" + + "ORG_ID, PARTITION_KEY, ACTIVITY_DATE, FK1_ID, FK2_ID, TYPE" + "))"; + createTestTable(getUrl(), ddl); + + String idx1ddl = "CREATE INDEX " + indexName1 + " ON " + tableName + + " (FK1_ID, ACTIVITY_DATE DESC) INCLUDE (IS_OPEN)"; + PreparedStatement stmt1 = conn.prepareStatement(idx1ddl); + stmt1.execute(); + + String idx2ddl = "CREATE INDEX " + indexName2 + " ON " + tableName + + " (FK2_ID, ACTIVITY_DATE DESC) INCLUDE (IS_OPEN)"; + PreparedStatement stmt2 = conn.prepareStatement(idx2ddl); + stmt2.execute(); + + ddl = "ALTER TABLE " + tableName + " ADD SOURCE VARCHAR(25) NULL PRIMARY KEY"; + PreparedStatement stmt3 = conn.prepareStatement(ddl); + stmt3.execute(); + } finally { + conn.close(); + } + } + }