Skip to content

Commit 4b22fc1

Browse files
authored
[Feature](update) Support update on current_timestamp (apache#25884)
1 parent 5d9c555 commit 4b22fc1

18 files changed

Lines changed: 605 additions & 59 deletions

File tree

docs/en/docs/sql-manual/sql-reference/Data-Definition-Statements/Create/CREATE-TABLE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Column definition list:
5858

5959
Column definition:
6060

61-
`column_name column_type [KEY] [aggr_type] [NULL] [AUTO_INCREMENT] [default_value] [column_comment]`
61+
`column_name column_type [KEY] [aggr_type] [NULL] [AUTO_INCREMENT] [default_value] [on update current_timestamp] [column_comment]`
6262

6363
* `column_type`
6464

@@ -142,6 +142,10 @@ Column definition list:
142142
dt DATETIME DEFAULT CURRENT_TIMESTAMP
143143
```
144144
145+
* `on update current_timestamp`
146+
147+
To indicate that whether the value of this column should be updated to the current timestamp (`current_timestamp`) when there is an update on the row. The feature is only available on unique table with merge-on-write enabled. Columns with this feature enabled must declare a default value, and the default value must be `current_timestamp`. If the precision of the timestamp is declared here, the timestamp precision in the default value of the column must be the same as the precision declared here."
148+
145149
Example:
146150
147151
```
@@ -152,6 +156,7 @@ Column definition list:
152156
v2 BITMAP BITMAP_UNION,
153157
v3 HLL HLL_UNION,
154158
v4 INT SUM NOT NULL DEFAULT "1" COMMENT "This is column v4"
159+
dt datetime(6) default current_timestamp(6) on update current_timestamp(6)
155160
```
156161
157162
#### index_definition_list

docs/zh-CN/docs/sql-manual/sql-reference/Data-Definition-Statements/Create/CREATE-TABLE.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ distribution_desc
5656
* `column_definition`
5757
列定义:
5858

59-
`column_name column_type [KEY] [aggr_type] [NULL] [AUTO_INCREMENT] [default_value] [column_comment]`
59+
`column_name column_type [KEY] [aggr_type] [NULL] [AUTO_INCREMENT] [default_value] [on update current_timestamp] [column_comment]`
6060
* `column_type`
6161
列类型,支持以下类型:
6262
```
@@ -129,6 +129,10 @@ distribution_desc
129129
// 只用于DATETIME类型,导入数据缺失该值时系统将赋予当前时间
130130
dt DATETIME DEFAULT CURRENT_TIMESTAMP
131131
```
132+
* `on update current_timestamp`
133+
134+
是否在该行有列更新时将该列的值更新为当前时间(`current_timestamp`)。该特性只能在开启了merge-on-write的unique表上使用,开启了这个特性的列必须声明默认值,且默认值必须为`current_timestamp`。如果此处声明了时间戳的精度,则该列默认值中的时间戳精度必须与该处的时间戳精度相同。
135+
132136
133137
示例:
134138

@@ -140,6 +144,7 @@ distribution_desc
140144
v2 BITMAP BITMAP_UNION,
141145
v3 HLL HLL_UNION,
142146
v4 INT SUM NOT NULL DEFAULT "1" COMMENT "This is column v4"
147+
dt datetime(6) default current_timestamp(6) on update current_timestamp(6)
143148
```
144149

145150
#### index_definition_list

fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ columnDef
462462
: colName=identifier type=dataType
463463
KEY? (aggType=aggTypeDef)? ((NOT NULL) | NULL)?
464464
(DEFAULT (nullValue=NULL | INTEGER_VALUE | stringValue=STRING_LITERAL
465-
| CURRENT_TIMESTAMP (LEFT_PAREN precision=number RIGHT_PAREN)?))?
465+
| CURRENT_TIMESTAMP (LEFT_PAREN defaultValuePrecision=number RIGHT_PAREN)?))?
466+
(ON UPDATE CURRENT_TIMESTAMP (LEFT_PAREN onUpdateValuePrecision=number RIGHT_PAREN)?)?
466467
(COMMENT comment=STRING_LITERAL)?
467468
;
468469

fe/fe-core/src/main/java/org/apache/doris/catalog/Column.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ public class Column implements Writable, GsonPostProcessable {
130130

131131
private boolean isCompoundKey = false;
132132

133+
@SerializedName(value = "hasOnUpdateDefaultValue")
134+
private boolean hasOnUpdateDefaultValue = false;
135+
136+
@SerializedName(value = "onUpdateDefaultValueExprDef")
137+
private DefaultValueExprDef onUpdateDefaultValueExprDef;
138+
133139
public Column() {
134140
this.name = "";
135141
this.type = Type.NULL;
@@ -170,24 +176,33 @@ public Column(String name, Type type, boolean isKey, AggregateType aggregateType
170176
public Column(String name, Type type, boolean isKey, AggregateType aggregateType, boolean isAllowNull,
171177
String defaultValue, String comment) {
172178
this(name, type, isKey, aggregateType, isAllowNull, false, defaultValue, comment, true, null,
173-
COLUMN_UNIQUE_ID_INIT_VALUE, defaultValue);
179+
COLUMN_UNIQUE_ID_INIT_VALUE, defaultValue, false, null);
174180
}
175181

176182
public Column(String name, Type type, boolean isKey, AggregateType aggregateType, boolean isAllowNull,
177183
String comment, boolean visible, int colUniqueId) {
178-
this(name, type, isKey, aggregateType, isAllowNull, false, null, comment, visible, null, colUniqueId, null);
184+
this(name, type, isKey, aggregateType, isAllowNull, false, null, comment, visible, null, colUniqueId, null,
185+
false, null);
179186
}
180187

181188
public Column(String name, Type type, boolean isKey, AggregateType aggregateType, boolean isAllowNull,
182189
String defaultValue, String comment, boolean visible, DefaultValueExprDef defaultValueExprDef,
183190
int colUniqueId, String realDefaultValue) {
184191
this(name, type, isKey, aggregateType, isAllowNull, false, defaultValue, comment, visible, defaultValueExprDef,
185-
colUniqueId, realDefaultValue);
192+
colUniqueId, realDefaultValue, false, null);
186193
}
187194

188195
public Column(String name, Type type, boolean isKey, AggregateType aggregateType, boolean isAllowNull,
189196
boolean isAutoInc, String defaultValue, String comment, boolean visible,
190197
DefaultValueExprDef defaultValueExprDef, int colUniqueId, String realDefaultValue) {
198+
this(name, type, isKey, aggregateType, isAllowNull, isAutoInc, defaultValue, comment, visible,
199+
defaultValueExprDef, colUniqueId, realDefaultValue, false, null);
200+
}
201+
202+
public Column(String name, Type type, boolean isKey, AggregateType aggregateType, boolean isAllowNull,
203+
boolean isAutoInc, String defaultValue, String comment, boolean visible,
204+
DefaultValueExprDef defaultValueExprDef, int colUniqueId, String realDefaultValue,
205+
boolean hasOnUpdateDefaultValue, DefaultValueExprDef onUpdateDefaultValueExprDef) {
191206
this.name = name;
192207
if (this.name == null) {
193208
this.name = "";
@@ -212,6 +227,8 @@ public Column(String name, Type type, boolean isKey, AggregateType aggregateType
212227
this.children = new ArrayList<>();
213228
createChildrenColumn(this.type, this);
214229
this.uniqueId = colUniqueId;
230+
this.hasOnUpdateDefaultValue = hasOnUpdateDefaultValue;
231+
this.onUpdateDefaultValueExprDef = onUpdateDefaultValueExprDef;
215232

216233
if (type.isAggStateType()) {
217234
AggStateType aggState = (AggStateType) type;
@@ -244,6 +261,8 @@ public Column(Column column) {
244261
this.uniqueId = column.getUniqueId();
245262
this.defineExpr = column.getDefineExpr();
246263
this.defineName = column.getDefineName();
264+
this.hasOnUpdateDefaultValue = column.hasOnUpdateDefaultValue;
265+
this.onUpdateDefaultValueExprDef = column.onUpdateDefaultValueExprDef;
247266
}
248267

249268
public void createChildrenColumn(Type type, Column column) {
@@ -489,6 +508,14 @@ public int getOlapColumnIndexSize() {
489508
}
490509
}
491510

511+
public boolean hasOnUpdateDefaultValue() {
512+
return hasOnUpdateDefaultValue;
513+
}
514+
515+
public Expr getOnUpdateDefaultValueExpr() {
516+
return onUpdateDefaultValueExprDef.getExpr(type);
517+
}
518+
492519
public TColumn toThrift() {
493520
TColumn tColumn = new TColumn();
494521
tColumn.setColumnName(removeNamePrefix(this.name));
@@ -766,6 +793,9 @@ public String toSql(boolean isUniqueTable, boolean isCompatible) {
766793
sb.append(" DEFAULT \"").append(defaultValue).append("\"");
767794
}
768795
}
796+
if (hasOnUpdateDefaultValue) {
797+
sb.append(" ON UPDATE ").append(defaultValue).append("");
798+
}
769799
if (StringUtils.isNotBlank(comment)) {
770800
sb.append(" COMMENT '").append(getComment(true)).append("'");
771801
}

fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,16 @@ private void createOlapTable(Database db, CreateTableStmt stmt) throws UserExcep
21662166
}
21672167
olapTable.setEnableSingleReplicaCompaction(enableSingleReplicaCompaction);
21682168

2169+
// check `update on current_timestamp`
2170+
if (!enableUniqueKeyMergeOnWrite) {
2171+
for (Column column : baseSchema) {
2172+
if (column.hasOnUpdateDefaultValue()) {
2173+
throw new DdlException("'ON UPDATE CURRENT_TIMESTAMP' is only supportted"
2174+
+ " in unique table with merge-on-write enabled.");
2175+
}
2176+
}
2177+
}
2178+
21692179
// analyze bloom filter columns
21702180
Set<String> bfColumns = null;
21712181
double bfFpp = 0;

fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -379,31 +379,9 @@ public PlanFragment visitPhysicalOlapTableSink(PhysicalOlapTableSink<? extends P
379379
HashSet<String> partialUpdateCols = new HashSet<>();
380380
boolean isPartialUpdate = olapTableSink.isPartialUpdate();
381381
if (isPartialUpdate) {
382-
OlapTable olapTable = olapTableSink.getTargetTable();
383-
if (!olapTable.getEnableUniqueKeyMergeOnWrite()) {
384-
throw new AnalysisException("Partial update is only allowed in"
385-
+ "unique table with merge-on-write enabled.");
386-
}
387-
for (Column col : olapTable.getFullSchema()) {
388-
boolean exists = false;
389-
for (Column insertCol : olapTableSink.getCols()) {
390-
if (insertCol.getName() != null && insertCol.getName().equals(col.getName())) {
391-
exists = true;
392-
break;
393-
}
394-
}
395-
if (col.isKey() && !exists) {
396-
throw new AnalysisException("Partial update should include all key columns, missing: "
397-
+ col.getName());
398-
}
399-
}
400382
for (Column col : olapTableSink.getCols()) {
401383
partialUpdateCols.add(col.getName());
402384
}
403-
if (olapTable.hasSequenceCol() && olapTable.getSequenceMapCol() != null
404-
&& partialUpdateCols.contains(olapTable.getSequenceMapCol())) {
405-
partialUpdateCols.add(Column.SEQUENCE_COL);
406-
}
407385
}
408386
TupleDescriptor olapTuple = context.generateTupleDesc();
409387
List<Column> targetTableColumns = olapTableSink.getTargetTable().getFullSchema();

fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2156,6 +2156,7 @@ public ColumnDefinition visitColumnDef(ColumnDefContext ctx) {
21562156
boolean isNotNull = ctx.NOT() != null;
21572157
String aggTypeString = ctx.aggType != null ? ctx.aggType.getText() : null;
21582158
Optional<DefaultValue> defaultValue = Optional.empty();
2159+
Optional<DefaultValue> onUpdateDefaultValue = Optional.empty();
21592160
if (ctx.DEFAULT() != null) {
21602161
if (ctx.INTEGER_VALUE() != null) {
21612162
defaultValue = Optional.of(new DefaultValue(ctx.INTEGER_VALUE().getText()));
@@ -2164,14 +2165,24 @@ public ColumnDefinition visitColumnDef(ColumnDefContext ctx) {
21642165
} else if (ctx.nullValue != null) {
21652166
defaultValue = Optional.of(DefaultValue.NULL_DEFAULT_VALUE);
21662167
} else if (ctx.CURRENT_TIMESTAMP() != null) {
2167-
if (ctx.precision == null) {
2168+
if (ctx.defaultValuePrecision == null) {
21682169
defaultValue = Optional.of(DefaultValue.CURRENT_TIMESTAMP_DEFAULT_VALUE);
21692170
} else {
21702171
defaultValue = Optional.of(DefaultValue
2171-
.currentTimeStampDefaultValueWithPrecision(Long.valueOf(ctx.precision.getText())));
2172+
.currentTimeStampDefaultValueWithPrecision(
2173+
Long.valueOf(ctx.defaultValuePrecision.getText())));
21722174
}
21732175
}
21742176
}
2177+
if (ctx.UPDATE() != null) {
2178+
if (ctx.onUpdateValuePrecision == null) {
2179+
onUpdateDefaultValue = Optional.of(DefaultValue.CURRENT_TIMESTAMP_DEFAULT_VALUE);
2180+
} else {
2181+
onUpdateDefaultValue = Optional.of(DefaultValue
2182+
.currentTimeStampDefaultValueWithPrecision(
2183+
Long.valueOf(ctx.onUpdateValuePrecision.getText())));
2184+
}
2185+
}
21752186
AggregateType aggType = null;
21762187
if (aggTypeString != null) {
21772188
try {
@@ -2182,7 +2193,8 @@ public ColumnDefinition visitColumnDef(ColumnDefContext ctx) {
21822193
}
21832194
}
21842195
String comment = ctx.comment != null ? ctx.comment.getText() : "";
2185-
return new ColumnDefinition(colName, colType, isKey, aggType, !isNotNull, defaultValue, comment);
2196+
return new ColumnDefinition(colName, colType, isKey, aggType, !isNotNull, defaultValue,
2197+
onUpdateDefaultValue, comment);
21862198
}
21872199

21882200
@Override

0 commit comments

Comments
 (0)