[feature](alter) support rename column for table with unique column id (#13410)

This commit is contained in:
Xin Liao
2022-10-21 08:45:34 +08:00
committed by GitHub
parent 1b0dafcaa1
commit 27d84eafc5
9 changed files with 505 additions and 4 deletions

View File

@ -190,6 +190,7 @@ import org.apache.doris.persist.StorageInfo;
import org.apache.doris.persist.StorageInfoV2;
import org.apache.doris.persist.TableInfo;
import org.apache.doris.persist.TablePropertyInfo;
import org.apache.doris.persist.TableRenameColumnInfo;
import org.apache.doris.persist.TruncateTableInfo;
import org.apache.doris.persist.meta.MetaHeader;
import org.apache.doris.persist.meta.MetaReader;
@ -4030,12 +4031,114 @@ public class Env {
}
}
public void renameColumn(Database db, OlapTable table, ColumnRenameClause renameClause) throws DdlException {
throw new DdlException("not implemented");
public void renameColumn(Database db, OlapTable table, String colName,
String newColName, boolean isReplay) throws DdlException {
if (table.getState() != OlapTableState.NORMAL) {
throw new DdlException("Table[" + table.getName() + "] is under " + table.getState());
}
if (colName.equalsIgnoreCase(newColName)) {
throw new DdlException("Same column name");
}
Map<Long, MaterializedIndexMeta> indexIdToMeta = table.getIndexIdToMeta();
for (Map.Entry<Long, MaterializedIndexMeta> entry : indexIdToMeta.entrySet()) {
// rename column is not implemented for table without column unique id.
if (entry.getValue().getMaxColUniqueId() < 0) {
throw new DdlException("not implemented for table without column unique id,"
+ " which are created with property 'light_schema_change'.");
}
// check if new name is already used
if (entry.getValue().getColumnByName(newColName) != null) {
throw new DdlException("Column name[" + newColName + "] is already used");
}
}
// 1. modify MaterializedIndexMeta
boolean hasColumn = false;
for (Map.Entry<Long, MaterializedIndexMeta> entry : indexIdToMeta.entrySet()) {
Column column = entry.getValue().getColumnByName(colName);
if (column != null) {
column.setName(newColName);
hasColumn = true;
}
}
if (!hasColumn) {
throw new DdlException("Column[" + colName + "] does not exists");
}
// 2. modify partition key
PartitionInfo partitionInfo = table.getPartitionInfo();
List<Column> partitionColumns = partitionInfo.getPartitionColumns();
for (Column column : partitionColumns) {
if (column.getName().equalsIgnoreCase(colName)) {
column.setName(newColName);
break;
}
}
// 3. modify index
List<Index> indexes = table.getIndexes();
for (Index index : indexes) {
List<String> columns = index.getColumns();
for (int i = 0; i < columns.size(); i++) {
if (columns.get(i).equalsIgnoreCase(colName)) {
columns.set(i, newColName);
}
}
}
// 4. modify distribution info
DistributionInfo distributionInfo = table.getDefaultDistributionInfo();
if (distributionInfo.getType() == DistributionInfoType.HASH) {
List<Column> distributionColumns = ((HashDistributionInfo) distributionInfo).getDistributionColumns();
for (Column column : distributionColumns) {
if (column.getName().equalsIgnoreCase(colName)) {
column.setName(newColName);
break;
}
}
}
table.rebuildFullSchema();
if (!isReplay) {
// log
TableRenameColumnInfo info = new TableRenameColumnInfo(db.getId(), table.getId(), colName, newColName);
editLog.logColumnRename(info);
LOG.info("rename coloumn[{}] to {}", colName, newColName);
}
}
public void replayRenameColumn(TableInfo tableInfo) throws DdlException {
throw new DdlException("not implemented");
public void renameColumn(Database db, OlapTable table, ColumnRenameClause renameClause) throws DdlException {
table.writeLockOrDdlException();
try {
String colName = renameClause.getColName();
String newColName = renameClause.getNewColName();
renameColumn(db, table, colName, newColName, false);
} finally {
table.writeUnlock();
}
}
public void replayRenameColumn(TableRenameColumnInfo info) throws MetaNotFoundException {
LOG.debug("info:{}", info);
long dbId = info.getDbId();
long tableId = info.getTableId();
String colName = info.getColName();
String newColName = info.getNewColName();
Database db = getCurrentEnv().getInternalCatalog().getDbOrMetaException(dbId);
OlapTable table = (OlapTable) db.getTableOrMetaException(tableId, TableType.OLAP);
table.writeLock();
try {
renameColumn(db, table, colName, newColName, true);
} catch (DdlException e) {
// should not happen
LOG.warn("failed to replay rename column", e);
} finally {
table.writeUnlock();
}
}
public void modifyTableDynamicPartition(Database db, OlapTable table, Map<String, String> properties)

View File

@ -92,6 +92,7 @@ import org.apache.doris.persist.SetReplicaStatusOperationLog;
import org.apache.doris.persist.TableAddOrDropColumnsInfo;
import org.apache.doris.persist.TableInfo;
import org.apache.doris.persist.TablePropertyInfo;
import org.apache.doris.persist.TableRenameColumnInfo;
import org.apache.doris.persist.TruncateTableInfo;
import org.apache.doris.plugin.PluginInfo;
import org.apache.doris.policy.DropPolicyLog;
@ -256,6 +257,11 @@ public class JournalEntity implements Writable {
isRead = true;
break;
}
case OperationType.OP_RENAME_COLUMN: {
data = TableRenameColumnInfo.read(in);
isRead = true;
break;
}
case OperationType.OP_MODIFY_VIEW_DEF: {
data = AlterViewInfo.read(in);
isRead = true;

View File

@ -279,6 +279,11 @@ public class EditLog {
env.replayRenamePartition(info);
break;
}
case OperationType.OP_RENAME_COLUMN: {
TableRenameColumnInfo info = (TableRenameColumnInfo) journal.getData();
env.replayRenameColumn(info);
break;
}
case OperationType.OP_BACKUP_JOB: {
BackupJob job = (BackupJob) journal.getData();
env.getBackupHandler().replayAddJob(job);
@ -1220,6 +1225,10 @@ public class EditLog {
logEdit(OperationType.OP_RENAME_PARTITION, tableInfo);
}
public void logColumnRename(TableRenameColumnInfo info) {
logEdit(OperationType.OP_RENAME_COLUMN, info);
}
public void logCreateCluster(Cluster cluster) {
logEdit(OperationType.OP_CREATE_CLUSTER, cluster);
}

View File

@ -46,6 +46,7 @@ public class OperationType {
public static final short OP_RECOVER_PARTITION = 18;
public static final short OP_RENAME_TABLE = 19;
public static final short OP_RENAME_PARTITION = 110;
public static final short OP_RENAME_COLUMN = 115;
public static final short OP_BACKUP_JOB = 116;
public static final short OP_RESTORE_JOB = 117;
public static final short OP_TRUNCATE_TABLE = 118;

View File

@ -0,0 +1,101 @@
// 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.doris.persist;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import org.apache.doris.persist.gson.GsonUtils;
import com.google.gson.annotations.SerializedName;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* PersistInfo for Table rename column info
*/
public class TableRenameColumnInfo implements Writable {
@SerializedName(value = "dbId")
private long dbId;
@SerializedName(value = "tableId")
private long tableId;
@SerializedName(value = "colName")
private String colName;
@SerializedName(value = "newColName")
private String newColName;
public TableRenameColumnInfo(long dbId, long tableId,
String colName, String newColName) {
this.dbId = dbId;
this.tableId = tableId;
this.colName = colName;
this.newColName = newColName;
}
public long getDbId() {
return dbId;
}
public long getTableId() {
return tableId;
}
public String getColName() {
return colName;
}
public String getNewColName() {
return newColName;
}
@Override
public void write(DataOutput out) throws IOException {
Text.writeString(out, GsonUtils.GSON.toJson(this));
}
public static TableRenameColumnInfo read(DataInput in) throws IOException {
return GsonUtils.GSON.fromJson(Text.readString(in), TableRenameColumnInfo.class);
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof TableRenameColumnInfo)) {
return false;
}
TableRenameColumnInfo info = (TableRenameColumnInfo) obj;
return (dbId == info.dbId && tableId == tableId
&& colName.equals(info.colName) && newColName.equals(info.newColName));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(" dbId: ").append(dbId);
sb.append(" tableId: ").append(tableId);
sb.append(" colName: ").append(colName);
sb.append(" newColName: ").append(newColName);
return sb.toString();
}
}