From 87f9d7e9f480db964cffa037e2548b5c0b0310f4 Mon Sep 17 00:00:00 2001 From: codeworm96 Date: Fri, 24 Mar 2017 12:39:37 +0800 Subject: [PATCH] builtin: add quarter built-in function Implement the QUARTER built-in function. --- expression/builtin_time.go | 30 ++++++++++++++++++++++++++- expression/builtin_time_test.go | 36 +++++++++++++++++++++++++++++++++ plan/typeinferer.go | 2 +- plan/typeinferer_test.go | 1 + 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/expression/builtin_time.go b/expression/builtin_time.go index ab850f36888bb..31d7f7bc5dfb9 100644 --- a/expression/builtin_time.go +++ b/expression/builtin_time.go @@ -1729,7 +1729,35 @@ type builtinQuarterSig struct { // See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_quarter func (b *builtinQuarterSig) eval(row []types.Datum) (d types.Datum, err error) { - return d, errFunctionNotExists.GenByArgs("QUARTER") + args, err := b.evalArgs(row) + if err != nil { + return types.Datum{}, errors.Trace(err) + } + + d, err = builtinMonth(args, b.ctx) + if err != nil || d.IsNull() { + return d, errors.Trace(err) + } + + mon := int(d.GetInt64()) + switch mon { + case 0: + // An undocumented behavior of the mysql implementation + d.SetInt64(0) + case 1, 2, 3: + d.SetInt64(1) + case 4, 5, 6: + d.SetInt64(2) + case 7, 8, 9: + d.SetInt64(3) + case 10, 11, 12: + d.SetInt64(4) + default: + d.SetNull() + return d, errors.Errorf("no quarter for invalid month: %d.", mon) + } + + return d, nil } type secToTimeFunctionClass struct { diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index 79b563afcf29c..cdc108c9048e8 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -1013,3 +1013,39 @@ func (s *testEvaluatorSuite) TestTimestamp(c *C) { c.Assert(err, IsNil) c.Assert(d.Kind(), Equals, types.KindNull) } + +func (s *testEvaluatorSuite) TestQuarter(c *C) { + tests := []struct { + t string + expect int64 + }{ + // Test case from https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_quarter + {"2008-04-01", 2}, + // Test case for boundary values + {"2008-01-01", 1}, + {"2008-03-31", 1}, + {"2008-06-30", 2}, + {"2008-07-01", 3}, + {"2008-09-30", 3}, + {"2008-10-01", 4}, + {"2008-12-31", 4}, + // Test case for month 0 + {"2008-00-01", 0}, + } + fc := funcs["quarter"] + for _, test := range tests { + arg := types.NewStringDatum(test.t) + f, err := fc.getFunction(datumsToConstants([]types.Datum{arg}), s.ctx) + c.Assert(err, IsNil) + result, err := f.eval(nil) + c.Assert(err, IsNil) + c.Assert(result.GetInt64(), Equals, test.expect) + } + + // test invalid input + argInvalid := types.NewStringDatum("2008-13-01") + f, err := fc.getFunction(datumsToConstants([]types.Datum{argInvalid}), s.ctx) + c.Assert(err, IsNil) + result, err := f.eval(nil) + c.Assert(result.IsNull(), IsTrue) +} diff --git a/plan/typeinferer.go b/plan/typeinferer.go index 968bd4a07ab3d..481e863116875 100644 --- a/plan/typeinferer.go +++ b/plan/typeinferer.go @@ -359,7 +359,7 @@ func (v *typeInferrer) handleFuncCallExpr(x *ast.FuncCallExpr) { tp = types.NewFieldType(mysql.TypeDatetime) case "microsecond", "second", "minute", "hour", "day", "week", "month", "year", "dayofweek", "dayofmonth", "dayofyear", "weekday", "weekofyear", "yearweek", "datediff", - "found_rows", "length", "extract", "locate", "unix_timestamp": + "found_rows", "length", "extract", "locate", "unix_timestamp", "quarter": tp = types.NewFieldType(mysql.TypeLonglong) case "now", "sysdate", "current_timestamp", "utc_timestamp": tp = types.NewFieldType(mysql.TypeDatetime) diff --git a/plan/typeinferer_test.go b/plan/typeinferer_test.go index 1960694f95d4f..fff96461270d5 100644 --- a/plan/typeinferer_test.go +++ b/plan/typeinferer_test.go @@ -156,6 +156,7 @@ func (ts *testTypeInferrerSuite) TestInferType(c *C) { {"day('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin}, {"week('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin}, {"month('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin}, + {"quarter('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin}, {"year('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin}, {"dayofweek('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin}, {"dayofmonth('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin},