diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core-client/src/main/java/org/apache/phoenix/schema/MetaDataClient.java index edb38da970c..481b44bfa9e 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/schema/MetaDataClient.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/schema/MetaDataClient.java @@ -2529,7 +2529,11 @@ private PTable createTableInternal(CreateTableStatement statement, byte[][] spli } else { ttlFromHierarchy = checkAndGetTTLFromHierarchy(parent, tableName); if (!ttlFromHierarchy.equals(TTL_EXPRESSION_NOT_DEFINED)) { - ttlFromHierarchy.validateTTLOnCreate(connection, statement, parent, tableProps); + if (parent.hasConditionalTTL() && !parent.isStrictTTL()) { + ttlFromHierarchy = TTL_EXPRESSION_NOT_DEFINED; + } else { + ttlFromHierarchy.validateTTLOnCreate(connection, statement, parent, tableProps); + } } } @@ -6413,7 +6417,11 @@ private boolean evaluateStmtProperties(MetaProperties metaProperties, } if (metaProperties.getTTL() != table.getTTLExpression()) { TTLExpression newTTL = metaProperties.getTTL(); - newTTL.validateTTLOnAlter(connection, table); + boolean isStrictTTL = + metaProperties.isStrictTTL() != null ? metaProperties.isStrictTTL : table.isStrictTTL(); + if (!(newTTL instanceof ConditionalTTLExpression) || isStrictTTL) { + newTTL.validateTTLOnAlter(connection, table); + } metaPropertiesEvaluated.setTTL(getCompatibleTTLExpression(metaProperties.getTTL(), table.getType(), table.getViewType(), table.getName().toString())); changingPhoenixTableProperty = true; diff --git a/phoenix-core/src/test/java/org/apache/phoenix/schema/ConditionalTTLExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/schema/ConditionalTTLExpressionTest.java index b82dd5e72d8..7e6fa9128f2 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/schema/ConditionalTTLExpressionTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/schema/ConditionalTTLExpressionTest.java @@ -55,7 +55,7 @@ public class ConditionalTTLExpressionTest extends BaseConnectionlessQueryTest { - private static void assertConditonTTL(Connection conn, String tableName, String ttlExpr) + private static void assertConditionTTL(Connection conn, String tableName, String ttlExpr) throws SQLException { TTLExpression expected = new ConditionalTTLExpression(ttlExpr); assertTTL(conn, tableName, expected); @@ -105,7 +105,7 @@ public void testBasicExpression() throws SQLException { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); String query = String.format("SELECT count(*) from %s where k1 > 3", tableName); validateScan(conn, tableName, query, ttl, false, Lists.newArrayList("col1")); } @@ -174,17 +174,17 @@ public void testSingleNonDefaultColumnFamilyIsAllowed() throws SQLException { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); // create global index String indexName = "I_" + generateUniqueName(); ddl = String.format("create index %s on %s (col2) include(col1)", indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); // create local index indexName = "L_" + generateUniqueName(); ddl = String.format("create local index %s on %s (col2) include(col1)", indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); } } @@ -198,23 +198,23 @@ public void testDefaultColumnFamily() throws SQLException { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); // create view String viewName = "GV_" + generateUniqueName(); ddl = String.format("create view %s (col3 varchar) as select * from %s where k1 = 2", viewName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, viewName, ttl); + assertConditionTTL(conn, viewName, ttl); // create global index String indexName = "I_" + generateUniqueName(); ddl = String.format("create index %s on %s (col2) include(col1)", indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); // create local index indexName = "L_" + generateUniqueName(); ddl = String.format("create local index %s on %s (col2) include(col1)", indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); } } @@ -301,7 +301,7 @@ public void testMultipleColumnFamilyNotAllowedOnAddColumn3() throws SQLException String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); // add a new column in a different column family String alterDDL = String.format("alter table %s add A.col3 varchar", tableName); try { @@ -369,7 +369,7 @@ public void testNullExpression() throws SQLException { String ddl = String.format(ddlTemplate, tableName, ttl); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); String query = String.format("SELECT count(*) from %s", tableName); validateScan(conn, tableName, query, ttl, false, Lists.newArrayList("col1", "col2")); } @@ -387,14 +387,14 @@ public void testBooleanColumn() throws SQLException { try (Connection conn = DriverManager.getConnection(getUrl())) { String ddl = String.format(ddlTemplate, tableName, ttl); conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); query = String.format("SELECT k1, k2 from %s where (k1,k2) IN ((1,2), (3,4))", tableName); validateScan(conn, tableName, query, ttl, false, Lists.newArrayList("expired")); ddl = String.format(indexTemplate, indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); // validate the scan on index query = String.format("SELECT count(*) from %s", tableName); @@ -411,7 +411,7 @@ public void testNot() throws SQLException { String ddl = String.format(ddlTemplate, tableName, ttl); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); } } @@ -425,7 +425,7 @@ public void testPhoenixRowTimestamp() throws SQLException { String query; try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); query = String.format("select col1 from %s where k1 = 7 AND k2 > 12", tableName); validateScan(conn, tableName, query, ttl, false, Lists.newArrayList("col1")); } @@ -441,7 +441,7 @@ public void testBooleanCaseExpression() throws SQLException { String ddl = String.format(ddlTemplate, tableName, ttl); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, expectedTTLExpr); + assertConditionTTL(conn, tableName, expectedTTLExpr); } } @@ -460,7 +460,7 @@ public void testCondTTLOnTopLevelView() throws SQLException { ddl = String.format(viewTemplate, viewName, tableName, ttl); conn.createStatement().execute(ddl); assertTTL(conn, tableName, TTL_EXPRESSION_NOT_DEFINED); - assertConditonTTL(conn, viewName, ttl); + assertConditionTTL(conn, viewName, ttl); String query = String.format("select k3 from %s", viewName); validateScan(conn, viewName, query, ttl, false, Lists.newArrayList("k2", "k3")); } @@ -487,11 +487,11 @@ public void testCondTTLOnMultiLevelView() throws SQLException { conn.createStatement().execute(ddl); assertTTL(conn, tableName, TTL_EXPRESSION_NOT_DEFINED); assertTTL(conn, parentView, TTL_EXPRESSION_NOT_DEFINED); - assertConditonTTL(conn, childView, ttl); + assertConditionTTL(conn, childView, ttl); // create an index on child view ddl = String.format(indexOnChildTemplate, indexName, childView); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); } } @@ -505,7 +505,7 @@ public void testInListTTLExpr() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); query = String.format("select col1 from %s where id IN ('abc', 'fff')", tableName); validateScan(conn, tableName, query, ttl, false, Lists.newArrayList("col1", "col2")); } @@ -524,10 +524,10 @@ public void testPartialIndex() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); ddl = String.format(indexTemplate, indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); query = String.format("select col3 from %s where col1 > 60", tableName); validateScan(conn, tableName, query, ttl, true, Lists.newArrayList("0:col2", "0:col3", "0:col4")); @@ -535,7 +535,7 @@ public void testPartialIndex() throws Exception { } @Test - public void testUncoveredIndex() throws Exception { + public void testUncoveredIndexStrictTTL() throws Exception { String ddlTemplate = "create table %s (id varchar not null primary key, " + "col1 integer, col2 integer, col3 double, col4 varchar) TTL = '%s'"; String tableName = generateUniqueName(); @@ -546,7 +546,7 @@ public void testUncoveredIndex() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); ddl = String.format(indexTemplate, indexName, tableName); try { conn.createStatement().execute(ddl); @@ -557,7 +557,25 @@ public void testUncoveredIndex() throws Exception { indexTemplate = "create uncovered index %s on %s (col4, col2) "; ddl = String.format(indexTemplate, indexName, tableName); conn.createStatement().execute(ddl); - assertConditonTTL(conn, indexName, ttl); + assertConditionTTL(conn, indexName, ttl); + } + } + + @Test + public void testUncoveredIndexRelaxedTTL() throws Exception { + String ddlTemplate = "create table %s (id varchar not null primary key, " + + "col1 integer, col2 integer, col3 double, col4 varchar) TTL = '%s', IS_STRICT_TTL=false"; + String tableName = generateUniqueName(); + String indexTemplate = "create uncovered index %s on %s (col1) "; + String indexName = generateUniqueName(); + String ttl = "col2 > 100 AND col4='expired'"; + try (Connection conn = DriverManager.getConnection(getUrl())) { + String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); + conn.createStatement().execute(ddl); + assertConditionTTL(conn, tableName, ttl); + ddl = String.format(indexTemplate, indexName, tableName); + conn.createStatement().execute(ddl); + assertTTL(conn, indexName, TTL_EXPRESSION_NOT_DEFINED); } } @@ -602,6 +620,30 @@ public void testSettingCondTTLOnTableWithIndexWithMissingExprCols() throws Excep } catch (SQLException e) { assertTrue(e.getCause() instanceof ColumnNotFoundException); } + // relaxed ttl + ddl = String.format("alter table %s set TTL = '%s', IS_STRICT_TTL = false", tableName, + retainSingleQuotes(ttl)); + conn.createStatement().execute(ddl); + assertTTL(conn, indexName, TTL_EXPRESSION_NOT_DEFINED); + } + } + + @Test + public void testSettingCondTTLOnTableWithRelaxedTTLAndUncoveredIndex() throws Exception { + String ddlTemplate = "create table %s (id varchar not null primary key, " + + "col1 integer, col2 integer, col3 double, col4 varchar) IS_STRICT_TTL = false"; + String tableName = generateUniqueName(); + String indexTemplate = "create uncovered index %s on %s (col1)"; + String indexName = generateUniqueName(); + String ttl = "col2 > 100 AND col4='expired'"; + try (Connection conn = DriverManager.getConnection(getUrl())) { + String ddl = String.format(ddlTemplate, tableName); + conn.createStatement().execute(ddl); + ddl = String.format(indexTemplate, indexName, tableName); + conn.createStatement().execute(ddl); + ddl = String.format("alter table %s set TTL = '%s'", tableName, retainSingleQuotes(ttl)); + conn.createStatement().execute(ddl); + assertTTL(conn, indexName, TTL_EXPRESSION_NOT_DEFINED); } } @@ -615,7 +657,7 @@ public void testScanColumns() throws Exception { String ddl = String.format(ddlTemplate, tableName, retainSingleQuotes(ttl)); try (Connection conn = DriverManager.getConnection(getUrl())) { conn.createStatement().execute(ddl); - assertConditonTTL(conn, tableName, ttl); + assertConditionTTL(conn, tableName, ttl); String query = String.format("select * from %s where k1 > 3", tableName); // select * so all columns should be read validateScan(conn, tableName, query, ttl, false, Collections.EMPTY_LIST);