Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Support alter table API #4775

Merged
merged 7 commits into from
Dec 26, 2024
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
34 changes: 22 additions & 12 deletions paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.paimon.rest.exceptions.ForbiddenException;
import org.apache.paimon.rest.exceptions.NoSuchResourceException;
import org.apache.paimon.rest.requests.AlterDatabaseRequest;
import org.apache.paimon.rest.requests.AlterTableRequest;
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
import org.apache.paimon.rest.requests.CreateTableRequest;
import org.apache.paimon.rest.requests.RenameTableRequest;
Expand Down Expand Up @@ -302,7 +303,13 @@ public void createTable(Identifier identifier, Schema schema, boolean ignoreIfEx
public void renameTable(Identifier fromTable, Identifier toTable, boolean ignoreIfNotExists)
throws TableNotExistException, TableAlreadyExistException {
try {
renameTable(fromTable, toTable);
RenameTableRequest request = new RenameTableRequest(toTable);
client.post(
resourcePaths.renameTable(
fromTable.getDatabaseName(), fromTable.getTableName()),
request,
GetTableResponse.class,
headers());
} catch (NoSuchResourceException e) {
if (!ignoreIfNotExists) {
throw new TableNotExistException(fromTable);
Expand All @@ -318,7 +325,20 @@ public void renameTable(Identifier fromTable, Identifier toTable, boolean ignore
public void alterTable(
Identifier identifier, List<SchemaChange> changes, boolean ignoreIfNotExists)
throws TableNotExistException, ColumnAlreadyExistException, ColumnNotExistException {
throw new UnsupportedOperationException("TODO");
try {
AlterTableRequest request = new AlterTableRequest(changes);
client.post(
resourcePaths.table(identifier.getDatabaseName(), identifier.getTableName()),
request,
GetTableResponse.class,
headers());
} catch (NoSuchResourceException e) {
if (!ignoreIfNotExists) {
throw new TableNotExistException(identifier);
}
} catch (ForbiddenException e) {
throw new TableNoPermissionException(identifier, e);
}
}

@Override
Expand Down Expand Up @@ -376,16 +396,6 @@ Map<String, String> fetchOptionsFromServer(
return response.merge(clientProperties);
}

@VisibleForTesting
void renameTable(Identifier fromTable, Identifier newIdentifier) {
RenameTableRequest request = new RenameTableRequest(newIdentifier);
client.post(
resourcePaths.table(fromTable.getDatabaseName(), fromTable.getTableName()),
request,
GetTableResponse.class,
headers());
}

@VisibleForTesting
Table getDataOrFormatTable(Identifier identifier) throws TableNotExistException {
Preconditions.checkArgument(identifier.getSystemTableName() == null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,15 @@ public String table(String databaseName, String tableName) {
.add(tableName)
.toString();
}

public String renameTable(String databaseName, String tableName) {
return SLASH.add("v1")
.add(prefix)
.add("databases")
.add(databaseName)
.add("tables")
.add(tableName)
.add("rename")
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.paimon.rest.requests;

import org.apache.paimon.rest.RESTRequest;
import org.apache.paimon.schema.SchemaChange;

import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonCreator;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonGetter;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

/** Request for altering table. */
@JsonIgnoreProperties(ignoreUnknown = true)
public class AlterTableRequest implements RESTRequest {

private static final String FIELD_NEW_UPDATE = "changes";

@JsonProperty(FIELD_NEW_UPDATE)
private final List<SchemaChange> changes;

@JsonCreator
public AlterTableRequest(@JsonProperty(FIELD_NEW_UPDATE) List<SchemaChange> changes) {
this.changes = changes;
}

@JsonGetter(FIELD_NEW_UPDATE)
public List<SchemaChange> getChanges() {
return changes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonGetter;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonSubTypes;
import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.annotation.JsonTypeInfo;

import javax.annotation.Nullable;

Expand All @@ -38,6 +40,42 @@
* @since 0.4.0
*/
@Public
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = SchemaChange.Actions.FIELD_ACTION)
@JsonSubTypes({
@JsonSubTypes.Type(
value = SchemaChange.SetOption.class,
name = SchemaChange.Actions.SET_OPTION_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.RemoveOption.class,
name = SchemaChange.Actions.REMOVE_OPTION_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.UpdateComment.class,
name = SchemaChange.Actions.UPDATE_COMMENT_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.AddColumn.class,
name = SchemaChange.Actions.ADD_COLUMN_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.RenameColumn.class,
name = SchemaChange.Actions.RENAME_COLUMN_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.DropColumn.class,
name = SchemaChange.Actions.DROP_COLUMN_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.UpdateColumnType.class,
name = SchemaChange.Actions.UPDATE_COLUMN_TYPE_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.UpdateColumnNullability.class,
name = SchemaChange.Actions.UPDATE_COLUMN_NULLABILITY_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.UpdateColumnComment.class,
name = SchemaChange.Actions.UPDATE_COLUMN_COMMENT_ACTION),
@JsonSubTypes.Type(
value = SchemaChange.UpdateColumnPosition.class,
name = SchemaChange.Actions.UPDATE_COLUMN_POSITION_ACTION),
})
public interface SchemaChange extends Serializable {

static SchemaChange setOption(String key, String value) {
Expand Down Expand Up @@ -124,18 +162,28 @@ final class SetOption implements SchemaChange {

private static final long serialVersionUID = 1L;

private static final String FIELD_KEY = "key";
private static final String FIELD_VALUE = "value";

@JsonProperty(FIELD_KEY)
private final String key;

@JsonProperty(FIELD_VALUE)
private final String value;

private SetOption(String key, String value) {
@JsonCreator
private SetOption(
@JsonProperty(FIELD_KEY) String key, @JsonProperty(FIELD_VALUE) String value) {
this.key = key;
this.value = value;
}

@JsonGetter(FIELD_KEY)
public String key() {
return key;
}

@JsonGetter(FIELD_VALUE)
public String value() {
return value;
}
Expand Down Expand Up @@ -163,12 +211,16 @@ final class RemoveOption implements SchemaChange {

private static final long serialVersionUID = 1L;

private static final String FIELD_KEY = "key";

@JsonProperty(FIELD_KEY)
private final String key;

private RemoveOption(String key) {
private RemoveOption(@JsonProperty(FIELD_KEY) String key) {
this.key = key;
}

@JsonGetter(FIELD_KEY)
public String key() {
return key;
}
Expand Down Expand Up @@ -196,13 +248,17 @@ final class UpdateComment implements SchemaChange {

private static final long serialVersionUID = 1L;

private static final String FIELD_COMMENT = "comment";

// If comment is null, means to remove comment
@JsonProperty(FIELD_COMMENT)
private final @Nullable String comment;

private UpdateComment(@Nullable String comment) {
private UpdateComment(@JsonProperty(FIELD_COMMENT) @Nullable String comment) {
this.comment = comment;
}

@JsonGetter(FIELD_COMMENT)
public @Nullable String comment() {
return comment;
}
Expand Down Expand Up @@ -467,13 +523,17 @@ public int hashCode() {
final class UpdateColumnPosition implements SchemaChange {

private static final long serialVersionUID = 1L;
private static final String FIELD_MOVE = "move";

@JsonProperty(FIELD_MOVE)
private final Move move;

private UpdateColumnPosition(Move move) {
@JsonCreator
private UpdateColumnPosition(@JsonProperty(FIELD_MOVE) Move move) {
this.move = move;
}

@JsonGetter(FIELD_MOVE)
public Move move() {
return move;
}
Expand Down Expand Up @@ -525,11 +585,11 @@ public static Move last(String fieldName) {

private static final long serialVersionUID = 1L;

private static final String FIELD_FILED_NAMES = "fieldName";
private static final String FIELD_FILED_NAME = "fieldName";
private static final String FIELD_REFERENCE_FIELD_NAME = "referenceFieldName";
private static final String FIELD_TYPE = "type";

@JsonProperty(FIELD_FILED_NAMES)
@JsonProperty(FIELD_FILED_NAME)
private final String fieldName;

@JsonProperty(FIELD_REFERENCE_FIELD_NAME)
Expand All @@ -540,15 +600,15 @@ public static Move last(String fieldName) {

@JsonCreator
public Move(
@JsonProperty(FIELD_FILED_NAMES) String fieldName,
@JsonProperty(FIELD_FILED_NAME) String fieldName,
@JsonProperty(FIELD_REFERENCE_FIELD_NAME) String referenceFieldName,
@JsonProperty(FIELD_TYPE) MoveType type) {
this.fieldName = fieldName;
this.referenceFieldName = referenceFieldName;
this.type = type;
}

@JsonGetter(FIELD_FILED_NAMES)
@JsonGetter(FIELD_FILED_NAME)
public String fieldName() {
return fieldName;
}
Expand Down Expand Up @@ -690,4 +750,21 @@ public int hashCode() {
return result;
}
}

/** Actions for schema changes: identify for schema change. */
class Actions {
public static final String FIELD_ACTION = "action";
public static final String SET_OPTION_ACTION = "setOption";
public static final String REMOVE_OPTION_ACTION = "removeOption";
public static final String UPDATE_COMMENT_ACTION = "updateComment";
public static final String ADD_COLUMN_ACTION = "addColumn";
public static final String RENAME_COLUMN_ACTION = "renameColumn";
public static final String DROP_COLUMN_ACTION = "dropColumn";
public static final String UPDATE_COLUMN_TYPE_ACTION = "updateColumnType";
public static final String UPDATE_COLUMN_NULLABILITY_ACTION = "updateColumnNullability";
public static final String UPDATE_COLUMN_COMMENT_ACTION = "updateColumnComment";
public static final String UPDATE_COLUMN_POSITION_ACTION = "updateColumnPosition";

private Actions() {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.apache.paimon.catalog.Identifier;
import org.apache.paimon.rest.requests.AlterDatabaseRequest;
import org.apache.paimon.rest.requests.AlterTableRequest;
import org.apache.paimon.rest.requests.CreateDatabaseRequest;
import org.apache.paimon.rest.requests.CreateTableRequest;
import org.apache.paimon.rest.requests.RenameTableRequest;
Expand Down Expand Up @@ -126,11 +127,17 @@ public static RenameTableRequest renameRequest(String toTableName) {
return new RenameTableRequest(newIdentifier);
}

public static AlterTableRequest alterTableRequest() {
return new AlterTableRequest(getChanges());
}

public static List<SchemaChange> getChanges() {
// add option
SchemaChange addOption = SchemaChange.setOption("snapshot.time-retained", "2h");
// remove option
SchemaChange removeOption = SchemaChange.removeOption("compaction.max.file-num");
// update comment
SchemaChange updateComment = SchemaChange.updateComment(null);
// add column
SchemaChange addColumn =
SchemaChange.addColumn("col1_after", DataTypes.ARRAY(DataTypes.STRING()));
Expand Down Expand Up @@ -179,6 +186,7 @@ public static List<SchemaChange> getChanges() {
List<SchemaChange> schemaChanges = new ArrayList<>();
schemaChanges.add(addOption);
schemaChanges.add(removeOption);
schemaChanges.add(updateComment);
schemaChanges.add(addColumn);
schemaChanges.add(addColumnMap);
schemaChanges.add(addColumnRowType);
Expand Down
Loading
Loading