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
30 changes: 26 additions & 4 deletions presto-docs/src/main/sphinx/sql/alter-table.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,57 @@ Synopsis

.. code-block:: none

ALTER TABLE name RENAME TO new_name
ALTER TABLE name ADD COLUMN column_name data_type [ COMMENT comment ] [ WITH ( property_name = expression [, ...] ) ]
ALTER TABLE name DROP COLUMN column_name
ALTER TABLE name RENAME COLUMN column_name TO new_column_name
ALTER TABLE [ IF EXISTS ] name RENAME TO new_name
ALTER TABLE [ IF EXISTS ] name ADD COLUMN [ IF NOT EXISTS ] column_name data_type [ COMMENT comment ] [ WITH ( property_name = expression [, ...] ) ]
ALTER TABLE [ IF EXISTS ] name DROP COLUMN column_name
ALTER TABLE [ IF EXISTS ] name RENAME COLUMN [ IF EXISTS ] column_name TO new_column_name

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

Change the definition of an existing table.

The optional ``IF EXISTS`` (when used before the table name) clause causes the error to be suppressed if the table does not exists.

The optional ``IF EXISTS`` (when used before the column name) clause causes the error to be suppressed if the column does not exists.

The optional ``IF NOT EXISTS`` clause causes the error to be suppressed if the column already exists.

Examples
--------

Rename table ``users`` to ``people``::

ALTER TABLE users RENAME TO people;

Rename table ``users`` to ``people`` if table ``users`` exists::

ALTER TABLE IF EXISTS users RENAME TO people;

Add column ``zip`` to the ``users`` table::

ALTER TABLE users ADD COLUMN zip varchar;

Add column ``zip`` to the ``users`` table if table ``users`` exists and column ``zip`` not already exists::

ALTER TABLE IF EXISTS users ADD COLUMN IF NOT EXISTS zip varchar;

Drop column ``zip`` from the ``users`` table::

ALTER TABLE users DROP COLUMN zip;

Drop column ``zip`` from the ``users`` table if table ``users`` and column ``zip`` exists::

ALTER TABLE IF EXISTS users DROP COLUMN IF EXISTS zip;

Rename column ``id`` to ``user_id`` in the ``users`` table::

ALTER TABLE users RENAME COLUMN id TO user_id;

Rename column ``id`` to ``user_id`` in the ``users`` table if table ``users`` and column ``id`` exists::

ALTER TABLE IF EXISTS users RENAME column IF EXISTS id to user_id;

See Also
--------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ public ListenableFuture<?> execute(AddColumn statement, TransactionManager trans
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getName());
Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName);
if (!tableHandle.isPresent()) {
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
if (!statement.isTableExists()) {
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
}
return immediateFuture(null);
}

ConnectorId connectorId = metadata.getCatalogHandle(session, tableName.getCatalogName())
Expand All @@ -85,7 +88,10 @@ public ListenableFuture<?> execute(AddColumn statement, TransactionManager trans
throw new SemanticException(TYPE_MISMATCH, element, "Unknown type '%s' for column '%s'", element.getType(), element.getName());
}
if (columnHandles.containsKey(element.getName().getValue().toLowerCase(ENGLISH))) {
throw new SemanticException(COLUMN_ALREADY_EXISTS, statement, "Column '%s' already exists", element.getName());
if (!statement.isColumnNotExists()) {
throw new SemanticException(COLUMN_ALREADY_EXISTS, statement, "Column '%s' already exists", element.getName());
}
return immediateFuture(null);
}
if (!element.isNullable() && !metadata.getConnectorCapabilities(session, connectorId).contains(NOT_NULL_COLUMN_CONSTRAINT)) {
throw new SemanticException(NOT_SUPPORTED, element, "Catalog '%s' does not support NOT NULL for column '%s'", connectorId.getCatalogName(), element.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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_COLUMN;
Expand All @@ -48,16 +49,26 @@ public ListenableFuture<?> execute(DropColumn statement, TransactionManager tran
{
Session session = stateMachine.getSession();
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getTable());
TableHandle tableHandle = metadata.getTableHandle(session, tableName)
.orElseThrow(() -> new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName));
Optional<TableHandle> tableHandleOptional = metadata.getTableHandle(session, tableName);

if (!tableHandleOptional.isPresent()) {
if (!statement.isTableExists()) {
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
}
return immediateFuture(null);
}
TableHandle tableHandle = tableHandleOptional.get();

String column = statement.getColumn().getValue().toLowerCase(ENGLISH);

accessControl.checkCanDropColumn(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), tableName);

ColumnHandle columnHandle = metadata.getColumnHandles(session, tableHandle).get(column);
if (columnHandle == null) {
throw new SemanticException(MISSING_COLUMN, statement, "Column '%s' does not exist", column);
if (!statement.isColumnExists()) {
throw new SemanticException(MISSING_COLUMN, statement, "Column '%s' does not exist", column);
}
return immediateFuture(null);
}

if (metadata.getColumnMetadata(session, tableHandle, columnHandle).isHidden()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

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

import static com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.COLUMN_ALREADY_EXISTS;
Expand All @@ -50,8 +51,14 @@ public ListenableFuture<?> execute(RenameColumn statement, TransactionManager tr
{
Session session = stateMachine.getSession();
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getTable());
TableHandle tableHandle = metadata.getTableHandle(session, tableName)
.orElseThrow(() -> new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName));
Optional<TableHandle> tableHandleOptional = metadata.getTableHandle(session, tableName);
if (!tableHandleOptional.isPresent()) {
if (!statement.isTableExists()) {
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
}
return immediateFuture(null);
}
TableHandle tableHandle = tableHandleOptional.get();

String source = statement.getSource().getValue().toLowerCase(ENGLISH);
String target = statement.getTarget().getValue().toLowerCase(ENGLISH);
Expand All @@ -61,7 +68,10 @@ public ListenableFuture<?> execute(RenameColumn statement, TransactionManager tr
Map<String, ColumnHandle> columnHandles = metadata.getColumnHandles(session, tableHandle);
ColumnHandle columnHandle = columnHandles.get(source);
if (columnHandle == null) {
throw new SemanticException(MISSING_COLUMN, statement, "Column '%s' does not exist", source);
if (!statement.isColumnExists()) {
throw new SemanticException(MISSING_COLUMN, statement, "Column '%s' does not exist", source);
}
return immediateFuture(null);
}

if (columnHandles.containsKey(target)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ public ListenableFuture<?> execute(RenameTable statement, TransactionManager tra
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getSource());
Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName);
if (!tableHandle.isPresent()) {
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
if (!statement.isExists()) {
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
}
return immediateFuture(null);
}

QualifiedObjectName target = createQualifiedObjectName(session, statement, statement.getTarget());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,14 @@ statement
| DROP TABLE (IF EXISTS)? qualifiedName #dropTable
| INSERT INTO qualifiedName columnAliases? query #insertInto
| DELETE FROM qualifiedName (WHERE booleanExpression)? #delete
| ALTER TABLE from=qualifiedName RENAME TO to=qualifiedName #renameTable
| ALTER TABLE tableName=qualifiedName
RENAME COLUMN from=identifier TO to=identifier #renameColumn
| ALTER TABLE tableName=qualifiedName
DROP COLUMN column=qualifiedName #dropColumn
| ALTER TABLE tableName=qualifiedName
ADD COLUMN column=columnDefinition #addColumn
| ALTER TABLE (IF EXISTS)? from=qualifiedName
RENAME TO to=qualifiedName #renameTable
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName
RENAME COLUMN (IF EXISTS)? from=identifier TO to=identifier #renameColumn
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName
DROP COLUMN (IF EXISTS)? column=qualifiedName #dropColumn
| ALTER TABLE (IF EXISTS)? tableName=qualifiedName
ADD COLUMN (IF NOT EXISTS)? column=columnDefinition #addColumn
| ANALYZE qualifiedName (WITH properties)? #analyze
| CREATE (OR REPLACE)? VIEW qualifiedName
(SECURITY (DEFINER | INVOKER))? AS query #createView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1067,8 +1067,11 @@ protected Void visitDropTable(DropTable node, Integer context)
@Override
protected Void visitRenameTable(RenameTable node, Integer context)
{
builder.append("ALTER TABLE ")
.append(node.getSource())
builder.append("ALTER TABLE ");
if (node.isExists()) {
builder.append("IF EXISTS ");
}
builder.append(node.getSource())
.append(" RENAME TO ")
.append(node.getTarget());

Expand All @@ -1078,10 +1081,16 @@ protected Void visitRenameTable(RenameTable node, Integer context)
@Override
protected Void visitRenameColumn(RenameColumn node, Integer context)
{
builder.append("ALTER TABLE ")
.append(node.getTable())
.append(" RENAME COLUMN ")
.append(node.getSource())
builder.append("ALTER TABLE ");
if (node.isTableExists()) {
builder.append("IF EXISTS ");
}
builder.append(node.getTable())
.append(" RENAME COLUMN ");
if (node.isColumnExists()) {
builder.append("IF EXISTS ");
}
builder.append(node.getSource())
.append(" TO ")
.append(node.getTarget());

Expand All @@ -1091,10 +1100,16 @@ protected Void visitRenameColumn(RenameColumn node, Integer context)
@Override
protected Void visitDropColumn(DropColumn node, Integer context)
{
builder.append("ALTER TABLE ")
.append(formatName(node.getTable()))
.append(" DROP COLUMN ")
.append(formatExpression(node.getColumn(), parameters));
builder.append("ALTER TABLE ");
if (node.isTableExists()) {
builder.append("IF EXISTS ");
}
builder.append(formatName(node.getTable()))
.append(" DROP COLUMN ");
if (node.isColumnExists()) {
builder.append("IF EXISTS ");
}
builder.append(formatExpression(node.getColumn(), parameters));

return null;
}
Expand All @@ -1111,10 +1126,16 @@ protected Void visitAnalyze(Analyze node, Integer context)
@Override
protected Void visitAddColumn(AddColumn node, Integer indent)
{
builder.append("ALTER TABLE ")
.append(node.getName())
.append(" ADD COLUMN ")
.append(formatColumnDefinition(node.getColumn()));
builder.append("ALTER TABLE ");
if (node.isTableExists()) {
builder.append("IF EXISTS ");
}
builder.append(node.getName())
.append(" ADD COLUMN ");
if (node.isColumnNotExists()) {
builder.append("IF NOT EXISTS ");
}
builder.append(formatColumnDefinition(node.getColumn()));

return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ public Node visitDelete(SqlBaseParser.DeleteContext context)
@Override
public Node visitRenameTable(SqlBaseParser.RenameTableContext context)
{
return new RenameTable(getLocation(context), getQualifiedName(context.from), getQualifiedName(context.to));
return new RenameTable(getLocation(context), getQualifiedName(context.from), getQualifiedName(context.to), context.EXISTS() != null);
}

@Override
Expand All @@ -382,7 +382,9 @@ public Node visitRenameColumn(SqlBaseParser.RenameColumnContext context)
getLocation(context),
getQualifiedName(context.tableName),
(Identifier) visit(context.from),
(Identifier) visit(context.to));
(Identifier) visit(context.to),
context.EXISTS().stream().anyMatch(node -> node.getSymbol().getTokenIndex() < context.COLUMN().getSymbol().getTokenIndex()),
context.EXISTS().stream().anyMatch(node -> node.getSymbol().getTokenIndex() > context.COLUMN().getSymbol().getTokenIndex()));
}

@Override
Expand All @@ -401,13 +403,21 @@ public Node visitAnalyze(SqlBaseParser.AnalyzeContext context)
@Override
public Node visitAddColumn(SqlBaseParser.AddColumnContext context)
{
return new AddColumn(getLocation(context), getQualifiedName(context.qualifiedName()), (ColumnDefinition) visit(context.columnDefinition()));
return new AddColumn(getLocation(context),
getQualifiedName(context.qualifiedName()),
(ColumnDefinition) visit(context.columnDefinition()),
context.EXISTS().stream().anyMatch(node -> node.getSymbol().getTokenIndex() < context.COLUMN().getSymbol().getTokenIndex()),
context.EXISTS().stream().anyMatch(node -> node.getSymbol().getTokenIndex() > context.COLUMN().getSymbol().getTokenIndex()));
}

@Override
public Node visitDropColumn(SqlBaseParser.DropColumnContext context)
{
return new DropColumn(getLocation(context), getQualifiedName(context.tableName), (Identifier) visit(context.column));
return new DropColumn(getLocation(context),
getQualifiedName(context.tableName),
(Identifier) visit(context.column),
context.EXISTS().stream().anyMatch(node -> node.getSymbol().getTokenIndex() < context.COLUMN().getSymbol().getTokenIndex()),
context.EXISTS().stream().anyMatch(node -> node.getSymbol().getTokenIndex() > context.COLUMN().getSymbol().getTokenIndex()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,27 @@ public class AddColumn
{
private final QualifiedName name;
private final ColumnDefinition column;
private final boolean tableExists;
private final boolean columnNotExists;

public AddColumn(QualifiedName name, ColumnDefinition column, boolean tableExists, boolean columnNotExists)

public AddColumn(QualifiedName name, ColumnDefinition column)
{
this(Optional.empty(), name, column);
this(Optional.empty(), name, column, tableExists, columnNotExists);
}

public AddColumn(NodeLocation location, QualifiedName name, ColumnDefinition column)
public AddColumn(NodeLocation location, QualifiedName name, ColumnDefinition column, boolean tableExists, boolean columnNotExists)
{
this(Optional.of(location), name, column);
this(Optional.of(location), name, column, tableExists, columnNotExists);
}

private AddColumn(Optional<NodeLocation> location, QualifiedName name, ColumnDefinition column)
private AddColumn(Optional<NodeLocation> location, QualifiedName name, ColumnDefinition column, boolean tableExists, boolean columnNotExists)
{
super(location);
this.name = requireNonNull(name, "table is null");
this.column = requireNonNull(column, "column is null");
this.tableExists = tableExists;
this.columnNotExists = columnNotExists;
}

public QualifiedName getName()
Expand All @@ -55,6 +60,16 @@ public ColumnDefinition getColumn()
return column;
}

public boolean isTableExists()
{
return tableExists;
}

public boolean isColumnNotExists()
{
return columnNotExists;
}

@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
Expand Down
Loading