This is an automated email from the ASF dual-hosted git repository.
palashc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/master by this push:
new 18d3841d30 PHOENIX-7509 : Metadata Cache should handle tables which
have LAST_DDL_TIMESTAMP column null in syscat (#2059)
18d3841d30 is described below
commit 18d3841d305c722bb924e41ddd6b28aac79a1f8c
Author: Palash Chauhan <[email protected]>
AuthorDate: Mon Jan 27 18:33:34 2025 -0800
PHOENIX-7509 : Metadata Cache should handle tables which have
LAST_DDL_TIMESTAMP column null in syscat (#2059)
Co-authored-by: Palash Chauhan
<[email protected]>
---
.../phoenix/query/ConnectionQueryServicesImpl.java | 1 +
.../phoenix/util/ValidateLastDDLTimestampUtil.java | 17 +++++++++-
.../phoenix/coprocessor/MetaDataEndpointImpl.java | 2 +-
.../phoenix/cache/ServerMetadataCacheIT.java | 36 ++++++++++++++++++++++
4 files changed, 54 insertions(+), 2 deletions(-)
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index bb6a648c7d..dba599f25c 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -4444,6 +4444,7 @@ public class ConnectionQueryServicesImpl extends
DelegateQueryServices implement
//move TTL values stored in descriptor to SYSCAT TTL column.
moveTTLFromHBaseLevelTTLToPhoenixLevelTTL(metaConnection);
+
UpgradeUtil.bootstrapLastDDLTimestampForTablesAndViews(metaConnection);
UpgradeUtil.bootstrapLastDDLTimestampForIndexes(metaConnection);
}
return metaConnection;
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/util/ValidateLastDDLTimestampUtil.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/util/ValidateLastDDLTimestampUtil.java
index 95b1d1537a..faab529c03 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/util/ValidateLastDDLTimestampUtil.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/util/ValidateLastDDLTimestampUtil.java
@@ -124,6 +124,9 @@ public class ValidateLastDDLTimestampUtil {
= getValidateDDLTimestampRequest(tableRefs);
service.validateLastDDLTimestamp(null, request);
} catch (Exception e) {
+ if (e instanceof StaleMetadataCacheException) {
+ throw (StaleMetadataCacheException) e;
+ }
SQLException parsedException = ClientUtil.parseServerException(e);
if (parsedException instanceof StaleMetadataCacheException) {
throw parsedException;
@@ -152,7 +155,7 @@ public class ValidateLastDDLTimestampUtil {
* @return ValidateLastDDLTimestampRequest for the table in tableRef
*/
private static RegionServerEndpointProtos.ValidateLastDDLTimestampRequest
- getValidateDDLTimestampRequest(List<TableRef> tableRefs) {
+ getValidateDDLTimestampRequest(List<TableRef> tableRefs) throws
StaleMetadataCacheException {
RegionServerEndpointProtos.ValidateLastDDLTimestampRequest.Builder
requestBuilder
=
RegionServerEndpointProtos.ValidateLastDDLTimestampRequest.newBuilder();
@@ -168,12 +171,20 @@ public class ValidateLastDDLTimestampUtil {
:
tableRef.getTable().getAncestorLastDDLTimestampMap().entrySet()) {
innerBuilder =
RegionServerEndpointProtos.LastDDLTimestampRequest.newBuilder();
PTableKey ancestorKey = entry.getKey();
+ if (entry.getValue() == null) {
+ throw new StaleMetadataCacheException(
+ "LAST_DDL_TIMESTAMP set to null in client cache
for {}" + ancestorKey);
+ }
setLastDDLTimestampRequestParameters(innerBuilder,
ancestorKey, entry.getValue());
requestBuilder.addLastDDLTimestampRequests(innerBuilder);
}
// add the current table to the request
PTable ptable = tableRef.getTable();
+ if (ptable.getLastDDLTimestamp() == null) {
+ throw new StaleMetadataCacheException(
+ "LAST_DDL_TIMESTAMP set to null in client cache for
{}" + ptable.getKey());
+ }
innerBuilder =
RegionServerEndpointProtos.LastDDLTimestampRequest.newBuilder();
setLastDDLTimestampRequestParameters(innerBuilder, ptable.getKey(),
ptable.getLastDDLTimestamp());
@@ -181,6 +192,10 @@ public class ValidateLastDDLTimestampUtil {
// add all indexes of the current table
for (PTable idxPTable : tableRef.getTable().getIndexes()) {
+ if (idxPTable.getLastDDLTimestamp() == null) {
+ throw new StaleMetadataCacheException(
+ "LAST_DDL_TIMESTAMP set to null in client cache
for {}" + idxPTable.getKey());
+ }
innerBuilder =
RegionServerEndpointProtos.LastDDLTimestampRequest.newBuilder();
setLastDDLTimestampRequestParameters(innerBuilder,
idxPTable.getKey(),
idxPTable.getLastDDLTimestamp());
diff --git
a/phoenix-core-server/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
b/phoenix-core-server/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
index 435c8886f1..2cb00501d8 100644
---
a/phoenix-core-server/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
+++
b/phoenix-core-server/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
@@ -1420,7 +1420,7 @@ TABLE_FAMILY_BYTES, TABLE_SEQ_NUM_BYTES);
null :
PLong.INSTANCE.getCodec().decodeLong(lastDDLTimestampKv.getValueArray(),
lastDDLTimestampKv.getValueOffset(), SortOrder.getDefault());
builder.setLastDDLTimestamp(lastDDLTimestampKv != null ?
lastDDLTimestamp :
- oldTable != null ? oldTable.getLastDDLTimestamp() : null);
+ oldTable != null ? oldTable.getLastDDLTimestamp() : timeStamp);
Cell changeDetectionEnabledKv =
tableKeyValues[CHANGE_DETECTION_ENABLED_INDEX];
boolean isChangeDetectionEnabled = changeDetectionEnabledKv != null
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/cache/ServerMetadataCacheIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/cache/ServerMetadataCacheIT.java
index 8e309cbc2f..fa051203ca 100644
---
a/phoenix-core/src/it/java/org/apache/phoenix/cache/ServerMetadataCacheIT.java
+++
b/phoenix-core/src/it/java/org/apache/phoenix/cache/ServerMetadataCacheIT.java
@@ -39,6 +39,7 @@ import org.apache.phoenix.schema.ColumnNotFoundException;
import org.apache.phoenix.schema.PIndexState;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.thirdparty.com.google.common.collect.Maps;
@@ -66,6 +67,14 @@ import java.util.Properties;
import java.util.Random;
import static
org.apache.hadoop.hbase.coprocessor.CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_FAMILY;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.COLUMN_NAME;
+import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LAST_DDL_TIMESTAMP;
+import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_TYPE;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TENANT_ID;
import static
org.apache.phoenix.query.ConnectionQueryServicesImpl.INVALIDATE_SERVER_METADATA_CACHE_EX_MESSAGE;
import static
org.apache.phoenix.query.QueryServices.PHOENIX_METADATA_INVALIDATE_CACHE_ENABLED;
import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
@@ -1854,6 +1863,33 @@ public class ServerMetadataCacheIT extends
ParallelStatsDisabledIT {
}
}
+ @Test
+ public void testLastDDLTimestampNotSetOnTable() throws SQLException {
+ Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+ String url1 = QueryUtil.getConnectionUrl(props, config, "client1");
+ String tableName = generateUniqueName();
+ ConnectionQueryServices cqs1 = driver.getConnectionQueryServices(url1,
props);
+ try (Connection conn1 = cqs1.connect(url1, props)) {
+ createTable(conn1, tableName);
+ // null out LAST_DDL_TIMESTAMP and clear client/server caches
+ String pkCols = TENANT_ID + ", " + TABLE_SCHEM +
+ ", " + TABLE_NAME + ", " + COLUMN_NAME + ", " +
COLUMN_FAMILY;
+ String upsertSql =
+ "UPSERT INTO " + SYSTEM_CATALOG_NAME + " (" + pkCols + ",
" +
+ LAST_DDL_TIMESTAMP + ")" + " " +
+ "SELECT " + pkCols + ", NULL FROM " +
SYSTEM_CATALOG_NAME + " " +
+ "WHERE " + TABLE_NAME + " " + " = '" + tableName +
"'";
+ conn1.createStatement().executeUpdate(upsertSql);
+ conn1.commit();
+
conn1.unwrap(PhoenixConnection.class).getQueryServices().clearCache();
+
+ // refresh client's cache and query, it should not face NPE
+ PhoenixRuntime.getTableNoCache(conn1, tableName);
+ query(conn1, tableName);
+ Assert.assertNotNull(PhoenixRuntime.getTable(conn1,
tableName).getLastDDLTimestamp());
+ }
+ }
+
//Helper methods
public static void assertNumGetTableRPC(ConnectionQueryServices spyCqs,
String tableName, int numExpectedRPCs) throws SQLException {
Mockito.verify(spyCqs,
Mockito.times(numExpectedRPCs)).getTable(eq(null),