This is an automated email from the ASF dual-hosted git repository. apurtell pushed a commit to branch PHOENIX-7562-feature in repository https://gitbox.apache.org/repos/asf/phoenix.git
commit 1a9709b5736d0f2e78b96a74de3d97d3d789367a Author: Palash Chauhan <palashc...@gmail.com> AuthorDate: Thu May 15 19:58:18 2025 -0700 PHOENIX-7609 : CDC creation fails when data table has case sensitive name (#2149) Co-authored-by: Palash Chauhan <p.chau...@pchauha-ltmgv47.internal.salesforce.com> --- .../org/apache/phoenix/compile/QueryCompiler.java | 3 +- .../apache/phoenix/optimize/QueryOptimizer.java | 2 +- .../org/apache/phoenix/schema/MetaDataClient.java | 9 ++- .../main/java/org/apache/phoenix/util/CDCUtil.java | 2 +- .../apache/phoenix/end2end/CDCDefinitionIT.java | 40 ++++++++++ .../org/apache/phoenix/end2end/CDCQueryIT.java | 92 ++++++++++++++-------- .../phoenix/end2end/index/SingleCellIndexIT.java | 2 + 7 files changed, 112 insertions(+), 38 deletions(-) diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/compile/QueryCompiler.java b/phoenix-core-client/src/main/java/org/apache/phoenix/compile/QueryCompiler.java index efb25cb761..2d9a975ae1 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/compile/QueryCompiler.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/compile/QueryCompiler.java @@ -32,6 +32,7 @@ import org.apache.phoenix.coprocessorclient.BaseScannerRegionObserverConstants; import org.apache.phoenix.expression.function.PhoenixRowTimestampFunction; import org.apache.phoenix.parse.HintNode; import org.apache.phoenix.parse.NamedTableNode; +import org.apache.phoenix.parse.TableName; import org.apache.phoenix.parse.TerminalParseNode; import org.apache.phoenix.schema.PTableType; import org.apache.phoenix.schema.SortOrder; @@ -275,7 +276,7 @@ public class QueryCompiler { TableRef cdcTableRef = dataPlanForCDC.getTableRef(); PTable cdcTable = cdcTableRef.getTable(); NamedTableNode cdcDataTableName = NODE_FACTORY.namedTable(null, - NODE_FACTORY.table(cdcTable.getSchemaName().getString(), + TableName.create(cdcTable.getSchemaName().getString(), cdcTable.getParentTableName().getString()), select.getTableSamplingRate()); ColumnResolver dataTableResolver = FromCompiler.getResolver(cdcDataTableName, diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core-client/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java index a562b3ebc8..7cb75cad64 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java @@ -227,7 +227,7 @@ public class QueryOptimizer { PTable table = dataPlan.getTableRef().getTable(); if (table.getType() == PTableType.CDC) { NamedTableNode indexTableNode = FACTORY.namedTable(null, - FACTORY.table(table.getSchemaName().getString(), + TableName.create(table.getSchemaName().getString(), CDCUtil.getCDCIndexName(table.getTableName().getString())), select.getTableSamplingRate()); indexResolver = FromCompiler.getResolver(indexTableNode, 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 726e77ac4a..85fad7b96b 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 @@ -1986,11 +1986,14 @@ public class MetaDataClient { Properties props = connection.getClientInfo(); props.put(INDEX_CREATE_DEFAULT_STATE, "ACTIVE"); + String escapedDataTableFullName + = SchemaUtil.getFullTableNameWithQuotes(statement.getDataTable().getSchemaName(), + statement.getDataTable().getTableName(), true, true); String createIndexSql = "CREATE UNCOVERED INDEX " + (statement.isIfNotExists() ? "IF NOT EXISTS " : "") - + CDCUtil.getCDCIndexName(cdcObjName) - + " ON " + dataTableFullName + " (" + + "\"" + CDCUtil.getCDCIndexName(cdcObjName) + + "\" ON " + escapedDataTableFullName + " (" + PartitionIdFunction.NAME + "(), " + PhoenixRowTimestampFunction.NAME + "()) ASYNC"; List<String> indexProps = new ArrayList<>(); @@ -2041,7 +2044,7 @@ public class MetaDataClient { tableProps.put(TableProperty.MULTI_TENANT.getPropertyName(), Boolean.TRUE); } CreateTableStatement tableStatement = FACTORY.createTable( - FACTORY.table(dataTable.getSchemaName().getString(), cdcObjName), + TableName.create(dataTable.getSchemaName().getString(), cdcObjName), null, columnDefs, FACTORY.primaryKey(null, pkColumnDefs), Collections.emptyList(), PTableType.CDC, statement.isIfNotExists(), null, null, statement.getBindCount(), null); diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/util/CDCUtil.java b/phoenix-core-client/src/main/java/org/apache/phoenix/util/CDCUtil.java index 2a89798041..3b3c8b5315 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/util/CDCUtil.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/util/CDCUtil.java @@ -88,7 +88,7 @@ public class CDCUtil { } public static String getCDCIndexName(String cdcName) { - return CDC_INDEX_PREFIX + SchemaUtil.getTableNameFromFullName(cdcName.toUpperCase()); + return CDC_INDEX_PREFIX + SchemaUtil.getTableNameFromFullName(cdcName); } public static boolean isCDCIndex(String indexName) { diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCDefinitionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCDefinitionIT.java index 2847237c91..bb3263a93f 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCDefinitionIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCDefinitionIT.java @@ -128,6 +128,46 @@ public class CDCDefinitionIT extends CDCBaseIT { conn.close(); } + @Test + public void testCreateCaseSensitiveTable() throws Exception { + Connection conn = newConnection(); + String tableName = "\"" + generateUniqueName().toLowerCase() + "\""; + conn.createStatement().execute( + "CREATE TABLE " + tableName + " ( k INTEGER PRIMARY KEY," + " v1 INTEGER," + + " v2 DATE) TTL=100"); + if (forView) { + String viewName = "\"" + generateUniqueName().toLowerCase() + "\""; + conn.createStatement().execute( + "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName); + tableName = viewName; + } + String cdcName = "\"" + generateUniqueName().toLowerCase() + "\""; + String cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName; + conn.createStatement().execute(cdc_sql); + conn.createStatement().executeQuery("SELECT * FROM " + cdcName); + } + + @Test + public void testCreateCaseSensitiveSchemaAndTable() throws Exception { + Connection conn = newConnection(); + String schemaName = "\"" + generateUniqueName().toLowerCase() + "\""; + String tableName = SchemaUtil.getTableName(schemaName, "\"" + generateUniqueName().toLowerCase() + "\""); + conn.createStatement().execute( + "CREATE TABLE " + tableName + " ( k INTEGER PRIMARY KEY," + " v1 INTEGER," + + " v2 DATE) TTL=100"); + if (forView) { + String viewName = SchemaUtil.getTableName(schemaName, "\"" + generateUniqueName().toLowerCase() + "\""); + conn.createStatement().execute( + "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName); + tableName = viewName; + } + String cdcName = "\"" + generateUniqueName().toLowerCase() + "\""; + String cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName; + conn.createStatement().execute(cdc_sql); + String cdcFullName = SchemaUtil.getTableName(schemaName, cdcName); + conn.createStatement().executeQuery("SELECT * FROM " + cdcFullName); + } + @Test public void testCreateWithSchemaName() throws Exception { Properties props = new Properties(); diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCQueryIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCQueryIT.java index a1519cc64b..b7e4b2cd59 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCQueryIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CDCQueryIT.java @@ -97,27 +97,32 @@ public class CDCQueryIT extends CDCBaseIT { private final boolean multitenant; private final Integer tableSaltBuckets; private final boolean withSchemaName; + private final boolean caseSensitiveNames; public CDCQueryIT(Boolean forView, PTable.QualifierEncodingScheme encodingScheme, boolean multitenant, - Integer tableSaltBuckets, boolean withSchemaName) { + Integer tableSaltBuckets, boolean withSchemaName, boolean caseSensitiveNames) { this.forView = forView; this.encodingScheme = encodingScheme; this.multitenant = multitenant; this.tableSaltBuckets = tableSaltBuckets; this.withSchemaName = withSchemaName; + this.caseSensitiveNames = caseSensitiveNames; } @Parameterized.Parameters(name = "forView={0}, encodingScheme={1}, " + - "multitenant={2}, tableSaltBuckets={3}, withSchemaName={4}") + "multitenant={2}, tableSaltBuckets={3}, withSchemaName={4}, caseSensitiveNames={5}") public static synchronized Collection<Object[]> data() { return Arrays.asList(new Object[][] { - { Boolean.FALSE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE }, - { Boolean.FALSE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.TRUE }, - { Boolean.FALSE, NON_ENCODED_QUALIFIERS, Boolean.FALSE, 4, Boolean.FALSE }, - { Boolean.FALSE, NON_ENCODED_QUALIFIERS, Boolean.TRUE, 2, Boolean.TRUE }, - { Boolean.FALSE, NON_ENCODED_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE }, - { Boolean.TRUE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE }, + { Boolean.FALSE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE, Boolean.FALSE }, + { Boolean.FALSE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.TRUE, Boolean.FALSE }, + { Boolean.FALSE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE, Boolean.TRUE }, + { Boolean.FALSE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.TRUE, Boolean.TRUE }, + { Boolean.FALSE, NON_ENCODED_QUALIFIERS, Boolean.FALSE, 4, Boolean.FALSE, Boolean.FALSE }, + { Boolean.FALSE, NON_ENCODED_QUALIFIERS, Boolean.TRUE, 2, Boolean.TRUE, Boolean.FALSE }, + { Boolean.FALSE, NON_ENCODED_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE, Boolean.FALSE }, + { Boolean.TRUE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE, Boolean.FALSE }, + { Boolean.TRUE, TWO_BYTE_QUALIFIERS, Boolean.FALSE, null, Boolean.FALSE, Boolean.TRUE }, }); } @@ -294,8 +299,8 @@ public class CDCQueryIT extends CDCBaseIT { @Test public void testSelectCDC() throws Exception { String cdcName, cdc_sql; - String schemaName = withSchemaName ? generateUniqueName() : null; - String tableName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String schemaName = getSchemaName(); + String tableName = getTableOrViewName(schemaName); String datatableName = tableName; try (Connection conn = newConnection()) { createTable(conn, "CREATE TABLE " + tableName + " (" @@ -304,12 +309,12 @@ public class CDCQueryIT extends CDCBaseIT { + "CONSTRAINT PK PRIMARY KEY " + (multitenant ? "(TENANT_ID, k) " : "(k)") + ")", encodingScheme, multitenant, tableSaltBuckets, false, null); if (forView) { - String viewName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String viewName = getTableOrViewName(schemaName); createTable(conn, "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName, encodingScheme); tableName = viewName; } - cdcName = generateUniqueName(); + cdcName = getCDCName(); cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName; createCDC(conn, cdc_sql, encodingScheme); } @@ -423,8 +428,8 @@ public class CDCQueryIT extends CDCBaseIT { @Test public void testSelectGeneric() throws Exception { String cdcName, cdc_sql; - String schemaName = withSchemaName ? generateUniqueName() : null; - String tableName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String schemaName = getSchemaName(); + String tableName = getTableOrViewName(schemaName); String datatableName = tableName; Map<String, String> pkColumns = new TreeMap<String, String>() {{ put("K1", "INTEGER"); @@ -447,12 +452,14 @@ public class CDCQueryIT extends CDCBaseIT { createTable(conn, tableName, pkColumns, dataColumns, multitenant, encodingScheme, tableSaltBuckets, false, null); if (forView) { - String viewName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String viewName = caseSensitiveNames + ? SchemaUtil.getTableName(schemaName, SchemaUtil.getEscapedArgument(generateUniqueName().toLowerCase())) + : SchemaUtil.getTableName(schemaName, generateUniqueName()); createTable(conn, "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName, encodingScheme); tableName = viewName; } - cdcName = generateUniqueName(); + cdcName = getCDCName(); cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName + " INCLUDE (change)"; createCDC(conn, cdc_sql, encodingScheme); } @@ -526,8 +533,8 @@ public class CDCQueryIT extends CDCBaseIT { private void _testSelectCDCImmutable(PTable.ImmutableStorageScheme immutableStorageScheme) throws Exception { String cdcName, cdc_sql; - String schemaName = withSchemaName ? generateUniqueName() : null; - String tableName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String schemaName = getSchemaName(); + String tableName = getTableOrViewName(schemaName); String datatableName = tableName; try (Connection conn = newConnection()) { createTable(conn, "CREATE TABLE " + tableName + " (" + @@ -536,12 +543,13 @@ public class CDCQueryIT extends CDCBaseIT { (multitenant ? "(TENANT_ID, k) " : "(k)") + ")", encodingScheme, multitenant, tableSaltBuckets, true, immutableStorageScheme); if (forView) { - String viewName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String viewName = getTableOrViewName(schemaName); + createTable(conn, "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName, encodingScheme); tableName = viewName; } - cdcName = generateUniqueName(); + cdcName = getCDCName(); cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName; createCDC(conn, cdc_sql, encodingScheme); @@ -598,8 +606,8 @@ public class CDCQueryIT extends CDCBaseIT { @Test public void testSelectWithTimeRange() throws Exception { String cdcName, cdc_sql; - String schemaName = withSchemaName ? generateUniqueName() : null; - String tableName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String schemaName = getSchemaName(); + String tableName = getTableOrViewName(schemaName); String datatableName = tableName; Map<String, String> pkColumns = new TreeMap<String, String>() {{ put("K1", "INTEGER"); @@ -611,12 +619,12 @@ public class CDCQueryIT extends CDCBaseIT { createTable(conn, tableName, pkColumns, dataColumns, multitenant, encodingScheme, tableSaltBuckets, false, null); if (forView) { - String viewName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String viewName = getTableOrViewName(schemaName); createTable(conn, "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName, encodingScheme); tableName = viewName; } - cdcName = generateUniqueName(); + cdcName = getCDCName(); cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName + " INCLUDE (change)"; createCDC(conn, cdc_sql, encodingScheme); cdcIndexShouldNotBeUsedForDataTableQueries(conn, tableName,cdcName); @@ -674,8 +682,8 @@ public class CDCQueryIT extends CDCBaseIT { @Test public void testSelectCDCWithDDL() throws Exception { - String schemaName = withSchemaName ? generateUniqueName() : null; - String tableName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String schemaName = getSchemaName(); + String tableName = getTableOrViewName(schemaName); String datatableName = tableName; String cdcName, cdc_sql; try (Connection conn = newConnection()) { @@ -686,13 +694,13 @@ public class CDCQueryIT extends CDCBaseIT { (multitenant ? "(TENANT_ID, k) " : "(k)") + ")", encodingScheme, multitenant, tableSaltBuckets, false, null); if (forView) { - String viewName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String viewName = getTableOrViewName(schemaName); createTable(conn, "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName, encodingScheme); tableName = viewName; } - cdcName = generateUniqueName(); + cdcName = getCDCName(); cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName; createCDC(conn, cdc_sql, encodingScheme); conn.createStatement().execute("ALTER TABLE " + datatableName + " DROP COLUMN v0"); @@ -727,8 +735,8 @@ public class CDCQueryIT extends CDCBaseIT { @Test public void testSelectCDCFailDataTableUpdate() throws Exception { - String schemaName = withSchemaName ? generateUniqueName() : null; - String tableName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String schemaName = getSchemaName(); + String tableName = getTableOrViewName(schemaName); String cdcName, cdc_sql; try (Connection conn = newConnection()) { createTable(conn, "CREATE TABLE " + tableName + " (" + @@ -738,12 +746,12 @@ public class CDCQueryIT extends CDCBaseIT { (multitenant ? "(TENANT_ID, k) " : "(k)") + ")", encodingScheme, multitenant, tableSaltBuckets, false, null); if (forView) { - String viewName = SchemaUtil.getTableName(schemaName, generateUniqueName()); + String viewName = getTableOrViewName(schemaName); createTable(conn, "CREATE VIEW " + viewName + " AS SELECT * FROM " + tableName, encodingScheme); tableName = viewName; } - cdcName = generateUniqueName(); + cdcName = getCDCName(); cdc_sql = "CREATE CDC " + cdcName + " ON " + tableName; createCDC(conn, cdc_sql, encodingScheme); cdcIndexShouldNotBeUsedForDataTableQueries(conn, tableName, cdcName); @@ -938,4 +946,24 @@ public class CDCQueryIT extends CDCBaseIT { } } + + private String getSchemaName() { + return withSchemaName + ? caseSensitiveNames + ? SchemaUtil.getEscapedArgument(generateUniqueName().toLowerCase()) + : generateUniqueName() + : null; + } + + private String getTableOrViewName(String schemaName) { + return caseSensitiveNames + ? SchemaUtil.getTableName(schemaName, SchemaUtil.getEscapedArgument(generateUniqueName().toLowerCase())) + : SchemaUtil.getTableName(schemaName, generateUniqueName()); + } + + private String getCDCName() { + return caseSensitiveNames + ? SchemaUtil.getEscapedArgument(generateUniqueName().toLowerCase()) + : generateUniqueName(); + } } diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SingleCellIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SingleCellIndexIT.java index 2dbbabe76b..8ebd4f36c6 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SingleCellIndexIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/SingleCellIndexIT.java @@ -498,6 +498,8 @@ public class SingleCellIndexIT extends ParallelStatsDisabledIT { } public static void dumpTable(String tableName) throws Exception { + // this method is also used by CDCBaseIT where case sensitive tableNames are also used + tableName = tableName.replaceAll("\"", ""); try (Connection conn = DriverManager.getConnection(getUrl())) { Table hTable = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(tableName.getBytes());