This is an automated email from the ASF dual-hosted git repository.
preetham02 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git
The following commit(s) were added to refs/heads/master by this push:
new 242011f380 [NO ISSUE][EXT]: ensure no dependent collections on catalog
drop
242011f380 is described below
commit 242011f380fbc49cde244087a4c117155ea74e2e
Author: Hussain Towaileb <[email protected]>
AuthorDate: Wed Feb 4 13:06:02 2026 +0300
[NO ISSUE][EXT]: ensure no dependent collections on catalog drop
Ext-ref: MB-70463
Change-Id: I52bafb87fbe5fb856a6220ee11b2bf985bc3b70c
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/20866
Reviewed-by: Hussain Towaileb <[email protected]>
Integration-Tests: Jenkins <[email protected]>
Tested-by: Jenkins <[email protected]>
Reviewed-by: Ali Alsuliman <[email protected]>
---
.../handlers/CatalogStatementHandler.java | 26 ++--------
.../catalog-already-exists/test.001.ddl.sqlpp | 20 ++++++++
.../test.000.ddl.sqlpp | 59 ++++++++++++++++++++++
.../test.001.ddl.sqlpp | 22 ++++++++
.../test/resources/runtimets/testsuite_iceberg.xml | 6 +++
.../org/apache/asterix/metadata/MetadataNode.java | 30 +++++++++++
6 files changed, 141 insertions(+), 22 deletions(-)
diff --git
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/handlers/CatalogStatementHandler.java
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/handlers/CatalogStatementHandler.java
index 8c33407e44..3f88893404 100644
---
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/handlers/CatalogStatementHandler.java
+++
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/translator/handlers/CatalogStatementHandler.java
@@ -49,7 +49,6 @@ import org.apache.asterix.metadata.utils.Creator;
import org.apache.asterix.object.base.AdmObjectNode;
import org.apache.asterix.translator.SessionConfig;
import org.apache.hyracks.algebricks.common.exceptions.AlgebricksException;
-import org.apache.hyracks.api.exceptions.SourceLocation;
public class CatalogStatementHandler {
@@ -119,8 +118,8 @@ public class CatalogStatementHandler {
validateCatalogType(statement.getCatalogType());
validateCatalogProperties(statement, mdTxnCtx, metadataProvider);
- beforeAddTxnCommit(metadataProvider, creator,
EntityDetails.newCatalog(catalogName));
MetadataManager.INSTANCE.addCatalog(mdTxnCtx,
getCatalog(statement));
+ beforeAddTxnCommit(metadataProvider, creator,
EntityDetails.newCatalog(catalogName));
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
return true;
} catch (Exception e) {
@@ -149,24 +148,8 @@ public class CatalogStatementHandler {
metadataProvider.setMetadataTxnContext(mdTxnCtx);
try {
String catalogName = statement.getCatalogName();
- Catalog catalog = MetadataManager.INSTANCE.getCatalog(mdTxnCtx,
catalogName);
- if (catalog == null) {
- if (statement.getIfExists()) {
- MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
- return false;
- } else {
- SourceLocation srcLoc = statement.getSourceLocation();
- throw new CompilationException(ErrorCode.UNKNOWN_CATALOG,
srcLoc, catalogName);
- }
- }
-
- // if we have any collections on catalog without cascade passed,
we fail the drop, so check one only
- // otherwise, list all so we drop them all
- // TODO(htowaileb): list collections on catalog to drop
- boolean firstOnly = !statement.isCascade();
-
- beforeDropTxnCommit(metadataProvider, creator,
EntityDetails.newCatalog(catalogName));
MetadataManager.INSTANCE.dropCatalog(mdTxnCtx, catalogName);
+ beforeDropTxnCommit(metadataProvider, creator,
EntityDetails.newCatalog(catalogName));
MetadataManager.INSTANCE.commitTransaction(mdTxnCtx);
return true;
} catch (Exception e) {
@@ -220,7 +203,7 @@ public class CatalogStatementHandler {
*/
protected IcebergCatalog createIcebergCatalog(CatalogCreateStatement
statement) throws AlgebricksException {
IcebergCatalogCreateStatement icebergStatement =
(IcebergCatalogCreateStatement) statement;
- IcebergCatalogDetailsDecl detailsDecl = (IcebergCatalogDetailsDecl)
icebergStatement.getCatalogDetailsDecl();
+ IcebergCatalogDetailsDecl detailsDecl =
icebergStatement.getCatalogDetailsDecl();
Map<String, String> properties =
createCatalogDetailsProperties(icebergStatement);
IcebergCatalogDetails details = new
IcebergCatalogDetails(detailsDecl.getAdapter(), properties);
return new IcebergCatalog(statement.getCatalogName(),
statement.getCatalogType(), details,
@@ -230,8 +213,7 @@ public class CatalogStatementHandler {
protected Map<String, String>
createCatalogDetailsProperties(IcebergCatalogCreateStatement statement)
throws AlgebricksException {
AdmObjectNode withObjectNode = statement.getWithObjectNode();
- IcebergCatalogDetailsDecl icebergCatalogDetailsDecl =
- (IcebergCatalogDetailsDecl) statement.getCatalogDetailsDecl();
+ IcebergCatalogDetailsDecl icebergCatalogDetailsDecl =
statement.getCatalogDetailsDecl();
Map<String, String> properties = new
HashMap<>(icebergCatalogDetailsDecl.getProperties());
Map<String, String> withClauseProperties = ExternalDataUtils
.convertStringArrayParamIntoNumberedParameters(withObjectNode,
statement.getSourceLocation());
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/catalog-already-exists/test.001.ddl.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/catalog-already-exists/test.001.ddl.sqlpp
new file mode 100644
index 0000000000..75d7436298
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/catalog-already-exists/test.001.ddl.sqlpp
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+DROP CATALOG myGlueCatalog;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/drop-has-dependent-collections/test.000.ddl.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/drop-has-dependent-collections/test.000.ddl.sqlpp
new file mode 100644
index 0000000000..7532b5ebcc
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/drop-has-dependent-collections/test.000.ddl.sqlpp
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+CREATE CATALOG myGlueCatalog
+TYPE Iceberg
+SOURCE AWS_GLUE
+WITH {
+ "warehouse": "s3://cbas-iceberg-playground/my-glue-catalog/warehouse/",
+ "accessKeyId" : "myAccessKeyId",
+ "secretAccessKey" : "mySecretAccessKey",
+ "region" : "us-west-2"
+};
+
+CREATE TYPE test AS OPEN {};
+CREATE EXTERNAL COLLECTION test(test) USING S3
+(
+ ("table-format"="iceberg"),
+ ("namespace"="glue_namespace"),
+ ("tableName"="users"),
+ ("accessKeyId"="fakeAccessKeyId"),
+ ("secretAccessKey"="fakeSecretAccessKey"),
+ ("region"="eu-central-1"),
+ ("catalogName"="myGlueCatalog"),
+ ("format"="parquet"),
+ ("decimal-to-double"="true")
+
+);
+
+CREATE EXTERNAL COLLECTION test2(test) USING S3
+(
+ ("table-format"="iceberg"),
+ ("namespace"="glue_namespace"),
+ ("tableName"="users"),
+ ("accessKeyId"="fakeAccessKeyId"),
+ ("secretAccessKey"="fakeSecretAccessKey"),
+ ("region"="eu-central-1"),
+ ("catalogName"="myGlueCatalog"),
+ ("format"="parquet"),
+ ("decimal-to-double"="true")
+
+);
+
+DROP CATALOG myGlueCatalog;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/drop-has-dependent-collections/test.001.ddl.sqlpp
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/drop-has-dependent-collections/test.001.ddl.sqlpp
new file mode 100644
index 0000000000..6ee0d0950a
--- /dev/null
+++
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/iceberg/catalog/negative/drop-has-dependent-collections/test.001.ddl.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+DROP COLLECTION test IF EXISTS;
+DROP COLLECTION test2 IF EXISTS;
+DROP CATALOG myGlueCatalog IF EXISTS;
\ No newline at end of file
diff --git
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_iceberg.xml
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_iceberg.xml
index e314d27d0e..d567e211a1 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_iceberg.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_iceberg.xml
@@ -59,5 +59,11 @@
<expected-error>ASX1227: Cannot find catalog with name
myDoesNotExistGlueCatalog</expected-error>
</compilation-unit>
</test-case>
+ <test-case FilePath="iceberg/catalog/negative">
+ <compilation-unit name="drop-has-dependent-collections">
+ <output-dir compare="Text">drop-has-dependent-collections</output-dir>
+ <expected-error>ASX1148: Cannot drop catalog myGlueCatalog being used
by collection Default.Default.test</expected-error>
+ </compilation-unit>
+ </test-case>
</test-group>
</test-suite>
diff --git
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
index e1c1f6e8cd..6060d94408 100644
---
a/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
+++
b/asterixdb/asterix-metadata/src/main/java/org/apache/asterix/metadata/MetadataNode.java
@@ -58,6 +58,7 @@ import static
org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_NODEGROUP;
import static org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_SYNONYM;
import static org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_TYPE;
import static org.apache.asterix.common.utils.IdentifierUtil.dataset;
+import static
org.apache.asterix.external.util.iceberg.IcebergConstants.ICEBERG_CATALOG_NAME;
import java.io.PrintStream;
import java.rmi.RemoteException;
@@ -72,10 +73,12 @@ import java.util.stream.Collectors;
import org.apache.asterix.common.api.IApplicationContext;
import org.apache.asterix.common.api.IDatasetLifecycleManager;
import org.apache.asterix.common.api.INcApplicationContext;
+import org.apache.asterix.common.config.DatasetConfig;
import org.apache.asterix.common.config.DatasetConfig.DatasetType;
import org.apache.asterix.common.dataflow.LSMIndexUtil;
import org.apache.asterix.common.exceptions.ACIDException;
import org.apache.asterix.common.exceptions.AsterixException;
+import org.apache.asterix.common.exceptions.CompilationException;
import org.apache.asterix.common.exceptions.MetadataException;
import org.apache.asterix.common.exceptions.NoOpWarningCollector;
import org.apache.asterix.common.functions.FunctionSignature;
@@ -117,6 +120,7 @@ import
org.apache.asterix.metadata.entities.DatasourceAdapter;
import org.apache.asterix.metadata.entities.Datatype;
import org.apache.asterix.metadata.entities.Dataverse;
import org.apache.asterix.metadata.entities.DependencyKind;
+import org.apache.asterix.metadata.entities.ExternalDatasetDetails;
import org.apache.asterix.metadata.entities.Feed;
import org.apache.asterix.metadata.entities.FeedConnection;
import org.apache.asterix.metadata.entities.FeedPolicyEntity;
@@ -3192,6 +3196,13 @@ public class MetadataNode implements IMetadataNode {
@Override
public void dropCatalog(TxnId txnId, String catalogName) throws
AlgebricksException, RemoteException {
try {
+ Catalog catalog = getCatalog(txnId, catalogName);
+ if (catalog == null) {
+ throw new
CompilationException(org.apache.asterix.common.exceptions.ErrorCode.UNKNOWN_CATALOG,
+ catalogName);
+ }
+ confirmCatalogIsUnusedByCollections(txnId, catalogName);
+
// delete the catalog entry from the 'Catalog' collection
ITupleReference searchKey = createTuple(catalogName);
MetadataIndex catalogIndex =
mdIndexesProvider.getCatalogEntity().getIndex();
@@ -3205,4 +3216,23 @@ public class MetadataNode implements IMetadataNode {
}
}
}
+
+ private void confirmCatalogIsUnusedByCollections(TxnId txnId, String
catalogName) throws AlgebricksException {
+ List<Dataset> allCollections = getAllDatasets(txnId);
+ for (Dataset collection : allCollections) {
+ if (collection.getDatasetType() !=
DatasetConfig.DatasetType.EXTERNAL) {
+ continue;
+ }
+ ExternalDatasetDetails details = (ExternalDatasetDetails)
collection.getDatasetDetails();
+ String collectionCatalogName =
details.getProperties().get(ICEBERG_CATALOG_NAME);
+ if (!catalogName.equals(collectionCatalogName)) {
+ continue;
+ }
+ String database = collection.getDatabaseName();
+ String dataverseName =
collection.getDataverseName().getCanonicalForm();
+ String collectionName = collection.getDatasetName();
+ throw new AsterixException(CANNOT_DROP_OBJECT_DEPENDENT_EXISTS,
"catalog", catalogName, "collection",
+ String.join(".", database, dataverseName, collectionName));
+ }
+ }
}