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 9d55500fe2f73717e69bc6c51b0a411ea6ebc715 Author: Palash Chauhan <palashc...@gmail.com> AuthorDate: Tue May 13 15:03:15 2025 -0700 PHOENIX-7608 : Partial index creation fails when creating it on a table with case sensitive table name (#2146) Co-authored-by: Palash Chauhan <p.chau...@pchauha-ltmgv47.internal.salesforce.com> --- .../phoenix/compile/CreateIndexCompiler.java | 5 +++- .../java/org/apache/phoenix/schema/PTableImpl.java | 5 +++- .../java/org/apache/phoenix/util/ColumnInfo.java | 3 +-- .../java/org/apache/phoenix/util/SchemaUtil.java | 10 ++++---- .../phoenix/end2end/index/PartialIndexIT.java | 29 +++++++++++++++++++--- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/compile/CreateIndexCompiler.java b/phoenix-core-client/src/main/java/org/apache/phoenix/compile/CreateIndexCompiler.java index bcdae4013d..b5678c41c1 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/compile/CreateIndexCompiler.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/compile/CreateIndexCompiler.java @@ -78,6 +78,7 @@ import java.util.List; import static org.apache.phoenix.query.QueryServices.DEFAULT_SYSTEM_KEEP_DELETED_CELLS_ATTRIB; import static org.apache.phoenix.query.QueryServices.SYSTEM_CATALOG_INDEXES_ENABLED; import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_SYSTEM_CATALOG_INDEXES_ENABLED; +import static org.apache.phoenix.util.SchemaUtil.ESCAPE_CHARACTER; public class CreateIndexCompiler { private final PhoenixStatement statement; @@ -150,7 +151,9 @@ public class CreateIndexCompiler { // Convert the index WHERE ParseNode to an Expression ExpressionCompiler expressionCompiler = new ExpressionCompiler(context); Expression indexWhereExpression = indexWhere.accept(expressionCompiler); - PTable dataTable = connection.getTable(dataTableName.toString()); + // if table name has lowercase characters, query would provide escaped table name + // so we need to unescape it to be able to lookup the ptable in the cache. + PTable dataTable = connection.getTable(SchemaUtil.getUnEscapedFullName(dataTableName.toString())); // Create a full data table row. Skip generating values for view constants as they // will be generated by the Upsert compiler diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/schema/PTableImpl.java b/phoenix-core-client/src/main/java/org/apache/phoenix/schema/PTableImpl.java index 7c72ea3f87..4d8f592be1 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/schema/PTableImpl.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/schema/PTableImpl.java @@ -2502,10 +2502,13 @@ public class PTableImpl implements PTable { } private void buildIndexWhereExpression(PhoenixConnection connection) throws SQLException { + // escape the full table name to be able to compile the select query in case tablename had lowercase characters PhoenixPreparedStatement pstmt = new PhoenixPreparedStatement(connection, - "select * from " + SchemaUtil.getTableName(parentSchemaName, parentTableName).getString() + " where " + indexWhere); + "select * from " + + SchemaUtil.getEscapedTableName(parentSchemaName.getString(), parentTableName.getString()) + + " where " + indexWhere); QueryPlan plan = pstmt.compileQuery(); ParseNode where = plan.getStatement().getWhere(); plan.getContext().setResolver(FromCompiler.getResolver(plan.getTableRef())); diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/util/ColumnInfo.java b/phoenix-core-client/src/main/java/org/apache/phoenix/util/ColumnInfo.java index eea838d571..981d4ed19f 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/util/ColumnInfo.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/util/ColumnInfo.java @@ -10,7 +10,6 @@ package org.apache.phoenix.util; -import java.sql.Types; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; @@ -85,7 +84,7 @@ public class ColumnInfo { * @return */ public String getDisplayName() { - final String unescapedColumnName = SchemaUtil.getUnEscapedFullColumnName(columnName); + final String unescapedColumnName = SchemaUtil.getUnEscapedFullName(columnName); int index = unescapedColumnName.indexOf(QueryConstants.NAME_SEPARATOR); if (index < 0) { return unescapedColumnName; diff --git a/phoenix-core-client/src/main/java/org/apache/phoenix/util/SchemaUtil.java b/phoenix-core-client/src/main/java/org/apache/phoenix/util/SchemaUtil.java index 2e0fd1b323..fb0bdc0c82 100644 --- a/phoenix-core-client/src/main/java/org/apache/phoenix/util/SchemaUtil.java +++ b/phoenix-core-client/src/main/java/org/apache/phoenix/util/SchemaUtil.java @@ -929,13 +929,13 @@ public class SchemaUtil { /** * Replaces all occurrences of {@link #ESCAPE_CHARACTER} with an empty character. - * @param fullColumnName + * @param fullName * @return */ - public static String getUnEscapedFullColumnName(String fullColumnName) { - checkArgument(!isNullOrEmpty(fullColumnName), "Column name cannot be null or empty"); - fullColumnName = fullColumnName.replaceAll(ESCAPE_CHARACTER, ""); - return fullColumnName.trim(); + public static String getUnEscapedFullName(String fullName) { + checkArgument(!isNullOrEmpty(fullName), "Given name cannot be null or empty"); + fullName = fullName.replaceAll(ESCAPE_CHARACTER, ""); + return fullName.trim(); } /** diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/PartialIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/PartialIndexIT.java index aabee243a7..2fb1553ae5 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/PartialIndexIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/PartialIndexIT.java @@ -1074,13 +1074,13 @@ public class PartialIndexIT extends BaseTest { stmt.execute("CREATE " + (uncovered ? "UNCOVERED " : " ") + (local ? "LOCAL " : " ") + "INDEX " + indexName1 + " on " + dataTableName + " (v1) " + - (uncovered ? "" : "INCLUDE (\"CoL\", \"coLUmn3\")")); + (uncovered ? "" : "INCLUDE (\"CoL\", \"coLUmn3\")") + "WHERE v1='b'"); stmt.execute("CREATE " + (uncovered ? "UNCOVERED " : " ") + (local ? "LOCAL " : " ") + "INDEX " + indexName2 + " on " + dataTableName + " (\"CoL\") " + - (uncovered ? "" : "INCLUDE (v1, \"coLUmn3\")")); + (uncovered ? "" : "INCLUDE (v1, \"coLUmn3\")") + " WHERE \"CoL\"='c'"); stmt.execute("CREATE " + (uncovered ? "UNCOVERED " : " ") + (local ? "LOCAL " : " ") + "INDEX " + indexName3 + " on " + dataTableName + " (\"coLUmn3\") " + - (uncovered ? "" : "INCLUDE (\"CoL\", v1)")); + (uncovered ? "" : "INCLUDE (\"CoL\", v1)") + " WHERE \"coLUmn3\"='d'"); stmt.execute("UPSERT INTO " + dataTableName + " VALUES ('a', 'b', 'c', 'd')"); conn.commit(); @@ -1099,6 +1099,29 @@ public class PartialIndexIT extends BaseTest { } } + @Test + public void testPartialIndexOnTableWithCaseSensitiveName() throws Exception { + try(Connection conn = DriverManager.getConnection(getUrl()); + PhoenixStatement stmt = conn.createStatement().unwrap(PhoenixStatement.class)) { + String dataTableName = "\"" + generateUniqueName().toLowerCase() + "\""; + String indexName1 = generateUniqueName(); + + stmt.execute("CREATE TABLE " + dataTableName + + " (\"hashKeY\" VARCHAR NOT NULL PRIMARY KEY, v1 VARCHAR, \"CoL\" VARCHAR, \"coLUmn3\" VARCHAR)" + + (salted ? " SALT_BUCKETS=4" : "")); + stmt.execute("CREATE " + (uncovered ? "UNCOVERED " : " ") + (local ? "LOCAL " : " ") + + "INDEX " + indexName1 + " on " + dataTableName + " (\"CoL\") " + + (uncovered ? "" : "INCLUDE (v1, \"coLUmn3\")") + " WHERE \"CoL\"='c'"); + + stmt.execute("UPSERT INTO " + dataTableName + " VALUES ('a', 'b', 'c', 'd')"); + conn.commit(); + + ResultSet rs = stmt.executeQuery("SELECT v1 FROM " + dataTableName + " WHERE \"CoL\"='c'"); + Assert.assertTrue(rs.next()); + Assert.assertEquals(indexName1, stmt.getQueryPlan().getTableRef().getTable().getTableName().toString()); + } + } + @Test public void testPartialIndexWithVarbinaryEncoded() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) {