This is an automated email from the ASF dual-hosted git repository. lokiore pushed a commit to branch PHOENIX-6978-feature in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/PHOENIX-6978-feature by this push: new 021a7d52a3 PHOENIX-7040 (ADDENDUM): Support TTL for views using the new column TTL in SYSTEM.CATALOG (#1782) 021a7d52a3 is described below commit 021a7d52a395c1b49423be848ec9f5f5ef5c3b0e Author: Lokesh Khurana <khuranalokes...@gmail.com> AuthorDate: Mon Feb 19 20:20:26 2024 -0800 PHOENIX-7040 (ADDENDUM): Support TTL for views using the new column TTL in SYSTEM.CATALOG (#1782) Co-authored-by: lokesh-khurana <lokesh.khur...@salesforce.com> --- .../apache/phoenix/end2end/TTLAsPhoenixTTLIT.java | 37 +- .../it/java/org/apache/phoenix/end2end/TTLIT.java | 853 +++++++++++++++++++++ .../phoenix/coprocessor/MetaDataEndpointImpl.java | 144 ++-- .../org/apache/phoenix/schema/MetaDataClient.java | 4 +- 4 files changed, 970 insertions(+), 68 deletions(-) diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLAsPhoenixTTLIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLAsPhoenixTTLIT.java index 62fc219e9c..82735fa7b0 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLAsPhoenixTTLIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLAsPhoenixTTLIT.java @@ -53,9 +53,9 @@ import static org.junit.Assert.fail; @Category(ParallelStatsDisabledTest.class) public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ - private static final long DEFAULT_TTL_FOR_TEST = 86400; - private static final long DEFAULT_TTL_FOR_CHILD = 10000; - public static final String TENANT_URL_FMT = "%s;%s=%s"; + private static final int DEFAULT_TTL_FOR_TEST = 86400; + private static final int DEFAULT_TTL_FOR_CHILD = 10000; + private static final int DEFAULT_TTL_FOR_ALTER = 7000; /** * test TTL is being set as PhoenixTTL when PhoenixTTL is enabled. @@ -153,9 +153,10 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ //Checking Default TTL in case of PhoenixTTLEnabled assertTTLValueOfTableOrView(conn.unwrap(PhoenixConnection.class), PhoenixDatabaseMetaData.TTL_NOT_DEFINED, tableName); String ddl = "ALTER TABLE " + tableName - + " SET TTL=1000"; + + " SET TTL = " + DEFAULT_TTL_FOR_ALTER; conn.createStatement().execute(ddl); - assertTTLValueOfTableOrView(conn.unwrap(PhoenixConnection.class), 1000, tableName); + assertTTLValueOfTableOrView(conn.unwrap(PhoenixConnection.class), + DEFAULT_TTL_FOR_ALTER, tableName); //Asserting TTL should not be stored as CF Descriptor properties when //phoenix.table.ttl.enabled is true Admin admin = driver.getConnectionQueryServices(getUrl(), new Properties()).getAdmin(); @@ -339,7 +340,7 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ } try { - ddl = "ALTER TABLE " + tableName + " SET TTL=" + DEFAULT_TTL_FOR_TEST; + ddl = "ALTER TABLE " + tableName + " SET TTL=" + DEFAULT_TTL_FOR_ALTER; conn.createStatement().execute(ddl); } catch (SQLException sqe) { assertEquals("Should fail with TTL already defined in hierarchy", @@ -359,9 +360,9 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ assertTTLValueOfTableOrView(tenantConn.unwrap(PhoenixConnection.class), TTL_NOT_DEFINED, childView); - ddl = "ALTER VIEW " + viewName + " SET TTL=" + DEFAULT_TTL_FOR_CHILD; + ddl = "ALTER VIEW " + viewName + " SET TTL=" + DEFAULT_TTL_FOR_ALTER; conn.createStatement().execute(ddl); - assertTTLValueOfTableOrView(conn.unwrap(PhoenixConnection.class), DEFAULT_TTL_FOR_CHILD, viewName); + assertTTLValueOfTableOrView(conn.unwrap(PhoenixConnection.class), DEFAULT_TTL_FOR_ALTER, viewName); } } @@ -398,7 +399,7 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ assertTTLValueOfTableOrView(tenantConn1.unwrap(PhoenixConnection.class), DEFAULT_TTL_FOR_TEST, childView1); - String alter = "ALTER TABLE " + tableName + " SET TTL = " + DEFAULT_TTL_FOR_CHILD; + String alter = "ALTER TABLE " + tableName + " SET TTL = " + DEFAULT_TTL_FOR_ALTER; conn.createStatement().execute(alter); //Clear Cache for all Tables to reflect Alter TTL commands in hierarchy @@ -409,11 +410,11 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ //Assert TTL for each entity again with altered value assertTTLValueOfTableOrView(conn.unwrap(PhoenixConnection.class), - DEFAULT_TTL_FOR_CHILD, viewName); + DEFAULT_TTL_FOR_ALTER, viewName); assertTTLValueOfTableOrView(tenantConn.unwrap(PhoenixConnection.class), - DEFAULT_TTL_FOR_CHILD, childView); + DEFAULT_TTL_FOR_ALTER, childView); assertTTLValueOfTableOrView(tenantConn1.unwrap(PhoenixConnection.class), - DEFAULT_TTL_FOR_CHILD, childView1); + DEFAULT_TTL_FOR_ALTER, childView1); } } @@ -435,8 +436,8 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ + " COL2 bigint NOT NULL," + " CREATED_DATE DATE," + " CREATION_TIME BIGINT," - + " CONSTRAINT NAME_PK PRIMARY KEY (ID, COL1, COL2))" - + ( withTTL ? " TTL = " + DEFAULT_TTL_FOR_TEST : "")); + + " CONSTRAINT NAME_PK PRIMARY KEY (ID, COL1, COL2)) MULTI_TENANT=true " + + ( withTTL ? ", TTL = " + DEFAULT_TTL_FOR_TEST : "")); return tableName; } @@ -446,13 +447,13 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ case LOCAL: String localIndexName = baseTableOrViewName + "_Local_" + generateUniqueName(); conn.createStatement().execute("CREATE LOCAL INDEX " + localIndexName + " ON " + - baseTableOrViewName + " (COL1) " + (withTTL ? "TTL = " + DEFAULT_TTL_FOR_CHILD : "")); + baseTableOrViewName + " (COL2) " + (withTTL ? "TTL = " + DEFAULT_TTL_FOR_CHILD : "")); return localIndexName; case GLOBAL: String globalIndexName = baseTableOrViewName + "_Global_" + generateUniqueName(); conn.createStatement().execute("CREATE INDEX " + globalIndexName + " ON " + - baseTableOrViewName + " (COL1) " + (withTTL ? "TTL = " + DEFAULT_TTL_FOR_CHILD : "")); + baseTableOrViewName + " (COL2) " + (withTTL ? "TTL = " + DEFAULT_TTL_FOR_CHILD : "")); return globalIndexName; default: @@ -465,7 +466,7 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ String viewName = "VIEW_" + baseTableName + "_" + generateUniqueName(); conn.createStatement().execute("CREATE VIEW " + viewName + " (" + generateUniqueName() + " SMALLINT) as select * from " - + baseTableName + " where id > 1 " + + baseTableName + " where COL1 > 1 " + (withTTL ? "TTL = " + DEFAULT_TTL_FOR_CHILD : "") ); return viewName; } @@ -475,7 +476,7 @@ public class TTLAsPhoenixTTLIT extends ParallelStatsDisabledIT{ String viewName = "VIEW_" + baseTableName + "_" + generateUniqueName(); conn.createStatement().execute("CREATE VIEW " + viewName + " (" + generateUniqueName() + " SMALLINT) as select * from " - + baseTableName + " where id = 1 " + + baseTableName + " where COL1 = 1 " + (withTTL ? "TTL = " + DEFAULT_TTL_FOR_CHILD : "") ); return viewName; } diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLIT.java new file mode 100644 index 0000000000..63bf22f594 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TTLIT.java @@ -0,0 +1,853 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.phoenix.end2end; + +import org.apache.phoenix.exception.SQLExceptionCode; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.query.PhoenixTestBuilder; +import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder; +import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TableOptions; +import org.apache.phoenix.schema.PTable; +import org.apache.phoenix.thirdparty.com.google.common.collect.Lists; +import org.apache.phoenix.util.PhoenixRuntime; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TTL_NOT_DEFINED; +import static org.apache.phoenix.util.PhoenixRuntime.TENANT_ID_ATTRIB; + +@Category(ParallelStatsDisabledTest.class) +@RunWith(Parameterized.class) +public class TTLIT extends ParallelStatsDisabledIT { + + private final boolean isMultiTenant; + + private static final int DEFAULT_TEST_TTL_VALUE = 800000; + private static final int ALTER_TEST_TTL_VALUE = 100000; + private static final int DEFAULT_TEST_TTL_VALUE_AT_GLOBAL = 400000; + private static final int DEFAULT_TEST_TTL_VALUE_AT_TENANT = 200000; + public static final String SKIP_ASSERT = "SKIP_ASSERT"; + + public TTLIT (boolean isMultiTenant) { + this.isMultiTenant = isMultiTenant; + } + + @Parameterized.Parameters(name="isMultiTenant={0}") + public static synchronized Collection<Object[]> data() { + return Arrays.asList(new Object[][] { + { true }, + { false }, + }); + } + + /** + * BUILD methods to create Table/Index/View/ViewIndexes with or without TTL as table props + * at different levels + */ + + private SchemaBuilder createTableWithTTL(boolean addTTL, boolean addIndex, + SchemaBuilder.TableIndexOptions indexOptions) { + SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl()); + TableOptions tableOptions = TableOptions.withDefaults(); + tableOptions.setMultiTenant(isMultiTenant); + if (addTTL) { + tableOptions.setTableProps("TTL = " + DEFAULT_TEST_TTL_VALUE); + } + if (addIndex) { + if (indexOptions == null) { + indexOptions = SchemaBuilder.TableIndexOptions.withDefaults(); + } + schemaBuilder.withTableIndexOptions(indexOptions); + } + return schemaBuilder.withTableOptions(tableOptions); + } + + private SchemaBuilder createGlobalViewOnTable(boolean addTTL, boolean addIndex) { + return createGlobalViewOnTable(createTableWithTTL(false, false, null), addTTL, addIndex, true); + } + + private SchemaBuilder createGlobalViewOnTable(SchemaBuilder schemaBuilder, boolean addTTL, + boolean addIndex, boolean addPK) { + SchemaBuilder.GlobalViewOptions globalViewOptions = SchemaBuilder.GlobalViewOptions.withDefaults(); + if (!addPK) { + globalViewOptions.setGlobalViewPKColumns(Lists.newArrayList()); + } + if (addTTL) { + globalViewOptions.setTableProps("TTL = " + DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + } + if (addIndex) { + schemaBuilder.withGlobalViewIndexDefaults(); + } + return schemaBuilder.withGlobalViewOptions(globalViewOptions); + } + + private SchemaBuilder createTenantViewOnTable(boolean addTTL, boolean addIndex) { + return createTenantViewOnTableOrGlobalView(createTableWithTTL(false, false, null), + addTTL, addIndex, true); + } + + private SchemaBuilder createTenantViewOnGlobalView(boolean addTTL, boolean addIndex) { + return createTenantViewOnTableOrGlobalView(createGlobalViewOnTable(false, false), + addTTL, addIndex, true); + } + + private SchemaBuilder createTenantViewOnTableOrGlobalView(SchemaBuilder schemaBuilder, boolean addTTL, + boolean addIndex, boolean addPK) { + SchemaBuilder.TenantViewOptions tenantViewOptions = SchemaBuilder.TenantViewOptions.withDefaults(); + if (!addPK) { + tenantViewOptions.setTenantViewPKColumns(Lists.newArrayList()); + } + if (addTTL) { + tenantViewOptions.setTableProps("TTL = " + DEFAULT_TEST_TTL_VALUE_AT_TENANT); + } + if (addIndex) { + schemaBuilder.withTenantViewIndexDefaults(); + } + return schemaBuilder.withTenantViewOptions(tenantViewOptions); + } + + /** + * Assert Methods + */ + + private void assertTTLForGivenPTable(PTable table, int ttl) { + Assert.assertEquals(ttl, table.getTTL()); + } + + + private void assertTTLForGivenEntity(Connection connection, String entityName, int ttl) throws SQLException { + PTable pTable = PhoenixRuntime.getTable(connection, entityName); + Assert.assertEquals(ttl,pTable.getTTL()); + } + + private void assertTTLForIndexName(Connection connection, String indexName, int ttl) throws SQLException { + if (!indexName.equals(SKIP_ASSERT)) { + PTable index = PhoenixRuntime.getTable(connection, indexName); + Assert.assertEquals(ttl,index.getTTL()); + } + } + + private void assertTTLForIndexFromParentPTable(Connection connection, String baseEntity, int ttl) throws SQLException { + PTable entity = PhoenixRuntime.getTable(connection, baseEntity); + List<PTable> indexes = entity.getIndexes(); + for (PTable index : indexes) { + assertTTLForGivenPTable(index, ttl); + } + } + + /* + * TEST METHODS + */ + + @Test + public void testTTLAtTableLevelWithIndex() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(true, true,null); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String indexName = schemaBuilder.getEntityTableIndexName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl())) { + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexName(globalConnection, indexName, DEFAULT_TEST_TTL_VALUE); + //Assert TTL for index by getting PTable from table's PTable + assertTTLForIndexFromParentPTable(globalConnection, schemaBuilder.getEntityTableName(), DEFAULT_TEST_TTL_VALUE); + } + } + + + @Test + public void testSettingTTLForIndex() throws Exception { + SchemaBuilder.TableIndexOptions indexOptions = new SchemaBuilder.TableIndexOptions(); + indexOptions.setTableIndexColumns(PhoenixTestBuilder.DDLDefaults.TABLE_INDEX_COLUMNS); + indexOptions.setTableIncludeColumns(PhoenixTestBuilder.DDLDefaults.TABLE_INCLUDE_COLUMNS); + indexOptions.setIndexProps("TTL = " + DEFAULT_TEST_TTL_VALUE); + SchemaBuilder schemaBuilder = createTableWithTTL(false, true, indexOptions); + try { + schemaBuilder.build(); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.CANNOT_SET_OR_ALTER_PROPERTY_FOR_INDEX.getErrorCode() + ,sqe.getErrorCode()); + } + } + + /** + * Test TTL defined at Table level for 2 level View Hierarchy, TTL value should be passed down + * to view at Global Level as well as Child Views of Global View. + * @throws Exception + */ + + @Test + public void testTTLInHierarchyDefinedAtTableLevel() throws Exception { + //Create Table with TTL as table option. + SchemaBuilder schemaBuilder = createTableWithTTL(true, false, null); + //Create Global View on top of table without defining TTL. + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, true); + //Create Tenant View on top of Global View without defining TTL. + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String globalView = schemaBuilder.getEntityGlobalViewName(); + String childView = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(globalConnection, globalView, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE); + } + } + + @Test + public void testSettingTTLForViewsInHierarchyWithTTLAtTableLevel() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(true, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, true,false,true); + try { + schemaBuilder.build(); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + schemaBuilder = createTableWithTTL(true, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false,false,true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, true, false, true); + try { + schemaBuilder.build(); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + } + + @Test + public void testAlteringTTLForViewsInHierarchyWithTTLAtTableLevel() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(true, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String childViewName = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, childViewName, DEFAULT_TEST_TTL_VALUE); + + //Altering TTL at globalView should fail + String dml = "ALTER VIEW " + globalViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + try { + globalConnection.createStatement().execute(dml); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + //Altering TTL at tenantView should fail + dml = "ALTER VIEW " + childViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + try { + tenantConnection.createStatement().execute(dml); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + } + + + } + + + @Test + public void testTTLInHierarchyDefinedAtTableLevelWithIndex() throws Exception { + //Create Table with TTL as table option and also build index. + SchemaBuilder schemaBuilder = createTableWithTTL(true, true, null); + //Create Global View on top of table without defining TTL but don't extend PK as we are building index on table. + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, false); + //Create Tenant View on top of Global View without defining TTL but don't extend PK as we are building index on table. + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false, false); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String indexName = schemaBuilder.getEntityTableIndexName(); + String globalView = schemaBuilder.getEntityGlobalViewName(); + String childView = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexName(globalConnection, indexName, DEFAULT_TEST_TTL_VALUE); + //Assert TTL for index by getting PTable from table's PTable + assertTTLForIndexFromParentPTable(globalConnection, schemaBuilder.getEntityTableName(), DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(globalConnection, globalView, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE); + } + } + + @Test + public void testTTLInHierarchyDefinedAtTableLevelWithIndexAtGlobalLevel() throws Exception { + //Create Table with TTL as table option. + SchemaBuilder schemaBuilder = createTableWithTTL(true, false,null); + //Create Global View on top of table without defining TTL and create index on top of view. + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, true,true); + //Create Tenant View on top of Global View without defining TTL but don't extend PK as we are building index on global view. + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false, false); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + + String globalView = schemaBuilder.getEntityGlobalViewName(); + String globalViewIndexName = schemaBuilder.getEntityGlobalViewIndexName(); + + String childView = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + + assertTTLForGivenEntity(globalConnection, globalView, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexName(globalConnection, globalViewIndexName, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(globalConnection, globalView, DEFAULT_TEST_TTL_VALUE); + + assertTTLForGivenEntity(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE); + } + } + + @Test + public void testTTLInHierarchyDefinedAtTableLevelWithIndexAtTenantLevel() throws Exception { + //Create Table with TTL as table option. + SchemaBuilder schemaBuilder = createTableWithTTL(true, false,null); + //Create Global View on top of table without defining TTL. + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false,true); + //Create Tenant View on top of Global View without defining TTL and create index on top of view + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, isMultiTenant, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String globalView = schemaBuilder.getEntityGlobalViewName(); + String childView = schemaBuilder.getEntityTenantViewName(); + String childViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + + assertTTLForGivenEntity(globalConnection, globalView, DEFAULT_TEST_TTL_VALUE); + + assertTTLForGivenEntity(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, childViewIndexName, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE); + + } + } + + /** + * Test with TTL defined at Global View Level + */ + + @Test + public void testTTLHierarchyDefinedAtGlobalViewLevel() throws Exception { + SchemaBuilder schemaBuilder = createGlobalViewOnTable(true, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false,false); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String globalViewIndexName = schemaBuilder.getEntityGlobalViewIndexName(); + String childViewName = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForIndexName(globalConnection, globalViewIndexName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForIndexFromParentPTable(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForGivenEntity(tenantConnection, childViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + } + } + + @Test + public void testTTLHierarchyDefinedAtGlobalViewLevelWithTenantIndex() throws Exception { + SchemaBuilder schemaBuilder = createGlobalViewOnTable(true, false); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, isMultiTenant,true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String childViewName = schemaBuilder.getEntityTenantViewName(); + String childViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForGivenEntity(tenantConnection, childViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForIndexName(tenantConnection, childViewIndexName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForIndexFromParentPTable(tenantConnection, childViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + } + } + + @Test + public void testSettingTTLAtTenantViewLevelWithTTLDefinedAtGlobalView() throws Exception { + SchemaBuilder schemaBuilder = createGlobalViewOnTable(true, false); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, true, false,true); + try { + schemaBuilder.build(); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + schemaBuilder = createGlobalViewOnTable(true, false); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false,true); + schemaBuilder.build(); + PTable table = schemaBuilder.getBaseTable(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String childViewName = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForGivenEntity(tenantConnection, childViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + + + } + } + + @Test + public void testAlteringTTLAtDifferentLevelsWithTTLDefinedAtGlobalView() throws Exception { + SchemaBuilder schemaBuilder = createGlobalViewOnTable(true, false); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, false,true); + schemaBuilder.build(); + PTable table = schemaBuilder.getBaseTable(); + String tableName = schemaBuilder.getEntityTableName(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String childViewName = schemaBuilder.getEntityTenantViewName(); + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForGivenEntity(tenantConnection, childViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + + //Altering TTL at tenantView should fail + String dml = "ALTER VIEW " + childViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + try { + tenantConnection.createStatement().execute(dml); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + //Altering TTL at Table should fail + dml = "ALTER TABLE " + tableName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + try { + globalConnection.createStatement().execute(dml); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + } + } + + @Test + public void testTTLHierarchyDefinedAtTenantViewLevel() throws Exception { + SchemaBuilder schemaBuilder = createTenantViewOnGlobalView(true, isMultiTenant); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String globalView = schemaBuilder.getEntityGlobalViewName(); + String childView = schemaBuilder.getEntityTenantViewName(); + String childViewIndex = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalView, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexName(tenantConnection, childViewIndex, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexFromParentPTable(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + } + } + + @Test + public void testSettingAndAlteringTTLInHierarchyAboveOfTenantViewWithTTLDefined() throws Exception { + SchemaBuilder schemaBuilder = createTenantViewOnGlobalView(true, isMultiTenant); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String tableName = schemaBuilder.getEntityTableName(); + String globalView = schemaBuilder.getEntityGlobalViewName(); + String childView = schemaBuilder.getEntityTenantViewName(); + String childViewIndex = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalView, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexName(tenantConnection, childViewIndex, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexFromParentPTable(tenantConnection, childView, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + + //Altering TTL at globalView should fail + String dml = "ALTER VIEW " + globalView + " SET TTL = " + ALTER_TEST_TTL_VALUE; + try { + globalConnection.createStatement().execute(dml); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + //Altering TTL at Table should fail + dml = "ALTER TABLE " + tableName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + try { + globalConnection.createStatement().execute(dml); + Assert.fail(); + } catch (SQLException sqe) { + Assert.assertEquals(SQLExceptionCode.TTL_ALREADY_DEFINED_IN_HIERARCHY.getErrorCode() + ,sqe.getErrorCode()); + } + + } + } + + + @Test + public void testAlteringTTLFromTableToLevel1() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(true, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, isMultiTenant, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String schemaName = schemaBuilder.getTableOptions().getSchemaName(); + String tableName = schemaBuilder.getEntityTableName(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String tenantViewName = schemaBuilder.getEntityTenantViewName(); + String tenantViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE); + + //Alter TTL to NONE + String dml = "ALTER TABLE " + tableName + " SET TTL = NONE"; + globalConnection.createStatement().execute(dml); + + //Clearing cache as MetaDataCaching is not there for TTL usecase + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, TTL_NOT_DEFINED); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + + //Alter TTL From not defined to something at Global View Level + dml = "ALTER VIEW " + globalViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + globalConnection.createStatement().execute(dml); + + //Clearing cache again + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, ALTER_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + + } + + } + + @Test + public void testAlteringTTLFromTableToLevel2() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(true, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, isMultiTenant, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String schemaName = schemaBuilder.getTableOptions().getSchemaName(); + String tableName = schemaBuilder.getEntityTableName(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String tenantViewName = schemaBuilder.getEntityTenantViewName(); + String tenantViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, DEFAULT_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE); + + //Alter TTL to NONE + String dml = "ALTER TABLE " + tableName + " SET TTL = NONE"; + globalConnection.createStatement().execute(dml); + + //Clearing cache as MetaDataCaching is not there for TTL usecase + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, TTL_NOT_DEFINED); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + + //Alter TTL From not defined to something at Global View Level + dml = "ALTER VIEW " + tenantViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + tenantConnection.createStatement().execute(dml); + + //Clearing cache again + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + + } + + } + + @Test + public void testAlteringTTLFromLevel1ToLevel2() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(false, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, true, false, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, false, isMultiTenant, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String schemaName = schemaBuilder.getTableOptions().getSchemaName(); + String tableName = schemaBuilder.getEntityTableName(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String tenantViewName = schemaBuilder.getEntityTenantViewName(); + String tenantViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForGivenEntity(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE_AT_GLOBAL); + + //Alter TTL to NONE + String dml = "ALTER VIEW " + globalViewName + " SET TTL = NONE"; + globalConnection.createStatement().execute(dml); + + //Clearing cache as MetaDataCaching is not there for TTL usecase + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, TTL_NOT_DEFINED); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + + //Alter TTL From not defined to something at Global View Level + dml = "ALTER VIEW " + tenantViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + tenantConnection.createStatement().execute(dml); + + //Clearing cache again + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + + } + + } + + @Test + public void testAlteringTTLFromLevel2ToTable() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(false, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, true, isMultiTenant, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String schemaName = schemaBuilder.getTableOptions().getSchemaName(); + String tableName = schemaBuilder.getEntityTableName(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String tenantViewName = schemaBuilder.getEntityTenantViewName(); + String tenantViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + + //Alter TTL to NONE + String dml = "ALTER VIEW " + tenantViewName + " SET TTL = NONE"; + tenantConnection.createStatement().execute(dml); + + //Clearing cache as MetaDataCaching is not there for TTL usecase + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, TTL_NOT_DEFINED); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + + //Alter TTL From not defined to something at Global View Level + dml = "ALTER TABLE " + tableName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + globalConnection.createStatement().execute(dml); + + //Clearing cache again + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, ALTER_TEST_TTL_VALUE); + assertTTLForGivenEntity(globalConnection, globalViewName, ALTER_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + + } + + } + + + @Test + public void testAlteringTTLFromLevel2ToLevel1() throws Exception { + SchemaBuilder schemaBuilder = createTableWithTTL(false, false, null); + schemaBuilder = createGlobalViewOnTable(schemaBuilder, false, false, true); + schemaBuilder = createTenantViewOnTableOrGlobalView(schemaBuilder, true, isMultiTenant, true); + schemaBuilder.build(); + + PTable table = schemaBuilder.getBaseTable(); + String schemaName = schemaBuilder.getTableOptions().getSchemaName(); + String tableName = schemaBuilder.getEntityTableName(); + String globalViewName = schemaBuilder.getEntityGlobalViewName(); + String tenantViewName = schemaBuilder.getEntityTenantViewName(); + String tenantViewIndexName = isMultiTenant ? schemaBuilder.getEntityTenantViewIndexName() : SKIP_ASSERT; + + try (Connection globalConnection = DriverManager.getConnection(getUrl()); + Connection tenantConnection = DriverManager.getConnection( + getUrl() + ';' + TENANT_ID_ATTRIB + '=' + schemaBuilder.getDataOptions().getTenantId())) { + //All level entities should have TTL value equal to TTL defined at table level + assertTTLForGivenPTable(table, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, DEFAULT_TEST_TTL_VALUE_AT_TENANT); + + //Alter TTL to NONE + String dml = "ALTER VIEW " + tenantViewName + " SET TTL = NONE"; + tenantConnection.createStatement().execute(dml); + + //Clearing cache as MetaDataCaching is not there for TTL usecase + //Clearing cache as MetaDataCaching is not there for TTL usecase + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, TTL_NOT_DEFINED); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, TTL_NOT_DEFINED); + + //Alter TTL From not defined to something at Global View Level + dml = "ALTER VIEW " + globalViewName + " SET TTL = " + ALTER_TEST_TTL_VALUE; + globalConnection.createStatement().execute(dml); + + //Clearing cache again + //Clearing cache as MetaDataCaching is not there for TTL usecase + globalConnection.unwrap(PhoenixConnection.class).getQueryServices().clearCache(); + + assertTTLForGivenEntity(globalConnection, tableName, TTL_NOT_DEFINED); + assertTTLForGivenEntity(globalConnection, globalViewName, ALTER_TEST_TTL_VALUE); + assertTTLForGivenEntity(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexName(tenantConnection, tenantViewIndexName, ALTER_TEST_TTL_VALUE); + assertTTLForIndexFromParentPTable(tenantConnection, tenantViewName, ALTER_TEST_TTL_VALUE); + + } + + } + + + + +} 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 c79adaf030..f64e38c69a 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 @@ -89,6 +89,7 @@ import static org.apache.phoenix.query.QueryConstants.VIEW_MODIFIED_PROPERTY_TAG import static org.apache.phoenix.schema.PTable.LinkType.PARENT_TABLE; import static org.apache.phoenix.schema.PTable.LinkType.PHYSICAL_TABLE; import static org.apache.phoenix.schema.PTable.LinkType.VIEW_INDEX_PARENT_TABLE; +import static org.apache.phoenix.schema.PTable.ViewType.MAPPED; import static org.apache.phoenix.schema.PTableImpl.getColumnsToClone; import static org.apache.phoenix.schema.PTableType.INDEX; import static org.apache.phoenix.schema.PTableType.VIEW; @@ -98,7 +99,6 @@ import static org.apache.phoenix.util.ViewUtil.findAllDescendantViews; import static org.apache.phoenix.util.ViewUtil.getSystemTableForChildLinks; import java.io.IOException; -import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.PrivilegedExceptionAction; import java.sql.ResultSetMetaData; @@ -122,7 +122,6 @@ import org.apache.hadoop.hbase.ArrayBackedTag; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.CellComparatorImpl; -import org.apache.hadoop.hbase.CellScanner; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.CoprocessorEnvironment; import org.apache.hadoop.hbase.DoNotRetryIOException; @@ -690,7 +689,7 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES); if (request.getClientVersion() < MIN_SPLITTABLE_SYSTEM_CATALOG && table.getType() == PTableType.VIEW - && table.getViewType() != ViewType.MAPPED) { + && table.getViewType() != MAPPED) { try (PhoenixConnection connection = QueryUtil.getConnectionOnServer(env.getConfiguration()).unwrap(PhoenixConnection.class)) { PTable pTable = PhoenixRuntime.getTableNoCache(connection, table.getParentName().getString()); table = ViewUtil.addDerivedColumnsFromParent(connection, table, pTable); @@ -1421,11 +1420,11 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES); ttlKv.getValueOffset(), SortOrder.getDefault()); ttl = ttlKv != null ? ttl : oldTable != null ? oldTable.getTTL() : TTL_NOT_DEFINED; - if (tableType == VIEW && ttl == TTL_NOT_DEFINED) { + if (tableType == VIEW && viewType != MAPPED && ttl == TTL_NOT_DEFINED) { //Scan SysCat to get TTL from Parent View/Table byte[] viewKey = SchemaUtil.getTableKey(tenantId == null ? null : tenantId.getBytes(), schemaName == null ? null : schemaName.getBytes(), tableNameBytes); - ttl = scanTTLFromParent(viewKey, clientTimeStamp); + ttl = getTTLFromHierarchy(viewKey, clientTimeStamp, false); // TODO: Need to Update Cache for Alter Commands, can use PHOENIX-6883. } @@ -1477,7 +1476,7 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES); PTable transformingNewTable = null; - boolean isRegularView = (tableType == PTableType.VIEW && viewType != ViewType.MAPPED); + boolean isRegularView = (tableType == PTableType.VIEW && viewType != MAPPED); boolean isThisAViewIndex = false; for (List<Cell> columnCellList : allColumnCellList) { @@ -1562,9 +1561,11 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES); } } } else if (linkType == VIEW_INDEX_PARENT_TABLE) { - byte[] indexKey = SchemaUtil.getTableKey(tenantId == null ? null : tenantId.getBytes(), - schemaName == null ? null : schemaName.getBytes(), tableNameBytes); - ttl = scanTTLFromParent(indexKey, clientTimeStamp); + byte[] viewKey = getTableKey(tenantId == null ? null : tenantId.getBytes(), + parentSchemaName == null ? null : parentSchemaName.getBytes(), + parentTableName.getBytes()); + //parentViewType should not be Mapped + ttl = getTTLFromHierarchy(viewKey, clientTimeStamp, true); isThisAViewIndex = true; } } else { @@ -1583,7 +1584,7 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES); byte[] tableKey = getTableKey(tenantId == null ? null : tenantId.getBytes(), parentSchemaName == null ? null : parentSchemaName.getBytes(), parentTableName.getBytes()); - ttl = scanTTLFromParent(tableKey, clientTimeStamp); + ttl = getTTLForTable(tableKey, clientTimeStamp); } builder.setTTL(ttl); builder.setEncodedCQCounter(cqCounter); @@ -1616,66 +1617,111 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES); return builder.build(); } - private int scanTTLFromParent(byte[] viewKey, long clientTimeStamp) throws IOException, SQLException { + /** + * Method to return TTL value defined at current level or up the Hierarchy of the view. + * @param viewKey Key of the view for which we have to find TTL + * @param clientTimeStamp Client TimeStamp + * @return TTL value for a given view, if nothing is defined anywhere then return + * TTL_NOT_DEFINED(0). + * @throws IOException + * @throws SQLException + */ + + private int getTTLFromHierarchy(byte[] viewKey, long clientTimeStamp, boolean checkForMappedView) throws IOException, SQLException { Scan scan = MetaDataUtil.newTableRowsScan(viewKey, MIN_TABLE_TIMESTAMP, clientTimeStamp); Table sysCat = ServerUtil.getHTableForCoprocessorScan(this.env, SchemaUtil.getPhysicalTableName(SYSTEM_CATALOG_NAME_BYTES, env.getConfiguration())); ResultScanner scanner = sysCat.getScanner(scan); Result result = scanner.next(); - boolean startCheckingForLink = false; + + byte[] tableKey = null; do { + if (result == null) { return TTL_NOT_DEFINED; } - if (startCheckingForLink) { - byte[] linkTypeBytes = result.getValue(TABLE_FAMILY_BYTES, LINK_TYPE_BYTES); - if (linkTypeBytes != null) { - byte[][] rowKeyMetaData = new byte[5][]; - getVarChars(result.getRow(), 5, rowKeyMetaData); - byte[] parentViewTenantId = null; - if (LinkType.fromSerializedValue(linkTypeBytes[0]) == PARENT_TABLE) { - parentViewTenantId = result.getValue(TABLE_FAMILY_BYTES, - PARENT_TENANT_ID_BYTES); - return getTTLFromAppropriateParent(parentViewTenantId, rowKeyMetaData, clientTimeStamp); - } else if (LinkType.fromSerializedValue(linkTypeBytes[0]) == - VIEW_INDEX_PARENT_TABLE) { - //We are calculating TTL for indexes on Views - parentViewTenantId = rowKeyMetaData - [PhoenixDatabaseMetaData.TENANT_ID_INDEX]; - return getTTLFromAppropriateParent(parentViewTenantId, rowKeyMetaData, clientTimeStamp); - } else if (LinkType.fromSerializedValue(linkTypeBytes[0]) == - PHYSICAL_TABLE) { - return getTTLFromAppropriateParent(parentViewTenantId, rowKeyMetaData, clientTimeStamp); - } - } - } else { - if (result.getValue(TABLE_FAMILY_BYTES, TTL_BYTES) != null) { + + //return TTL_NOT_DEFINED for Index on a Mapped View. + if (checkForMappedView && checkIfViewIsMappedView(result)) { + return TTL_NOT_DEFINED; + } + + byte[] linkTypeBytes = result.getValue(TABLE_FAMILY_BYTES, LINK_TYPE_BYTES); + byte[][] rowKeyMetaData = new byte[5][]; + getVarChars(result.getRow(), 5, rowKeyMetaData); + //Check if TTL is defined at the current given level + if (result.getValue(TABLE_FAMILY_BYTES, TTL_BYTES) != null) { return PInteger.INSTANCE.getCodec().decodeInt( result.getValue(DEFAULT_COLUMN_FAMILY_BYTES, TTL_BYTES), 0, SortOrder.getDefault()); + } else if (linkTypeBytes != null ) { + String parentSchema =SchemaUtil.getSchemaNameFromFullName( + rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX]); + byte[] parentViewSchemaName = parentSchema != null + ? parentSchema.getBytes(StandardCharsets.UTF_8) : null; + byte[] parentViewName = SchemaUtil.getTableNameFromFullName( + rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX]) + .getBytes(StandardCharsets.UTF_8); + //Get TTL from up the hierarchy, Checking for Parent view link and getting TTL from it. + if (LinkType.fromSerializedValue(linkTypeBytes[0]) == PARENT_TABLE) { + byte[] parentViewTenantId = result.getValue(TABLE_FAMILY_BYTES, + PARENT_TENANT_ID_BYTES); + byte[] parentViewKey = SchemaUtil.getTableKey(parentViewTenantId, + parentViewSchemaName, parentViewName); + return getTTLFromHierarchy(parentViewKey, clientTimeStamp, false); + } + + //Store tableKey to use if we don't find TTL at current level and from + //parent views above the hierarchy + if (LinkType.fromSerializedValue(linkTypeBytes[0]) == PHYSICAL_TABLE) { + tableKey = SchemaUtil.getTableKey(null, parentViewSchemaName, + parentViewName); } } result = scanner.next(); - startCheckingForLink = true; } while (result != null); - return TTL_NOT_DEFINED; + //Return TTL defined at Table level for the given hierarchy as we didn't find TTL any of the views. + return getTTLForTable(tableKey, clientTimeStamp); + } - private int getTTLFromAppropriateParent(byte[] parentViewTenantId, byte[][] rowKeyMetaData, - long clientTimeStamp) throws IOException, SQLException { - String parentSchema =SchemaUtil.getSchemaNameFromFullName( - rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX]); - byte[] parentViewSchemaName = parentSchema != null - ? parentSchema.getBytes(StandardCharsets.UTF_8) : null; - byte[] parentViewName = SchemaUtil.getTableNameFromFullName( - rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX]) - .getBytes(StandardCharsets.UTF_8); - byte[] parentViewKey = SchemaUtil.getTableKey(parentViewTenantId, - parentViewSchemaName, parentViewName); - return scanTTLFromParent(parentViewKey, clientTimeStamp); + private boolean checkIfViewIsMappedView(Result result) { + byte[] viewTypeBytes = result.getValue(TABLE_FAMILY_BYTES, VIEW_TYPE_BYTES); + if (viewTypeBytes != null && ViewType.fromSerializedValue(viewTypeBytes[0]) == MAPPED) { + return true; + } + return false; + } + + /*** + * Get TTL Value stored in SYSCAT for a given table + * @param tableKey of table for which we are fining TTL + * @param clientTimeStamp client TimeStamp value + * @return TTL defined for a given table if it is null then return TTL_NOT_DEFINED(0) + * @throws IOException + */ + private int getTTLForTable(byte[] tableKey, long clientTimeStamp) throws IOException { + Scan scan = MetaDataUtil.newTableRowsScan(tableKey, MIN_TABLE_TIMESTAMP, clientTimeStamp); + Table sysCat = ServerUtil.getHTableForCoprocessorScan(this.env, + SchemaUtil.getPhysicalTableName(SYSTEM_CATALOG_NAME_BYTES, + env.getConfiguration())); + ResultScanner scanner = sysCat.getScanner(scan); + Result result = scanner.next(); + do { + if (result == null) { + return TTL_NOT_DEFINED; + } + if (result.getValue(TABLE_FAMILY_BYTES, TTL_BYTES) != null) { + return PInteger.INSTANCE.getCodec().decodeInt( + result.getValue(DEFAULT_COLUMN_FAMILY_BYTES, TTL_BYTES), + 0, SortOrder.getDefault()); + } + result = scanner.next(); + } while (result != null); + return TTL_NOT_DEFINED; } private Long getViewIndexId(Cell[] tableKeyValues, PDataType viewIndexIdType) { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java index 28cc250444..c99f3a0127 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java @@ -2089,7 +2089,7 @@ public class MetaDataClient { */ private Integer checkAndGetTTLFromHierarchy(PTable parent) throws SQLException { return parent != null ? (parent.getType() == TABLE ? parent.getTTL() - : (parent.getType() == VIEW ? getTTLFromViewHierarchy(parent) : TTL_NOT_DEFINED)) + : (parent.getType() == VIEW && parent.getViewType() != MAPPED ? getTTLFromViewHierarchy(parent) : TTL_NOT_DEFINED)) : TTL_NOT_DEFINED; } @@ -2203,6 +2203,8 @@ public class MetaDataClient { } ttl = ttlProp; + } else { + ttlFromHierarchy = checkAndGetTTLFromHierarchy(parent); } Boolean isChangeDetectionEnabledProp =