Skip to content

Commit 7b915f5

Browse files
dmariamgeorgePratyaksh Sharma
authored andcommitted
Add support for ALTER COLUMN SET DATA TYPE in the Iceberg connector
cherry pick of PR : https://github.ibm.com/lakehouse/presto/pull/732
1 parent cd3e3c8 commit 7b915f5

File tree

43 files changed

+886
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+886
-3
lines changed

presto-analyzer/src/main/java/com/facebook/presto/sql/analyzer/utils/StatementUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import com.facebook.presto.sql.tree.Revoke;
5858
import com.facebook.presto.sql.tree.RevokeRoles;
5959
import com.facebook.presto.sql.tree.Rollback;
60+
import com.facebook.presto.sql.tree.SetColumnType;
6061
import com.facebook.presto.sql.tree.SetProperties;
6162
import com.facebook.presto.sql.tree.SetRole;
6263
import com.facebook.presto.sql.tree.SetSession;
@@ -162,6 +163,7 @@ private StatementUtils() {}
162163
builder.put(Revoke.class, QueryType.DATA_DEFINITION);
163164
builder.put(Prepare.class, QueryType.CONTROL);
164165
builder.put(Deallocate.class, QueryType.CONTROL);
166+
builder.put(SetColumnType.class, QueryType.DATA_DEFINITION);
165167

166168
STATEMENT_QUERY_TYPES = builder.build();
167169
}

presto-blackhole/src/main/java/com/facebook/presto/plugin/blackhole/BlackHoleMetadata.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package com.facebook.presto.plugin.blackhole;
1515

1616
import com.facebook.airlift.units.Duration;
17+
import com.facebook.presto.common.type.Type;
1718
import com.facebook.presto.spi.ColumnHandle;
1819
import com.facebook.presto.spi.ColumnMetadata;
1920
import com.facebook.presto.spi.ConnectorInsertTableHandle;
@@ -286,4 +287,23 @@ private void checkSchemaExists(String schemaName)
286287
throw new SchemaNotFoundException(schemaName);
287288
}
288289
}
290+
291+
@Override
292+
public void setColumnType(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle columnHandle, Type type)
293+
{
294+
BlackHoleTableHandle table = (BlackHoleTableHandle) tableHandle;
295+
BlackHoleColumnHandle column = (BlackHoleColumnHandle) columnHandle;
296+
List<BlackHoleColumnHandle> columns = new ArrayList<>(table.getColumnHandles());
297+
columns.set(columns.indexOf(column), new BlackHoleColumnHandle(column.getName(), type));
298+
299+
tables.put(table.toSchemaTableName(), new BlackHoleTableHandle(
300+
table.getSchemaName(),
301+
table.getTableName(),
302+
ImmutableList.copyOf(columns),
303+
table.getSplitCount(),
304+
table.getPagesPerSplit(),
305+
table.getRowsPerPage(),
306+
table.getFieldsLength(),
307+
table.getPageProcessingDelay()));
308+
}
289309
}

presto-common/src/main/java/com/facebook/presto/common/type/DoubleType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.facebook.presto.common.block.Block;
1717
import com.facebook.presto.common.block.BlockBuilder;
1818
import com.facebook.presto.common.block.BlockBuilderStatus;
19+
import com.facebook.presto.common.block.IntArrayBlock;
1920
import com.facebook.presto.common.block.LongArrayBlockBuilder;
2021
import com.facebook.presto.common.block.PageBuilderStatus;
2122
import com.facebook.presto.common.block.UncheckedBlock;
@@ -27,6 +28,7 @@
2728
import static com.facebook.presto.common.type.TypeUtils.doubleHashCode;
2829
import static java.lang.Double.doubleToLongBits;
2930
import static java.lang.Double.longBitsToDouble;
31+
import static java.lang.Float.intBitsToFloat;
3032

3133
public final class DoubleType
3234
extends AbstractPrimitiveType
@@ -67,6 +69,9 @@ public Object getObjectValue(SqlFunctionProperties properties, Block block, int
6769
if (block.isNull(position)) {
6870
return null;
6971
}
72+
if (IntArrayBlock.class.isInstance(block)) {
73+
return intBitsToFloat(block.getInt(position));
74+
}
7075
return longBitsToDouble(block.getLong(position));
7176
}
7277

presto-docs/src/main/sphinx/sql/alter-table.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Synopsis
1515
ALTER TABLE [ IF EXISTS ] name DROP CONSTRAINT [ IF EXISTS ] constraint_name
1616
ALTER TABLE [ IF EXISTS ] name ALTER [ COLUMN ] column_name { SET | DROP } NOT NULL
1717
ALTER TABLE [ IF EXISTS ] name SET PROPERTIES (property_name=value, [, ...])
18+
ALTER TABLE [ IF EXISTS ] name ALTER COLUMN column_name SET DATA TYPE new_type
1819
1920
Description
2021
-----------

presto-hive/src/main/java/com/facebook/presto/hive/security/LegacyAccessControl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ public void checkCanCreateViewWithSelectFromColumns(ConnectorTransactionHandle t
236236
{
237237
}
238238

239+
@Override
240+
public void checkCanAlterColumn(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName tableName) {}
241+
239242
@Override
240243
public void checkCanSetCatalogSessionProperty(ConnectorTransactionHandle transactionHandle, ConnectorIdentity identity, AccessControlContext context, String propertyName)
241244
{

presto-hive/src/main/java/com/facebook/presto/hive/security/SqlStandardAccessControl.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import static com.facebook.presto.hive.metastore.thrift.ThriftMetastoreUtil.listEnabledTablePrivileges;
5757
import static com.facebook.presto.spi.security.AccessDeniedException.denyAddColumn;
5858
import static com.facebook.presto.spi.security.AccessDeniedException.denyAddConstraint;
59+
import static com.facebook.presto.spi.security.AccessDeniedException.denyAlterColumn;
5960
import static com.facebook.presto.spi.security.AccessDeniedException.denyCreateRole;
6061
import static com.facebook.presto.spi.security.AccessDeniedException.denyCreateSchema;
6162
import static com.facebook.presto.spi.security.AccessDeniedException.denyCreateTable;
@@ -317,6 +318,24 @@ public void checkCanUpdateTableColumns(ConnectorTransactionHandle transaction, C
317318
}
318319
}
319320

321+
@Override
322+
public void checkCanAlterColumn(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName tableName)
323+
{
324+
MetastoreContext metastoreContext = new MetastoreContext(
325+
identity, context.getQueryId().getId(),
326+
context.getClientInfo(),
327+
context.getClientTags(),
328+
context.getSource(),
329+
Optional.empty(),
330+
false,
331+
HiveColumnConverterProvider.DEFAULT_COLUMN_CONVERTER_PROVIDER,
332+
context.getWarningCollector(),
333+
context.getRuntimeStats());
334+
if (isTableOwner(transaction, identity, metastoreContext, tableName)) {
335+
denyAlterColumn(tableName.toString());
336+
}
337+
}
338+
320339
@Override
321340
public void checkCanCreateView(ConnectorTransactionHandle transaction, ConnectorIdentity identity, AccessControlContext context, SchemaTableName viewName)
322341
{

presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergAbstractMetadata.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,10 @@
193193
import static com.facebook.presto.iceberg.optimizer.IcebergPlanOptimizer.getEnforcedColumns;
194194
import static com.facebook.presto.iceberg.util.StatisticsUtil.calculateBaseTableStatistics;
195195
import static com.facebook.presto.iceberg.util.StatisticsUtil.calculateStatisticsConsideringLayout;
196+
import static com.facebook.presto.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR;
196197
import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED;
197198
import static com.facebook.presto.spi.statistics.TableStatisticType.ROW_COUNT;
199+
import static com.google.common.base.MoreObjects.firstNonNull;
198200
import static com.google.common.base.Strings.isNullOrEmpty;
199201
import static com.google.common.base.Verify.verify;
200202
import static com.google.common.collect.ImmutableList.toImmutableList;
@@ -1361,4 +1363,21 @@ public Optional<Object> getInfo(ConnectorTableLayoutHandle tableHandle)
13611363
icebergTableHandle.getTable().getIcebergTableName().getSnapshotId(),
13621364
outputPath.get()));
13631365
}
1366+
1367+
@Override
1368+
public void setColumnType(ConnectorSession session, ConnectorTableHandle tableHandle, ColumnHandle columnHandle, com.facebook.presto.common.type.Type type)
1369+
{
1370+
IcebergTableHandle table = (IcebergTableHandle) tableHandle;
1371+
IcebergColumnHandle column = (IcebergColumnHandle) columnHandle;
1372+
1373+
Table icebergTable = getIcebergTable(session, table.getSchemaTableName());
1374+
try {
1375+
icebergTable.updateSchema()
1376+
.updateColumn(column.getName(), toIcebergType(type).asPrimitiveType())
1377+
.commit();
1378+
}
1379+
catch (RuntimeException e) {
1380+
throw new PrestoException(GENERIC_INTERNAL_ERROR, "Failed to set column type: " + firstNonNull(e.getMessage(), e), e);
1381+
}
1382+
}
13641383
}

presto-main-base/src/main/java/com/facebook/presto/catalogserver/RemoteMetadataManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.facebook.presto.Session;
1818
import com.facebook.presto.common.CatalogSchemaName;
1919
import com.facebook.presto.common.QualifiedObjectName;
20+
import com.facebook.presto.common.type.Type;
2021
import com.facebook.presto.metadata.CatalogMetadata;
2122
import com.facebook.presto.metadata.DelegatingMetadataManager;
2223
import com.facebook.presto.metadata.MetadataManager;
@@ -108,6 +109,9 @@ public List<QualifiedObjectName> listTables(Session session, QualifiedTablePrefi
108109
: readValue(tableListJson, new TypeReference<List<QualifiedObjectName>>() {});
109110
}
110111

112+
@Override
113+
public void setColumnType(Session session, TableHandle tableHandle, ColumnHandle column, Type type) {}
114+
111115
@Override
112116
public List<QualifiedObjectName> listViews(Session session, QualifiedTablePrefix prefix)
113117
{
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.facebook.presto.execution;
15+
16+
import com.facebook.presto.Session;
17+
import com.facebook.presto.common.QualifiedObjectName;
18+
import com.facebook.presto.common.type.RowType;
19+
import com.facebook.presto.common.type.Type;
20+
import com.facebook.presto.common.type.TypeManager;
21+
import com.facebook.presto.metadata.Metadata;
22+
import com.facebook.presto.spi.ColumnHandle;
23+
import com.facebook.presto.spi.MaterializedViewDefinition;
24+
import com.facebook.presto.spi.PrestoException;
25+
import com.facebook.presto.spi.TableHandle;
26+
import com.facebook.presto.spi.WarningCollector;
27+
import com.facebook.presto.spi.security.AccessControl;
28+
import com.facebook.presto.sql.analyzer.SemanticErrorCode;
29+
import com.facebook.presto.sql.analyzer.SemanticException;
30+
import com.facebook.presto.sql.tree.Expression;
31+
import com.facebook.presto.sql.tree.SetColumnType;
32+
import com.facebook.presto.transaction.TransactionManager;
33+
import com.google.common.util.concurrent.ListenableFuture;
34+
import com.google.inject.Inject;
35+
36+
import java.util.List;
37+
import java.util.Map;
38+
import java.util.Optional;
39+
40+
import static com.facebook.presto.common.type.TypeSignature.parseTypeSignature;
41+
import static com.facebook.presto.common.type.UnknownType.UNKNOWN;
42+
import static com.facebook.presto.metadata.MetadataUtil.createQualifiedObjectName;
43+
import static com.facebook.presto.spi.StandardErrorCode.NOT_SUPPORTED;
44+
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_COLUMN;
45+
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_TABLE;
46+
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.TYPE_MISMATCH;
47+
import static com.google.common.collect.ImmutableList.toImmutableList;
48+
import static com.google.common.util.concurrent.Futures.immediateFuture;
49+
import static java.util.Objects.requireNonNull;
50+
51+
public class SetColumnTypeTask
52+
implements DDLDefinitionTask<SetColumnType>
53+
{
54+
private final Metadata metadata;
55+
private final TypeManager typeManager;
56+
private final AccessControl accessControl;
57+
58+
@Inject
59+
public SetColumnTypeTask(Metadata metadata, TypeManager typeManager, AccessControl accessControl)
60+
{
61+
this.metadata = requireNonNull(metadata, "metadata is null");
62+
this.typeManager = requireNonNull(typeManager, "typeManager is null");
63+
this.accessControl = requireNonNull(accessControl, "accessControl is null");
64+
}
65+
66+
@Override
67+
public String getName()
68+
{
69+
return "SET COLUMN TYPE";
70+
}
71+
72+
public ListenableFuture<Void> execute(SetColumnType statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector, String query)
73+
{
74+
QualifiedObjectName tableName = createQualifiedObjectName(session, statement, statement.getTableName(), metadata);
75+
Optional<TableHandle> tableHandle = metadata.getMetadataResolver(session).getTableHandle(tableName);
76+
if (!tableHandle.isPresent()) {
77+
if (!statement.isTableExists()) {
78+
throw new SemanticException(MISSING_TABLE, statement, "Table '%s' does not exist", tableName);
79+
}
80+
return immediateFuture(null);
81+
}
82+
83+
Optional<MaterializedViewDefinition> optionalMaterializedView = metadata.getMetadataResolver(session).getMaterializedView(tableName);
84+
if (optionalMaterializedView.isPresent()) {
85+
if (!statement.isTableExists()) {
86+
throw new SemanticException(SemanticErrorCode.NOT_SUPPORTED, statement, "'%s' is a materialized view, and alter column is not supported", tableName);
87+
}
88+
return immediateFuture(null);
89+
}
90+
91+
accessControl.checkCanAlterColumn(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), tableName);
92+
93+
TableHandle tableHandleOptional = tableHandle.get();
94+
Map<String, ColumnHandle> columnHandles = metadata.getColumnHandles(session, tableHandleOptional);
95+
ColumnHandle column = columnHandles.get(statement.getColumnName().getValue());
96+
if (column == null) {
97+
throw new SemanticException(MISSING_COLUMN, statement, "Column '%s' does not exist", statement.getColumnName());
98+
}
99+
metadata.setColumnType(session, tableHandleOptional, column, getColumnType(statement));
100+
101+
return immediateFuture(null);
102+
}
103+
104+
private static List<RowType.Field> getCandidates(Type type, String fieldName)
105+
{
106+
if (!(type instanceof RowType)) {
107+
throw new PrestoException(NOT_SUPPORTED, "Unsupported type: " + type);
108+
}
109+
RowType rowType = (RowType) type;
110+
List<RowType.Field> candidates = rowType.getFields().stream()
111+
// case-insensitive match
112+
.filter(rowField -> rowField.getName().isPresent() && rowField.getName().get().equalsIgnoreCase(fieldName))
113+
.collect(toImmutableList());
114+
115+
return candidates;
116+
}
117+
118+
private Type getColumnType(SetColumnType statement)
119+
{
120+
Type type;
121+
try {
122+
type = metadata.getType(parseTypeSignature(statement.getType()));
123+
}
124+
catch (IllegalArgumentException e) {
125+
throw new SemanticException(TYPE_MISMATCH, statement, "Unknown type '%s' for column '%s'", statement.getType(), statement.getColumnName());
126+
}
127+
if (type.equals(UNKNOWN)) {
128+
throw new SemanticException(TYPE_MISMATCH, statement, "Unknown type '%s' for column '%s'", statement.getType(), statement.getColumnName());
129+
}
130+
return type;
131+
}
132+
}

presto-main-base/src/main/java/com/facebook/presto/metadata/Metadata.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,11 @@ public interface Metadata
238238
*/
239239
void addColumn(Session session, TableHandle tableHandle, ColumnMetadata column);
240240

241+
/**
242+
* Set the specified type to the column.
243+
*/
244+
void setColumnType(Session session, TableHandle tableHandle, ColumnHandle column, Type type);
245+
241246
/**
242247
* Drop the specified column.
243248
*/

0 commit comments

Comments
 (0)