From 89673da0beb2b64434d29a94e07fa9c6fb4a93e8 Mon Sep 17 00:00:00 2001 From: Eduard Tudenhoefner Date: Tue, 5 Dec 2023 10:29:32 -0800 Subject: [PATCH] [SPARK-45807][SQL] Add createOrReplaceView(..) / replaceView(..) to ViewCatalog ### What changes were proposed in this pull request? ViewCatalog API improvements described in [SPIP](https://docs.google.com/document/d/1XOxFtloiMuW24iqJ-zJnDzHl2KMxipTjJoxleJFz66A/edit?usp=sharing) that didn't make it into the codebase as part of #37556 ### Why are the changes needed? Required for DataSourceV2 view support. ### Does this PR introduce _any_ user-facing change? No ### How was this patch tested? N/A ### Was this patch authored or co-authored using generative AI tooling? N/A Closes #43677 from nastra/SPARK-45807. Authored-by: Eduard Tudenhoefner Signed-off-by: Holden Karau --- .../sql/connector/catalog/ViewCatalog.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ViewCatalog.java b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ViewCatalog.java index eb67b9904869d..eef348928b2ca 100644 --- a/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ViewCatalog.java +++ b/sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/ViewCatalog.java @@ -140,6 +140,92 @@ View createView( String[] columnComments, Map properties) throws ViewAlreadyExistsException, NoSuchNamespaceException; + /** + * Replace a view in the catalog. + *

+ * The default implementation has a race condition. + * Catalogs are encouraged to implement this operation atomically. + * + * @param ident a view identifier + * @param sql the SQL text that defines the view + * @param currentCatalog the current catalog + * @param currentNamespace the current namespace + * @param schema the view query output schema + * @param queryColumnNames the query column names + * @param columnAliases the column aliases + * @param columnComments the column comments + * @param properties the view properties + * @throws NoSuchViewException If the view doesn't exist or is a table + * @throws NoSuchNamespaceException If the identifier namespace does not exist (optional) + */ + default void replaceView( + Identifier ident, + String sql, + String currentCatalog, + String[] currentNamespace, + StructType schema, + String[] queryColumnNames, + String[] columnAliases, + String[] columnComments, + Map properties) throws NoSuchViewException, NoSuchNamespaceException { + if (viewExists(ident)) { + dropView(ident); + try { + createView(ident, sql, currentCatalog, currentNamespace, schema, + queryColumnNames, columnAliases, columnComments, properties); + } + catch (ViewAlreadyExistsException e) { + throw new RuntimeException("Race condition when dropping and creating view", e); + } + } else { + throw new NoSuchViewException(ident); + } + } + + /** + * Create or replace a view in the catalog. + *

+ * The default implementation has race conditions. + * Catalogs are encouraged to implement this operation atomically. + * + * @param ident a view identifier + * @param sql the SQL text that defines the view + * @param currentCatalog the current catalog + * @param currentNamespace the current namespace + * @param schema the view query output schema + * @param queryColumnNames the query column names + * @param columnAliases the column aliases + * @param columnComments the column comments + * @param properties the view properties + * @throws NoSuchNamespaceException If the identifier namespace does not exist (optional) + */ + default void createOrReplaceView( + Identifier ident, + String sql, + String currentCatalog, + String[] currentNamespace, + StructType schema, + String[] queryColumnNames, + String[] columnAliases, + String[] columnComments, + Map properties) throws NoSuchNamespaceException { + if (viewExists(ident)) { + try { + replaceView(ident, sql, currentCatalog, currentNamespace, schema, + queryColumnNames, columnAliases, columnComments, properties); + } catch (NoSuchViewException e) { + throw new RuntimeException("Race condition when checking and replacing view", e); + } + } else { + try { + createView(ident, sql, currentCatalog, currentNamespace, schema, + queryColumnNames, columnAliases, columnComments, properties); + } catch (ViewAlreadyExistsException e) { + throw new RuntimeException("Race condition when checking and creating view", e); + } + } + } + /** * Apply {@link ViewChange changes} to a view in the catalog. *