This is an automated email from the ASF dual-hosted git repository. yuqi4733 pushed a commit to branch internal-main in repository https://gitbox.apache.org/repos/asf/gravitino.git
commit d3c0e7d5f32914d86edc0d6a59022e421fb0586c Author: Salmane Khalili <[email protected]> AuthorDate: Fri Dec 12 10:39:16 2025 +0100 [#9078] Improvement(core):In SchemaMetaService.java block non-cascading schema deletions when topics still exist (#9465) ## What changes were proposed in this pull request? This PR implements a check to prevent the deletion of non-cascading schemas that still contain topic metadata. ## Why are the changes needed? Currently, schema deletion checks for dependant tables, filesets and models. If the schema contains topics, the deletion proceeds regardless. Leaving orphaned topic metadata in the database. This fix ensures a NonEmptyEntityException is thrown if any active topics are found within the schema. This matches previous checks for other subschema entities. The fix was implemeted through a check in the non cascading branch of deleteSchema method in SchemaMetaService.java. Fix: #9078 ## Does this PR introduce any user-facing change? Nothing more than an error message. ## How was this patch tested? Added testDeleteSchemaNonCascadingFailsWhenTopicExists, to TestSchemaMetaService.java ./gradlew :core:test All tests passed. [#9078] Improvement(core):In SchemaMetaService.java block non-cascading schema deletions when topics still exist --- .../relational/service/SchemaMetaService.java | 13 ++++++++ .../relational/service/TestSchemaMetaService.java | 38 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java b/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java index 44e2e58c7c..c6eb4becf3 100644 --- a/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java +++ b/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java @@ -37,6 +37,7 @@ import org.apache.gravitino.meta.ModelEntity; import org.apache.gravitino.meta.NamespacedEntityId; import org.apache.gravitino.meta.SchemaEntity; import org.apache.gravitino.meta.TableEntity; +import org.apache.gravitino.meta.TopicEntity; import org.apache.gravitino.metrics.Monitored; import org.apache.gravitino.storage.relational.helper.SchemaIds; import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper; @@ -327,6 +328,18 @@ public class SchemaMetaService { "Entity %s has sub-entities, you should remove sub-entities first", identifier); } + List<TopicEntity> topicEntities = + TopicMetaService.getInstance() + .listTopicsByNamespace( + NamespaceUtil.ofTopic( + identifier.namespace().level(0), + identifier.namespace().level(1), + schemaName)); + if (!topicEntities.isEmpty()) { + throw new NonEmptyEntityException( + "Entity %s has sub-entities, you should remove sub-entities first", identifier); + } + SessionUtils.doMultipleWithCommit( () -> SessionUtils.doWithoutCommit( diff --git a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSchemaMetaService.java b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSchemaMetaService.java index 799a21432f..5e9a345ee3 100644 --- a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSchemaMetaService.java +++ b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestSchemaMetaService.java @@ -27,7 +27,9 @@ import java.time.Instant; import java.util.List; import org.apache.gravitino.Entity; import org.apache.gravitino.EntityAlreadyExistsException; +import org.apache.gravitino.exceptions.NonEmptyEntityException; import org.apache.gravitino.meta.SchemaEntity; +import org.apache.gravitino.meta.TopicEntity; import org.apache.gravitino.storage.RandomIdGenerator; import org.apache.gravitino.storage.relational.TestJDBCBackend; import org.apache.gravitino.utils.NameIdentifierUtil; @@ -167,4 +169,40 @@ public class TestSchemaMetaService extends TestJDBCBackend { } assertFalse(legacyRecordExistsInDB(schema.id(), Entity.EntityType.SCHEMA)); } + + @TestTemplate + public void testDeleteSchemlaaNonCascadingFailsWhenTopicExists() throws IOException { + + createAndInsertMakeLake(metalakeName); + createAndInsertCatalog(metalakeName, catalogName); + + SchemaMetaService schemaMetaService = SchemaMetaService.getInstance(); + TopicMetaService topicMetaService = TopicMetaService.getInstance(); + + final String schemaName = "schema_with_topic"; + SchemaEntity schema = + createSchemaEntity( + RandomIdGenerator.INSTANCE.nextId(), + NamespaceUtil.ofSchema(metalakeName, catalogName), + schemaName, + AUDIT_INFO); + schemaMetaService.insertSchema(schema, false); + + final String topicName = "test_topic_dependency"; + TopicEntity topic = + createTopicEntity( + RandomIdGenerator.INSTANCE.nextId(), + NamespaceUtil.ofTopic(metalakeName, catalogName, schemaName), + topicName, + AUDIT_INFO); + topicMetaService.insertTopic(topic, false); + + Assertions.assertThrows( + NonEmptyEntityException.class, + () -> schemaMetaService.deleteSchema(schema.nameIdentifier(), false), + "Non-cascading delete must fail when dependent topics exist."); + + topicMetaService.deleteTopic(topic.nameIdentifier()); + schemaMetaService.deleteSchema(schema.nameIdentifier(), false); + } }
