This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new 2623282de7f branch-3.1: [Enhancement] reject schema change on hidden
columns #53376 (#55385)
2623282de7f is described below
commit 2623282de7f5e2ff7b8d7d351f06adbfd0a87b38
Author: csding <[email protected]>
AuthorDate: Thu Sep 4 09:53:08 2025 +0800
branch-3.1: [Enhancement] reject schema change on hidden columns #53376
(#55385)
picked from #53376
---
.../java/org/apache/doris/analysis/ColumnDef.java | 56 +++++++++++++---
.../main/java/org/apache/doris/catalog/Column.java | 1 +
.../java/org/apache/doris/common/FeNameFormat.java | 24 +++++--
.../plans/commands/info/ColumnDefinition.java | 78 ++++++++++++++--------
4 files changed, 115 insertions(+), 44 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java
b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java
index 7d0d24aa4e5..91812858846 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnDef.java
@@ -199,6 +199,8 @@ public class ColumnDef {
private int clusterKeyId = -1;
private Optional<GeneratedColumnInfo> generatedColumnInfo =
Optional.empty();
private Set<String> generatedColumnsThatReferToThis = new HashSet<>();
+ // if add hidden column, must set enableAddHiddenColumn true
+ private boolean enableAddHiddenColumn = false;
public ColumnDef(String name, TypeDef typeDef) {
@@ -262,6 +264,10 @@ public class ColumnDef {
this.visible = visible;
}
+ public void setEnableAddHiddenColumn(boolean enableAddHiddenColumn) {
+ this.enableAddHiddenColumn = enableAddHiddenColumn;
+ }
+
public ColumnDef(String name, TypeDef typeDef, boolean isKey,
ColumnNullableType nullableType, String comment,
Optional<GeneratedColumnInfo> generatedColumnInfo) {
this(name, typeDef, isKey, null, nullableType, -1,
DefaultValue.NOT_SET,
@@ -269,50 +275,72 @@ public class ColumnDef {
}
public static ColumnDef newDeleteSignColumnDef() {
- return new ColumnDef(Column.DELETE_SIGN,
TypeDef.create(PrimitiveType.TINYINT), false, null,
- ColumnNullableType.NOT_NULLABLE, -1, new
ColumnDef.DefaultValue(true, "0"),
+ ColumnDef columnDef = new ColumnDef(Column.DELETE_SIGN,
TypeDef.create(PrimitiveType.TINYINT), false, null,
+ ColumnNullableType.NOT_NULLABLE, -1, new DefaultValue(true,
"0"),
"doris delete flag hidden column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newDeleteSignColumnDef(AggregateType
aggregateType) {
- return new ColumnDef(Column.DELETE_SIGN,
TypeDef.create(PrimitiveType.TINYINT), false, aggregateType,
- ColumnNullableType.NOT_NULLABLE, -1, new
ColumnDef.DefaultValue(true, "0"),
+ ColumnDef columnDef = new ColumnDef(Column.DELETE_SIGN,
TypeDef.create(PrimitiveType.TINYINT), false,
+ aggregateType,
+ ColumnNullableType.NOT_NULLABLE, -1, new DefaultValue(true,
"0"),
"doris delete flag hidden column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newSequenceColumnDef(Type type) {
- return new ColumnDef(Column.SEQUENCE_COL, new TypeDef(type), false,
null, ColumnNullableType.NULLABLE, -1,
+ ColumnDef columnDef = new ColumnDef(Column.SEQUENCE_COL, new
TypeDef(type),
+ false, null, ColumnNullableType.NULLABLE, -1,
DefaultValue.NULL_DEFAULT_VALUE, "sequence column hidden
column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newSequenceColumnDef(Type type, AggregateType
aggregateType) {
- return new ColumnDef(Column.SEQUENCE_COL, new TypeDef(type), false,
aggregateType, ColumnNullableType.NULLABLE,
+ ColumnDef columnDef = new ColumnDef(Column.SEQUENCE_COL, new
TypeDef(type),
+ false, aggregateType, ColumnNullableType.NULLABLE,
-1, DefaultValue.NULL_DEFAULT_VALUE, "sequence column hidden
column", false,
Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newRowStoreColumnDef(AggregateType aggregateType) {
- return new ColumnDef(Column.ROW_STORE_COL,
TypeDef.create(PrimitiveType.STRING), false, aggregateType,
+ ColumnDef columnDef = new ColumnDef(Column.ROW_STORE_COL,
TypeDef.create(PrimitiveType.STRING),
+ false, aggregateType,
ColumnNullableType.NOT_NULLABLE, -1, new
ColumnDef.DefaultValue(true, ""),
"doris row store hidden column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newVersionColumnDef() {
- return new ColumnDef(Column.VERSION_COL,
TypeDef.create(PrimitiveType.BIGINT), false, null,
+ ColumnDef columnDef = new ColumnDef(Column.VERSION_COL,
TypeDef.create(PrimitiveType.BIGINT), false, null,
ColumnNullableType.NOT_NULLABLE, -1, new
ColumnDef.DefaultValue(true, "0"),
"doris version hidden column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newVersionColumnDef(AggregateType aggregateType) {
- return new ColumnDef(Column.VERSION_COL,
TypeDef.create(PrimitiveType.BIGINT), false, aggregateType,
+ ColumnDef columnDef = new ColumnDef(Column.VERSION_COL,
TypeDef.create(PrimitiveType.BIGINT),
+ false, aggregateType,
ColumnNullableType.NOT_NULLABLE, -1, new
ColumnDef.DefaultValue(true, "0"),
"doris version hidden column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public static ColumnDef newSkipBitmapColumnDef(AggregateType
aggregateType) {
- return new ColumnDef(Column.SKIP_BITMAP_COL,
TypeDef.create(PrimitiveType.BITMAP), false, aggregateType,
+ ColumnDef columnDef = new ColumnDef(Column.SKIP_BITMAP_COL,
TypeDef.create(PrimitiveType.BITMAP),
+ false, aggregateType,
ColumnNullableType.NOT_NULLABLE, -1,
DefaultValue.BITMAP_EMPTY_DEFAULT_VALUE,
"doris skip bitmap hidden column", false, Optional.empty());
+ columnDef.setEnableAddHiddenColumn(true);
+ return columnDef;
}
public boolean isAllowNull() {
@@ -375,7 +403,13 @@ public class ColumnDef {
if (name == null || typeDef == null) {
throw new AnalysisException("No column name or column type in
column definition.");
}
- FeNameFormat.checkColumnName(name);
+
+ if (enableAddHiddenColumn) {
+ FeNameFormat.checkColumnNameBypassHiddenColumn(name);
+ } else {
+ FeNameFormat.checkColumnName(name);
+ }
+
FeNameFormat.checkColumnCommentLength(comment);
typeDef.analyze(null);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java
index 47cca3b90bb..ab6b423d976 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java
@@ -62,6 +62,7 @@ import java.util.Set;
*/
public class Column implements GsonPostProcessable {
private static final Logger LOG = LogManager.getLogger(Column.class);
+ public static final String HIDDEN_COLUMN_PREFIX = "__DORIS_";
// NOTE: you should name hidden column start with '__DORIS_'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
public static final String DELETE_SIGN = "__DORIS_DELETE_SIGN__";
public static final String WHERE_SIGN = "__DORIS_WHERE_SIGN__";
diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
b/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
index a7165c3d815..c6c751a88c6 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/FeNameFormat.java
@@ -20,6 +20,7 @@ package org.apache.doris.common;
import org.apache.doris.alter.SchemaChangeHandler;
import org.apache.doris.analysis.CreateMaterializedViewStmt;
import org.apache.doris.analysis.ResourceTypeEnum;
+import org.apache.doris.catalog.Column;
import org.apache.doris.datasource.InternalCatalog;
import org.apache.doris.mysql.privilege.Role;
import org.apache.doris.mysql.privilege.RoleManager;
@@ -93,18 +94,29 @@ public class FeNameFormat {
}
public static void checkColumnName(String columnName) throws
AnalysisException {
+ // if need check another column name prefix, add in
`checkColumnNameBypassHiddenColumn`
+ checkColumnNameBypassHiddenColumn(columnName);
+ checkColumnNamePrefix(columnName, Column.HIDDEN_COLUMN_PREFIX);
+ }
+
+ public static void checkColumnNameBypassHiddenColumn(String columnName)
throws AnalysisException {
if (Strings.isNullOrEmpty(columnName) ||
!columnName.matches(getColumnNameRegex())) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_COLUMN_NAME,
columnName, getColumnNameRegex());
}
- if (columnName.startsWith(SchemaChangeHandler.SHADOW_NAME_PREFIX)) {
-
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_COLUMN_NAME,
- columnName, getColumnNameRegex());
+ checkColumnNamePrefix(columnName,
SchemaChangeHandler.SHADOW_NAME_PREFIX);
+ checkColumnNamePrefix(columnName,
CreateMaterializedViewStmt.MATERIALIZED_VIEW_NAME_PREFIX);
+ checkColumnNamePrefix(columnName,
CreateMaterializedViewStmt.MATERIALIZED_VIEW_AGGREGATE_NAME_PREFIX);
+ }
+
+ private static void checkColumnNamePrefix(String columnName, String
prefix) throws AnalysisException {
+ int prefixLength = prefix.length();
+ if (columnName.length() < prefixLength) {
+ return;
}
- if
(columnName.startsWith(CreateMaterializedViewStmt.MATERIALIZED_VIEW_NAME_PREFIX)
- ||
columnName.startsWith(CreateMaterializedViewStmt.MATERIALIZED_VIEW_AGGREGATE_NAME_PREFIX))
{
+ if (columnName.substring(0, prefixLength).equalsIgnoreCase(prefix)) {
throw new AnalysisException(
- "Incorrect column name " + columnName + ", column name
can't start with 'mv_'/'mva_'");
+ "Incorrect column name " + columnName + ", column name can't
start with '" + prefix + "'");
}
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
index 367bdff18fc..77c712de990 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/info/ColumnDefinition.java
@@ -69,6 +69,8 @@ public class ColumnDefinition {
private int clusterKeyId = -1;
private Optional<GeneratedColumnDesc> generatedColumnDesc =
Optional.empty();
private Set<String> generatedColumnsThatReferToThis = new HashSet<>();
+ // if add hidden column, must set enableAddHiddenColumn true
+ private boolean enableAddHiddenColumn = false;
public ColumnDefinition(String name, DataType type, boolean isKey,
AggregateType aggType, boolean isNullable,
Optional<DefaultValue> defaultValue, String comment) {
@@ -232,7 +234,14 @@ public class ColumnDefinition {
public void validate(boolean isOlap, Set<String> keysSet, Set<String>
clusterKeySet, boolean isEnableMergeOnWrite,
KeysType keysType) {
try {
- FeNameFormat.checkColumnName(name);
+ // if enableAddHiddenColumn is true, can add hidden column.
+ // So does not check if the column name starts with __DORIS_
+ if (enableAddHiddenColumn) {
+ FeNameFormat.checkColumnNameBypassHiddenColumn(name);
+ } else {
+ FeNameFormat.checkColumnName(name);
+ }
+
FeNameFormat.checkColumnCommentLength(comment);
} catch (Exception e) {
throw new AnalysisException(e.getMessage(), e);
@@ -689,43 +698,54 @@ public class ColumnDefinition {
return column;
}
- // hidden column
- public static ColumnDefinition newDeleteSignColumnDefinition() {
- return new ColumnDefinition(Column.DELETE_SIGN, TinyIntType.INSTANCE,
false, null, false,
- Optional.of(new DefaultValue(DefaultValue.ZERO_NUMBER)),
"doris delete flag hidden column", false);
- }
-
+ /**
+ * add hidden column
+ */
public static ColumnDefinition newDeleteSignColumnDefinition(AggregateType
aggregateType) {
- return new ColumnDefinition(Column.DELETE_SIGN, TinyIntType.INSTANCE,
false, aggregateType, false,
- Optional.of(new DefaultValue(DefaultValue.ZERO_NUMBER)),
"doris delete flag hidden column", false);
- }
+ ColumnDefinition columnDefinition = new
ColumnDefinition(Column.DELETE_SIGN, TinyIntType.INSTANCE, false,
+ aggregateType, false, Optional.of(new
DefaultValue(DefaultValue.ZERO_NUMBER)),
+ "doris delete flag hidden column", false);
+ columnDefinition.setEnableAddHiddenColumn(true);
- public static ColumnDefinition newSequenceColumnDefinition(DataType type) {
- return new ColumnDefinition(Column.SEQUENCE_COL, type, false, null,
true,
- Optional.empty(), "sequence column hidden column", false);
- }
-
- public static ColumnDefinition newSequenceColumnDefinition(DataType type,
AggregateType aggregateType) {
- return new ColumnDefinition(Column.SEQUENCE_COL, type, false,
aggregateType, true,
- Optional.empty(), "sequence column hidden column", false);
+ return columnDefinition;
}
+ /**
+ * add hidden column
+ */
public static ColumnDefinition newRowStoreColumnDefinition(AggregateType
aggregateType) {
- return new ColumnDefinition(Column.ROW_STORE_COL, StringType.INSTANCE,
false, aggregateType, false,
- Optional.of(new DefaultValue("")), "doris row store hidden
column", false);
+ ColumnDefinition columnDefinition = new
ColumnDefinition(Column.ROW_STORE_COL, StringType.INSTANCE, false,
+ aggregateType, false, Optional.of(new
DefaultValue("")),
+ "doris row store hidden column", false);
+ columnDefinition.setEnableAddHiddenColumn(true);
+
+ return columnDefinition;
}
+ /**
+ * add hidden column
+ */
public static ColumnDefinition newVersionColumnDefinition(AggregateType
aggregateType) {
- return new ColumnDefinition(Column.VERSION_COL, BigIntType.INSTANCE,
false, aggregateType, false,
- Optional.of(new DefaultValue(DefaultValue.ZERO_NUMBER)),
"doris version hidden column", false);
+ ColumnDefinition columnDefinition = new
ColumnDefinition(Column.VERSION_COL, BigIntType.INSTANCE, false,
+ aggregateType, false, Optional.of(new
DefaultValue(DefaultValue.ZERO_NUMBER)),
+ "doris version hidden column", false);
+ columnDefinition.setEnableAddHiddenColumn(true);
+
+ return columnDefinition;
}
- // used in CreateTableInfo.validate(), specify the default value as
DefaultValue.NULL_DEFAULT_VALUE
- // becasue ColumnDefinition.validate() will check that bitmap type column
don't set default value
- // and then set the default value of that column to bitmap_empty()
+ /**
+ * used in CreateTableInfo.validate(), specify the default value as
DefaultValue.NULL_DEFAULT_VALUE
+ * becasue ColumnDefinition.validate() will check that bitmap type column
don't set default value
+ * and then set the default value of that column to bitmap_empty()
+ */
public static ColumnDefinition newSkipBitmapColumnDef(AggregateType
aggregateType) {
- return new ColumnDefinition(Column.SKIP_BITMAP_COL,
BitmapType.INSTANCE, false, aggregateType, false,
- Optional.of(DefaultValue.BITMAP_EMPTY_DEFAULT_VALUE), "doris
skip bitmap hidden column", false);
+ ColumnDefinition columnDefinition = new
ColumnDefinition(Column.SKIP_BITMAP_COL, BitmapType.INSTANCE, false,
+ aggregateType, false,
Optional.of(DefaultValue.BITMAP_EMPTY_DEFAULT_VALUE),
+ "doris skip bitmap hidden column", false);
+ columnDefinition.setEnableAddHiddenColumn(true);
+
+ return columnDefinition;
}
public Optional<GeneratedColumnDesc> getGeneratedColumnDesc() {
@@ -740,6 +760,10 @@ public class ColumnDefinition {
generatedColumnsThatReferToThis.addAll(list);
}
+ public void setEnableAddHiddenColumn(boolean enableAddHiddenColumn) {
+ this.enableAddHiddenColumn = enableAddHiddenColumn;
+ }
+
private void validateGeneratedColumnInfo() {
// for generated column
if (generatedColumnDesc.isPresent()) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]