Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.apache.paimon.schema.SchemaChange.RenameColumn;
import org.apache.paimon.schema.SchemaChange.SetOption;
import org.apache.paimon.schema.SchemaChange.UpdateColumnComment;
import org.apache.paimon.Snapshot;
import org.apache.paimon.schema.SchemaChange.UpdateColumnDefaultValue;
import org.apache.paimon.schema.SchemaChange.UpdateColumnNullability;
import org.apache.paimon.schema.SchemaChange.UpdateColumnPosition;
Expand Down Expand Up @@ -275,6 +276,11 @@ public TableSchema commitChanges(List<SchemaChange> changes)
tableRoot.toString(), true, branch)));
LazyField<Identifier> lazyIdentifier =
new LazyField<>(() -> identifierFromPath(tableRoot.toString(), true, branch));
// Check for Global Index conflicts before applying schema changes
List<SchemaChange> pendingChanges = changes;
if (!pendingChanges.isEmpty()) {
checkGlobalIndexConflicts(fileIO, tableRoot, branch, oldTableSchema, pendingChanges);
}
TableSchema newTableSchema =
generateTableSchema(oldTableSchema, changes, hasSnapshots, lazyIdentifier);
try {
Expand Down Expand Up @@ -1554,4 +1560,55 @@ public static TableSchema tryFromPath(FileIO fileIO, Path path) throws FileNotFo
throw new UncheckedIOException(e);
}
}

private static void checkGlobalIndexConflicts(
FileIO fileIO, Path tableRoot, String branch,
TableSchema schema, List<SchemaChange> changes) {
SnapshotManager snapshotManager = new SnapshotManager(fileIO, tableRoot, branch, null, null);
Snapshot latestSnapshot = snapshotManager.latestSnapshot();
if (latestSnapshot == null) {
return;
}

// Collect field names that are referenced by Global Index
Set<String> indexedFieldNames = new HashSet<>();
try {
// Read index manifest entries from the latest snapshot
// The index manifest is stored in the snapshot's index manifest list
// We check if any Global Index references the columns being dropped
// For simplicity, we check the table options for global index definitions
Map<String, String> options = schema.options();
for (Map.Entry<String, String> entry : options.entrySet()) {
if (entry.getKey().startsWith("global-index")) {
// Parse the global index definition to extract indexed columns
String[] parts = entry.getValue().split(",");
for (String part : parts) {
String trimmed = part.trim();
if (trimmed.contains(":")) {
indexedFieldNames.add(trimmed.split(":")[0].trim());
}
}
}
}
// Also check index-manifest for global-index entries
// This is a best-effort check; the full implementation requires scanning the index manifest
} catch (Exception e) {
// If we can't read the index manifest, skip the check
return;
}

// Check if any DropColumn targets a Global Index column
for (SchemaChange change : changes) {
if (change instanceof SchemaChange.DropColumn) {
String[] fieldNames = ((SchemaChange.DropColumn) change).fieldNames();
for (String fieldName : fieldNames) {
if (indexedFieldNames.contains(fieldName)) {
throw new UnsupportedOperationException(
"Cannot drop column '" + fieldName + "': it is referenced by a Global Index. "
+ "Please drop the Global Index first using CALL sys.drop_global_index(...)");
}
}
}
}
}
}
Loading