You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by bl...@apache.org on 2020/04/17 21:35:27 UTC

[incubator-iceberg] branch master updated: Add SupportsNamespaces extension to Catalog (#919)

This is an automated email from the ASF dual-hosted git repository.

blue pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-iceberg.git


The following commit(s) were added to refs/heads/master by this push:
     new 34126d2  Add SupportsNamespaces extension to Catalog (#919)
34126d2 is described below

commit 34126d20d29fa12848dd28b305a918f8a1219979
Author: XiaokunDing <di...@gmail.com>
AuthorDate: Sat Apr 18 05:35:19 2020 +0800

    Add SupportsNamespaces extension to Catalog (#919)
    
    This also adds implementations for HadoopCatalog and HiveCatalog.
---
 .../apache/iceberg/catalog/SupportsNamespaces.java | 141 +++++++++++++
 .../exceptions/NamespaceNotEmptyException.java     |  33 +++
 .../exceptions/NoSuchNamespaceException.java       |  33 +++
 .../org/apache/iceberg/hadoop/HadoopCatalog.java   | 126 +++++++++++-
 .../apache/iceberg/hadoop/TestHadoopCatalog.java   | 168 +++++++++++++++-
 .../java/org/apache/iceberg/hive/HiveCatalog.java  | 221 ++++++++++++++++++++-
 .../org/apache/iceberg/hive/TestHiveCatalog.java   | 192 ++++++++++++++++++
 7 files changed, 894 insertions(+), 20 deletions(-)

diff --git a/api/src/main/java/org/apache/iceberg/catalog/SupportsNamespaces.java b/api/src/main/java/org/apache/iceberg/catalog/SupportsNamespaces.java
new file mode 100644
index 0000000..0e3302a
--- /dev/null
+++ b/api/src/main/java/org/apache/iceberg/catalog/SupportsNamespaces.java
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+package org.apache.iceberg.catalog;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.iceberg.exceptions.AlreadyExistsException;
+import org.apache.iceberg.exceptions.NamespaceNotEmptyException;
+import org.apache.iceberg.exceptions.NoSuchNamespaceException;
+
+/**
+ * Catalog methods for working with namespaces.
+ * <p>
+ * If an object such as a table, view, or function exists, its parent namespaces must also exist
+ * and must be returned by the discovery methods {@link #listNamespaces()} and
+ * {@link #listNamespaces(Namespace namespace)}.
+ * <p>
+ * Catalog implementations are not required to maintain the existence of namespaces independent of
+ * objects in a namespace. For example, a function catalog that loads functions using reflection
+ * and uses Java packages as namespaces is not required to support the methods to create, alter, or
+ * drop a namespace. Implementations are allowed to discover the existence of objects or namespaces
+ * without throwing {@link NoSuchNamespaceException} when no namespace is found.
+ */
+public interface SupportsNamespaces {
+  /**
+   * Create a namespace in the catalog.
+   *
+   * @param namespace a namespace. {@link Namespace}.
+   * @throws AlreadyExistsException If the namespace already exists
+   * @throws UnsupportedOperationException If create is not a supported operation
+   */
+  default void createNamespace(Namespace namespace) {
+    createNamespace(namespace, ImmutableMap.of());
+  }
+
+  /**
+   * Create a namespace in the catalog.
+   *
+   * @param namespace a multi-part namespace
+   * @param metadata a string Map of properties for the given namespace
+   * @throws AlreadyExistsException If the namespace already exists
+   * @throws UnsupportedOperationException If create is not a supported operation
+   */
+  void createNamespace(Namespace namespace, Map<String, String> metadata);
+
+  /**
+   * List top-level namespaces from the catalog.
+   * <p>
+   * If an object such as a table, view, or function exists, its parent namespaces must also exist
+   * and must be returned by this discovery method. For example, if table a.b.t exists, this method
+   * must return ["a"] in the result array.
+   *
+   * @return an List of namespace {@link Namespace} names
+   */
+  default List<Namespace> listNamespaces() {
+    return listNamespaces(Namespace.empty());
+  }
+
+  /**
+   * List namespaces from the namespace.
+   * <p>
+   * For example, if table a.b.t exists, use 'SELECT NAMESPACE IN a' this method
+   * must return Namepace.of("a","b") {@link Namespace}.
+   *
+   * @return a List of namespace {@link Namespace} names
+   * @throws NoSuchNamespaceException If the namespace does not exist (optional)
+   */
+  List<Namespace> listNamespaces(Namespace namespace) throws NoSuchNamespaceException;
+
+  /**
+   * Load metadata properties for a namespace.
+   *
+   * @param namespace a namespace. {@link Namespace}
+   * @return a string map of properties for the given namespace
+   * @throws NoSuchNamespaceException If the namespace does not exist (optional)
+   */
+  Map<String, String> loadNamespaceMetadata(Namespace namespace) throws NoSuchNamespaceException;
+
+  /**
+   * Drop a namespace. If the namespace exists and was dropped, this will return true.
+   *
+   * @param namespace a namespace. {@link Namespace}
+   * @return true if the namespace was dropped, false otherwise.
+   * @throws NamespaceNotEmptyException If the namespace does not empty
+   */
+  boolean dropNamespace(Namespace namespace) throws NamespaceNotEmptyException;
+
+  /**
+   * Apply a set of metadata to a namespace in the catalog.
+   *
+   * @param namespace a namespace. {@link Namespace}
+   * @param properties a collection of metadata to apply to the namespace
+   * @throws NoSuchNamespaceException If the namespace does not exist (optional)
+   * @throws UnsupportedOperationException If namespace properties are not supported
+   */
+  boolean setProperties(Namespace namespace, Map<String, String> properties) throws NoSuchNamespaceException;
+
+  /**
+   * Remove a set of metadata from a namespace in the catalog.
+   *
+   * @param namespace a namespace. {@link Namespace}
+   * @param properties a collection of metadata to apply to the namespace
+   * @throws NoSuchNamespaceException If the namespace does not exist (optional)
+   * @throws UnsupportedOperationException If namespace properties are not supported
+   */
+  boolean removeProperties(Namespace namespace, Set<String> properties) throws NoSuchNamespaceException;
+
+  /**
+   * Checks whether the Namespace exists.
+   *
+   * @param namespace a namespace. {@link Namespace}
+   * @return true if the Namespace exists, false otherwise
+   */
+  default boolean namespaceExists(Namespace namespace) {
+    try {
+      loadNamespaceMetadata(namespace);
+      return true;
+    } catch (NoSuchNamespaceException e) {
+      return false;
+    }
+  }
+}
diff --git a/api/src/main/java/org/apache/iceberg/exceptions/NamespaceNotEmptyException.java b/api/src/main/java/org/apache/iceberg/exceptions/NamespaceNotEmptyException.java
new file mode 100644
index 0000000..130cd3e
--- /dev/null
+++ b/api/src/main/java/org/apache/iceberg/exceptions/NamespaceNotEmptyException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package org.apache.iceberg.exceptions;
+
+/**
+ * Exception raised when attempting to drop a namespace that is not empty.
+ */
+public class NamespaceNotEmptyException extends RuntimeException {
+  public NamespaceNotEmptyException(String message, Object... args) {
+    super(String.format(message, args));
+  }
+
+  public NamespaceNotEmptyException(Throwable cause, String message, Object... args) {
+    super(String.format(message, args), cause);
+  }
+}
diff --git a/api/src/main/java/org/apache/iceberg/exceptions/NoSuchNamespaceException.java b/api/src/main/java/org/apache/iceberg/exceptions/NoSuchNamespaceException.java
new file mode 100644
index 0000000..f9348f7
--- /dev/null
+++ b/api/src/main/java/org/apache/iceberg/exceptions/NoSuchNamespaceException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package org.apache.iceberg.exceptions;
+
+/**
+ * Exception raised when attempting to load a namespace that does not exist.
+ */
+public class NoSuchNamespaceException extends RuntimeException {
+  public NoSuchNamespaceException(String message, Object... args) {
+    super(String.format(message, args));
+  }
+
+  public NoSuchNamespaceException(Throwable cause, String message, Object... args) {
+    super(String.format(message, args), cause);
+  }
+}
diff --git a/core/src/main/java/org/apache/iceberg/hadoop/HadoopCatalog.java b/core/src/main/java/org/apache/iceberg/hadoop/HadoopCatalog.java
index 04b8747..200e979 100644
--- a/core/src/main/java/org/apache/iceberg/hadoop/HadoopCatalog.java
+++ b/core/src/main/java/org/apache/iceberg/hadoop/HadoopCatalog.java
@@ -21,13 +21,17 @@ package org.apache.iceberg.hadoop;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
@@ -40,9 +44,11 @@ import org.apache.iceberg.Table;
 import org.apache.iceberg.TableMetadata;
 import org.apache.iceberg.TableOperations;
 import org.apache.iceberg.catalog.Namespace;
+import org.apache.iceberg.catalog.SupportsNamespaces;
 import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.iceberg.exceptions.AlreadyExistsException;
+import org.apache.iceberg.exceptions.NoSuchNamespaceException;
 import org.apache.iceberg.exceptions.NoSuchTableException;
-import org.apache.iceberg.exceptions.NotFoundException;
 import org.apache.iceberg.exceptions.RuntimeIOException;
 
 /**
@@ -58,12 +64,16 @@ import org.apache.iceberg.exceptions.RuntimeIOException;
  *
  * Note: The HadoopCatalog requires that the underlying file system supports atomic rename.
  */
-public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
+public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable, SupportsNamespaces {
+
   private static final String ICEBERG_HADOOP_WAREHOUSE_BASE = "iceberg/warehouse";
   private static final String TABLE_METADATA_FILE_EXTENSION = ".metadata.json";
+  private static final Joiner SLASH = Joiner.on("/");
   private static final PathFilter TABLE_FILTER = path -> path.getName().endsWith(TABLE_METADATA_FILE_EXTENSION);
+
   private final Configuration conf;
-  private String warehouseLocation;
+  private final String warehouseLocation;
+  private final FileSystem fs;
 
   /**
    * The constructor of the HadoopCatalog. It uses the passed location as its warehouse directory.
@@ -77,6 +87,7 @@ public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
 
     this.conf = conf;
     this.warehouseLocation = warehouseLocation.replaceAll("/*$", "");
+    this.fs = Util.getFs(new Path(warehouseLocation), conf);
   }
 
   /**
@@ -89,6 +100,7 @@ public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
   public HadoopCatalog(Configuration conf) {
     this.conf = conf;
     this.warehouseLocation = conf.get("fs.defaultFS") + "/" + ICEBERG_HADOOP_WAREHOUSE_BASE;
+    this.fs = Util.getFs(new Path(warehouseLocation), conf);
   }
 
   @Override
@@ -101,14 +113,12 @@ public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
     Preconditions.checkArgument(namespace.levels().length >= 1,
         "Missing database in table identifier: %s", namespace);
 
-    Joiner slash = Joiner.on("/");
-    Path nsPath = new Path(slash.join(warehouseLocation, slash.join(namespace.levels())));
-    FileSystem fs = Util.getFs(nsPath, conf);
+    Path nsPath = new Path(warehouseLocation, SLASH.join(namespace.levels()));
     Set<TableIdentifier> tblIdents = Sets.newHashSet();
 
     try {
       if (!fs.exists(nsPath) || !fs.isDirectory(nsPath)) {
-        throw new NotFoundException("Unknown namespace " + namespace);
+        throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
       }
 
       for (FileStatus s : fs.listStatus(nsPath)) {
@@ -128,7 +138,7 @@ public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
         }
       }
     } catch (IOException ioe) {
-      throw new RuntimeException("Failed to list tables under " + namespace, ioe);
+      throw new RuntimeIOException(ioe, "Failed to list tables under: %s", namespace);
     }
 
     return Lists.newArrayList(tblIdents);
@@ -180,7 +190,6 @@ public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
       lastMetadata = null;
     }
 
-    FileSystem fs = Util.getFs(tablePath, conf);
     try {
       if (purge && lastMetadata != null) {
         // Since the data files and the metadata files may store in different locations,
@@ -200,7 +209,104 @@ public class HadoopCatalog extends BaseMetastoreCatalog implements Closeable {
   }
 
   @Override
-  public void close() throws IOException {
+  public void createNamespace(Namespace namespace, Map<String, String> meta) {
+    Preconditions.checkArgument(
+        !namespace.isEmpty(),
+        "Cannot create namespace with invalid name: %s", namespace);
+    if (!meta.isEmpty()) {
+      throw new UnsupportedOperationException("Cannot create namespace " + namespace + " : metadata is not supported");
+    }
+
+    Path nsPath = new Path(warehouseLocation, SLASH.join(namespace.levels()));
+
+    if (isNamespace(nsPath)) {
+      throw new AlreadyExistsException("Namespace '%s' already exists!", namespace);
+    }
+
+    try {
+      fs.mkdirs(nsPath);
+
+    } catch (IOException e) {
+      throw new RuntimeIOException(e, "Create namespace failed: %s", namespace);
+    }
   }
 
+  @Override
+  public List<Namespace> listNamespaces(Namespace namespace) {
+    Path nsPath = namespace.isEmpty() ? new Path(warehouseLocation)
+        : new Path(warehouseLocation, SLASH.join(namespace.levels()));
+    if (!isNamespace(nsPath)) {
+      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
+    }
+
+    try {
+      return Stream.of(fs.listStatus(nsPath))
+        .map(FileStatus::getPath)
+        .filter(path -> isNamespace(path))
+        .map(path -> append(namespace, path.getName()))
+        .collect(Collectors.toList());
+    } catch (IOException ioe) {
+      throw new RuntimeIOException(ioe, "Failed to list namespace under: %s", namespace);
+    }
+  }
+
+  private Namespace append(Namespace ns, String name) {
+    String[] levels = Arrays.copyOfRange(ns.levels(), 0, ns.levels().length + 1);
+    levels[ns.levels().length] = name;
+    return Namespace.of(levels);
+  }
+
+  @Override
+  public boolean dropNamespace(Namespace namespace) {
+    Path nsPath = new Path(warehouseLocation, SLASH.join(namespace.levels()));
+
+    if (!isNamespace(nsPath) || namespace.isEmpty()) {
+      return false;
+    }
+
+    try {
+      return fs.delete(nsPath, false /* recursive */);
+
+    } catch (IOException e) {
+      throw new RuntimeIOException(e, "Namespace delete failed: %s", namespace);
+    }
+  }
+
+  @Override
+  public boolean setProperties(Namespace namespace,  Map<String, String> properties) {
+    throw new UnsupportedOperationException(
+        "Cannot set namespace properties " + namespace + " : setProperties is not supported");
+  }
+
+  @Override
+  public boolean removeProperties(Namespace namespace,  Set<String> properties) {
+    throw new UnsupportedOperationException(
+        "Cannot remove properties " + namespace + " : removeProperties is not supported");
+  }
+
+  @Override
+  public Map<String, String> loadNamespaceMetadata(Namespace namespace) {
+    Path nsPath = new Path(warehouseLocation, SLASH.join(namespace.levels()));
+
+    if (!isNamespace(nsPath) || namespace.isEmpty()) {
+      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
+    }
+
+    return ImmutableMap.of("location", nsPath.toString());
+  }
+
+  private boolean isNamespace(Path path) {
+    Path metadataPath = new Path(path, "metadata");
+    try {
+      return fs.isDirectory(path) && !(fs.exists(metadataPath) && fs.isDirectory(metadataPath) &&
+          (fs.listStatus(metadataPath, TABLE_FILTER).length >= 1));
+
+    } catch (IOException ioe) {
+      throw new RuntimeIOException(ioe, "Failed to list namespace info: %s ", path);
+    }
+  }
+
+  @Override
+  public void close() throws IOException {
+  }
 }
diff --git a/core/src/test/java/org/apache/iceberg/hadoop/TestHadoopCatalog.java b/core/src/test/java/org/apache/iceberg/hadoop/TestHadoopCatalog.java
index 1e86720..1cafc25 100644
--- a/core/src/test/java/org/apache/iceberg/hadoop/TestHadoopCatalog.java
+++ b/core/src/test/java/org/apache/iceberg/hadoop/TestHadoopCatalog.java
@@ -19,6 +19,7 @@
 
 package org.apache.iceberg.hadoop;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.io.IOException;
@@ -33,11 +34,14 @@ import org.apache.iceberg.Table;
 import org.apache.iceberg.Transaction;
 import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
-import org.apache.iceberg.exceptions.NotFoundException;
+import org.apache.iceberg.exceptions.NoSuchNamespaceException;
+import org.apache.iceberg.exceptions.RuntimeIOException;
 import org.junit.Assert;
 import org.junit.Test;
 
 public class TestHadoopCatalog extends HadoopTableTestBase {
+  private static ImmutableMap<String, String> meta = ImmutableMap.of();
+
   @Test
   public void testBasicCatalog() throws Exception {
     Configuration conf = new Configuration();
@@ -129,8 +133,8 @@ public class TestHadoopCatalog extends HadoopTableTestBase {
     Assert.assertEquals(tbls2.size(), 1);
     Assert.assertTrue(tbls2.get(0).name().equals("tbl3"));
 
-    AssertHelpers.assertThrows("should throw exception", NotFoundException.class,
-        "Unknown namespace", () -> {
+    AssertHelpers.assertThrows("should throw exception", NoSuchNamespaceException.class,
+        "Namespace does not exist: ", () -> {
         catalog.listTables(Namespace.of("db", "ns1", "ns2"));
       });
   }
@@ -149,4 +153,162 @@ public class TestHadoopCatalog extends HadoopTableTestBase {
     Assert.assertEquals("1 table expected", 1, catalog.listTables(Namespace.of("ns1", "ns2")).size());
     catalog.dropTable(tableIdent, true);
   }
+
+  @Test
+  public void testCreateNamespace() throws Exception {
+    Configuration conf = new Configuration();
+    String warehousePath = temp.newFolder().getAbsolutePath();
+    HadoopCatalog catalog = new HadoopCatalog(conf, warehousePath);
+
+    TableIdentifier tbl1 = TableIdentifier.of("db", "ns1", "ns2", "metadata");
+    TableIdentifier tbl2 = TableIdentifier.of("db", "ns2", "ns3", "tbl2");
+
+    Lists.newArrayList(tbl1, tbl2).forEach(t ->
+        catalog.createNamespace(t.namespace(), meta)
+    );
+
+    String metaLocation1 = warehousePath + "/" + "db/ns1/ns2";
+    FileSystem fs1 = Util.getFs(new Path(metaLocation1), conf);
+    Assert.assertTrue(fs1.isDirectory(new Path(metaLocation1)));
+
+    String metaLocation2 = warehousePath + "/" + "db/ns2/ns3";
+    FileSystem fs2 = Util.getFs(new Path(metaLocation2), conf);
+    Assert.assertTrue(fs2.isDirectory(new Path(metaLocation2)));
+
+    AssertHelpers.assertThrows("Should fail to create when namespace already exist: " + tbl1.namespace(),
+        org.apache.iceberg.exceptions.AlreadyExistsException.class,
+        "Namespace '" + tbl1.namespace() + "' already exists!", () -> {
+          catalog.createNamespace(tbl1.namespace());
+        });
+  }
+
+  @Test
+  public void testListNamespace() throws Exception {
+    Configuration conf = new Configuration();
+    String warehousePath = temp.newFolder().getAbsolutePath();
+    HadoopCatalog catalog = new HadoopCatalog(conf, warehousePath);
+
+    TableIdentifier tbl1 = TableIdentifier.of("db", "ns1", "ns2", "metadata");
+    TableIdentifier tbl2 = TableIdentifier.of("db", "ns2", "ns3", "tbl2");
+    TableIdentifier tbl3 = TableIdentifier.of("db", "ns3", "tbl4");
+    TableIdentifier tbl4 = TableIdentifier.of("db", "metadata");
+    TableIdentifier tbl5 = TableIdentifier.of("db2", "metadata");
+
+    Lists.newArrayList(tbl1, tbl2, tbl3, tbl4, tbl5).forEach(t ->
+        catalog.createTable(t, SCHEMA, PartitionSpec.unpartitioned())
+    );
+
+    List<Namespace> nsp1 = catalog.listNamespaces(Namespace.of("db"));
+    Set<String> tblSet = Sets.newHashSet(nsp1.stream().map(t -> t.toString()).iterator());
+    Assert.assertEquals(tblSet.size(), 3);
+    Assert.assertTrue(tblSet.contains("db.ns1"));
+    Assert.assertTrue(tblSet.contains("db.ns2"));
+    Assert.assertTrue(tblSet.contains("db.ns3"));
+
+    List<Namespace> nsp2 = catalog.listNamespaces(Namespace.of("db", "ns1"));
+    Assert.assertEquals(nsp2.size(), 1);
+    Assert.assertTrue(nsp2.get(0).toString().equals("db.ns1.ns2"));
+
+    List<Namespace> nsp3 = catalog.listNamespaces();
+    Set<String> tblSet2 = Sets.newHashSet(nsp3.stream().map(t -> t.toString()).iterator());
+    Assert.assertEquals(tblSet2.size(), 2);
+    Assert.assertTrue(tblSet2.contains("db"));
+    Assert.assertTrue(tblSet2.contains("db2"));
+
+    List<Namespace> nsp4 = catalog.listNamespaces();
+    Set<String> tblSet3 = Sets.newHashSet(nsp4.stream().map(t -> t.toString()).iterator());
+    Assert.assertEquals(tblSet3.size(), 2);
+    Assert.assertTrue(tblSet3.contains("db"));
+    Assert.assertTrue(tblSet3.contains("db2"));
+
+    AssertHelpers.assertThrows("Should fail to list namespace doesn't exist", NoSuchNamespaceException.class,
+        "Namespace does not exist: ", () -> {
+          catalog.listNamespaces(Namespace.of("db", "db2", "ns2"));
+        });
+  }
+
+  @Test
+  public void testLoadNamespaceMeta() throws IOException {
+    Configuration conf = new Configuration();
+    String warehousePath = temp.newFolder().getAbsolutePath();
+    HadoopCatalog catalog = new HadoopCatalog(conf, warehousePath);
+
+    TableIdentifier tbl1 = TableIdentifier.of("db", "ns1", "ns2", "metadata");
+    TableIdentifier tbl2 = TableIdentifier.of("db", "ns2", "ns3", "tbl2");
+    TableIdentifier tbl3 = TableIdentifier.of("db", "ns3", "tbl4");
+    TableIdentifier tbl4 = TableIdentifier.of("db", "metadata");
+
+    Lists.newArrayList(tbl1, tbl2, tbl3, tbl4).forEach(t ->
+        catalog.createTable(t, SCHEMA, PartitionSpec.unpartitioned())
+    );
+    catalog.loadNamespaceMetadata(Namespace.of("db"));
+
+    AssertHelpers.assertThrows("Should fail to load namespace doesn't exist", NoSuchNamespaceException.class,
+        "Namespace does not exist: ", () -> {
+          catalog.loadNamespaceMetadata(Namespace.of("db", "db2", "ns2"));
+        });
+  }
+
+  @Test
+  public void testNamespaceExists() throws IOException {
+    Configuration conf = new Configuration();
+    String warehousePath = temp.newFolder().getAbsolutePath();
+    HadoopCatalog catalog = new HadoopCatalog(conf, warehousePath);
+
+    TableIdentifier tbl1 = TableIdentifier.of("db", "ns1", "ns2", "metadata");
+    TableIdentifier tbl2 = TableIdentifier.of("db", "ns2", "ns3", "tbl2");
+    TableIdentifier tbl3 = TableIdentifier.of("db", "ns3", "tbl4");
+    TableIdentifier tbl4 = TableIdentifier.of("db", "metadata");
+
+    Lists.newArrayList(tbl1, tbl2, tbl3, tbl4).forEach(t ->
+        catalog.createTable(t, SCHEMA, PartitionSpec.unpartitioned())
+    );
+    Assert.assertTrue("Should true to namespace exist",
+        catalog.namespaceExists(Namespace.of("db", "ns1", "ns2")));
+    Assert.assertTrue("Should false to namespace doesn't exist",
+        !catalog.namespaceExists(Namespace.of("db", "db2", "ns2")));
+  }
+
+  @Test
+  public void testAlterNamespaceMeta() throws IOException {
+    Configuration conf = new Configuration();
+    String warehousePath = temp.newFolder().getAbsolutePath();
+    HadoopCatalog catalog = new HadoopCatalog(conf, warehousePath);
+    AssertHelpers.assertThrows("Should fail to change namespace", UnsupportedOperationException.class,
+        "Cannot set namespace properties db.db2.ns2 : setProperties is not supported", () -> {
+          catalog.setProperties(Namespace.of("db", "db2", "ns2"), ImmutableMap.of("property", "test"));
+        });
+  }
+
+  @Test
+  public void testDropNamespace() throws IOException {
+    Configuration conf = new Configuration();
+    String warehousePath = temp.newFolder().getAbsolutePath();
+    HadoopCatalog catalog = new HadoopCatalog(conf, warehousePath);
+    Namespace namespace1 = Namespace.of("db");
+    Namespace namespace2 = Namespace.of("db", "ns1");
+
+    TableIdentifier tbl1 = TableIdentifier.of(namespace1, "tbl1");
+    TableIdentifier tbl2 = TableIdentifier.of(namespace2, "tbl1");
+
+    Lists.newArrayList(tbl1, tbl2).forEach(t ->
+        catalog.createTable(t, SCHEMA, PartitionSpec.unpartitioned())
+    );
+
+    AssertHelpers.assertThrows("Should fail to drop namespace is not empty " + namespace1,
+        RuntimeIOException.class,
+        "Namespace delete failed: " + namespace1, () -> {
+          catalog.dropNamespace(Namespace.of("db"));
+        });
+    Assert.assertFalse("Should fail to drop namespace doesn't exist",
+          catalog.dropNamespace(Namespace.of("db2")));
+    Assert.assertTrue(catalog.dropTable(tbl1));
+    Assert.assertTrue(catalog.dropTable(tbl2));
+    Assert.assertTrue(catalog.dropNamespace(namespace2));
+    Assert.assertTrue(catalog.dropNamespace(namespace1));
+    String metaLocation = warehousePath + "/" + "db";
+    FileSystem fs = Util.getFs(new Path(metaLocation), conf);
+    Assert.assertFalse(fs.isDirectory(new Path(metaLocation)));
+  }
 }
+
diff --git a/hive/src/main/java/org/apache/iceberg/hive/HiveCatalog.java b/hive/src/main/java/org/apache/iceberg/hive/HiveCatalog.java
index d00a151..4973b06 100644
--- a/hive/src/main/java/org/apache/iceberg/hive/HiveCatalog.java
+++ b/hive/src/main/java/org/apache/iceberg/hive/HiveCatalog.java
@@ -21,12 +21,20 @@ package org.apache.iceberg.hive;
 
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
 import java.io.Closeable;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
 import org.apache.hadoop.hive.metastore.api.AlreadyExistsException;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.InvalidOperationException;
 import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
 import org.apache.hadoop.hive.metastore.api.Table;
 import org.apache.hadoop.hive.metastore.api.UnknownDBException;
@@ -34,14 +42,16 @@ import org.apache.iceberg.BaseMetastoreCatalog;
 import org.apache.iceberg.TableMetadata;
 import org.apache.iceberg.TableOperations;
 import org.apache.iceberg.catalog.Namespace;
+import org.apache.iceberg.catalog.SupportsNamespaces;
 import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.iceberg.exceptions.NamespaceNotEmptyException;
+import org.apache.iceberg.exceptions.NoSuchNamespaceException;
 import org.apache.iceberg.exceptions.NoSuchTableException;
-import org.apache.iceberg.exceptions.NotFoundException;
 import org.apache.thrift.TException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
+public class HiveCatalog extends BaseMetastoreCatalog implements Closeable, SupportsNamespaces {
   private static final Logger LOG = LoggerFactory.getLogger(HiveCatalog.class);
 
   private final HiveClientPool clients;
@@ -58,7 +68,7 @@ public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
 
   @Override
   public List<TableIdentifier> listTables(Namespace namespace) {
-    Preconditions.checkArgument(namespace.levels().length == 1,
+    Preconditions.checkArgument(isValidateNamespace(namespace),
         "Missing database in namespace: %s", namespace);
     String database = namespace.level(0);
 
@@ -69,10 +79,10 @@ public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
           .collect(Collectors.toList());
 
     } catch (UnknownDBException e) {
-      throw new NotFoundException(e, "Unknown namespace " + namespace.toString());
+      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
 
     } catch (TException e) {
-      throw new RuntimeException("Failed to list all tables under namespace " + namespace.toString(), e);
+      throw new RuntimeException("Failed to list all tables under namespace " + namespace, e);
 
     } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
@@ -119,7 +129,7 @@ public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
       return false;
 
     } catch (TException e) {
-      throw new RuntimeException("Failed to drop " + identifier.toString(), e);
+      throw new RuntimeException("Failed to drop " + identifier, e);
 
     } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
@@ -155,7 +165,7 @@ public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
       throw new org.apache.iceberg.exceptions.AlreadyExistsException("Table already exists: %s", to);
 
     } catch (TException e) {
-      throw new RuntimeException("Failed to rename " + from.toString() + " to " + to.toString(), e);
+      throw new RuntimeException("Failed to rename " + from + " to " + to, e);
 
     } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
@@ -164,10 +174,167 @@ public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
   }
 
   @Override
+  public void createNamespace(Namespace namespace, Map<String, String> meta) {
+    Preconditions.checkArgument(
+        !namespace.isEmpty(),
+        "Cannot create namespace with invalid name: %s", namespace);
+    Preconditions.checkArgument(isValidateNamespace(namespace),
+        "Cannot support multi part namespace in Hive MetaStore: %s", namespace);
+
+    try {
+      clients.run(client -> {
+        client.createDatabase(convertToDatabase(namespace, meta));
+        return null;
+      });
+
+    } catch (AlreadyExistsException e) {
+      throw new org.apache.iceberg.exceptions.AlreadyExistsException(e, "Namespace '%s' already exists!",
+            namespace);
+
+    } catch (TException e) {
+      throw new RuntimeException("Failed to create namespace " + namespace + " in Hive MataStore", e);
+
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new RuntimeException(
+          "Interrupted in call to createDatabase(name) " + namespace + " in Hive MataStore", e);
+    }
+  }
+
+  @Override
+  public List<Namespace> listNamespaces(Namespace namespace) {
+    if (!isValidateNamespace(namespace) && !namespace.isEmpty()) {
+      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
+    }
+    if (!namespace.isEmpty()) {
+      return ImmutableList.of();
+    }
+    try {
+      return clients.run(
+          HiveMetaStoreClient::getAllDatabases)
+          .stream()
+          .map(Namespace::of)
+          .collect(Collectors.toList());
+
+    } catch (TException e) {
+      throw new RuntimeException("Failed to list all namespace: " + namespace + " in Hive MataStore",  e);
+
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new RuntimeException(
+          "Interrupted in call to getAllDatabases() " + namespace + " in Hive MataStore", e);
+    }
+  }
+
+  @Override
+  public boolean dropNamespace(Namespace namespace) {
+    if (!isValidateNamespace(namespace)) {
+      return false;
+    }
+
+    try {
+      clients.run(client -> {
+        client.dropDatabase(namespace.level(0),
+            false /* deleteData */,
+            false /* ignoreUnknownDb */,
+            false /* cascade */);
+        return null;
+      });
+
+      return true;
+
+    } catch (InvalidOperationException e) {
+      throw new NamespaceNotEmptyException("Namespace " + namespace + " is not empty. One or more tables exist.", e);
+
+    } catch (NoSuchObjectException e) {
+      return false;
+
+    } catch (TException e) {
+      throw new RuntimeException("Failed to drop namespace " + namespace + " in Hive MataStore", e);
+
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new RuntimeException(
+          "Interrupted in call to drop dropDatabase(name) " + namespace + " in Hive MataStore", e);
+    }
+  }
+
+  @Override
+  public boolean setProperties(Namespace namespace,  Map<String, String> properties) {
+    Map<String, String> parameter = Maps.newHashMap();
+
+    parameter.putAll(loadNamespaceMetadata(namespace));
+    parameter.putAll(properties);
+    Database database = convertToDatabase(namespace, parameter);
+
+    return alterHiveDataBase(namespace, database);
+  }
+
+  @Override
+  public boolean removeProperties(Namespace namespace,  Set<String> properties) {
+    Map<String, String> parameter = Maps.newHashMap();
+
+    parameter.putAll(loadNamespaceMetadata(namespace));
+    properties.forEach(key -> parameter.put(key, null));
+    Database database = convertToDatabase(namespace, parameter);
+
+    return alterHiveDataBase(namespace, database);
+  }
+
+  private boolean alterHiveDataBase(Namespace namespace,  Database database) {
+    try {
+      clients.run(client -> {
+        client.alterDatabase(namespace.level(0), database);
+        return null;
+      });
+
+      return true;
+
+    } catch (NoSuchObjectException | UnknownDBException e) {
+      throw new NoSuchNamespaceException(e, "Namespace does not exist: %s", namespace);
+
+    } catch (TException e) {
+      throw new RuntimeException(
+          "Failed to list namespace under namespace: " + namespace + " in Hive MataStore", e);
+
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new RuntimeException("Interrupted in call to getDatabase(name) " + namespace + " in Hive MataStore", e);
+    }
+  }
+
+  @Override
+  public Map<String, String> loadNamespaceMetadata(Namespace namespace) {
+    if (!isValidateNamespace(namespace)) {
+      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
+    }
+
+    try {
+      Database database = clients.run(client -> client.getDatabase(namespace.level(0)));
+      return convertToMetadata(database);
+
+    } catch (NoSuchObjectException | UnknownDBException e) {
+      throw new NoSuchNamespaceException(e, "Namespace does not exist: %s", namespace);
+
+    } catch (TException e) {
+      throw new RuntimeException("Failed to list namespace under namespace: " + namespace + " in Hive MataStore", e);
+
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new RuntimeException(
+          "Interrupted in call to getDatabase(name) " + namespace + " in Hive MataStore", e);
+    }
+  }
+
+  @Override
   protected boolean isValidIdentifier(TableIdentifier tableIdentifier) {
     return tableIdentifier.namespace().levels().length == 1;
   }
 
+  private boolean isValidateNamespace(Namespace namespace) {
+    return namespace.levels().length == 1;
+  }
+
   @Override
   public TableOperations newTableOps(TableIdentifier tableIdentifier) {
     String dbName = tableIdentifier.namespace().level(0);
@@ -188,6 +355,46 @@ public class HiveCatalog extends BaseMetastoreCatalog implements Closeable {
         tableIdentifier.name());
   }
 
+  private Map<String, String> convertToMetadata(Database database) {
+
+    Map<String, String> meta = Maps.newHashMap();
+
+    meta.putAll(database.getParameters());
+    meta.put("location", database.getLocationUri());
+    meta.put("comment", database.getDescription());
+
+    return meta;
+  }
+
+  Database convertToDatabase(Namespace namespace, Map<String, String> meta) {
+    String warehouseLocation = conf.get("hive.metastore.warehouse.dir");
+
+    if (!isValidateNamespace(namespace)) {
+      throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
+    }
+
+    Database database  = new Database();
+    Map<String, String> parameter = Maps.newHashMap();
+
+    database.setName(namespace.level(0));
+    database.setLocationUri(new Path(warehouseLocation, namespace.level(0)).toString() + ".db");
+
+    meta.forEach((key, value) -> {
+      if (key.equals("comment")) {
+        database.setDescription(value);
+      } else if (key.equals("location")) {
+        database.setLocationUri(value);
+      } else {
+        if (value != null) {
+          parameter.put(key, value);
+        }
+      }
+    });
+    database.setParameters(parameter);
+
+    return database;
+  }
+
   @Override
   public void close() {
     if (!closed) {
diff --git a/hive/src/test/java/org/apache/iceberg/hive/TestHiveCatalog.java b/hive/src/test/java/org/apache/iceberg/hive/TestHiveCatalog.java
new file mode 100644
index 0000000..744295c
--- /dev/null
+++ b/hive/src/test/java/org/apache/iceberg/hive/TestHiveCatalog.java
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ */
+
+package org.apache.iceberg.hive;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.iceberg.AssertHelpers;
+import org.apache.iceberg.Schema;
+import org.apache.iceberg.catalog.Namespace;
+import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.iceberg.exceptions.AlreadyExistsException;
+import org.apache.iceberg.exceptions.NamespaceNotEmptyException;
+import org.apache.iceberg.exceptions.NoSuchNamespaceException;
+import org.apache.iceberg.types.Types;
+import org.apache.thrift.TException;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.apache.iceberg.types.Types.NestedField.required;
+
+public class TestHiveCatalog extends HiveMetastoreTest {
+  private static final String hiveLocalDir = "file:/tmp/hive/" + UUID.randomUUID().toString();
+  private static ImmutableMap meta = ImmutableMap.of(
+      "owner", "apache",
+      "group", "iceberg",
+      "comment", "iceberg  hiveCatalog test");
+
+  @Test
+  public void testCreateNamespace() throws TException {
+    Namespace namespace1 = Namespace.of("noLocation");
+    catalog.createNamespace(namespace1, meta);
+    Database database1 = metastoreClient.getDatabase(namespace1.toString());
+
+    Assert.assertTrue(database1.getParameters().get("owner").equals("apache"));
+    Assert.assertTrue(database1.getParameters().get("group").equals("iceberg"));
+
+    Assert.assertEquals("There no same location for db and namespace",
+        database1.getLocationUri(), defaultUri(namespace1));
+
+    AssertHelpers.assertThrows("Should fail to create when namespace already exist " + namespace1,
+        AlreadyExistsException.class, "Namespace '" + namespace1 + "' already exists!", () -> {
+          catalog.createNamespace(namespace1);
+        });
+    ImmutableMap newMeta = ImmutableMap.<String, String>builder()
+        .putAll(meta)
+        .put("location", hiveLocalDir)
+        .build();
+    Namespace namespace2 = Namespace.of("haveLocation");
+
+    catalog.createNamespace(namespace2, newMeta);
+    Database database2 = metastoreClient.getDatabase(namespace2.toString());
+    Assert.assertEquals("There no same location for db and namespace",
+        database2.getLocationUri(), hiveLocalDir);
+  }
+
+  @Test
+  public void testListNamespace() throws TException {
+    List<Namespace> namespaces;
+    Namespace namespace1 = Namespace.of("dbname1");
+    catalog.createNamespace(namespace1, meta);
+    namespaces = catalog.listNamespaces(namespace1);
+    Assert.assertTrue("Hive db not hive the namespace 'dbname1'", namespaces.isEmpty());
+
+    Namespace namespace2 = Namespace.of("dbname2");
+    catalog.createNamespace(namespace2, meta);
+    namespaces = catalog.listNamespaces();
+
+    Assert.assertTrue("Hive db not hive the namespace 'dbname2'", namespaces.contains(namespace2));
+  }
+
+  @Test
+  public void testLoadNamespaceMeta() throws TException {
+    Namespace namespace = Namespace.of("dbname_load");
+
+    catalog.createNamespace(namespace, meta);
+
+    Map<String, String> nameMata = catalog.loadNamespaceMetadata(namespace);
+    Assert.assertTrue(nameMata.get("owner").equals("apache"));
+    Assert.assertTrue(nameMata.get("group").equals("iceberg"));
+    Assert.assertEquals("There no same location for db and namespace",
+        nameMata.get("location"), catalog.convertToDatabase(namespace, meta).getLocationUri());
+  }
+
+  @Test
+  public void testNamespaceExists() throws TException {
+    Namespace namespace = Namespace.of("dbname_exists");
+
+    catalog.createNamespace(namespace, meta);
+
+    Assert.assertTrue("Should true to namespace exist",
+        catalog.namespaceExists(namespace));
+    Assert.assertTrue("Should false to namespace doesn't exist",
+        !catalog.namespaceExists(Namespace.of("db2", "db2", "ns2")));
+  }
+
+  @Test
+  public void testSetNamespaceProperties() throws TException {
+    Namespace namespace = Namespace.of("dbname_set");
+
+    catalog.createNamespace(namespace, meta);
+    catalog.setProperties(namespace,
+        ImmutableMap.of(
+            "owner", "alter_apache",
+            "test", "test",
+            "location", "file:/data/tmp",
+            "comment", "iceberg test")
+    );
+
+    Database database = metastoreClient.getDatabase(namespace.level(0));
+    Assert.assertEquals(database.getParameters().get("owner"), "alter_apache");
+    Assert.assertEquals(database.getParameters().get("test"), "test");
+    Assert.assertEquals(database.getParameters().get("group"), "iceberg");
+    AssertHelpers.assertThrows("Should fail to namespace not exist" + namespace,
+        NoSuchNamespaceException.class, "Namespace does not exist: ", () -> {
+          catalog.setProperties(Namespace.of("db2", "db2", "ns2"), meta);
+        });
+  }
+
+  @Test
+  public void testRemoveNamespaceProperties() throws TException {
+    Namespace namespace = Namespace.of("dbname_remove");
+
+    catalog.createNamespace(namespace, meta);
+
+    catalog.removeProperties(namespace, ImmutableSet.of("comment", "owner"));
+
+    Database database = metastoreClient.getDatabase(namespace.level(0));
+
+    Assert.assertEquals(database.getParameters().get("owner"), null);
+    Assert.assertEquals(database.getParameters().get("group"), "iceberg");
+    AssertHelpers.assertThrows("Should fail to namespace not exist" + namespace,
+        NoSuchNamespaceException.class, "Namespace does not exist: ", () -> {
+          catalog.removeProperties(Namespace.of("db2", "db2", "ns2"), ImmutableSet.of("comment", "owner"));
+        });
+  }
+
+  @Test
+  public void testDropNamespace() throws TException {
+    Namespace namespace = Namespace.of("dbname_drop");
+    TableIdentifier identifier = TableIdentifier.of(namespace, "table");
+    Schema schema = new Schema(Types.StructType.of(
+        required(1, "id", Types.LongType.get())).fields());
+
+    catalog.createNamespace(namespace, meta);
+    catalog.createTable(identifier, schema);
+    Map<String, String> nameMata = catalog.loadNamespaceMetadata(namespace);
+    Assert.assertTrue(nameMata.get("owner").equals("apache"));
+    Assert.assertTrue(nameMata.get("group").equals("iceberg"));
+
+    AssertHelpers.assertThrows("Should fail to drop namespace is not empty" + namespace,
+        NamespaceNotEmptyException.class,
+        "Namespace dbname_drop is not empty. One or more tables exist.", () -> {
+          catalog.dropNamespace(namespace);
+        });
+    Assert.assertTrue(catalog.dropTable(identifier, true));
+    Assert.assertTrue("Should fail to drop namespace if it is not empty",
+        catalog.dropNamespace(namespace));
+    Assert.assertFalse("Should fail to drop when namespace doesn't exist",
+        catalog.dropNamespace(Namespace.of("db.ns1")));
+    AssertHelpers.assertThrows("Should fail to drop namespace exist" + namespace,
+        NoSuchNamespaceException.class, "Namespace does not exist: ", () -> {
+          catalog.loadNamespaceMetadata(namespace);
+        });
+  }
+
+  private String defaultUri(Namespace namespace) throws TException {
+    return metastoreClient.getConfigValue(
+        "hive.metastore.warehouse.dir", "") +  "/" + namespace.level(0) + ".db";
+  }
+
+}