diff --git a/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/TableCatalog.java b/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/TableCatalog.java index 4b9498d601c26..6e3851de42f80 100644 --- a/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/TableCatalog.java +++ b/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/TableCatalog.java @@ -89,7 +89,7 @@ default boolean tableExists(Identifier ident) { * @param partitions transforms to use for partitioning data in the table * @param properties a string map of table properties * @return metadata for the new table - * @throws TableAlreadyExistsException If a table already exists for the identifier + * @throws TableAlreadyExistsException If a table or view already exists for the identifier * @throws UnsupportedOperationException If a requested partition transform is not supported * @throws NoSuchNamespaceException If the identifier namespace does not exist (optional) */ diff --git a/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/View.java b/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/View.java new file mode 100644 index 0000000000000..26961d6c82786 --- /dev/null +++ b/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/View.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.spark.sql.catalog.v2; + +public interface View { + /** + * A name to identify this view. Implementations should provide a meaningful name, like the + * database and view name from the catalog. + */ + String name(); + + /** + * SQL text that defines the view. + * + * @return the SQL query text that defines this view + */ + String sql(); +} diff --git a/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/ViewCatalog.java b/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/ViewCatalog.java new file mode 100644 index 0000000000000..70e2bd2f672a7 --- /dev/null +++ b/sql/catalyst/src/main/java/org/apache/spark/sql/catalog/v2/ViewCatalog.java @@ -0,0 +1,91 @@ +/* + * 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.spark.sql.catalog.v2; + +import org.apache.spark.sql.catalyst.analysis.NoSuchNamespaceException; +import org.apache.spark.sql.catalyst.analysis.NoSuchViewException; +import org.apache.spark.sql.catalyst.analysis.ViewAlreadyExistsException; + +/** + * Catalog methods for working with Views. + */ +public interface ViewCatalog extends CatalogPlugin { + /** + * List the views in a namespace from the catalog. + *
+ * If the catalog supports tables, this must return identifiers for only views and not tables. + * + * @param namespace a multi-part namespace + * @return an array of Identifiers for views + * @throws NoSuchNamespaceException If the namespace does not exist (optional). + */ + Identifier[] listViews(String[] namespace) throws NoSuchNamespaceException; + + /** + * Load view metadata by {@link Identifier identifier} from the catalog. + *
+ * If the catalog supports tables and contains a table for the identifier and not a view, this + * must throw {@link NoSuchViewException}. + * + * @param ident a view identifier + * @return the view's metadata + * @throws NoSuchViewException If the view doesn't exist or is a table + */ + View loadView(Identifier ident) throws NoSuchViewException; + + /** + * Test whether a view exists using an {@link Identifier identifier} from the catalog. + *
+ * If the catalog supports views and contains a view for the identifier and not a table, this + * must return false. + * + * @param ident a view identifier + * @return true if the view exists, false otherwise + */ + default boolean viewExists(Identifier ident) { + try { + return loadView(ident) != null; + } catch (NoSuchViewException e) { + return false; + } + } + + /** + * Create a view in the catalog. + * + * @param ident a view identifier + * @param sql SQL text that defines the view + * @return metadata for the new view + * @throws ViewAlreadyExistsException If a view or table already exists for the identifier + * @throws NoSuchNamespaceException If the identifier namespace does not exist (optional) + */ + View createView( + Identifier ident, + String sql) throws ViewAlreadyExistsException, NoSuchNamespaceException; + + /** + * Drop a view in the catalog. + *
+ * If the catalog supports tables and contains a table for the identifier and not a view, this + * must not drop the table and must return false. + * + * @param ident a view identifier + * @return true if a view was deleted, false if no view exists for the identifier + */ + boolean dropView(Identifier ident); +} diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AlreadyExistException.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AlreadyExistException.scala index f5e9a146bf359..9eb140c81173a 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AlreadyExistException.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AlreadyExistException.scala @@ -45,6 +45,12 @@ class TableAlreadyExistsException(message: String) extends AnalysisException(mes } } +class ViewAlreadyExistsException(message: String) extends TableAlreadyExistsException(message) { + def this(tableIdent: Identifier) = { + this(s"View ${tableIdent.quoted} already exists") + } +} + class TempTableAlreadyExistsException(table: String) extends TableAlreadyExistsException(s"Temporary view '$table' already exists") diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/NoSuchItemException.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/NoSuchItemException.scala index 7ac8ae61ed537..b4171660b2e1b 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/NoSuchItemException.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/NoSuchItemException.scala @@ -46,6 +46,12 @@ class NoSuchTableException(message: String) extends AnalysisException(message) { } } +class NoSuchViewException(message: String) extends NoSuchTableException(message) { + def this(tableIdent: Identifier) = { + this(s"View ${tableIdent.quoted} not found") + } +} + class NoSuchPartitionException( db: String, table: String,