Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expression,table: fix insert partitioned table bug when the time zone change (#14370) #14476

Merged
merged 3 commits into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions expression/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ type builtinFunc interface {
Clone() builtinFunc
}

type builtinFuncNew interface {
evalIntWithCtx(ctx sessionctx.Context, row chunk.Row) (val int64, isNull bool, err error)
}

// baseFunctionClass will be contained in every struct that implement functionClass interface.
type baseFunctionClass struct {
funcName string
Expand Down
4 changes: 4 additions & 0 deletions expression/builtin_compare.go
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,10 @@ func (b *builtinLTIntSig) Clone() builtinFunc {
return newSig
}

func (b *builtinLTIntSig) evalIntWithCtx(ctx sessionctx.Context, row chunk.Row) (val int64, isNull bool, err error) {
return resOfLT(CompareInt(ctx, b.args[0], b.args[1], row, row))
}

func (b *builtinLTIntSig) evalInt(row chunk.Row) (val int64, isNull bool, err error) {
return resOfLT(CompareInt(b.ctx, b.args[0], b.args[1], row, row))
}
Expand Down
15 changes: 12 additions & 3 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ var (
_ functionClass = &subDateFunctionClass{}
)

var (
_ builtinFuncNew = &builtinUnixTimestampIntSig{}
)

var (
_ builtinFunc = &builtinDateSig{}
_ builtinFunc = &builtinDateLiteralSig{}
Expand Down Expand Up @@ -4315,15 +4319,20 @@ func (b *builtinUnixTimestampIntSig) Clone() builtinFunc {
// evalInt evals a UNIX_TIMESTAMP(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampIntSig) evalInt(row chunk.Row) (int64, bool, error) {
val, isNull, err := b.args[0].EvalTime(b.ctx, row)
return b.evalIntWithCtx(b.ctx, row)
}

func (b *builtinUnixTimestampIntSig) evalIntWithCtx(ctx sessionctx.Context, row chunk.Row) (int64, bool, error) {
val, isNull, err := b.args[0].EvalTime(ctx, row)
if err != nil && terror.ErrorEqual(types.ErrInvalidTimeFormat.GenWithStackByArgs(val), err) {
// Return 0 for invalid date time.
return 0, false, nil
}
if isNull {
return 0, true, nil
}
t, err := val.Time.GoTime(getTimeZone(b.ctx))

tz := ctx.GetSessionVars().Location()
t, err := val.Time.GoTime(tz)
if err != nil {
return 0, false, nil
}
Expand Down
3 changes: 3 additions & 0 deletions expression/scalar_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ func (sf *ScalarFunction) Eval(row chunk.Row) (d types.Datum, err error) {

// EvalInt implements Expression interface.
func (sf *ScalarFunction) EvalInt(ctx sessionctx.Context, row chunk.Row) (int64, bool, error) {
if f, ok := sf.Function.(builtinFuncNew); ok {
return f.evalIntWithCtx(ctx, row)
}
return sf.Function.evalInt(row)
}

Expand Down
57 changes: 57 additions & 0 deletions table/tables/partition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,60 @@ func (ts *testSuite) TestLocateRangePartitionErr(c *C) {
_, err := tk.Exec("INSERT INTO t_month_data_monitor VALUES (4, '2019-04-04')")
c.Assert(table.ErrNoPartitionForGivenValue.Equal(err), IsTrue)
}

func (ts *testSuite) TestTimeZoneChange(c *C) {
tk := testkit.NewTestKitWithInit(c, ts.store)
tk.MustExec("use test")
createTable := `CREATE TABLE timezone_test (
id int(11) NOT NULL,
creation_dt timestamp DEFAULT CURRENT_TIMESTAMP ) PARTITION BY RANGE ( unix_timestamp(creation_dt) )
( PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2020-01-03 15:10:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2020-01-03 15:15:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2020-01-03 15:20:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2020-01-03 15:25:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE) )`
tk.MustExec("SET @@time_zone = 'Asia/Shanghai'")
tk.MustExec(createTable)
tk.MustQuery("SHOW CREATE TABLE timezone_test").Check(testkit.Rows("timezone_test CREATE TABLE `timezone_test` (\n" +
" `id` int(11) NOT NULL,\n" +
" `creation_dt` timestamp DEFAULT CURRENT_TIMESTAMP\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY RANGE ( unix_timestamp(`creation_dt`) ) (\n" +
" PARTITION p5 VALUES LESS THAN (1578035400),\n" +
" PARTITION p6 VALUES LESS THAN (1578035700),\n" +
" PARTITION p7 VALUES LESS THAN (1578036000),\n" +
" PARTITION p8 VALUES LESS THAN (1578036300),\n" +
" PARTITION p9 VALUES LESS THAN (MAXVALUE)\n)"))
tk.MustExec("DROP TABLE timezone_test")

// Note that the result of "show create table" varies with time_zone.
tk.MustExec("SET @@time_zone = 'UTC'")
tk.MustExec(createTable)
tk.MustQuery("SHOW CREATE TABLE timezone_test").Check(testkit.Rows("timezone_test CREATE TABLE `timezone_test` (\n" +
" `id` int(11) NOT NULL,\n" +
" `creation_dt` timestamp DEFAULT CURRENT_TIMESTAMP\n" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin\n" +
"PARTITION BY RANGE ( unix_timestamp(`creation_dt`) ) (\n" +
" PARTITION p5 VALUES LESS THAN (1578064200),\n" +
" PARTITION p6 VALUES LESS THAN (1578064500),\n" +
" PARTITION p7 VALUES LESS THAN (1578064800),\n" +
" PARTITION p8 VALUES LESS THAN (1578065100),\n" +
" PARTITION p9 VALUES LESS THAN (MAXVALUE)\n)"))

// Change time zone and insert data, check the data locates in the correct partition.
tk.MustExec("SET @@time_zone = 'Asia/Shanghai'")
tk.MustExec("INSERT INTO timezone_test VALUES (1,'2020-01-03 15:16:59')")
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p5)").Check(testkit.Rows("1 2020-01-03 15:16:59"))
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p6)").Check(testkit.Rows())
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p7)").Check(testkit.Rows())
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p8)").Check(testkit.Rows())
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p9)").Check(testkit.Rows())

tk.MustExec("SET @@time_zone = 'UTC'")
tk.MustExec("INSERT INTO timezone_test VALUES (1,'2020-01-03 15:16:59')")
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p5)").Check(testkit.Rows("1 2020-01-03 07:16:59"))
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p6)").Check(testkit.Rows())
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p7)").Check(testkit.Rows("1 2020-01-03 15:16:59"))
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p8)").Check(testkit.Rows())
tk.MustQuery("SELECT * FROM timezone_test PARTITION (p9)").Check(testkit.Rows())
}