You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ja...@apache.org on 2026/07/28 21:30:30 UTC

(pinot) branch master updated: Harden schema case-collision validation with Locale.ROOT (#19089)

This is an automated email from the ASF dual-hosted git repository.

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 7ecf65743e6 Harden schema case-collision validation with Locale.ROOT (#19089)
7ecf65743e6 is described below

commit 7ecf65743e676497d4fad4de0a0fd6098715764c
Author: deepinsight coder <32...@users.noreply.github.com>
AuthorDate: Tue Jul 28 14:30:24 2026 -0700

    Harden schema case-collision validation with Locale.ROOT (#19089)
---
 .../apache/pinot/core/util/SchemaUtilsTest.java    | 29 ++++++++++++++++++++++
 .../pinot/segment/local/utils/SchemaUtils.java     |  8 +++---
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/pinot-core/src/test/java/org/apache/pinot/core/util/SchemaUtilsTest.java b/pinot-core/src/test/java/org/apache/pinot/core/util/SchemaUtilsTest.java
index a335a66fe36..f2d4f07df81 100644
--- a/pinot-core/src/test/java/org/apache/pinot/core/util/SchemaUtilsTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/core/util/SchemaUtilsTest.java
@@ -331,6 +331,35 @@ public class SchemaUtilsTest {
     checkValidationFails(pinotSchema, true);
   }
 
+  /**
+   * Case-only column collisions (e.g. memberId / MemberID) are rejected when case-insensitive mode is on.
+   * Cluster default is enable.case.insensitive=true, so new schemas on default clusters are already protected.
+   * When case-insensitive mode is off, collisions are allowed (always-on rejection needs validation levels #6645).
+   */
+  @Test
+  public void testValidateCaseOnlyColumnCollision() {
+    Schema collidingSchema = new Schema.SchemaBuilder().setSchemaName(TABLE_NAME)
+        .addSingleValueDimension("memberId", DataType.STRING)
+        .addSingleValueDimension("MemberID", DataType.STRING)
+        .addDateTime(TIME_COLUMN, DataType.LONG, "1:MILLISECONDS:EPOCH", "1:MILLISECONDS")
+        .build();
+
+    // Default cluster path: enable.case.insensitive=true rejects case-only collisions
+    checkValidationFails(collidingSchema, true);
+
+    // Case-sensitive mode still allows collisions (compat; do not force always-on without #6645)
+    SchemaUtils.validate(collidingSchema, false);
+
+    // Distinct after lowercasing is fine even when case-insensitive
+    Schema distinctSchema = new Schema.SchemaBuilder().setSchemaName(TABLE_NAME)
+        .addSingleValueDimension("memberId", DataType.STRING)
+        .addSingleValueDimension("memberName", DataType.STRING)
+        .addDateTime(TIME_COLUMN, DataType.LONG, "1:MILLISECONDS:EPOCH", "1:MILLISECONDS")
+        .build();
+    SchemaUtils.validate(distinctSchema, true);
+    SchemaUtils.validate(distinctSchema, false);
+  }
+
   @Test
   public void testValidatePrimaryKeyColumns() {
     Schema pinotSchema;
diff --git a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java
index 7bcfbc053b6..99ec4d9ddc2 100644
--- a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java
+++ b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/SchemaUtils.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
@@ -121,9 +122,10 @@ public class SchemaUtils {
     if (isIgnoreCase) {
       Set<String> lowerCaseColumnNames = new HashSet<>();
       for (String column : schema.getColumnNames()) {
-        Preconditions.checkState(lowerCaseColumnNames.add(column.toLowerCase()),
-            "When enable case insensitive, you can't use the same lowercase column name: %s",
-            column.toLowerCase());
+        // Locale.ROOT avoids locale-dependent lowercasing (e.g. Turkish dotted/dotless I)
+        String lowerCaseColumn = column.toLowerCase(Locale.ROOT);
+        Preconditions.checkState(lowerCaseColumnNames.add(lowerCaseColumn),
+            "When enable case insensitive, you can't use the same lowercase column name: %s", lowerCaseColumn);
       }
     }
     Set<String> transformedColumns = new HashSet<>();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org