From aee4fd26f0c4927fd9e7f32208441f22ad481dd7 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 22 Nov 2021 01:21:43 +0100 Subject: [PATCH] fix for INSERT INTO t SET timestamp_col = DEFAULT (#29926) --- parser/ast/expressions.go | 5 ++++- parser/parser.y | 4 +--- planner/core/expression_rewriter.go | 16 ++++++++++++++-- planner/core/planbuilder.go | 3 ++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/parser/ast/expressions.go b/parser/ast/expressions.go index 6a46ab332c831..412e75edd0af9 100644 --- a/parser/ast/expressions.go +++ b/parser/ast/expressions.go @@ -606,12 +606,15 @@ type DefaultExpr struct { exprNode // Name is the column name. Name *ColumnName + // True - DEFAULT(ColumnName), False - just DEFAULT, but name filled in afterwards + // like for: INSERT INTO t1 SET t = DEFAULT + NameIsGiven bool } // Restore implements Node interface. func (n *DefaultExpr) Restore(ctx *format.RestoreCtx) error { ctx.WriteKeyWord("DEFAULT") - if n.Name != nil { + if n.NameIsGiven && n.Name != nil { ctx.WritePlain("(") if err := n.Name.Restore(ctx); err != nil { return errors.Annotate(err, "An error occurred while restore DefaultExpr.Name") diff --git a/parser/parser.y b/parser/parser.y index e339af5ed92da..deade84a1d860 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -6207,7 +6207,6 @@ ProcedureCall: * * Insert Statements * - * TODO: support PARTITION **********************************************************************************/ InsertIntoStmt: "INSERT" TableOptimizerHintsOpt PriorityOpt IgnoreOptional IntoOpt TableName PartitionNameListOpt InsertValues OnDuplicateKeyUpdate @@ -6381,7 +6380,6 @@ OnDuplicateKeyUpdate: * Replace Statements * See https://dev.mysql.com/doc/refman/5.7/en/replace.html * - * TODO: support PARTITION **********************************************************************************/ ReplaceIntoStmt: "REPLACE" PriorityOpt IntoOpt TableName PartitionNameListOpt InsertValues @@ -6848,7 +6846,7 @@ SimpleExpr: } | "DEFAULT" '(' SimpleIdent ')' { - $$ = &ast.DefaultExpr{Name: $3.(*ast.ColumnNameExpr).Name} + $$ = &ast.DefaultExpr{Name: $3.(*ast.ColumnNameExpr).Name NameIsGiven: true} } | "VALUES" '(' SimpleIdent ')' %prec lowerThanInsertValues { diff --git a/planner/core/expression_rewriter.go b/planner/core/expression_rewriter.go index 570c5b30c8b56..38f6bb5cf56ab 100644 --- a/planner/core/expression_rewriter.go +++ b/planner/core/expression_rewriter.go @@ -1941,11 +1941,23 @@ func (er *expressionRewriter) evalDefaultExpr(v *ast.DefaultExpr) { isCurrentTimestamp := hasCurrentDatetimeDefault(col) var val *expression.Constant switch { - case isCurrentTimestamp && col.Tp == mysql.TypeDatetime: + case isCurrentTimestamp && !v.NameIsGiven && (col.Tp == mysql.TypeDatetime || col.Tp == mysql.TypeTimestamp): + // SET col = DEFAULT + t, err := expression.GetTimeValue(er.sctx, ast.CurrentTimestamp, col.Tp, int8(col.Decimal)) + if err != nil { + return + } + val = &expression.Constant{ + Value: t, + RetType: types.NewFieldType(col.Tp), + } + case isCurrentTimestamp && v.NameIsGiven && col.Tp == mysql.TypeDatetime: // for DATETIME column with current_timestamp, use NULL to be compatible with MySQL 5.7 + // DEFAULT(colname) val = expression.NewNull() - case isCurrentTimestamp && col.Tp == mysql.TypeTimestamp: + case isCurrentTimestamp && v.NameIsGiven && col.Tp == mysql.TypeTimestamp: // for TIMESTAMP column with current_timestamp, use 0 to be compatible with MySQL 5.7 + // DEFAULT(colname) zero := types.NewTime(types.ZeroCoreTime, mysql.TypeTimestamp, int8(col.Decimal)) val = &expression.Constant{ Value: types.NewDatum(zero), diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index d1fc3ba01cdc3..105a0427bab2e 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -3215,7 +3215,8 @@ func (b *PlanBuilder) buildSetValuesOfInsert(ctx context.Context, insert *ast.In insertPlan.AllAssignmentsAreConstant = true for i, assign := range insert.Setlist { defaultExpr := extractDefaultExpr(assign.Expr) - if defaultExpr != nil { + if defaultExpr != nil && !defaultExpr.NameIsGiven { + // Set the name of the column in the assignment defaultExpr.Name = assign.Column } // Note: For INSERT, REPLACE, and UPDATE, if a generated column is inserted into, replaced, or updated explicitly, the only permitted value is DEFAULT.