This is an automated email from the ASF dual-hosted git repository. yuqi1129 pushed a commit to branch cherry-pick-27201d34-to-branch-1.3 in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit 0e462b225e261dec0c01b62f324f6fc63cfc30d1 Author: yuqi <[email protected]> AuthorDate: Tue Nov 3 10:12:52 2026 +0800 fix(backport): adapt schema identity checks to branch 1.3 --- .../catalog/SchemaOperationDispatcher.java | 4 +- .../catalog/TestSchemaOperationDispatcher.java | 48 +++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java b/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java index 833b317a20..298fd91455 100644 --- a/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java +++ b/core/src/main/java/org/apache/gravitino/catalog/SchemaOperationDispatcher.java @@ -22,6 +22,7 @@ import static org.apache.gravitino.Entity.EntityType.SCHEMA; import static org.apache.gravitino.catalog.PropertiesMetadataHelpers.validatePropertyForCreate; import static org.apache.gravitino.utils.NameIdentifierUtil.getCatalogIdentifier; +import java.io.IOException; import java.time.Instant; import java.util.Map; import org.apache.gravitino.EntityAlreadyExistsException; @@ -449,7 +450,8 @@ public class SchemaOperationDispatcher extends OperationDispatcher implements Sc SCHEMA, existing -> { if (!existing.id().equals(schemaEntity.id())) { - throw new OptimisticLockException("Schema identifier changed during import"); + throw new IllegalStateException( + "Schema identifier changed during import: " + identifier); } return schemaEntity; }); diff --git a/core/src/test/java/org/apache/gravitino/catalog/TestSchemaOperationDispatcher.java b/core/src/test/java/org/apache/gravitino/catalog/TestSchemaOperationDispatcher.java index 23bd391d62..5805a4b66d 100644 --- a/core/src/test/java/org/apache/gravitino/catalog/TestSchemaOperationDispatcher.java +++ b/core/src/test/java/org/apache/gravitino/catalog/TestSchemaOperationDispatcher.java @@ -24,6 +24,7 @@ import static org.apache.gravitino.TestBasePropertiesMetadata.COMMENT_KEY; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -37,6 +38,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.gravitino.Config; import org.apache.gravitino.Configs; @@ -50,6 +52,7 @@ import org.apache.gravitino.SchemaChange; import org.apache.gravitino.StringIdentifier; import org.apache.gravitino.auth.AuthConstants; import org.apache.gravitino.exceptions.NoSuchEntityException; +import org.apache.gravitino.exceptions.SchemaAlreadyExistsException; import org.apache.gravitino.lock.LockManager; import org.apache.gravitino.meta.AuditInfo; import org.apache.gravitino.meta.SchemaEntity; @@ -78,7 +81,7 @@ public class TestSchemaOperationDispatcher extends TestOperationDispatcher { NameIdentifier renamed = NameIdentifier.of(metalake, catalog, "external_rename_new"); dispatcher.createSchema(original, "original", ImmutableMap.of("k1", "v1", "k2", "v2")); SchemaEntity originalEntity = entityStore.get(original, SCHEMA, SchemaEntity.class); - Map<String, String> properties = new HashMap<>(originalEntity.properties()); + Map<String, String> properties = new HashMap<>(); properties.put("k1", "v1"); properties.put("k2", "v2"); properties.put(ID_KEY, StringIdentifier.fromId(originalEntity.id()).toString()); @@ -98,6 +101,49 @@ public class TestSchemaOperationDispatcher extends TestOperationDispatcher { Assertions.assertFalse(entityStore.exists(original, SCHEMA)); } + @Test + void testExternalRenameRejectsChangedSchemaIdentity() throws Exception { + NameIdentifier original = NameIdentifier.of(metalake, catalog, "replaced_original"); + NameIdentifier renamed = NameIdentifier.of(metalake, catalog, "replaced_renamed"); + dispatcher.createSchema(original, "original", ImmutableMap.of("k1", "v1", "k2", "v2")); + SchemaEntity originalEntity = entityStore.get(original, SCHEMA, SchemaEntity.class); + Map<String, String> properties = new HashMap<>(); + properties.put("k1", "v1"); + properties.put("k2", "v2"); + properties.put(ID_KEY, StringIdentifier.fromId(originalEntity.id()).toString()); + catalogManager.doWithCatalogWrapper( + NameIdentifier.of(metalake, catalog), + c -> { + c.doWithSchemaOps( + ops -> { + ops.dropSchema(original, false); + return ops.createSchema(renamed, "renamed", properties); + }); + return null; + }); + SchemaEntity replacement = + SchemaEntity.builder() + .withId(originalEntity.id() + 1) + .withName(original.name()) + .withNamespace(original.namespace()) + .withAuditInfo(originalEntity.auditInfo()) + .build(); + doAnswer( + invocation -> { + Function<SchemaEntity, SchemaEntity> updater = invocation.getArgument(3); + return updater.apply(replacement); + }) + .when(entityStore) + .update(eq(original), eq(SchemaEntity.class), eq(SCHEMA), any()); + RuntimeException error = + Assertions.assertThrows(RuntimeException.class, () -> dispatcher.loadSchema(renamed)); + Assertions.assertInstanceOf(IllegalStateException.class, error.getCause()); + Assertions.assertTrue(error.getCause().getMessage().contains(renamed.toString())); + Assertions.assertEquals( + originalEntity.id(), entityStore.get(original, SCHEMA, SchemaEntity.class).id()); + Assertions.assertFalse(entityStore.exists(renamed, SCHEMA)); + } + @Test void testCopiedSchemaIdentifierCannotMoveExistingEntity() throws Exception { NameIdentifier original = NameIdentifier.of(metalake, catalog, "marker_original");
