in fe/fe-core/src/main/java/org/apache/doris/alter/SchemaChangeHandler.java [1905:2208]
public void process(String rawSql, List<AlterClause> alterClauses, Database db,
OlapTable olapTable)
throws UserException {
olapTable.writeLockOrDdlException();
try {
olapTable.checkNormalStateForAlter();
//alterClauses can or cannot light schema change
boolean lightSchemaChange = true;
boolean lightIndexChange = false;
boolean buildIndexChange = false;
// index id -> index schema
Map<Long, LinkedList<Column>> indexSchemaMap = new HashMap<>();
//for multi add columns clauses
//index id -> index col_unique_id supplier
Map<Long, IntSupplier> colUniqueIdSupplierMap = new HashMap<>();
for (Map.Entry<Long, List<Column>> entry : olapTable.getIndexIdToSchema(true).entrySet()) {
indexSchemaMap.put(entry.getKey(), new LinkedList<>(entry.getValue()));
IntSupplier colUniqueIdSupplier = null;
if (olapTable.getEnableLightSchemaChange()) {
colUniqueIdSupplier = new IntSupplier() {
public int pendingMaxColUniqueId = olapTable.getIndexMetaByIndexId(entry.getKey())
.getMaxColUniqueId();
public long indexId = entry.getKey();
@Override
public int getAsInt() {
pendingMaxColUniqueId++;
if (LOG.isDebugEnabled()) {
LOG.debug("index id:{}, pendingMaxColUniqueId:{}", indexId, pendingMaxColUniqueId);
}
return pendingMaxColUniqueId;
}
};
}
colUniqueIdSupplierMap.put(entry.getKey(), colUniqueIdSupplier);
}
if (LOG.isDebugEnabled()) {
LOG.debug("in process indexSchemaMap:{}", indexSchemaMap);
}
List<Index> newIndexes = olapTable.getCopiedIndexes();
List<Index> alterIndexes = new ArrayList<>();
Map<Long, Set<String>> invertedIndexOnPartitions = new HashMap<>();
boolean isDropIndex = false;
Map<String, String> propertyMap = new HashMap<>();
for (AlterClause alterClause : alterClauses) {
Map<String, String> properties = alterClause.getProperties();
if (properties != null) {
if (propertyMap.isEmpty()) {
propertyMap.putAll(properties);
} else {
throw new DdlException("reduplicated PROPERTIES");
}
// modification of colocate property is handle alone.
// And because there should be only one colocate property modification clause in stmt,
// so just return after finished handling.
if (properties.containsKey(PropertyAnalyzer.PROPERTIES_COLOCATE_WITH)) {
String colocateGroup = properties.get(PropertyAnalyzer.PROPERTIES_COLOCATE_WITH);
Env.getCurrentEnv().modifyTableColocate(db, olapTable, colocateGroup, false, null);
return;
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_DISTRIBUTION_TYPE)) {
String distributionType = properties.get(PropertyAnalyzer.PROPERTIES_DISTRIBUTION_TYPE);
if (!distributionType.equalsIgnoreCase("random")) {
throw new DdlException(
"Only support modifying distribution type of table from" + " hash to random");
}
Env.getCurrentEnv().convertDistributionType(db, olapTable);
return;
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_SEND_CLEAR_ALTER_TASK)) {
/*
* This is only for fixing bug when upgrading Doris from 0.9.x to 0.10.x.
*/
sendClearAlterTask(db, olapTable);
return;
} else if (DynamicPartitionUtil.checkDynamicPartitionPropertiesExist(properties)) {
DynamicPartitionUtil.checkDynamicPartitionPropertyKeysValid(properties);
if (!olapTable.dynamicPartitionExists()) {
try {
DynamicPartitionUtil.checkInputDynamicPartitionProperties(properties,
olapTable);
} catch (DdlException e) {
// This table is not a dynamic partition table
// and didn't supply all dynamic partition properties
throw new DdlException("Table " + db.getFullName() + "." + olapTable.getName()
+ " is not a dynamic partition table." + " Use command `HELP ALTER TABLE` "
+ "to see how to change a normal table to a dynamic partition table.");
}
}
Env.getCurrentEnv().modifyTableDynamicPartition(db, olapTable, properties);
return;
} else if (properties.containsKey(
"default." + PropertyAnalyzer.PROPERTIES_REPLICATION_ALLOCATION)) {
Preconditions.checkNotNull(
properties.get("default." + PropertyAnalyzer.PROPERTIES_REPLICATION_ALLOCATION));
Env.getCurrentEnv().modifyTableDefaultReplicaAllocation(db, olapTable, properties);
return;
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_REPLICATION_ALLOCATION)) {
Env.getCurrentEnv().modifyTableReplicaAllocation(db, olapTable, properties);
return;
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_STORAGE_POLICY)) {
olapTable.setStoragePolicy(properties.get(PropertyAnalyzer.PROPERTIES_STORAGE_POLICY));
return;
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_ENABLE_LIGHT_SCHEMA_CHANGE)) {
lightSchemaChange = Boolean.parseBoolean(
properties.get(PropertyAnalyzer.PROPERTIES_ENABLE_LIGHT_SCHEMA_CHANGE));
if (Objects.equals(olapTable.getEnableLightSchemaChange(), lightSchemaChange)) {
return;
}
if (!lightSchemaChange) {
throw new DdlException("Can not alter light_schema_change from true to false currently");
}
enableLightSchemaChange(db, olapTable);
return;
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_STORE_ROW_COLUMN)
|| properties.containsKey(PropertyAnalyzer.PROPERTIES_ROW_STORE_COLUMNS)) {
String value = properties.get(PropertyAnalyzer.PROPERTIES_STORE_ROW_COLUMN);
if (value != null && value.equalsIgnoreCase("false")) {
throw new DdlException("Can not alter store_row_column from true to false currently");
}
if (!olapTable.storeRowColumn()) {
Column rowColumn = ColumnDefinition
.newRowStoreColumnDefinition(null).translateToCatalogStyle();
int maxColUniqueId = olapTable
.getIndexMetaByIndexId(olapTable.getBaseIndexId()).getMaxColUniqueId();
rowColumn.setUniqueId(maxColUniqueId + 1);
indexSchemaMap.get(olapTable.getBaseIndexId()).add(rowColumn);
}
} else if (properties.containsKey(PropertyAnalyzer.PROPERTIES_STORAGE_MEDIUM)) {
Env.getCurrentEnv().modifyTableProperties(db, olapTable, properties);
return;
}
}
// the following operations can not be done when there are temp partitions exist.
if (olapTable.existTempPartitions()) {
throw new DdlException("Can not alter table when there are temp partitions in table");
}
if (alterClause instanceof AddColumnClause) {
// add column
boolean clauseCanLightSchemaChange = processAddColumn((AddColumnClause) alterClause, olapTable,
indexSchemaMap, colUniqueIdSupplierMap);
if (!clauseCanLightSchemaChange) {
lightSchemaChange = false;
}
} else if (alterClause instanceof AddColumnsClause) {
// add columns
boolean clauseCanLightSchemaChange = processAddColumns((AddColumnsClause) alterClause, olapTable,
indexSchemaMap, false, colUniqueIdSupplierMap);
if (!clauseCanLightSchemaChange) {
lightSchemaChange = false;
}
} else if (alterClause instanceof DropColumnClause) {
// drop column and drop indexes on this column
boolean clauseCanLightSchemaChange = processDropColumn((DropColumnClause) alterClause, olapTable,
indexSchemaMap, newIndexes);
if (!clauseCanLightSchemaChange) {
lightSchemaChange = false;
}
} else if (alterClause instanceof ModifyColumnClause) {
// modify column
boolean clauseCanLightSchemaChange = processModifyColumn((ModifyColumnClause) alterClause,
olapTable, indexSchemaMap);
if (!clauseCanLightSchemaChange) {
lightSchemaChange = false;
}
} else if (alterClause instanceof ReorderColumnsClause) {
// reorder column
processReorderColumn((ReorderColumnsClause) alterClause, olapTable, indexSchemaMap);
lightSchemaChange = false;
} else if (alterClause instanceof ModifyTablePropertiesClause) {
// modify table properties
// do nothing, properties are already in propertyMap
lightSchemaChange = false;
} else if (alterClause instanceof CreateIndexClause) {
CreateIndexClause createIndexClause = (CreateIndexClause) alterClause;
Index index = createIndexClause.getIndex();
if (processAddIndex(createIndexClause, olapTable, newIndexes)) {
return;
}
lightSchemaChange = false;
if (index.isLightIndexChangeSupported() && !Config.isCloudMode()) {
alterIndexes.add(index);
isDropIndex = false;
// now only support light index change for inverted index
lightIndexChange = true;
}
} else if (alterClause instanceof BuildIndexClause) {
BuildIndexClause buildIndexClause = (BuildIndexClause) alterClause;
IndexDef indexDef = buildIndexClause.getIndexDef();
Index index = buildIndexClause.getIndex();
if (Config.isCloudMode()) {
throw new DdlException("BUILD INDEX operation failed: No need to do it in cloud mode.");
}
if (!olapTable.isPartitionedTable()) {
List<String> specifiedPartitions = indexDef.getPartitionNames();
if (!specifiedPartitions.isEmpty()) {
throw new DdlException("table " + olapTable.getName()
+ " is not partitioned, cannot build index with partitions.");
}
}
List<Index> existedIndexes = olapTable.getIndexes();
boolean found = false;
for (Index existedIdx : existedIndexes) {
if (existedIdx.getIndexName().equalsIgnoreCase(indexDef.getIndexName())) {
found = true;
if (!existedIdx.isLightIndexChangeSupported()) {
throw new DdlException("BUILD INDEX operation failed: The index "
+ existedIdx.getIndexName() + " of type " + existedIdx.getIndexType()
+ " does not support lightweight index changes.");
}
for (Column column : olapTable.getBaseSchema()) {
if (!column.getType().isVariantType()) {
continue;
}
// variant type column can not support for building index
for (String indexColumn : existedIdx.getColumns()) {
if (column.getName().equalsIgnoreCase(indexColumn)) {
throw new DdlException("BUILD INDEX operation failed: The "
+ indexDef.getIndexName() + " index can not be built on the "
+ indexColumn + " column, because it is a variant type column.");
}
}
}
index = existedIdx.clone();
if (indexDef.getPartitionNames().isEmpty()) {
invertedIndexOnPartitions.put(index.getIndexId(), olapTable.getPartitionNames());
} else {
invertedIndexOnPartitions.put(
index.getIndexId(), new HashSet<>(indexDef.getPartitionNames()));
}
break;
}
}
if (!found) {
throw new DdlException("index " + indexDef.getIndexName()
+ " not exist, cannot build it with defferred.");
}
if (indexDef.isInvertedIndex()) {
alterIndexes.add(index);
}
buildIndexChange = true;
lightSchemaChange = false;
} else if (alterClause instanceof DropIndexClause) {
if (processDropIndex((DropIndexClause) alterClause, olapTable, newIndexes)) {
return;
}
lightSchemaChange = false;
DropIndexClause dropIndexClause = (DropIndexClause) alterClause;
List<Index> existedIndexes = olapTable.getIndexes();
Index found = null;
for (Index existedIdx : existedIndexes) {
if (existedIdx.getIndexName().equalsIgnoreCase(dropIndexClause.getIndexName())) {
found = existedIdx;
break;
}
}
if (found.isLightIndexChangeSupported() && !Config.isCloudMode()) {
alterIndexes.add(found);
isDropIndex = true;
lightIndexChange = true;
}
} else {
Preconditions.checkState(false);
}
} // end for alter clauses
if (LOG.isDebugEnabled()) {
LOG.debug("table: {}({}), lightSchemaChange: {}, lightIndexChange: {},"
+ " buildIndexChange: {}, indexSchemaMap:{}",
olapTable.getName(), olapTable.getId(), lightSchemaChange,
lightIndexChange, buildIndexChange, indexSchemaMap);
}
if (lightSchemaChange) {
long jobId = Env.getCurrentEnv().getNextId();
//for schema change add/drop value column optimize, direct modify table meta.
modifyTableLightSchemaChange(rawSql, db, olapTable, indexSchemaMap, newIndexes,
null, isDropIndex, jobId, false);
} else if (Config.enable_light_index_change && lightIndexChange) {
long jobId = Env.getCurrentEnv().getNextId();
//for schema change add/drop inverted index optimize, direct modify table meta firstly.
modifyTableLightSchemaChange(rawSql, db, olapTable, indexSchemaMap, newIndexes,
alterIndexes, isDropIndex, jobId, false);
} else if (buildIndexChange) {
if (Config.enable_light_index_change) {
buildOrDeleteTableInvertedIndices(db, olapTable, indexSchemaMap,
alterIndexes, invertedIndexOnPartitions, false);
}
} else {
createJob(rawSql, db.getId(), olapTable, indexSchemaMap, propertyMap, newIndexes);
}
} finally {
olapTable.writeUnlock();
}
}