diff --git a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java index 3a0e7608e6..f1820ae3cb 100644 --- a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java +++ b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java @@ -1158,8 +1158,42 @@ private void drop_database_core(RawStore ms, } if (tables != null && !tables.isEmpty()) { - for (Table table : tables) { + Iterator it = tables.iterator(); + while (it.hasNext()) { + // First pass deletes the materialized views + Table table = it.next(); + if (MetaStoreUtils.isMaterializedViewTable(table)) { + CreationMetadata cm = table.getCreationMetadata(); + for (String tableName : cm.getTablesUsed()) { + String[] names = tableName.split("\\."); + if (!names[0].equals(name)) { + throw new MetaException("Materialized view " + table.getTableName() + " uses table from a " + + "different database " + names[0] + ". The materialized view should be explicitly dropped " + + "before dropping this database"); + } + } + // The table might not be in a subdirectory of the database, hence add its locations + // to the list of paths to delete + Path tablePath = null; + if (table.getSd().getLocation() != null) { + tablePath = wh.getDnsPath(new Path(table.getSd().getLocation())); + if (!wh.isWritable(tablePath.getParent())) { + throw new MetaException("Database metadata not deleted since table: " + + table.getTableName() + " has a parent location " + tablePath.getParent() + + " which is not writable by " + SecurityUtils.getUser()); + } + if (!isSubdirectory(databasePath, tablePath)) { + tablePaths.add(tablePath); + } + } + // Drop the table but not its data + drop_table(name, table.getTableName(), false); + // Remove from list + it.remove(); + } + } + for (Table table : tables) { // If the table is not external and it might not be in a subdirectory of the database // add it's locations to the list of paths to delete Path tablePath = null; diff --git a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java index 1755700b0e..03a49df2cd 100644 --- a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java +++ b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStoreClient.java @@ -907,17 +907,6 @@ public void dropDatabase(String name, boolean deleteData, boolean ignoreUnknownD return; } - if (cascade) { - List tableList = getAllTables(name); - for (String table : tableList) { - try { - // Subclasses can override this step (for example, for temporary tables) - dropTable(name, table, deleteData, true); - } catch (UnsupportedOperationException e) { - // Ignore Index tables, those will be dropped with parent tables - } - } - } client.drop_database(name, deleteData, cascade); } diff --git a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java index 88d88ed4df..d7dfc1c96b 100644 --- a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java +++ b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/ObjectStore.java @@ -1655,7 +1655,13 @@ private MTable getMTable(String db, String table) { query.declareParameters("java.lang.String db, java.util.Collection tbl_names"); Collection mtables = (Collection) query.execute(db, lowered_tbl_names); for (Iterator iter = mtables.iterator(); iter.hasNext();) { - tables.add(convertToTable((MTable) iter.next())); + Table tbl = convertToTable((MTable) iter.next()); + // Retrieve creation metadata if needed + if (TableType.MATERIALIZED_VIEW.toString().equals(tbl.getTableType())) { + tbl.setCreationMetadata( + convertToCreationMetadata(getCreationMetadata(tbl.getDbName(), tbl.getTableName()))); + } + tables.add(tbl); } committed = commitTransaction(); } finally { diff --git a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/client/builder/TableBuilder.java b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/client/builder/TableBuilder.java index 2b9f816960..f229513f37 100644 --- a/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/client/builder/TableBuilder.java +++ b/standalone-metastore/src/main/java/org/apache/hadoop/hive/metastore/client/builder/TableBuilder.java @@ -18,6 +18,7 @@ package org.apache.hadoop.hive.metastore.client.builder; import org.apache.hadoop.hive.metastore.TableType; +import org.apache.hadoop.hive.metastore.api.CreationMetadata; import org.apache.hadoop.hive.metastore.api.Database; import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.metastore.api.MetaException; @@ -37,6 +38,7 @@ */ public class TableBuilder extends StorageDescriptorBuilder { private String dbName, tableName, owner, viewOriginalText, viewExpandedText, type; + private CreationMetadata cm; private List partCols; private int createTime, lastAccessTime, retention; private Map tableParams; @@ -87,6 +89,11 @@ public TableBuilder setType(String type) { return this; } + public TableBuilder setCreationMetadata(CreationMetadata cm) { + this.cm = cm; + return this; + } + public TableBuilder setPartCols(List partCols) { this.partCols = partCols; return this; @@ -155,6 +162,9 @@ public Table build() throws MetaException { if (rewriteEnabled) { t.setRewriteEnabled(true); } + if (cm != null) { + t.setCreationMetadata(cm); + } if (temporary) { t.setTemporary(temporary); } diff --git a/standalone-metastore/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetaStore.java b/standalone-metastore/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetaStore.java index 7091c5b2f5..cde90d355d 100644 --- a/standalone-metastore/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetaStore.java +++ b/standalone-metastore/src/test/java/org/apache/hadoop/hive/metastore/TestHiveMetaStore.java @@ -39,6 +39,8 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import com.google.common.collect.Sets; +import org.apache.hadoop.hive.metastore.api.CreationMetadata; import org.apache.hadoop.hive.metastore.client.builder.DatabaseBuilder; import org.apache.hadoop.hive.metastore.client.builder.TableBuilder; import org.apache.hadoop.hive.metastore.conf.MetastoreConf; @@ -2726,6 +2728,19 @@ private void createTable(String dbName, String tableName) throws TException { client.createTable(t); } + private void createMaterializedView(String dbName, String tableName, Set tablesUsed) + throws TException { + Table t = new TableBuilder() + .setDbName(dbName) + .setTableName(tableName) + .setType(TableType.MATERIALIZED_VIEW.name()) + .setCreationMetadata(new CreationMetadata(dbName, tableName, tablesUsed)) + .addCol("foo", "string") + .addCol("bar", "string") + .build(); + client.createTable(t); + } + private List createPartitions(String dbName, Table tbl, List> values) throws Throwable { int i = 1; @@ -2833,6 +2848,7 @@ public void testGetTableObjects() throws Exception { for (String tableName : tableNames) { createTable(dbName, tableName); } + createMaterializedView(dbName, "mv1", Sets.newHashSet("db.table1", "db.table2")); // Test List
tableObjs = client.getTableObjectsByName(dbName, tableNames); @@ -2847,6 +2863,45 @@ public void testGetTableObjects() throws Exception { client.dropDatabase(dbName, true, true, true); } + @Test + public void testDropDatabaseCascadeMVMultiDB() throws Exception { + String dbName1 = "db1"; + String tableName1 = "table1"; + String dbName2 = "db2"; + String tableName2 = "table2"; + String mvName = "mv1"; + + // Setup + silentDropDatabase(dbName1); + silentDropDatabase(dbName2); + + Database db1 = new Database(); + db1.setName(dbName1); + client.createDatabase(db1); + createTable(dbName1, tableName1); + Database db2 = new Database(); + db2.setName(dbName2); + client.createDatabase(db2); + createTable(dbName2, tableName2); + + createMaterializedView(dbName2, mvName, Sets.newHashSet("db1.table1", "db2.table2")); + + boolean exceptionFound = false; + try { + client.dropDatabase(dbName2, true, true, true); + } catch (Exception e) { + assertEquals("Materialized view mv1 uses table from a different database db1. " + + "The materialized view should be explicitly dropped before dropping this database", + e.getMessage()); + exceptionFound = true; + } + assertTrue(exceptionFound); + + client.dropTable(dbName2, mvName); + client.dropDatabase(dbName2, true, true, true); + client.dropDatabase(dbName1, true, true, true); + } + @Test public void testDBLocationChange() throws IOException, TException { final String dbName = "alterDbLocation";