-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
parser, ast, expression: fix bug on DATE literal #4362
Changes from 13 commits
33a0aaf
f9aef71
95adc56
e21a583
581abaf
d1f5df9
09c6f08
503db45
db0ad3d
552bf49
49a945f
1d62af9
b0f844b
02248c7
9a26d31
ff2b23e
6c8296b
e1f107b
2f430ae
1065b7f
1c1ea57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,8 +53,12 @@ const ( // GET_FORMAT location. | |
// DurationPattern determine whether to match the format of duration. | ||
var DurationPattern = regexp.MustCompile(`^(|[-]?)(|\d{1,2}\s)(\d{2,3}:\d{2}:\d{2}|\d{1,2}:\d{2}|\d{1,6})(|\.\d*)$`) | ||
|
||
// DatePattern determine whether to match the format of date. | ||
var DatePattern = regexp.MustCompile(`^\s*((0*\d{1,4}([^\d]0*\d{1,2}){2})|(\d{2,4}(\d{2}){2}))\s*$`) | ||
|
||
var ( | ||
_ functionClass = &dateFunctionClass{} | ||
_ functionClass = &dateLiteralFunctionClass{} | ||
_ functionClass = &dateDiffFunctionClass{} | ||
_ functionClass = &timeDiffFunctionClass{} | ||
_ functionClass = &dateFormatFunctionClass{} | ||
|
@@ -107,6 +111,7 @@ var ( | |
|
||
var ( | ||
_ builtinFunc = &builtinDateSig{} | ||
_ builtinFunc = &builtinDateLiteralSig{} | ||
_ builtinFunc = &builtinDateDiffSig{} | ||
_ builtinFunc = &builtinTimeDiffSig{} | ||
_ builtinFunc = &builtinDateFormatSig{} | ||
|
@@ -283,6 +288,58 @@ func (b *builtinDateSig) evalTime(row []types.Datum) (types.Time, bool, error) { | |
return expr, false, nil | ||
} | ||
|
||
type dateLiteralFunctionClass struct { | ||
baseFunctionClass | ||
} | ||
|
||
func (c *dateLiteralFunctionClass) getFunction(ctx context.Context, args []Expression) (builtinFunc, error) { | ||
if err := c.verifyArgs(args); err != nil { | ||
return nil, errors.Trace(err) | ||
} | ||
constant, ok := args[0].(*Constant) | ||
if !ok { | ||
return nil, errors.Trace(types.ErrInvalidTimeFormat) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we handle this error to respect to sql mode ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nope. |
||
} | ||
str := constant.Value.GetString() | ||
if !DatePattern.MatchString(str) { | ||
return nil, errors.Trace(types.ErrInvalidTimeFormat) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
} | ||
tm, err := types.ParseDate(str) | ||
if err != nil { | ||
return nil, errors.Trace(err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
} | ||
bf := newBaseBuiltinFuncWithTp(args, ctx, tpDatetime, tpString) | ||
bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, 10, 0 | ||
sig := &builtinDateLiteralSig{baseTimeBuiltinFunc{bf}, tm} | ||
return sig.setSelf(sig), nil | ||
} | ||
|
||
type builtinDateLiteralSig struct { | ||
baseTimeBuiltinFunc | ||
tm types.Time | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/tm/literal/ ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
} | ||
|
||
// evalTime evals DATE 'stringLit'. | ||
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html | ||
func (b *builtinDateLiteralSig) evalTime(row []types.Datum) (types.Time, bool, error) { | ||
/* | ||
sc := b.ctx.GetSessionVars().StmtCtx | ||
str, isNull, err := b.args[0].EvalString(row, sc) | ||
if isNull || err != nil { | ||
return types.Time{}, true, errors.Trace(err) | ||
} | ||
if !DatePattern.MatchString(str) { | ||
return types.Time{}, true, errors.Trace(types.ErrInvalidTimeFormat) | ||
} | ||
ret, err := types.ParseDate(str) | ||
if err != nil { | ||
return types.Time{}, true, errors.Trace(err) | ||
} | ||
return ret, false, nil | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove the commented code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
return b.tm, false, nil | ||
} | ||
|
||
func convertDatumToTime(sc *variable.StatementContext, d types.Datum) (t types.Time, err error) { | ||
if d.Kind() != types.KindMysqlTime { | ||
d, err = convertToTime(sc, d, mysql.TypeDatetime) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2422,21 +2422,34 @@ func (s *testIntegrationSuite) TestDateBuiltin(c *C) { | |
r = tk.MustQuery("select date'2017/12-12'") | ||
r.Check(testkit.Rows("2017-12-12")) | ||
|
||
r = tk.MustQuery("select date'0000-00-00'") | ||
r.Check(testkit.Rows("<nil>")) | ||
r = tk.MustQuery("select date '0000-00-00';") | ||
r.Check(testkit.Rows("0000-00-00")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in mysql, this will cause an error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @XuHuaiyu What's your mysql version? It works on my computer. # ./mysql -uroot
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 35
Server version: 5.7.17-log MySQL Community Server (GPL)
Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> select date '0000-00-00';
+-------------------+
| date '0000-00-00' |
+-------------------+
| 0000-00-00 |
+-------------------+
1 row in set (0.00 sec)
mysql>
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @XuHuaiyu The result seems has something to do with |
||
|
||
r = tk.MustQuery("select date'0000-00-00 00:00:00'") | ||
r.Check(testkit.Rows("<nil>")) | ||
r = tk.MustQuery("select date'1998~01~02'") | ||
r.Check(testkit.Rows("1998-01-02")) | ||
|
||
r = tk.MustQuery("select date'2017-99-99';") | ||
r.Check(testkit.Rows("<nil>")) | ||
r = tk.MustQuery("select date'731124', date '011124'") | ||
r.Check(testkit.Rows("1973-11-24 2001-11-24")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add test for invalid time format There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
|
||
r = tk.MustQuery("select date'2017-2-31';") | ||
r.Check(testkit.Rows("<nil>")) | ||
_, err := tk.Exec("select date '0000-00-00 00:00:00';") | ||
c.Assert(err, NotNil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about add one more check for error message ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done @zz-jason |
||
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue) | ||
|
||
_, err = tk.Exec("select date '2017-99-99';") | ||
c.Assert(err, NotNil) | ||
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue) | ||
|
||
_, err = tk.Exec("select date '2017-2-31';") | ||
c.Assert(err, NotNil) | ||
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue) | ||
|
||
r = tk.MustQuery("select date'201712-31';") | ||
r.Check(testkit.Rows("<nil>")) | ||
_, err = tk.Exec("select date '201712-31';") | ||
c.Assert(err, NotNil) | ||
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue) | ||
|
||
_, err = tk.Exec("select date 'abcdefg';") | ||
c.Assert(err, NotNil) | ||
c.Assert(terror.ErrorEqual(err, types.ErrInvalidTimeFormat), IsTrue) | ||
} | ||
|
||
func (s *testIntegrationSuite) TestLiterals(c *C) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to export this variable, so does
DurationPattern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok