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

KKcorps 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 391f814e52c Add backward-incompatibility check for upsert 
deleteRecordColumn (#18552)
391f814e52c is described below

commit 391f814e52ca18960f6470413e8a0a86cb484264
Author: Mayank Shrivastava <[email protected]>
AuthorDate: Thu May 21 07:40:43 2026 -0700

    Add backward-incompatibility check for upsert deleteRecordColumn (#18552)
---
 .../segment/local/utils/TableConfigUtils.java      | 73 +++++++++++-----------
 .../segment/local/utils/TableConfigUtilsTest.java  | 55 ++++++++++++++++
 2 files changed, 93 insertions(+), 35 deletions(-)

diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java
index 31bea7e4a70..dc1d82c458f 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/utils/TableConfigUtils.java
@@ -1327,44 +1327,47 @@ public final class TableConfigUtils {
       UpsertConfig existingUpsertConfig = existingConfig.getUpsertConfig();
       UpsertConfig newUpsertConfig = newConfig.getUpsertConfig();
 
-      if (existingUpsertConfig.getMode() != newUpsertConfig.getMode()) {
+    if (existingUpsertConfig.getMode() != newUpsertConfig.getMode()) {
+      violations.add(
+          String.format("upsertConfig.mode (%s -> %s)", 
existingUpsertConfig.getMode(), newUpsertConfig.getMode()));
+    }
+    if (existingUpsertConfig.getHashFunction() != 
newUpsertConfig.getHashFunction()) {
+      violations.add(String.format("upsertConfig.hashFunction (%s -> %s)", 
existingUpsertConfig.getHashFunction(),
+          newUpsertConfig.getHashFunction()));
+    }
+    if (!Objects.equals(existingUpsertConfig.getComparisonColumns(), 
newUpsertConfig.getComparisonColumns())) {
+      violations.add(
+          String.format("upsertConfig.comparisonColumns (%s -> %s)", 
existingUpsertConfig.getComparisonColumns(),
+              newUpsertConfig.getComparisonColumns()));
+    }
+    List<String> existingComparisonColumns = 
existingUpsertConfig.getComparisonColumns();
+    if (existingComparisonColumns == null || 
existingComparisonColumns.isEmpty()) {
+      String existingTimeColumn =
+          existingConfig.getValidationConfig() != null ? 
existingConfig.getValidationConfig().getTimeColumnName()
+              : null;
+      String newTimeColumn =
+          newConfig.getValidationConfig() != null ? 
newConfig.getValidationConfig().getTimeColumnName() : null;
+      if (!Objects.equals(existingTimeColumn, newTimeColumn)) {
         violations.add(
-            String.format("upsertConfig.mode (%s -> %s)", 
existingUpsertConfig.getMode(), newUpsertConfig.getMode()));
-      }
-      if (existingUpsertConfig.getHashFunction() != 
newUpsertConfig.getHashFunction()) {
-        violations.add(String.format("upsertConfig.hashFunction (%s -> %s)", 
existingUpsertConfig.getHashFunction(),
-            newUpsertConfig.getHashFunction()));
-      }
-      if (!Objects.equals(existingUpsertConfig.getComparisonColumns(),
-          newUpsertConfig.getComparisonColumns())) {
-        violations.add(
-            String.format("upsertConfig.comparisonColumns (%s -> %s)", 
existingUpsertConfig.getComparisonColumns(),
-                newUpsertConfig.getComparisonColumns()));
-      }
-      List<String> existingComparisonColumns = 
existingUpsertConfig.getComparisonColumns();
-      if (existingComparisonColumns == null || 
existingComparisonColumns.isEmpty()) {
-        String existingTimeColumn =
-            existingConfig.getValidationConfig() != null ? 
existingConfig.getValidationConfig().getTimeColumnName()
-                : null;
-        String newTimeColumn =
-            newConfig.getValidationConfig() != null ? 
newConfig.getValidationConfig().getTimeColumnName() : null;
-        if (!Objects.equals(existingTimeColumn, newTimeColumn)) {
-          violations.add(
-              String.format("timeColumnName (%s -> %s) - used as default 
comparison column", existingTimeColumn,
-                  newTimeColumn));
-        }
-      }
-      if (existingUpsertConfig.isDropOutOfOrderRecord() != 
newUpsertConfig.isDropOutOfOrderRecord()) {
-        violations.add(
-            String.format("upsertConfig.dropOutOfOrderRecord (%s -> %s)", 
existingUpsertConfig.isDropOutOfOrderRecord(),
-                newUpsertConfig.isDropOutOfOrderRecord()));
-      }
-      if (!Objects.equals(existingUpsertConfig.getOutOfOrderRecordColumn(),
-          newUpsertConfig.getOutOfOrderRecordColumn())) {
-        violations.add(String.format("upsertConfig.outOfOrderRecordColumn (%s 
-> %s)",
-            existingUpsertConfig.getOutOfOrderRecordColumn(), 
newUpsertConfig.getOutOfOrderRecordColumn()));
+            String.format("timeColumnName (%s -> %s) - used as default 
comparison column", existingTimeColumn,
+                newTimeColumn));
       }
     }
+    if (existingUpsertConfig.isDropOutOfOrderRecord() != 
newUpsertConfig.isDropOutOfOrderRecord()) {
+      violations.add(
+          String.format("upsertConfig.dropOutOfOrderRecord (%s -> %s)", 
existingUpsertConfig.isDropOutOfOrderRecord(),
+              newUpsertConfig.isDropOutOfOrderRecord()));
+    }
+    if (!Objects.equals(existingUpsertConfig.getOutOfOrderRecordColumn(),
+        newUpsertConfig.getOutOfOrderRecordColumn())) {
+      violations.add(String.format("upsertConfig.outOfOrderRecordColumn (%s -> 
%s)",
+          existingUpsertConfig.getOutOfOrderRecordColumn(), 
newUpsertConfig.getOutOfOrderRecordColumn()));
+    }
+    if (!Objects.equals(existingUpsertConfig.getDeleteRecordColumn(), 
newUpsertConfig.getDeleteRecordColumn())) {
+      violations.add(String.format("upsertConfig.deleteRecordColumn (%s -> 
%s)",
+          existingUpsertConfig.getDeleteRecordColumn(), 
newUpsertConfig.getDeleteRecordColumn()));
+    }
+    }
   }
 
   /**
diff --git 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/TableConfigUtilsTest.java
 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/TableConfigUtilsTest.java
index b6eac19916d..68555e127a9 100644
--- 
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/TableConfigUtilsTest.java
+++ 
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/utils/TableConfigUtilsTest.java
@@ -4206,4 +4206,59 @@ public class TableConfigUtilsTest {
     assertTrue(violations.isEmpty(),
         "Expected no violations for partial-upsert strategy and 
default-strategy changes, but got: " + violations);
   }
+
+  @Test
+  public void 
testValidateBackwardCompatibilityRejectsDeleteRecordColumnChange() {
+    UpsertConfig existingUpsertConfig = new 
UpsertConfig(UpsertConfig.Mode.FULL);
+    existingUpsertConfig.setDeleteRecordColumn("deleted");
+    UpsertConfig newUpsertConfig = new UpsertConfig(UpsertConfig.Mode.FULL);
+    newUpsertConfig.setDeleteRecordColumn("is_deleted");
+
+    TableConfig existingConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        
.setTimeColumnName(TIME_COLUMN).setUpsertConfig(existingUpsertConfig).build();
+    TableConfig newConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        
.setTimeColumnName(TIME_COLUMN).setUpsertConfig(newUpsertConfig).build();
+
+    List<String> violations = 
TableConfigUtils.validateBackwardCompatibility(newConfig, existingConfig);
+    assertEquals(violations.size(), 1);
+    assertTrue(violations.get(0).contains("deleteRecordColumn"));
+
+    // Adding deleteRecordColumn where none existed
+    existingUpsertConfig.setDeleteRecordColumn(null);
+    existingConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        
.setTimeColumnName(TIME_COLUMN).setUpsertConfig(existingUpsertConfig).build();
+    violations = TableConfigUtils.validateBackwardCompatibility(newConfig, 
existingConfig);
+    assertEquals(violations.size(), 1);
+    assertTrue(violations.get(0).contains("deleteRecordColumn"));
+
+    // Removing deleteRecordColumn
+    violations = 
TableConfigUtils.validateBackwardCompatibility(existingConfig, newConfig);
+    assertEquals(violations.size(), 1);
+    assertTrue(violations.get(0).contains("deleteRecordColumn"));
+  }
+
+  @Test
+  public void testValidateBackwardCompatibilityAllowsIdenticalUpsertConfig() {
+    UpsertConfig upsertConfig = new UpsertConfig(UpsertConfig.Mode.FULL);
+    upsertConfig.setDeleteRecordColumn("deleted");
+
+    TableConfig existingConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        .setTimeColumnName(TIME_COLUMN).setUpsertConfig(upsertConfig).build();
+    TableConfig newConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        .setTimeColumnName(TIME_COLUMN).setUpsertConfig(upsertConfig).build();
+
+    List<String> violations = 
TableConfigUtils.validateBackwardCompatibility(newConfig, existingConfig);
+    assertTrue(violations.isEmpty(), "Expected no violations for identical 
config, but got: " + violations);
+  }
+
+  @Test
+  public void 
testValidateBackwardCompatibilityNoViolationsForNonUpsertTables() {
+    TableConfig existingConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        .setTimeColumnName(TIME_COLUMN).build();
+    TableConfig newConfig = new 
TableConfigBuilder(TableType.REALTIME).setTableName(TABLE_NAME)
+        .setTimeColumnName(TIME_COLUMN).build();
+
+    List<String> violations = 
TableConfigUtils.validateBackwardCompatibility(newConfig, existingConfig);
+    assertTrue(violations.isEmpty(), "Expected no violations for non-upsert 
tables, but got: " + violations);
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to