diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java index 0d5bf6c309b..1147195970b 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java @@ -301,6 +301,22 @@ public void testSetSaltedTableAsImmutable() throws Exception { } } + @Test + public void testSetPropertySchemaVersion() throws Exception { + Properties props = new Properties(); + final String schemaName = generateUniqueName(); + final String tableName = generateUniqueName(); + final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + CreateTableIT.testCreateTableSchemaVersionHelper(conn, schemaName, tableName, "V1.0"); + String version = "V1.1"; + String alterSql = "ALTER TABLE " + dataTableFullName + " SET SCHEMA_VERSION='" + version + "'"; + conn.createStatement().execute(alterSql); + PTable table = PhoenixRuntime.getTableNoCache(conn, dataTableFullName); + assertEquals(version, table.getSchemaVersion()); + } + } + @Test public void testDropColumnFromSaltedTable() throws Exception { 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 94aa75e2588..d79e96a42c9 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 @@ -1465,6 +1465,30 @@ public void testLastDDLTimestampWithChildViews() throws Exception { } - + @Test + public void testCreateViewSchemaVersion() throws Exception { + Properties props = new Properties(); + final String schemaName = generateUniqueName(); + final String tableName = generateUniqueName(); + final String viewName = generateUniqueName(); + final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName); + final String viewFullName = SchemaUtil.getTableName(schemaName, viewName); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + String oldVersion = "V1.0"; + CreateTableIT.testCreateTableSchemaVersionHelper(conn, schemaName, tableName, oldVersion); + String createViewSql = "CREATE VIEW " + viewFullName + " AS SELECT * FROM " + dataTableFullName + + " SCHEMA_VERSION='" + oldVersion + "'"; + conn.createStatement().execute(createViewSql); + PTable view = PhoenixRuntime.getTableNoCache(conn, viewFullName); + assertEquals(oldVersion, view.getSchemaVersion()); + String newVersion = "V1.1"; + String alterViewSql = "ALTER VIEW " + viewFullName + " SET SCHEMA_VERSION='" + newVersion + "'"; + conn.createStatement().execute(alterViewSql); + PTable view2 = PhoenixRuntime.getTableNoCache(conn, viewFullName); + assertEquals(newVersion, view2.getSchemaVersion()); + PTable baseTable = PhoenixRuntime.getTableNoCache(conn, dataTableFullName); + assertEquals(oldVersion, baseTable.getSchemaVersion()); + } + } } diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CreateTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CreateTableIT.java index 57714a21cd7..81f5c9c2bde 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CreateTableIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CreateTableIT.java @@ -1167,6 +1167,31 @@ public void testTableDescriptorPriority() throws SQLException, IOException { } } + @Test + public void testCreateTableSchemaVersion() throws Exception { + Properties props = new Properties(); + final String schemaName = generateUniqueName(); + final String tableName = generateUniqueName(); + final String version = "V1.0"; + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + testCreateTableSchemaVersionHelper(conn, schemaName, tableName, version); + } + } + + public static void testCreateTableSchemaVersionHelper(Connection conn, String schemaName, String tableName, + String dataTableVersion) + throws Exception { + final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName); + String ddl = + "CREATE TABLE " + dataTableFullName + " (\n" + "ID1 VARCHAR(15) NOT NULL,\n" + + "ID2 VARCHAR(15) NOT NULL,\n" + "CREATED_DATE DATE,\n" + + "CREATION_TIME BIGINT,\n" + "LAST_USED DATE,\n" + + "CONSTRAINT PK PRIMARY KEY (ID1, ID2)) SCHEMA_VERSION='" + dataTableVersion + "'"; + conn.createStatement().execute(ddl); + PTable table = PhoenixRuntime.getTableNoCache(conn, dataTableFullName); + assertEquals(dataTableVersion, table.getSchemaVersion()); + } + @Test public void testCreateTableDDLTimestamp() throws Exception { Properties props = new Properties(); diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java index 370629d0d36..be689ffb7d4 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java @@ -324,6 +324,25 @@ public void testViewUsesTableLocalIndex() throws Exception { } } + @Test + public void testCreateViewSchemaVersion() throws Exception { + Properties props = new Properties(); + final String schemaName = generateUniqueName(); + final String tableName = generateUniqueName(); + final String viewName = generateUniqueName(); + final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName); + final String viewFullName = SchemaUtil.getTableName(schemaName, viewName); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + String version = "V1.0"; + CreateTableIT.testCreateTableSchemaVersionHelper(conn, schemaName, tableName, version); + String createViewSql = "CREATE VIEW " + viewFullName + " AS SELECT * FROM " + dataTableFullName + + " SCHEMA_VERSION='" + version + "'"; + conn.createStatement().execute(createViewSql); + PTable view = PhoenixRuntime.getTableNoCache(conn, viewFullName); + assertEquals(version, view.getSchemaVersion()); + } + } + @Test public void testCreateViewTimestamp() throws Exception { String tenantId = null; diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java index a15456c90e8..e805bd91c52 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/MutableIndexIT.java @@ -34,10 +34,15 @@ import java.util.Properties; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.HBaseAdmin; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Threads; +import org.apache.phoenix.end2end.CreateTableIT; import org.apache.phoenix.end2end.ParallelStatsDisabledIT; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTableKey; import org.apache.phoenix.util.IndexScrutiny; import org.apache.phoenix.util.PhoenixRuntime; @@ -736,8 +741,8 @@ private void testUpsertingDeletedRowShouldGiveProperDataWithIndexes(boolean mult assertEquals(1, rs.getInt(2)); assertEquals(0.5F, rs.getFloat(1), 0.0); assertEquals("foo", rs.getString(3)); - } - } + } + } @Test public void testUpsertingDeletedRowWithNullCoveredColumn() throws Exception { @@ -916,6 +921,25 @@ public void testDeleteCount_index() throws Exception { } } + @Test + public void testCreateIndexSchemaVersion() throws Exception { + Properties props = new Properties(); + final String schemaName = generateUniqueName(); + final String tableName = generateUniqueName(); + final String indexName = generateUniqueName(); + final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName); + final String indexFullName = SchemaUtil.getTableName(schemaName, indexName); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + String version = "V1.0"; + CreateTableIT.testCreateTableSchemaVersionHelper(conn, schemaName, tableName, version); + String createIndexSql = "CREATE INDEX " + indexName + " ON " + dataTableFullName + + " (ID2) INCLUDE (ID1) SCHEMA_VERSION='" + version + "'"; + conn.createStatement().execute(createIndexSql); + PTable index = PhoenixRuntime.getTableNoCache(conn, indexFullName); + assertEquals(version, index.getSchemaVersion()); + } + } + private void upsertRow(String dml, Connection tenantConn, int i) throws SQLException { PreparedStatement stmt = tenantConn.prepareStatement(dml); stmt.setString(1, "00000000000000" + String.valueOf(i)); diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java index 85ea5ebcee7..f1259e05b07 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/ViewIndexIT.java @@ -54,6 +54,7 @@ import org.apache.hadoop.hbase.client.TableDescriptor; import org.apache.hadoop.hbase.util.Bytes; import org.apache.phoenix.compile.QueryPlan; +import org.apache.phoenix.end2end.CreateTableIT; import org.apache.phoenix.end2end.IndexToolIT; import org.apache.phoenix.end2end.SplitSystemCatalogIT; import org.apache.phoenix.hbase.index.IndexRegionObserver; @@ -805,6 +806,30 @@ public void testIndexIdDataTypeDefaultValue() throws Exception { } } + @Test + public void testCreateViewSchemaVersion() throws Exception { + Properties props = new Properties(); + final String schemaName = generateUniqueName(); + final String tableName = generateUniqueName(); + final String viewName = generateUniqueName(); + final String viewIndexName = generateUniqueName(); + final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName); + final String viewFullName = SchemaUtil.getTableName(schemaName, viewName); + final String viewIndexFullName = SchemaUtil.getTableName(schemaName, viewIndexName); + try (Connection conn = DriverManager.getConnection(getUrl(), props)) { + String version = "V1.0"; + CreateTableIT.testCreateTableSchemaVersionHelper(conn, schemaName, tableName, version); + String createViewSql = "CREATE VIEW " + viewFullName + " AS SELECT * FROM " + dataTableFullName + + " SCHEMA_VERSION='" + version + "'"; + conn.createStatement().execute(createViewSql); + String createViewIndexSql = "CREATE INDEX " + viewIndexName + " ON " + + viewFullName + " (ID2) INCLUDE (ID1) SCHEMA_VERSION='" + version + "'"; + conn.createStatement().execute(createViewIndexSql); + PTable viewIndex = PhoenixRuntime.getTableNoCache(conn, viewIndexFullName); + assertEquals(version, viewIndex.getSchemaVersion()); + } + } + public void createBaseTable(Connection conn, String schemaName, String tableName, boolean multiTenant, Integer saltBuckets, String splits, boolean immutable) 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 f690c4b3433..b4319ad9248 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 @@ -49,16 +49,20 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LAST_DDL_TIMESTAMP_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MAX_VALUE_BYTES; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_VALUE_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_PHOENIX_TTL_HWM; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_VALUE_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NULLABLE_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NUM_ARGS_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ORDINAL_POSITION_BYTES; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_BYTES; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_HWM_BYTES; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_NOT_DEFINED; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHYSICAL_TABLE_NAME_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.RETURN_TYPE_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCHEMA_VERSION_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SORT_ORDER_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORAGE_SCHEME_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORE_NULLS_BYTES; @@ -75,9 +79,6 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_DATA_TYPE_BYTES; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_STATEMENT_BYTES; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_BYTES; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_HWM_BYTES; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_NOT_DEFINED; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_TYPE_BYTES; import static org.apache.phoenix.query.QueryConstants.VIEW_MODIFIED_PROPERTY_TAG_TYPE; import static org.apache.phoenix.schema.PTableType.INDEX; @@ -348,6 +349,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements RegionCopr private static final Cell CHANGE_DETECTION_ENABLED_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, CHANGE_DETECTION_ENABLED_BYTES); + private static final Cell SCHEMA_VERSION_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, + TABLE_FAMILY_BYTES, SCHEMA_VERSION_BYTES); private static final List TABLE_KV_COLUMNS = Lists.newArrayList( EMPTY_KEYVALUE_KV, @@ -384,7 +387,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements RegionCopr PHOENIX_TTL_KV, PHOENIX_TTL_HWM_KV, LAST_DDL_TIMESTAMP_KV, - CHANGE_DETECTION_ENABLED_KV + CHANGE_DETECTION_ENABLED_KV, + SCHEMA_VERSION_KV ); static { @@ -427,6 +431,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements RegionCopr TABLE_KV_COLUMNS.indexOf(LAST_DDL_TIMESTAMP_KV); private static final int CHANGE_DETECTION_ENABLED_INDEX = TABLE_KV_COLUMNS.indexOf(CHANGE_DETECTION_ENABLED_KV); + private static final int SCHEMA_VERSION_INDEX = TABLE_KV_COLUMNS.indexOf(SCHEMA_VERSION_KV); // KeyValues for Column private static final KeyValue DECIMAL_DIGITS_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, DECIMAL_DIGITS_BYTES); private static final KeyValue COLUMN_SIZE_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, COLUMN_SIZE_BYTES); @@ -1227,6 +1232,11 @@ private PTable getTable(RegionScanner scanner, long clientTimeStamp, long tableT changeDetectionEnabledKv.getValueOffset(), changeDetectionEnabledKv.getValueLength())); + Cell schemaVersionKv = tableKeyValues[SCHEMA_VERSION_INDEX]; + String schemaVersion = schemaVersionKv != null ? (String) PVarchar.INSTANCE.toObject( + schemaVersionKv.getValueArray(), schemaVersionKv.getValueOffset(), schemaVersionKv.getValueLength()) + : null; + // Check the cell tag to see whether the view has modified this property final byte[] tagUseStatsForParallelization = (useStatsForParallelizationKv == null) ? HConstants.EMPTY_BYTE_ARRAY : @@ -1359,6 +1369,7 @@ private PTable getTable(RegionScanner scanner, long clientTimeStamp, long tableT .setViewModifiedPhoenixTTL(viewModifiedPhoenixTTL) .setLastDDLTimestamp(lastDDLTimestamp) .setIsChangeDetectionEnabled(isChangeDetectionEnabled) + .setSchemaVersion(schemaVersion) .setColumns(columns) .build(); } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java index 1add8ae76ec..accd757c9e0 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java @@ -100,7 +100,7 @@ public abstract class MetaDataProtocol extends MetaDataService { public static final long MIN_SYSTEM_TABLE_TIMESTAMP_4_15_0 = MIN_TABLE_TIMESTAMP + 29; public static final long MIN_SYSTEM_TABLE_TIMESTAMP_4_16_0 = MIN_TABLE_TIMESTAMP + 33; public static final long MIN_SYSTEM_TABLE_TIMESTAMP_5_1_0 = MIN_SYSTEM_TABLE_TIMESTAMP_4_16_0; - public static final long MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0 = MIN_TABLE_TIMESTAMP + 34; + public static final long MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0 = MIN_TABLE_TIMESTAMP + 35; public static final long MIN_SYSTEM_TABLE_TIMESTAMP_5_2_0 = MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0; // MIN_SYSTEM_TABLE_TIMESTAMP needs to be set to the max of all the MIN_SYSTEM_TABLE_TIMESTAMP_* constants public static final long MIN_SYSTEM_TABLE_TIMESTAMP = MIN_SYSTEM_TABLE_TIMESTAMP_5_2_0; diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java index 5f9407653c1..9f529472da8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java @@ -393,6 +393,9 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData { public static final byte[] CHANGE_DETECTION_ENABLED_BYTES = Bytes.toBytes(CHANGE_DETECTION_ENABLED); + public static final String SCHEMA_VERSION = "SCHEMA_VERSION"; + public static final byte[] SCHEMA_VERSION_BYTES = Bytes.toBytes(SCHEMA_VERSION); + public static final String SYSTEM_CHILD_LINK_TABLE = "CHILD_LINK"; public static final String SYSTEM_CHILD_LINK_NAME = SchemaUtil.getTableName(SYSTEM_CATALOG_SCHEMA, SYSTEM_CHILD_LINK_TABLE); public static final byte[] SYSTEM_CHILD_LINK_NAME_BYTES = Bytes.toBytes(SYSTEM_CHILD_LINK_NAME); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java index 4146c407f79..c9d1eee55b4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java @@ -2321,7 +2321,7 @@ public MetaDataMutationResult addColumn(final List tableMetaData, // In this, case we only include the table header row, as until we add schemaBytes and tableBytes // as args to this function, we have no way of getting them in this case. // TODO: change to if (tableMetaData.isEmpty()) once we pass through schemaBytes and tableBytes - // Also, could be used to update property values on ALTER TABLE t SET prop=xxx + // Also, could be used to update table descriptor property values on ALTER TABLE t SET prop=xxx if ((tableMetaData.isEmpty()) || (tableMetaData.size() == 1 && tableMetaData.get(0).isEmpty())) { if (modifyHTable) { sendHBaseMetaData(tableDescriptors, pollingNeeded); @@ -3859,9 +3859,13 @@ protected PhoenixConnection upgradeSystemCatalogIfRequired(PhoenixConnection met } if (currentServerSideTableTimeStamp < MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0) { metaConnection = addColumnsIfNotExists(metaConnection, - PhoenixDatabaseMetaData.SYSTEM_CATALOG, MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0, + PhoenixDatabaseMetaData.SYSTEM_CATALOG, MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0 -1, PhoenixDatabaseMetaData.PHYSICAL_TABLE_NAME + " " + PVarchar.INSTANCE.getSqlTypeName()); + + metaConnection = addColumnsIfNotExists(metaConnection, PhoenixDatabaseMetaData.SYSTEM_CATALOG, + MIN_SYSTEM_TABLE_TIMESTAMP_4_17_0, + PhoenixDatabaseMetaData.SCHEMA_VERSION + " " + PVarchar.INSTANCE.getSqlTypeName()); } return metaConnection; } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java index 4206c2674bb..88edd5005a6 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java @@ -113,6 +113,7 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.RETURN_TYPE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCAN_METRICS_JSON; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCHEMA_VERSION; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCOPE_CATALOG; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCOPE_SCHEMA; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCOPE_TABLE; @@ -312,8 +313,9 @@ enum JoinType {INNER, LEFT_OUTER} VIEW_INDEX_ID_DATA_TYPE + " INTEGER,\n" + PHOENIX_TTL + " BIGINT,\n" + PHOENIX_TTL_HWM + " BIGINT,\n" + - LAST_DDL_TIMESTAMP + " BIGINT, " + - CHANGE_DETECTION_ENABLED + " BOOLEAN, " + + LAST_DDL_TIMESTAMP + " BIGINT, \n" + + CHANGE_DETECTION_ENABLED + " BOOLEAN, \n" + + SCHEMA_VERSION + " VARCHAR, \n" + // Column metadata (will be null for table row) DATA_TYPE + " INTEGER," + COLUMN_SIZE + " INTEGER," + diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java index ff869690473..9f2f980a555 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java @@ -370,6 +370,11 @@ public boolean isChangeDetectionEnabled() { return delegate.isChangeDetectionEnabled(); } + @Override + public String getSchemaVersion() { + return delegate.getSchemaVersion(); + } + @Override public Map getPropertyValues() { return delegate.getPropertyValues(); } @Override public Map getDefaultPropertyValues() { return delegate.getDefaultPropertyValues(); } 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 2373818fb2b..a802b5e976a 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 @@ -66,17 +66,22 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LAST_STATS_UPDATE_TIME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MAX_VALUE; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_PHOENIX_TTL_HWM; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_VALUE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NULLABLE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NUM_ARGS; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ORDINAL_POSITION; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PARENT_TENANT_ID; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_HWM; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_NOT_DEFINED; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHYSICAL_NAME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHYSICAL_TABLE_NAME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.RETURN_TYPE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCHEMA_VERSION; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SORT_ORDER; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORE_NULLS; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYNC_INDEX_CREATED_DATE; @@ -94,13 +99,9 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.USE_STATS_FOR_PARALLELIZATION; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_CONSTANT; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_DATA_TYPE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_STATEMENT; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_TYPE; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID_DATA_TYPE; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_HWM; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHOENIX_TTL_NOT_DEFINED; -import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MIN_PHOENIX_TTL_HWM; import static org.apache.phoenix.query.QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT; import static org.apache.phoenix.query.QueryConstants.DEFAULT_COLUMN_FAMILY; import static org.apache.phoenix.query.QueryConstants.ENCODED_CQ_COUNTER_INITIAL_VALUE; @@ -328,9 +329,10 @@ public class MetaDataClient { PHOENIX_TTL +"," + PHOENIX_TTL_HWM + "," + CHANGE_DETECTION_ENABLED + "," + - PHYSICAL_TABLE_NAME + + PHYSICAL_TABLE_NAME + "," + + SCHEMA_VERSION + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + - "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String CREATE_SCHEMA = "UPSERT INTO " + SYSTEM_CATALOG_SCHEMA + ".\"" + SYSTEM_CATALOG_TABLE + "\"( " + TABLE_SCHEM + "," + TABLE_NAME + ") VALUES (?,?)"; @@ -2116,6 +2118,8 @@ private PTable createTableInternal(CreateTableStatement statement, byte[][] spli (Boolean) TableProperty.CHANGE_DETECTION_ENABLED.getValue(tableProps); verifyChangeDetectionTableType(tableType, isChangeDetectionEnabledProp); + String schemaVersion = (String) TableProperty.SCHEMA_VERSION.getValue(tableProps); + if (parent != null && tableType == PTableType.INDEX) { timestamp = TransactionUtil.getTableTimestamp(connection, transactionProvider != null, transactionProvider); isImmutableRows = parent.isImmutableRows(); @@ -3055,6 +3059,12 @@ public boolean isViewReferenced() { tableUpsert.setString(33, physicalTableName); } + if (schemaVersion == null) { + tableUpsert.setNull(34, Types.VARCHAR); + } else { + tableUpsert.setString(34, schemaVersion); + } + tableUpsert.execute(); if (asyncCreatedDate != null) { @@ -3201,6 +3211,7 @@ public boolean isViewReferenced() { .setLastDDLTimestamp(result.getTable() != null ? result.getTable().getLastDDLTimestamp() : null) .setIsChangeDetectionEnabled(isChangeDetectionEnabledProp) + .setSchemaVersion(schemaVersion) .build(); result = new MetaDataMutationResult(code, result.getMutationTime(), table, true); addTableToCache(result); @@ -3640,12 +3651,16 @@ private long incrementTableSeqNum(PTable table, PTableType expectedType, int col metaPropertiesEvaluated.getUseStatsForParallelization(), metaPropertiesEvaluated.getPhoenixTTL(), metaPropertiesEvaluated.isChangeDetectionEnabled(), - metaPropertiesEvaluated.getPhysicalTableName()); + metaPropertiesEvaluated.getPhysicalTableName(), + metaPropertiesEvaluated.getSchemaVersion()); } - private long incrementTableSeqNum(PTable table, PTableType expectedType, int columnCountDelta, Boolean isTransactional, Long updateCacheFrequency, Long phoenixTTL, String physicalTableName) throws SQLException { + private long incrementTableSeqNum(PTable table, PTableType expectedType, int columnCountDelta, + Boolean isTransactional, Long updateCacheFrequency, Long phoenixTTL, + String physicalTableName, String schemaVersion) throws SQLException { return incrementTableSeqNum(table, expectedType, columnCountDelta, isTransactional, null, - updateCacheFrequency, null, null, null, null, -1L, null, null, null,phoenixTTL, false, physicalTableName); + updateCacheFrequency, null, null, null, null, -1L, + null, null, null,phoenixTTL, false, physicalTableName, schemaVersion); } private long incrementTableSeqNum(PTable table, PTableType expectedType, int columnCountDelta, @@ -3653,7 +3668,7 @@ private long incrementTableSeqNum(PTable table, PTableType expectedType, int col Long updateCacheFrequency, Boolean isImmutableRows, Boolean disableWAL, Boolean isMultiTenant, Boolean storeNulls, Long guidePostWidth, Boolean appendOnlySchema, ImmutableStorageScheme immutableStorageScheme, Boolean useStatsForParallelization, - Long phoenixTTL, Boolean isChangeDetectionEnabled, String physicalTableName) + Long phoenixTTL, Boolean isChangeDetectionEnabled, String physicalTableName, String schemaVersion) throws SQLException { String schemaName = table.getSchemaName().getString(); String tableName = table.getTableName().getString(); @@ -3715,6 +3730,9 @@ private long incrementTableSeqNum(PTable table, PTableType expectedType, int col if (!Strings.isNullOrEmpty(physicalTableName)) { mutateStringProperty(tenantId, schemaName, tableName, PHYSICAL_TABLE_NAME, physicalTableName); } + if (!Strings.isNullOrEmpty(schemaVersion)) { + mutateStringProperty(tenantId, schemaName, tableName, SCHEMA_VERSION, schemaVersion); + } return seqNum; } @@ -4064,7 +4082,8 @@ public MutationState addColumn(PTable table, List origColumnDefs, metaProperties.getNonTxToTx() ? Boolean.TRUE : null, metaPropertiesEvaluated.getUpdateCacheFrequency(), metaPropertiesEvaluated.getPhoenixTTL(), - metaProperties.getPhysicalTableName()); + metaPropertiesEvaluated.getPhysicalTableName(), + metaPropertiesEvaluated.getSchemaVersion()); } tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond()); connection.rollback(); @@ -4076,7 +4095,8 @@ public MutationState addColumn(PTable table, List origColumnDefs, Boolean.FALSE, metaPropertiesEvaluated.getUpdateCacheFrequency(), metaPropertiesEvaluated.getPhoenixTTL(), - metaPropertiesEvaluated.getPhysicalTableName()); + metaPropertiesEvaluated.getPhysicalTableName(), + metaPropertiesEvaluated.getSchemaVersion()); } tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond()); connection.rollback(); @@ -4535,7 +4555,8 @@ else if (columnToDrop.isViewReferenced()) { } } if (!indexColumnsToDrop.isEmpty()) { - long indexTableSeqNum = incrementTableSeqNum(index, index.getType(), -indexColumnsToDrop.size(), null, null, null, null); + long indexTableSeqNum = incrementTableSeqNum(index, index.getType(), -indexColumnsToDrop.size(), + null, null, null, null, null); dropColumnMutations(index, indexColumnsToDrop); long clientTimestamp = MutationState.getTableTimestamp(timeStamp, connection.getSCN()); connection.removeColumn(tenantId, index.getName().getString(), @@ -4546,7 +4567,8 @@ else if (columnToDrop.isViewReferenced()) { tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond()); connection.rollback(); - long seqNum = incrementTableSeqNum(table, statement.getTableType(), -tableColumnsToDrop.size(), null, null, null, null); + long seqNum = incrementTableSeqNum(table, statement.getTableType(), -tableColumnsToDrop.size(), + null, null, null, null, null); tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond()); connection.rollback(); // Force table header to be first in list @@ -5112,6 +5134,8 @@ private MetaProperties loadStmtProperties(ListMultimap propertyValues; + private String schemaVersion; public static class Builder { private PTableKey key; @@ -264,6 +265,7 @@ public static class Builder { private Long lastDDLTimestamp; private boolean isChangeDetectionEnabled = false; private Map propertyValues = new HashMap<>(); + private String schemaVersion; // Used to denote which properties a view has explicitly modified private BitSet viewModifiedPropSet = new BitSet(3); @@ -625,6 +627,13 @@ public Builder setIsChangeDetectionEnabled(Boolean isChangeDetectionEnabled) { return this; } + public Builder setSchemaVersion(String schemaVersion) { + if (schemaVersion != null) { + this.schemaVersion = schemaVersion; + } + return this; + } + /** * Populate derivable attributes of the PTable * @return PTableImpl.Builder object @@ -892,6 +901,7 @@ private PTableImpl(Builder builder) { this.propertyValues = builder.propertyValues; this.lastDDLTimestamp = builder.lastDDLTimestamp; this.isChangeDetectionEnabled = builder.isChangeDetectionEnabled; + this.schemaVersion = builder.schemaVersion; } // When cloning table, ignore the salt column as it will be added back in the constructor @@ -967,7 +977,8 @@ private static PTableImpl.Builder builderFromExisting(PTable table) { .setPhoenixTTL(table.getPhoenixTTL()) .setPhoenixTTLHighWaterMark(table.getPhoenixTTLHighWaterMark()) .setLastDDLTimestamp(table.getLastDDLTimestamp()) - .setIsChangeDetectionEnabled(table.isChangeDetectionEnabled()); + .setIsChangeDetectionEnabled(table.isChangeDetectionEnabled()) + .setSchemaVersion(table.getSchemaVersion()); } @Override @@ -1858,6 +1869,10 @@ public static PTable createFromProto(PTableProtos.PTable table) { if (table.hasChangeDetectionEnabled()) { isChangeDetectionEnabled = table.getChangeDetectionEnabled(); } + String schemaVersion = null; + if (table.hasSchemaVersion()) { + schemaVersion = (String) PVarchar.INSTANCE.toObject(table.getSchemaVersion().toByteArray()); + } try { return new PTableImpl.Builder() .setType(tableType) @@ -1911,6 +1926,7 @@ public static PTable createFromProto(PTableProtos.PTable table) { .setViewModifiedPhoenixTTL(viewModifiedPhoenixTTL) .setLastDDLTimestamp(lastDDLTimestamp) .setIsChangeDetectionEnabled(isChangeDetectionEnabled) + .setSchemaVersion(schemaVersion) .build(); } catch (SQLException e) { throw new RuntimeException(e); // Impossible @@ -2037,6 +2053,7 @@ public static PTableProtos.PTable toProto(PTable table) { builder.setLastDDLTimestamp(table.getLastDDLTimestamp()); } builder.setChangeDetectionEnabled(table.isChangeDetectionEnabled()); + builder.setSchemaVersion(ByteStringer.wrap(PVarchar.INSTANCE.toBytes(table.getSchemaVersion()))); return builder.build(); } @@ -2164,6 +2181,11 @@ public boolean isChangeDetectionEnabled() { return isChangeDetectionEnabled; } + @Override + public String getSchemaVersion() { + return schemaVersion; + } + private static final class KVColumnFamilyQualifier { @Nonnull private final String colFamilyName; diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java index 4116bddcff5..169fbeefe1a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java @@ -300,6 +300,17 @@ public Object getPTableValue(PTable table) { @Override public Object getPTableValue(PTable table) { return table.getPhysicalName(true); } + }, + + SCHEMA_VERSION(PhoenixDatabaseMetaData.SCHEMA_VERSION, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, true, true) { + @Override + public Object getValue(Object value) { + return value == null ? null : SchemaUtil.normalizeIdentifier(value.toString()); + } + + @Override public Object getPTableValue(PTable table) { + return table.getSchemaVersion(); + } } ; diff --git a/phoenix-core/src/main/protobuf/PTable.proto b/phoenix-core/src/main/protobuf/PTable.proto index 07fe81f79f2..1a708684d99 100644 --- a/phoenix-core/src/main/protobuf/PTable.proto +++ b/phoenix-core/src/main/protobuf/PTable.proto @@ -113,6 +113,7 @@ message PTable { optional bool changeDetectionEnabled = 46; optional bytes physicalTableNameBytes = 47; optional bytes baseTableLogicalNameBytes = 48; + optional bytes schemaVersion = 49; } message EncodedCQCounter {