Skip to content

Commit

Permalink
executor, expression: fix current_timestamp/now not consistent… (#11342)
Browse files Browse the repository at this point in the history
  • Loading branch information
cfzjywxk authored and zz-jason committed Jul 23, 2019
1 parent e0e5b50 commit ca70d74
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 49 deletions.
12 changes: 12 additions & 0 deletions executor/write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2538,3 +2538,15 @@ func (s *testSuite4) TestSetWithRefGenCol(c *C) {
_, err = tk.Exec(`insert into t3 set j = i + 1`)
c.Assert(err, NotNil)
}

func (s *testSuite4) TestSetWithCurrentTimestampAndNow(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("use test")
tk.MustExec(`drop table if exists tbl;`)
tk.MustExec(`create table t1(c1 timestamp default current_timestamp, c2 int, c3 timestamp default current_timestamp);`)
//c1 insert using now() function result, c3 using default value calculation, should be same
tk.MustExec(`insert into t1 set c1 = current_timestamp, c2 = sleep(2);`)
tk.MustQuery("select c1 = c3 from t1").Check(testkit.Rows("1"))
tk.MustExec(`insert into t1 set c1 = current_timestamp, c2 = sleep(1);`)
tk.MustQuery("select c1 = c3 from t1").Check(testkit.Rows("1", "1"))
}
62 changes: 29 additions & 33 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -2028,9 +2028,9 @@ func (b *builtinCurrentDateSig) Clone() builtinFunc {
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_curdate
func (b *builtinCurrentDateSig) evalTime(row chunk.Row) (d types.Time, isNull bool, err error) {
tz := b.ctx.GetSessionVars().Location()
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return types.Time{}, true, err
}
year, month, day := nowTs.In(tz).Date()
result := types.Time{
Expand Down Expand Up @@ -2087,9 +2087,9 @@ func (b *builtinCurrentTime0ArgSig) Clone() builtinFunc {

func (b *builtinCurrentTime0ArgSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
tz := b.ctx.GetSessionVars().Location()
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return types.Duration{}, true, err
}
dur := nowTs.In(tz).Format(types.TimeFormat)
res, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, dur, types.MinFsp)
Expand All @@ -2115,9 +2115,9 @@ func (b *builtinCurrentTime1ArgSig) evalDuration(row chunk.Row) (types.Duration,
return types.Duration{}, true, err
}
tz := b.ctx.GetSessionVars().Location()
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return types.Duration{}, true, err
}
dur := nowTs.In(tz).Format(types.TimeFSPFormat)
res, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, dur, int(fsp))
Expand Down Expand Up @@ -2257,9 +2257,9 @@ func (b *builtinUTCDateSig) Clone() builtinFunc {
// evalTime evals UTC_DATE, UTC_DATE().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-date
func (b *builtinUTCDateSig) evalTime(row chunk.Row) (types.Time, bool, error) {
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return types.Time{}, true, err
}
year, month, day := nowTs.UTC().Date()
result := types.Time{
Expand Down Expand Up @@ -2318,9 +2318,9 @@ func (c *utcTimestampFunctionClass) getFunction(ctx sessionctx.Context, args []E
}

func evalUTCTimestampWithFsp(ctx sessionctx.Context, fsp int) (types.Time, bool, error) {
var nowTs = &ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(ctx)
if err != nil {
return types.Time{}, true, err
}
result, err := convertTimeToMysqlTime(nowTs.UTC(), fsp, types.ModeHalfEven)
if err != nil {
Expand Down Expand Up @@ -2405,13 +2405,9 @@ func (c *nowFunctionClass) getFunction(ctx sessionctx.Context, args []Expression
}

func evalNowWithFsp(ctx sessionctx.Context, fsp int) (types.Time, bool, error) {
var sysTs = &ctx.GetSessionVars().StmtCtx.SysTs
if sysTs.Equal(time.Time{}) {
var err error
*sysTs, err = getSystemTimestamp(ctx)
if err != nil {
return types.Time{}, true, err
}
nowTs, err := getStmtTimestamp(ctx)
if err != nil {
return types.Time{}, true, err
}

// In MySQL's implementation, now() will truncate the result instead of rounding it.
Expand All @@ -2422,7 +2418,7 @@ func evalNowWithFsp(ctx sessionctx.Context, fsp int) (types.Time, bool, error) {
// +----------------------------+-------------------------+---------------------+
// | 2019-03-25 15:57:56.612966 | 2019-03-25 15:57:56.612 | 2019-03-25 15:57:56 |
// +----------------------------+-------------------------+---------------------+
result, err := convertTimeToMysqlTime(*sysTs, fsp, types.ModeTruncate)
result, err := convertTimeToMysqlTime(nowTs, fsp, types.ModeTruncate)
if err != nil {
return types.Time{}, true, err
}
Expand Down Expand Up @@ -4278,11 +4274,11 @@ func (b *builtinUnixTimestampCurrentSig) Clone() builtinFunc {
// evalInt evals a UNIX_TIMESTAMP().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampCurrentSig) evalInt(row chunk.Row) (int64, bool, error) {
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return 0, true, err
}
dec, err := goTimeToMysqlUnixTimestamp(*nowTs, 1)
dec, err := goTimeToMysqlUnixTimestamp(nowTs, 1)
if err != nil {
return 0, true, err
}
Expand Down Expand Up @@ -6340,9 +6336,9 @@ func (b *builtinUTCTimeWithoutArgSig) Clone() builtinFunc {
// evalDuration evals a builtinUTCTimeWithoutArgSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-time
func (b *builtinUTCTimeWithoutArgSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return types.Duration{}, true, err
}
v, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, nowTs.UTC().Format(types.TimeFormat), 0)
return v, false, err
Expand Down Expand Up @@ -6371,9 +6367,9 @@ func (b *builtinUTCTimeWithArgSig) evalDuration(row chunk.Row) (types.Duration,
if fsp < int64(types.MinFsp) {
return types.Duration{}, true, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp)
}
var nowTs = &b.ctx.GetSessionVars().StmtCtx.NowTs
if nowTs.Equal(time.Time{}) {
*nowTs = time.Now()
nowTs, err := getStmtTimestamp(b.ctx)
if err != nil {
return types.Duration{}, true, err
}
v, err := types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, nowTs.UTC().Format(types.TimeFSPFormat), int(fsp))
return v, false, err
Expand Down
3 changes: 1 addition & 2 deletions expression/builtin_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -764,8 +764,7 @@ func (s *testEvaluatorSuite) TestTime(c *C) {
}

func resetStmtContext(ctx sessionctx.Context) {
ctx.GetSessionVars().StmtCtx.NowTs = time.Time{}
ctx.GetSessionVars().StmtCtx.SysTs = time.Time{}
ctx.GetSessionVars().StmtCtx.ResetNowTs()
}

func (s *testEvaluatorSuite) TestNowAndUTCTimestamp(c *C) {
Expand Down
27 changes: 15 additions & 12 deletions expression/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func GetTimeValue(ctx sessionctx.Context, v interface{}, tp byte, fsp int) (d ty
case string:
upperX := strings.ToUpper(x)
if upperX == strings.ToUpper(ast.CurrentTimestamp) {
defaultTime, err := getSystemTimestamp(ctx)
defaultTime, err := getStmtTimestamp(ctx)
if err != nil {
return d, err
}
Expand Down Expand Up @@ -120,7 +120,9 @@ func GetTimeValue(ctx sessionctx.Context, v interface{}, tp byte, fsp int) (d ty
return d, nil
}

func getSystemTimestamp(ctx sessionctx.Context) (time.Time, error) {
// if timestamp session variable set, use session variable as current time, otherwise use cached time
// during one sql statement, the "current_time" should be the same
func getStmtTimestamp(ctx sessionctx.Context) (time.Time, error) {
now := time.Now()

if ctx == nil {
Expand All @@ -133,15 +135,16 @@ func getSystemTimestamp(ctx sessionctx.Context) (time.Time, error) {
return now, err
}

if timestampStr == "" {
return now, nil
}
timestamp, err := types.StrToInt(sessionVars.StmtCtx, timestampStr)
if err != nil {
return time.Time{}, err
}
if timestamp <= 0 {
return now, nil
if timestampStr != "" {
timestamp, err := types.StrToInt(sessionVars.StmtCtx, timestampStr)
if err != nil {
return time.Time{}, err
}
if timestamp <= 0 {
return now, nil
}
return time.Unix(timestamp, 0), nil
}
return time.Unix(timestamp, 0), nil
stmtCtx := ctx.GetSessionVars().StmtCtx
return stmtCtx.GetNowTsCached(), nil
}
19 changes: 17 additions & 2 deletions sessionctx/stmtctx/stmtctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ type StatementContext struct {
RuntimeStatsColl *execdetails.RuntimeStatsColl
TableIDs []int64
IndexIDs []int64
NowTs time.Time
SysTs time.Time
nowTs time.Time // use this variable for now/current_timestamp calculation/cache for one stmt
stmtTimeCached bool
StmtType string
OriginalSQL string
digestMemo struct {
Expand All @@ -132,6 +132,21 @@ type StatementContext struct {
Tables []TableEntry
}

// GetNowTsCached getter for nowTs, if not set get now time and cache it
func (sc *StatementContext) GetNowTsCached() time.Time {
if !sc.stmtTimeCached {
now := time.Now()
sc.nowTs = now
sc.stmtTimeCached = true
}
return sc.nowTs
}

// ResetNowTs resetter for nowTs, clear cached time flag
func (sc *StatementContext) ResetNowTs() {
sc.stmtTimeCached = false
}

// SQLDigest gets normalized and digest for provided sql.
// it will cache result after first calling.
func (sc *StatementContext) SQLDigest() (normalized, sqlDigest string) {
Expand Down

0 comments on commit ca70d74

Please sign in to comment.