Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.phoenix.schema;

import static org.apache.phoenix.schema.PTable.ImmutableStorageScheme.ONE_CELL_PER_COLUMN;
import static org.apache.phoenix.schema.PTable.IndexType.UNCOVERED_GLOBAL;
import static org.apache.phoenix.schema.PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS;
import static org.apache.phoenix.schema.PTableType.CDC;
import static org.apache.phoenix.schema.PTableType.VIEW;
Expand Down Expand Up @@ -181,17 +182,22 @@ public void validateTTLOnCreate(PhoenixConnection conn, CreateTableStatement cre
/**
* @param table TABLE | VIEW referenced in ALTER statement
*/
public void validateTTLOnAlter(PhoenixConnection conn, PTable table) throws SQLException {
public void validateTTLOnAlter(PhoenixConnection conn, PTable table, boolean isStrictTTL)
throws SQLException {
// first validate the expression on the entity being changed
validateTTLExpression(conn, table, null);

for (PTable index : table.getIndexes()) {
try {
if (CDCUtil.isCDCIndex(index)) {
if (
CDCUtil.isCDCIndex(index)
|| (!isStrictTTL && UNCOVERED_GLOBAL.equals(index.getIndexType()))
) {
// CDC index doesn't inherit ConditionTTL expression
// skip validation if index is uncovered and TTL is not strict
continue;
}
// verify that the new expression is covered by all the existing indexes
// verify that the new expression is covered by all the existing covered indexes
buildExpression(conn, index, table);
} catch (ColumnNotFoundException | ColumnFamilyNotFoundException e) {
throw new SQLException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public void validateTTLOnCreate(PhoenixConnection conn, CreateTableStatement cre
}

@Override
public void validateTTLOnAlter(PhoenixConnection connection, PTable table) {
public void validateTTLOnAlter(PhoenixConnection connection, PTable table, boolean isStrictTTL) {
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
import static org.apache.phoenix.schema.PTable.EncodedCQCounter.NULL_COUNTER;
import static org.apache.phoenix.schema.PTable.ImmutableStorageScheme.ONE_CELL_PER_COLUMN;
import static org.apache.phoenix.schema.PTable.ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS;
import static org.apache.phoenix.schema.PTable.IndexType.UNCOVERED_GLOBAL;
import static org.apache.phoenix.schema.PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS;
import static org.apache.phoenix.schema.PTable.ViewType.MAPPED;
import static org.apache.phoenix.schema.PTableType.CDC;
Expand Down Expand Up @@ -2529,7 +2530,14 @@ private PTable createTableInternal(CreateTableStatement statement, byte[][] spli
} else {
ttlFromHierarchy = checkAndGetTTLFromHierarchy(parent, tableName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@palashc I think it would be better if we can enhance the API checkAndGetTTLFromHierarchy itself to return TTL_EXPRESSION_NOT_DEFINED in this case.

if (!ttlFromHierarchy.equals(TTL_EXPRESSION_NOT_DEFINED)) {
ttlFromHierarchy.validateTTLOnCreate(connection, statement, parent, tableProps);
if (
UNCOVERED_GLOBAL.equals(indexType) && parent.hasConditionalTTL()
&& !parent.isStrictTTL()
) {
ttlFromHierarchy = TTL_EXPRESSION_NOT_DEFINED;
} else {
ttlFromHierarchy.validateTTLOnCreate(connection, statement, parent, tableProps);
}
}
}

Expand Down Expand Up @@ -6413,7 +6421,9 @@ 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();
newTTL.validateTTLOnAlter(connection, table, isStrictTTL);
metaPropertiesEvaluated.setTTL(getCompatibleTTLExpression(metaProperties.getTTL(),
table.getType(), table.getViewType(), table.getName().toString()));
changingPhoenixTableProperty = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ void validateTTLOnCreate(PhoenixConnection conn, CreateTableStatement create, PT

/**
* Validate the TTL expression on ALTER [TABLE | VIEW]
* @param connection Phoenix connection
* @param table PTable of the entity being changed
* @param connection Phoenix connection
* @param table PTable of the entity being changed
* @param isStrictTTL True if the TTL being set is strict
*/
void validateTTLOnAlter(PhoenixConnection connection, PTable table) throws SQLException;
void validateTTLOnAlter(PhoenixConnection connection, PTable table, boolean isStrictTTL)
throws SQLException;

/**
* Compile the TTL expression so that it can be evaluated against of a row of cells
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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"));
}
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"));
}
Expand All @@ -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);
Expand All @@ -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);
}
}

Expand All @@ -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"));
}
Expand All @@ -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);
}
}

Expand All @@ -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"));
}
Expand All @@ -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);
}
}

Expand All @@ -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"));
}
Expand All @@ -524,18 +524,18 @@ 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"));
}
}

@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();
Expand All @@ -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);
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -602,6 +620,34 @@ 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));
try {
conn.createStatement().execute(ddl);
fail("Should have thrown ColumnNotFoundException");
} catch (SQLException e) {
assertTrue(e.getCause() instanceof ColumnNotFoundException);
}
}
}

@Test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a test case where the table has uncovered index and a literal TTL. Now you alter the ttl to conditional with IS_STRICT_TTL set to false. Then verify that the table has conditional ttl and the uncovered index has ttl undefined. I am suspecting that while you skipped checking for uncovered indexes during the ttl validation on alter, I am not seeing that you are actually updating the ttl on uncovered index to undefined.

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);
}
}

Expand All @@ -615,7 +661,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);
Expand Down