Repository: phoenix Updated Branches: refs/heads/4.x-HBase-0.98 64319e647 -> 318d096c3
PHOENIX-2110 Addendum to fix test failure and enforcing tenancy switch check Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/318d096c Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/318d096c Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/318d096c Branch: refs/heads/4.x-HBase-0.98 Commit: 318d096c34fb0fcba439ef4b000fb715c7ff02c4 Parents: 64319e6 Author: Samarth <samarth.j...@salesforce.com> Authored: Wed Jul 22 14:58:50 2015 -0700 Committer: Samarth <samarth.j...@salesforce.com> Committed: Wed Jul 22 14:58:50 2015 -0700 ---------------------------------------------------------------------- .../phoenix/end2end/AlterTableWithViewsIT.java | 31 +++++++++++++ .../end2end/TenantSpecificTablesDDLIT.java | 47 +++++++++++++++++--- .../coprocessor/MetaDataEndpointImpl.java | 26 +++++++++-- 3 files changed, 95 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/318d096c/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java index 0399af2..22abd38 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java @@ -18,6 +18,7 @@ package org.apache.phoenix.end2end; import static org.apache.phoenix.exception.SQLExceptionCode.CANNOT_MUTATE_TABLE; +import static org.apache.phoenix.query.QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT; import static org.apache.phoenix.query.QueryConstants.DIVERGED_VIEW_BASE_COLUMN_COUNT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -1025,6 +1026,36 @@ public class AlterTableWithViewsIT extends BaseHBaseManagedTimeIT { } } + @Test + public void testAlterSaltedBaseTableWithViews() throws Exception { + String baseTable = "testAlterSaltedBaseTableWithViews".toUpperCase(); + String view1 = "view1".toUpperCase(); + 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); + + 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); + } + + assertTableDefinition(conn, baseTable, PTableType.TABLE, null, 0, 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"); + + String alterBaseTable = "ALTER TABLE " + baseTable + " ADD KV VARCHAR, PK2 VARCHAR PRIMARY KEY"; + conn.createStatement().execute(alterBaseTable); + + assertTableDefinition(conn, baseTable, PTableType.TABLE, null, 1, 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"); + + // 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); + } + } + } + private static long getTableSequenceNumber(PhoenixConnection conn, String tableName) throws SQLException { PTable table = conn.getMetaDataCache().getTable(new PTableKey(conn.getTenantId(), SchemaUtil.normalizeIdentifier(tableName))); return table.getSequenceNumber(); http://git-wip-us.apache.org/repos/asf/phoenix/blob/318d096c/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLIT.java index bf86818..05b36c3 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDDLIT.java @@ -88,14 +88,49 @@ public class TenantSpecificTablesDDLIT extends BaseTenantSpecificTablesIT { } @Test - public void testAlterMultiTenantWithViewsToGlobal() throws Exception { + public void testAlteringMultiTenancyForTableWithViewsNotAllowed() throws Exception { Properties props = new Properties(); props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(nextTimestamp())); - Connection conn = DriverManager.getConnection(getUrl(), props); - try { - conn.createStatement().execute("alter table " + PARENT_TABLE_NAME + " set MULTI_TENANT=false"); - } catch (SQLException e) { - assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode()); + String multiTenantTable = "BASE_MULTI_TENANT_SWITCH"; + String globalTable = "GLOBAL_TABLE_SWITCH"; + // create the two base tables + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + String ddl = "CREATE TABLE " + multiTenantTable + " (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(ddl); + ddl = "CREATE TABLE " + globalTable + " (TENANT_ID VARCHAR NOT NULL, PK1 VARCHAR NOT NULL, V1 VARCHAR, V2 VARCHAR, V3 VARCHAR CONSTRAINT NAME_PK PRIMARY KEY(TENANT_ID, PK1)) "; + conn.createStatement().execute(ddl); + } + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(nextTimestamp())); + props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, "tenant1"); + // create view on multi-tenant table + try (Connection tenantConn = DriverManager.getConnection(getUrl(), props)) { + String viewName = "tenantview"; + String viewDDL = "CREATE VIEW " + viewName + " AS SELECT * FROM " + multiTenantTable; + tenantConn.createStatement().execute(viewDDL); + } + props = new Properties(); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(nextTimestamp())); + // create view on global table + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + String viewName = "globalView"; + conn.createStatement().execute("CREATE VIEW " + viewName + " AS SELECT * FROM " + globalTable); + } + props = new Properties(); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(nextTimestamp())); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + try { + conn.createStatement().execute("ALTER TABLE " + globalTable + " SET MULTI_TENANT = " + true); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode()); + } + + try { + conn.createStatement().execute("ALTER TABLE " + multiTenantTable + " SET MULTI_TENANT = " + false); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.CANNOT_MUTATE_TABLE.getErrorCode(), e.getErrorCode()); + } } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/318d096c/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 5a68e44..9dec592 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 @@ -1791,7 +1791,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso return columnKey; } - MetaDataMutationResult addRowsToChildViews(PTable basePhysicalTable, List<Mutation> tableMetadata, List<Mutation> mutationsForAddingColumnsToViews, byte[] schemaName, byte[] tableName, + private MetaDataMutationResult addRowsToChildViews(PTable basePhysicalTable, List<Mutation> tableMetadata, List<Mutation> mutationsForAddingColumnsToViews, byte[] schemaName, byte[] tableName, List<ImmutableBytesPtr> invalidateList, long clientTimeStamp, TableViewFinderResult childViewsResult, HRegion region, List<RowLock> locks) throws IOException, SQLException { List<PutWithOrdinalPosition> columnPutsForBaseTable = new ArrayList<>(tableMetadata.size()); @@ -2237,7 +2237,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso TableViewFinderResult childViewsResult = findChildViews(region, tenantId, table, PHYSICAL_TABLE_BYTES); if (childViewsResult.hasViews()) { /* - * Adding a column is not allowed if + * Dis-allow if: * 1) The meta-data for child view/s spans over * more than one region (since the changes cannot be made in a transactional fashion) * @@ -2247,8 +2247,13 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso * 3) If the request is from a client that is older than 4.5 version of phoenix. * Starting from 4.5, metadata requests have the client version included in them. * We don't want to allow clients before 4.5 to add a column to the base table if it has views. + * + * 4) Trying to switch a table that has views from multi-tenant to global. */ - if (!childViewsResult.allViewsInSingleRegion() || table.getBaseColumnCount() == 0 || !request.hasClientVersion()) { + if (!childViewsResult.allViewsInSingleRegion() + || table.getBaseColumnCount() == 0 + || !request.hasClientVersion() + || switchTenancy(table, tableMetaData)) { return new MetaDataMutationResult(MutationCode.UNALLOWED_TABLE_MUTATION, EnvironmentEdgeManager.currentTimeMillis(), null); } else { @@ -2324,6 +2329,21 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso tableMetaData.addAll(mutationsForAddingColumnsToViews); return null; } + + private boolean switchTenancy(PTable table, List<Mutation> tableMetaData) { + for (Mutation m : tableMetaData) { + if (m instanceof Put) { + Put p = (Put)m; + List<Cell> cells = p.get(TABLE_FAMILY_BYTES, MULTI_TENANT_BYTES); + if (cells != null && cells.size() > 0) { + Cell cell = cells.get(0); + boolean isMutlitenantProp = (boolean)PBoolean.INSTANCE.toObject(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()); + return table.isMultiTenant() != isMutlitenantProp; + } + } + } + return false; + } }); if (result != null) { done.run(MetaDataMutationResult.toProto(result));