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 aa44ae6dcb PHOENIX-7743 : Fix TNFE in IndexTool server side builds for 
case sensitive names (#2331)
aa44ae6dcb is described below

commit aa44ae6dcb307ab9fd30f25dae7f58e4203b6d5b
Author: Palash Chauhan <[email protected]>
AuthorDate: Wed Feb 4 14:05:47 2026 -0800

    PHOENIX-7743 : Fix TNFE in IndexTool server side builds for case sensitive 
names (#2331)
    
    Co-authored-by: Palash Chauhan 
<[email protected]>
---
 .../PhoenixServerBuildIndexInputFormat.java        | 16 ++++-
 .../apache/phoenix/mapreduce/index/IndexTool.java  |  2 +-
 .../org/apache/phoenix/end2end/IndexToolIT.java    | 82 ++++++++++++++++++++++
 3 files changed, 96 insertions(+), 4 deletions(-)

diff --git 
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/PhoenixServerBuildIndexInputFormat.java
 
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/PhoenixServerBuildIndexInputFormat.java
index ba9abe77ce..5bae99d883 100644
--- 
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/PhoenixServerBuildIndexInputFormat.java
+++ 
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/PhoenixServerBuildIndexInputFormat.java
@@ -62,6 +62,7 @@ import org.apache.phoenix.util.ByteUtil;
 import org.apache.phoenix.util.EnvironmentEdgeManager;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.ScanUtil;
+import org.apache.phoenix.util.SchemaUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -92,8 +93,9 @@ public class PhoenixServerBuildIndexInputFormat<T extends 
DBWritable> extends Ph
     public QueryPlan getQueryPlan(PhoenixConnection phoenixConnection, String 
oldTableFullName,
       String newTableFullName) throws SQLException {
       PTable newTable = phoenixConnection.getTableNoCache(newTableFullName);
+      String quotedOldTableName = getQuotedTableNameForSQL(oldTableFullName);
       ServerBuildTransformingTableCompiler compiler =
-        new ServerBuildTransformingTableCompiler(phoenixConnection, 
oldTableFullName);
+        new ServerBuildTransformingTableCompiler(phoenixConnection, 
quotedOldTableName);
       MutationPlan plan = compiler.compile(newTable);
       return plan.getQueryPlan();
     }
@@ -104,8 +106,9 @@ public class PhoenixServerBuildIndexInputFormat<T extends 
DBWritable> extends Ph
     public QueryPlan getQueryPlan(PhoenixConnection phoenixConnection, String 
dataTableFullName,
       String indexTableFullName) throws SQLException {
       PTable indexTable = 
phoenixConnection.getTableNoCache(indexTableFullName);
+      String quotedDataTableName = getQuotedTableNameForSQL(dataTableFullName);
       ServerBuildIndexCompiler compiler =
-        new ServerBuildIndexCompiler(phoenixConnection, dataTableFullName);
+        new ServerBuildIndexCompiler(phoenixConnection, quotedDataTableName);
       MutationPlan plan = compiler.compile(indexTable);
       return plan.getQueryPlan();
     }
@@ -117,7 +120,8 @@ public class PhoenixServerBuildIndexInputFormat<T extends 
DBWritable> extends Ph
       String indexTableFullName) throws SQLException {
       QueryPlan plan;
       try (final PhoenixStatement statement = new 
PhoenixStatement(phoenixConnection)) {
-        String query = "SELECT count(*) FROM " + indexTableFullName;
+        String quotedIndexName = getQuotedTableNameForSQL(indexTableFullName);
+        String query = "SELECT count(*) FROM " + quotedIndexName;
         plan = statement.compileQuery(query);
         TableRef tableRef = plan.getTableRef();
         Scan scan = plan.getContext().getScan();
@@ -139,6 +143,12 @@ public class PhoenixServerBuildIndexInputFormat<T extends 
DBWritable> extends Ph
 
   private QueryPlanBuilder queryPlanBuilder;
 
+  private String getQuotedTableNameForSQL(String normalizedFullTableName) {
+    String schemaName = 
SchemaUtil.getSchemaNameFromFullName(normalizedFullTableName);
+    String tableName = 
SchemaUtil.getTableNameFromFullName(normalizedFullTableName);
+    return SchemaUtil.getFullTableNameWithQuotes(schemaName, tableName);
+  }
+
   @Override
   protected QueryPlan getQueryPlan(final JobContext context, final 
Configuration configuration)
     throws IOException {
diff --git 
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/index/IndexTool.java
 
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/index/IndexTool.java
index 2ca544e0ee..6edfc9370c 100644
--- 
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/index/IndexTool.java
+++ 
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/index/IndexTool.java
@@ -756,7 +756,7 @@ public class IndexTool extends Configured implements Tool {
       configuration.setBooleanIfUnset(
         PhoenixConfigurationUtil.MAPREDUCE_RANDOMIZE_MAPPER_EXECUTION_ORDER, 
true);
 
-      PhoenixConfigurationUtil.setIndexToolDataTableName(configuration, 
dataTableWithSchema);
+      PhoenixConfigurationUtil.setIndexToolDataTableName(configuration, 
qDataTable);
       PhoenixConfigurationUtil.setIndexToolIndexTableName(configuration, 
qIndexTable);
       PhoenixConfigurationUtil.setIndexToolSourceTable(configuration, 
sourceTable);
       if (startTime != null) {
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java
index d8225e1458..db0ada9832 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java
@@ -34,6 +34,8 @@ import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.BEF
 import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.BEFORE_REBUILD_UNKNOWN_INDEX_ROW_COUNT;
 import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.BEFORE_REBUILD_UNVERIFIED_INDEX_ROW_COUNT;
 import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.BEFORE_REBUILD_VALID_INDEX_ROW_COUNT;
+import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.BEFORE_REPAIR_EXTRA_UNVERIFIED_INDEX_ROW_COUNT;
+import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.BEFORE_REPAIR_EXTRA_VERIFIED_INDEX_ROW_COUNT;
 import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.REBUILT_INDEX_ROW_COUNT;
 import static 
org.apache.phoenix.mapreduce.index.PhoenixIndexToolJobCounters.SCANNED_DATA_ROW_COUNT;
 import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
@@ -817,6 +819,86 @@ public class IndexToolIT extends BaseTest {
     }
   }
 
+  @Test
+  public void testIndexToDataVerification() throws Exception {
+    testIndexToDataVerificationHelper(false);
+  }
+
+  @Test
+  public void testIndexToDataVerificationCaseSensitive() throws Exception {
+    testIndexToDataVerificationHelper(true);
+  }
+
+  private void testIndexToDataVerificationHelper(boolean caseSensitive) throws 
Exception {
+    if (localIndex || transactional || useSnapshot) {
+      return;
+    }
+    String schemaName = caseSensitive ? generateUniqueName().toLowerCase() : 
generateUniqueName();
+    String dataTableName =
+      caseSensitive ? generateUniqueName().toLowerCase() : 
generateUniqueName();
+    String indexTableName =
+      caseSensitive ? generateUniqueName().toLowerCase() : 
generateUniqueName();
+    String sSchemaName = caseSensitive ? 
SchemaUtil.getEscapedArgument(schemaName) : schemaName;
+    String sDataTableName =
+      caseSensitive ? SchemaUtil.getEscapedArgument(dataTableName) : 
dataTableName;
+    String sIndexTableName =
+      caseSensitive ? SchemaUtil.getEscapedArgument(indexTableName) : 
indexTableName;
+    String qDataTableName = caseSensitive
+      ? SchemaUtil.getFullTableNameWithQuotes(schemaName, dataTableName)
+      : SchemaUtil.getTableName(schemaName, dataTableName);
+    String qIndexTableName = caseSensitive
+      ? SchemaUtil.getFullTableNameWithQuotes(schemaName, indexTableName)
+      : SchemaUtil.getTableName(schemaName, indexTableName);
+
+    Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+    try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+      if (namespaceMapped) {
+        conn.createStatement().execute("CREATE SCHEMA " + sSchemaName);
+      }
+      conn.createStatement().execute("CREATE TABLE " + qDataTableName
+        + " (ID INTEGER NOT NULL PRIMARY KEY, VAL1 INTEGER, VAL2 INTEGER) " + 
tableDDLOptions);
+
+      PreparedStatement dataStmt =
+        conn.prepareStatement("UPSERT INTO " + qDataTableName + " 
VALUES(?,?,?)");
+      for (int i = 1; i <= 4; i++) {
+        dataStmt.setInt(1, i);
+        dataStmt.setInt(2, i + 1);
+        dataStmt.setInt(3, i * 2);
+        dataStmt.execute();
+      }
+      conn.commit();
+
+      conn.createStatement()
+        .execute(String.format("CREATE INDEX %s ON %s (VAL1) INCLUDE (VAL2) " 
+ indexDDLOptions,
+          sIndexTableName, qDataTableName));
+
+      // Add extra rows directly to the index table
+      PreparedStatement indexStmt =
+        conn.prepareStatement("UPSERT INTO " + qIndexTableName + " 
VALUES(?,?,?)");
+      for (int i = 10; i <= 12; i++) {
+        indexStmt.setInt(1, i + 1);
+        indexStmt.setInt(2, i);
+        indexStmt.setInt(3, i * 2);
+        indexStmt.execute();
+      }
+      conn.commit();
+
+      // Run index-to-data verification
+      IndexTool indexTool = runIndexTool(false, sSchemaName, sDataTableName, 
sIndexTableName, null,
+        0, IndexTool.IndexVerifyType.ONLY, "-fi");
+
+      CounterGroup mrJobCounters = getMRJobCounters(indexTool);
+      // Extra index rows should be detected
+      if (mutable) {
+        assertEquals(3, mrJobCounters
+          
.findCounter(BEFORE_REPAIR_EXTRA_UNVERIFIED_INDEX_ROW_COUNT.name()).getValue());
+      } else {
+        assertEquals(3, mrJobCounters
+          
.findCounter(BEFORE_REPAIR_EXTRA_VERIFIED_INDEX_ROW_COUNT.name()).getValue());
+      }
+    }
+  }
+
   public static void assertExplainPlan(boolean localIndex, String 
actualExplainPlan,
     String dataTableFullName, String indexTableFullName) {
     assertExplainPlan(localIndex, actualExplainPlan, dataTableFullName, 
indexTableFullName, true);

Reply via email to