Skip to content

Commit

Permalink
types: support sql_mode ALLOW_INVALID_DATES (#9027) (#9110)
Browse files Browse the repository at this point in the history
  • Loading branch information
bobotu authored and ngaut committed Jan 20, 2019
1 parent 6ed7e9f commit 788fbf2
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 23 deletions.
12 changes: 9 additions & 3 deletions executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1250,23 +1250,26 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
sc.BadNullAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.TruncateAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr
sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode()
sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr || sc.AllowInvalidDate
sc.Priority = stmt.Priority
case *ast.DeleteStmt:
sc.InDeleteStmt = true
sc.DupKeyAsWarning = stmt.IgnoreErr
sc.BadNullAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.TruncateAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr
sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode()
sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr || sc.AllowInvalidDate
sc.Priority = stmt.Priority
case *ast.InsertStmt:
sc.InInsertStmt = true
sc.DupKeyAsWarning = stmt.IgnoreErr
sc.BadNullAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.TruncateAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.DividedByZeroAsWarning = !vars.StrictSQLMode || stmt.IgnoreErr
sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr
sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode()
sc.IgnoreZeroInDate = !vars.StrictSQLMode || stmt.IgnoreErr || sc.AllowInvalidDate
sc.Priority = stmt.Priority
case *ast.CreateTableStmt, *ast.AlterTableStmt:
// Make sure the sql_mode is strict when checking column default value.
Expand All @@ -1287,6 +1290,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
// Return warning for truncate error in selection.
sc.TruncateAsWarning = true
sc.IgnoreZeroInDate = true
sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode()
if opts := stmt.SelectStmtOpts; opts != nil {
sc.Priority = opts.Priority
sc.NotFillCache = !opts.SQLCache
Expand All @@ -1295,13 +1299,15 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
case *ast.ShowStmt:
sc.IgnoreTruncate = true
sc.IgnoreZeroInDate = true
sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode()
if stmt.Tp == ast.ShowWarnings || stmt.Tp == ast.ShowErrors {
sc.InShowWarning = true
sc.SetWarnings(vars.StmtCtx.GetWarnings())
}
default:
sc.IgnoreTruncate = true
sc.IgnoreZeroInDate = true
sc.AllowInvalidDate = vars.SQLMode.HasAllowInvalidDatesMode()
}
vars.PreparedParams = vars.PreparedParams[:0]
if !vars.InRestrictedSQL {
Expand Down
37 changes: 37 additions & 0 deletions executor/insert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package executor_test

import (
"fmt"

. "github.com/pingcap/check"
"github.com/pingcap/parser/terror"
"github.com/pingcap/tidb/table"
Expand Down Expand Up @@ -174,3 +176,38 @@ func (s *testSuite) TestInsertZeroYear(c *C) {
`2000`,
))
}

func (s *testSuite) TestAllowInvalidDates(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test`)
tk.MustExec(`drop table if exists t1, t2, t3, t4;`)
tk.MustExec(`create table t1(d date);`)
tk.MustExec(`create table t2(d datetime);`)
tk.MustExec(`create table t3(d date);`)
tk.MustExec(`create table t4(d datetime);`)

runWithMode := func(mode string) {
inputs := []string{"0000-00-00", "2019-00-00", "2019-01-00", "2019-00-01", "2019-02-31"}
results := testkit.Rows(`0 0 0`, `2019 0 0`, `2019 1 0`, `2019 0 1`, `2019 2 31`)
oldMode := tk.MustQuery(`select @@sql_mode`).Rows()[0][0]
defer func() {
tk.MustExec(fmt.Sprintf(`set sql_mode='%s'`, oldMode))
}()

tk.MustExec(`truncate t1;truncate t2;truncate t3;truncate t4;`)
tk.MustExec(fmt.Sprintf(`set sql_mode='%s';`, mode))
for _, input := range inputs {
tk.MustExec(fmt.Sprintf(`insert into t1 values ('%s')`, input))
tk.MustExec(fmt.Sprintf(`insert into t2 values ('%s')`, input))
}
tk.MustQuery(`select year(d), month(d), day(d) from t1;`).Check(results)
tk.MustQuery(`select year(d), month(d), day(d) from t2;`).Check(results)
tk.MustExec(`insert t3 select d from t1;`)
tk.MustQuery(`select year(d), month(d), day(d) from t3;`).Check(results)
tk.MustExec(`insert t4 select d from t2;`)
tk.MustQuery(`select year(d), month(d), day(d) from t4;`).Check(results)
}

runWithMode("STRICT_TRANS_TABLES,ALLOW_INVALID_DATES")
runWithMode("ALLOW_INVALID_DATES")
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ require (
github.com/pingcap/gofail v0.0.0-20181217135706-6a951c1e42c3
github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030
github.com/pingcap/kvproto v0.0.0-20181109035735-8e3f33ac4929
github.com/pingcap/parser v0.0.0-20190116142258-00e692951ce1
github.com/pingcap/parser v0.0.0-20190118033454-a52e5bde3bd2
github.com/pingcap/pd v2.1.0-rc.4+incompatible
github.com/pingcap/tidb-tools v2.1.1-0.20181218072513-b2235d442b06+incompatible
github.com/pingcap/tipb v0.0.0-20180910045846-371b48b15d93
github.com/pkg/errors v0.8.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v0.8.0
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5 // indirect
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5
github.com/prometheus/common v0.0.0-20180426121432-d811d2e9bf89 // indirect
github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d // indirect
github.com/sirupsen/logrus v0.0.0-20170323161349-3bcb09397d6d
Expand Down
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,8 @@ github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030 h1:XJLuW0lsP7vAt
github.com/pingcap/goleveldb v0.0.0-20171020084629-8d44bfdf1030/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw=
github.com/pingcap/kvproto v0.0.0-20181109035735-8e3f33ac4929 h1:NAq95+VGsS2G7SjzZ5LP9iUlCMNAs13QUzbNY3G90v8=
github.com/pingcap/kvproto v0.0.0-20181109035735-8e3f33ac4929/go.mod h1:0gwbe1F2iBIjuQ9AH0DbQhL+Dpr5GofU8fgYyXk+ykk=
github.com/pingcap/parser v0.0.0-20190107034620-db064135d7b0 h1:t/xlCk9karOvR8xrq7da4FAGLo3IHhbDeSTcA6taiUc=
github.com/pingcap/parser v0.0.0-20190107034620-db064135d7b0/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20190116142258-00e692951ce1 h1:fis1l2hPX1piYENHn5B9sMmpbUURp8l2IJJpKHP1aUk=
github.com/pingcap/parser v0.0.0-20190116142258-00e692951ce1/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20190118033454-a52e5bde3bd2 h1:7YGx4hF6M0nlFJVZrLF3EbMRI+XOizL+9aB8Txe745U=
github.com/pingcap/parser v0.0.0-20190118033454-a52e5bde3bd2/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE=
github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E=
github.com/pingcap/tidb-tools v2.1.1-0.20181218072513-b2235d442b06+incompatible h1:Bsd+NHosPVowEGB3BCx+2d8wUQGDTXSSC5ljeNS6cXo=
Expand All @@ -120,8 +118,6 @@ github.com/spaolacci/murmur3 v0.0.0-20150829172844-0d12bf811670 h1:hKP4ACPoBBCnB
github.com/spaolacci/murmur3 v0.0.0-20150829172844-0d12bf811670/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tiancaiamao/parser v0.0.0-20190116115114-e2ff6aa2040c h1:Jca3Kh29wy4T8etEUU+/SWbYoQHFqDJIzS0kIjuoCXU=
github.com/tiancaiamao/parser v0.0.0-20190116115114-e2ff6aa2040c/go.mod h1:vqvanuOAAZ9O2rVI51fUrA9P3nV7HoILjLby0/OKOqA=
github.com/twinj/uuid v0.0.0-20150629100731-70cac2bcd273 h1:YqFyfcgqxQqjpRr0SEG0Z555J/3kPqDL/xmRyeAaX/0=
github.com/twinj/uuid v0.0.0-20150629100731-70cac2bcd273/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY=
github.com/uber/jaeger-client-go v2.8.0+incompatible h1:7DGH8Hqk6PirD+GE+bvCf0cLnspLuae7N1NcwMeQcyg=
Expand Down
1 change: 1 addition & 0 deletions sessionctx/stmtctx/stmtctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type StatementContext struct {
PadCharToFullLength bool
BatchCheck bool
InNullRejectCheck bool
AllowInvalidDate bool

// mu struct holds variables that change during execution.
mu struct {
Expand Down
28 changes: 16 additions & 12 deletions types/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,18 +474,20 @@ func (t *Time) FromPackedUint(packed uint64) error {
// FIXME: See https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_zero_in_date
func (t *Time) check(sc *stmtctx.StatementContext) error {
allowZeroInDate := false
allowInvalidDate := false
// We should avoid passing sc as nil here as far as possible.
if sc != nil {
allowZeroInDate = sc.IgnoreZeroInDate
allowInvalidDate = sc.AllowInvalidDate
}
var err error
switch t.Type {
case mysql.TypeTimestamp:
err = checkTimestampType(sc, t.Time)
case mysql.TypeDatetime:
err = checkDatetimeType(t.Time, allowZeroInDate)
err = checkDatetimeType(t.Time, allowZeroInDate, allowInvalidDate)
case mysql.TypeDate:
err = checkDateType(t.Time, allowZeroInDate)
err = checkDateType(t.Time, allowZeroInDate, allowInvalidDate)
}
return errors.Trace(err)
}
Expand Down Expand Up @@ -1341,7 +1343,7 @@ func TimeFromDays(num int64) Time {
}
}

func checkDateType(t MysqlTime, allowZeroInDate bool) error {
func checkDateType(t MysqlTime, allowZeroInDate, allowInvalidDate bool) error {
year, month, day := t.Year(), t.Month(), t.Day()
if year == 0 && month == 0 && day == 0 {
return nil
Expand All @@ -1355,7 +1357,7 @@ func checkDateType(t MysqlTime, allowZeroInDate bool) error {
return errors.Trace(err)
}

if err := checkMonthDay(year, month, day); err != nil {
if err := checkMonthDay(year, month, day, allowInvalidDate); err != nil {
return errors.Trace(err)
}

Expand All @@ -1374,17 +1376,19 @@ func checkDateRange(t MysqlTime) error {
return nil
}

func checkMonthDay(year, month, day int) error {
func checkMonthDay(year, month, day int, allowInvalidDate bool) error {
if month < 0 || month > 12 {
return errors.Trace(ErrInvalidTimeFormat.GenWithStackByArgs(month))
}

maxDay := 31
if month > 0 {
maxDay = maxDaysInMonth[month-1]
}
if month == 2 && year%4 != 0 {
maxDay = 28
if !allowInvalidDate {
if month > 0 {
maxDay = maxDaysInMonth[month-1]
}
if month == 2 && year%4 != 0 {
maxDay = 28
}
}

if day < 0 || day > maxDay {
Expand Down Expand Up @@ -1424,8 +1428,8 @@ func checkTimestampType(sc *stmtctx.StatementContext, t MysqlTime) error {
return nil
}

func checkDatetimeType(t MysqlTime, allowZeroInDate bool) error {
if err := checkDateType(t, allowZeroInDate); err != nil {
func checkDatetimeType(t MysqlTime, allowZeroInDate, allowInvalidDate bool) error {
if err := checkDateType(t, allowZeroInDate, allowInvalidDate); err != nil {
return errors.Trace(err)
}

Expand Down

0 comments on commit 788fbf2

Please sign in to comment.