Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public enum SemanticErrorCode
VIEW_IS_STALE,
VIEW_IS_RECURSIVE,
MATERIALIZED_VIEW_IS_RECURSIVE,
MISSING_VIEW,
VIEW_ALREADY_EXISTS,

NON_NUMERIC_SAMPLE_PERCENTAGE,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import com.facebook.presto.sql.tree.RenameColumn;
import com.facebook.presto.sql.tree.RenameSchema;
import com.facebook.presto.sql.tree.RenameTable;
import com.facebook.presto.sql.tree.RenameView;
import com.facebook.presto.sql.tree.ResetSession;
import com.facebook.presto.sql.tree.Revoke;
import com.facebook.presto.sql.tree.RevokeRoles;
Expand Down Expand Up @@ -134,6 +135,7 @@ private StatementUtils() {}
builder.put(AddConstraint.class, QueryType.DATA_DEFINITION);
builder.put(AlterColumnNotNull.class, QueryType.DATA_DEFINITION);
builder.put(CreateView.class, QueryType.DATA_DEFINITION);
builder.put(RenameView.class, QueryType.DATA_DEFINITION);
builder.put(TruncateTable.class, QueryType.DATA_DEFINITION);
builder.put(DropView.class, QueryType.DATA_DEFINITION);
builder.put(CreateMaterializedView.class, QueryType.DATA_DEFINITION);
Expand Down
9 changes: 9 additions & 0 deletions presto-docs/src/main/sphinx/connector/iceberg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,15 @@ For example, to set `commit_retries` to 6 for the table `iceberg.web.page_views_

ALTER TABLE iceberg.web.page_views_v2 SET PROPERTIES (commit_retries = 6);

ALTER VIEW
^^^^^^^^^^

Alter view operations to alter the name of an existing view to a new name is supported in the Iceberg connector.

.. code-block:: sql

ALTER VIEW iceberg.web.page_views RENAME TO iceberg.web.page_new_views;

TRUNCATE
^^^^^^^^

Expand Down
9 changes: 9 additions & 0 deletions presto-docs/src/main/sphinx/connector/memory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ To delete an existing table:

.. note:: After using ``DROP TABLE``, memory is not released immediately. It is released after the next write access to the memory connector.

ALTER VIEW
^^^^^^^^^^

Alter view operations to alter the name of an existing view to a new name is supported in the Memory connector.

.. code-block:: sql

ALTER VIEW memory.default.nation RENAME TO memory.default.new_nation;

Memory Connector Limitations
----------------------------

Expand Down
1 change: 1 addition & 0 deletions presto-docs/src/main/sphinx/sql.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This chapter describes the SQL syntax used in Presto.
sql/alter-function
sql/alter-schema
sql/alter-table
sql/alter-view
sql/analyze
sql/call
sql/commit
Expand Down
42 changes: 42 additions & 0 deletions presto-docs/src/main/sphinx/sql/alter-view.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
==========
ALTER VIEW
==========

Synopsis
--------

.. code-block:: sql

ALTER VIEW [IF EXISTS] old_view_name RENAME TO new_view_name;

Description
-----------

The ``ALTER VIEW [IF EXISTS] RENAME TO`` statement renames an existing view to a
new name. This allows you to change the name of a view without having to drop
and recreate it. The view's definition, security settings, and dependencies
remain unchanged; only the name of the view is updated.

The optional ``IF EXISTS`` clause prevents an error from being raised if the
view does not exist. Instead, no action is taken, and a notice is issued.

Renaming a view does not affect the data or structure of the underlying
query used to define the view. Any permissions or dependencies on the
view are retained, and queries or applications using the old name must
be updated to use the new name.

Examples
--------

Rename the view ``users`` to ``people``::

ALTER VIEW users RENAME TO people;

Rename the view ``users`` to ``people`` if view ``users`` exists::

ALTER VIEW IF EXISTS users RENAME TO people;

See Also
--------

:doc:`create-view`
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,11 @@ public static boolean isIcebergTable(Map<String, String> tableParameters)
return ICEBERG_TABLE_TYPE_VALUE.equalsIgnoreCase(tableParameters.get(ICEBERG_TABLE_TYPE_NAME));
}

public static boolean isIcebergView(Table table)
{
return "true".equalsIgnoreCase(table.getParameters().get(PRESTO_VIEW_FLAG));
}

public static PrincipalPrivileges buildInitialPrivilegeSet(String tableOwner)
{
PrestoPrincipal owner = new PrestoPrincipal(USER, tableOwner);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
import static com.facebook.presto.hive.metastore.MetastoreUtil.getHiveBasicStatistics;
import static com.facebook.presto.hive.metastore.MetastoreUtil.getPartitionNamesWithEmptyVersion;
import static com.facebook.presto.hive.metastore.MetastoreUtil.isIcebergTable;
import static com.facebook.presto.hive.metastore.MetastoreUtil.isIcebergView;
import static com.facebook.presto.hive.metastore.MetastoreUtil.makePartName;
import static com.facebook.presto.hive.metastore.MetastoreUtil.toPartitionValues;
import static com.facebook.presto.hive.metastore.MetastoreUtil.updateStatisticsParameters;
Expand Down Expand Up @@ -511,13 +512,11 @@ public synchronized MetastoreOperationResult renameTable(MetastoreContext metast
requireNonNull(tableName, "tableName is null");
requireNonNull(newDatabaseName, "newDatabaseName is null");
requireNonNull(newTableName, "newTableName is null");

Table table = getRequiredTable(metastoreContext, databaseName, tableName);
getRequiredDatabase(metastoreContext, newDatabaseName);
if (isIcebergTable(table)) {
if (isIcebergTable(table) && !isIcebergView(table)) {
throw new PrestoException(NOT_SUPPORTED, "Rename not supported for Iceberg tables");
}

// verify new table does not exist
verifyTableNotExists(metastoreContext, newDatabaseName, newTableName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ public void checkCanCreateView(ConnectorTransactionHandle transaction, Connector
{
}

@Override
public void checkCanRenameView(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName, SchemaTableName newViewName)
{
}

@Override
public void checkCanDropView(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
import static com.facebook.presto.spi.security.AccessDeniedException.denyRenameColumn;
import static com.facebook.presto.spi.security.AccessDeniedException.denyRenameSchema;
import static com.facebook.presto.spi.security.AccessDeniedException.denyRenameTable;
import static com.facebook.presto.spi.security.AccessDeniedException.denyRenameView;
import static com.facebook.presto.spi.security.AccessDeniedException.denyRevokeRoles;
import static com.facebook.presto.spi.security.AccessDeniedException.denyRevokeTablePrivilege;
import static com.facebook.presto.spi.security.AccessDeniedException.denySelectTable;
Expand Down Expand Up @@ -451,6 +452,24 @@ public void checkCanCreateView(ConnectorTransactionHandle transaction, Connector
}
}

@Override
public void checkCanRenameView(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName, SchemaTableName newViewName)
{
MetastoreContext metastoreContext = new MetastoreContext(
identity, context.getQueryId().getId(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: split these arguments onto two lines

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZacBlanco - This syntax is used consistently for the other methods in the class.

context.getClientInfo(),
context.getClientTags(),
context.getSource(),
Optional.empty(),
false,
HiveColumnConverterProvider.DEFAULT_COLUMN_CONVERTER_PROVIDER,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: static import

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZacBlanco - This syntax is used consistently for the other methods in the class.

context.getWarningCollector(),
context.getRuntimeStats());
if (!isTableOwner(transaction, identity, metastoreContext, viewName)) {
denyRenameView(viewName.toString(), newViewName.toString());
}
}

@Override
public void checkCanDropView(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ public void checkCanCreateView(ConnectorTransactionHandle transactionHandle, Con
delegate.checkCanCreateView(transactionHandle, identity, context, viewName);
}

@Override
public void checkCanRenameView(ConnectorTransactionHandle transactionHandle, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName, SchemaTableName newViewName)
{
delegate.checkCanRenameView(transactionHandle, identity, context, viewName, newViewName);
}

@Override
public void checkCanDropView(ConnectorTransactionHandle transactionHandle, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,13 @@ public Map<SchemaTableName, ConnectorViewDefinition> getViews(ConnectorSession s
return views.build();
}

@Override
public void renameView(ConnectorSession session, SchemaTableName source, SchemaTableName target)
{
// Not checking if source view exists as this is already done in RenameViewTask
metastore.renameTable(getMetastoreContext(session), source.getSchemaName(), source.getTableName(), target.getSchemaName(), target.getTableName());
}

@Override
public void dropView(ConnectorSession session, SchemaTableName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,25 @@ public void testTableValidation()
assertQuerySucceeds("SELECT * FROM iceberg.test_schema.iceberg_table1");
assertQueryFails("SELECT * FROM iceberg.test_schema.hive_table", "Not an Iceberg table: test_schema.hive_table");
}

@Test
public void testRenameView()
{
assertQuerySucceeds("CREATE TABLE iceberg.test_schema.iceberg_test_table (_string VARCHAR, _integer INTEGER)");
assertUpdate("CREATE VIEW iceberg.test_schema.test_view_to_be_renamed AS SELECT * FROM iceberg.test_schema.iceberg_test_table");
assertUpdate("ALTER VIEW IF EXISTS iceberg.test_schema.test_view_to_be_renamed RENAME TO iceberg.test_schema.test_view_renamed");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a case without the IF EXISTS clause?

assertUpdate("CREATE VIEW iceberg.test_schema.test_view2_to_be_renamed AS SELECT * FROM iceberg.test_schema.iceberg_test_table");
assertUpdate("ALTER VIEW iceberg.test_schema.test_view2_to_be_renamed RENAME TO iceberg.test_schema.test_view2_renamed");
assertQuerySucceeds("SELECT * FROM iceberg.test_schema.test_view_renamed");
assertQuerySucceeds("SELECT * FROM iceberg.test_schema.test_view2_renamed");
assertUpdate("DROP VIEW iceberg.test_schema.test_view_renamed");
assertUpdate("DROP VIEW iceberg.test_schema.test_view2_renamed");
assertUpdate("DROP TABLE iceberg.test_schema.iceberg_test_table");
}
@Test
public void testRenameViewIfNotExists()
{
assertQueryFails("ALTER VIEW iceberg.test_schema.test_rename_view_not_exist RENAME TO iceberg.test_schema.test_renamed_view_not_exist", "line 1:1: View 'iceberg.test_schema.test_rename_view_not_exist' does not exist");
assertQuerySucceeds("ALTER VIEW IF EXISTS iceberg.test_schema.test_rename_view_not_exist RENAME TO iceberg.test_schema.test_renamed_view_not_exist");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Licensed 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 com.facebook.presto.execution;

import com.facebook.presto.Session;
import com.facebook.presto.common.QualifiedObjectName;
import com.facebook.presto.metadata.Metadata;
import com.facebook.presto.spi.WarningCollector;
import com.facebook.presto.spi.analyzer.ViewDefinition;
import com.facebook.presto.spi.security.AccessControl;
import com.facebook.presto.sql.analyzer.SemanticException;
import com.facebook.presto.sql.tree.Expression;
import com.facebook.presto.sql.tree.RenameView;
import com.facebook.presto.transaction.TransactionManager;
import com.google.common.util.concurrent.ListenableFuture;

import java.util.List;
import java.util.Optional;

import static com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_CATALOG;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_VIEW;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NOT_SUPPORTED;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.VIEW_ALREADY_EXISTS;
import static com.google.common.util.concurrent.Futures.immediateFuture;

public class RenameViewTask
implements DDLDefinitionTask<RenameView>
{
@Override
public String getName()
{
return "RENAME VIEW";
}

public ListenableFuture<?> execute(RenameView statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector)
{
QualifiedObjectName viewName = createQualifiedObjectName(session, statement, statement.getSource());

Optional<ViewDefinition> view = metadata.getMetadataResolver(session).getView(viewName);
if (!view.isPresent()) {
if (!statement.isExists()) {
throw new SemanticException(MISSING_VIEW, statement, "View '%s' does not exist", viewName);
}
return immediateFuture(null);
}

QualifiedObjectName target = createQualifiedObjectName(session, statement, statement.getTarget());
if (!metadata.getCatalogHandle(session, target.getCatalogName()).isPresent()) {
throw new SemanticException(MISSING_CATALOG, statement, "Target catalog '%s' does not exist", target.getCatalogName());
}
if (metadata.getMetadataResolver(session).getView(target).isPresent()) {
throw new SemanticException(VIEW_ALREADY_EXISTS, statement, "Target view '%s' already exists", target);
}
if (!viewName.getSchemaName().equals(target.getSchemaName())) {
throw new SemanticException(NOT_SUPPORTED, statement, "View rename across schemas is not supported");
}
if (!viewName.getCatalogName().equals(target.getCatalogName())) {
throw new SemanticException(NOT_SUPPORTED, statement, "View rename across catalogs is not supported");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We support renaming across schemas though? Does it make sense to rename across schemas? What if the source tables don't exist in the new schema?

}

accessControl.checkCanRenameView(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), viewName, target);

metadata.renameView(session, viewName, target);

return immediateFuture(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,12 @@ public void createView(Session session, String catalogName, ConnectorTableMetada
delegate.createView(session, catalogName, viewMetadata, viewData, replace);
}

@Override
public void renameView(Session session, QualifiedObjectName existingViewName, QualifiedObjectName newViewName)
{
delegate.renameView(session, existingViewName, newViewName);
}

@Override
public void dropView(Session session, QualifiedObjectName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ public interface Metadata
*/
void createView(Session session, String catalogName, ConnectorTableMetadata viewMetadata, String viewData, boolean replace);

/**
* Rename the specified view.
*/
void renameView(Session session, QualifiedObjectName existingViewName, QualifiedObjectName newViewName);

/**
* Drops the specified view.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,16 @@ public void createView(Session session, String catalogName, ConnectorTableMetada
metadata.createView(session.toConnectorSession(connectorId), viewMetadata, viewData, replace);
}

@Override
public void renameView(Session session, QualifiedObjectName source, QualifiedObjectName target)
{
CatalogMetadata catalogMetadata = getCatalogMetadataForWrite(session, target.getCatalogName());
ConnectorId connectorId = catalogMetadata.getConnectorId();
ConnectorMetadata metadata = catalogMetadata.getMetadata();

metadata.renameView(session.toConnectorSession(connectorId), toSchemaTableName(source), toSchemaTableName(target));
}

@Override
public void dropView(Session session, QualifiedObjectName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,23 @@ public void checkCanCreateView(TransactionId transactionId, Identity identity, A
}
}

@Override
public void checkCanRenameView(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName viewName, QualifiedObjectName newViewName)
{
requireNonNull(context, "context is null");
requireNonNull(viewName, "viewName is null");
requireNonNull(newViewName, "newViewName is null");

authenticationCheck(() -> checkCanAccessCatalog(identity, context, viewName.getCatalogName()));

authorizationCheck(() -> systemAccessControl.get().checkCanRenameView(identity, context, toCatalogSchemaTableName(viewName), toCatalogSchemaTableName(newViewName)));

CatalogAccessControlEntry entry = getConnectorAccessControl(transactionId, viewName.getCatalogName());
if (entry != null) {
authorizationCheck(() -> entry.getAccessControl().checkCanRenameView(entry.getTransactionHandle(transactionId), identity.toConnectorIdentity(viewName.getCatalogName()), context, toSchemaTableName(viewName), toSchemaTableName(newViewName)));
}
}

@Override
public void checkCanDropView(TransactionId transactionId, Identity identity, AccessControlContext context, QualifiedObjectName viewName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ public void checkCanCreateView(Identity identity, AccessControlContext context,
{
}

@Override
public void checkCanRenameView(Identity identity, AccessControlContext context, CatalogSchemaTableName view, CatalogSchemaTableName newView)
{
}

@Override
public void checkCanDropView(Identity identity, AccessControlContext context, CatalogSchemaTableName view)
{
Expand Down
Loading