Skip to content

Commit

Permalink
Support add datetime with real interval
Browse files Browse the repository at this point in the history
  • Loading branch information
erjiaqing committed May 9, 2019
1 parent 37e8241 commit 5002d4d
Show file tree
Hide file tree
Showing 2 changed files with 266 additions and 2 deletions.
246 changes: 244 additions & 2 deletions expression/builtin_time.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,21 +217,27 @@ var (
_ builtinFunc = &builtinExtractDurationSig{}
_ builtinFunc = &builtinAddDateStringStringSig{}
_ builtinFunc = &builtinAddDateStringIntSig{}
_ builtinFunc = &builtinAddDateStringRealSig{}
_ builtinFunc = &builtinAddDateStringDecimalSig{}
_ builtinFunc = &builtinAddDateIntStringSig{}
_ builtinFunc = &builtinAddDateIntIntSig{}
_ builtinFunc = &builtinAddDateIntRealSig{}
_ builtinFunc = &builtinAddDateIntDecimalSig{}
_ builtinFunc = &builtinAddDateDatetimeStringSig{}
_ builtinFunc = &builtinAddDateDatetimeIntSig{}
_ builtinFunc = &builtinAddDateDatetimeRealSig{}
_ builtinFunc = &builtinAddDateDatetimeDecimalSig{}
_ builtinFunc = &builtinSubDateStringStringSig{}
_ builtinFunc = &builtinSubDateStringIntSig{}
_ builtinFunc = &builtinSubDateStringRealSig{}
_ builtinFunc = &builtinSubDateStringDecimalSig{}
_ builtinFunc = &builtinSubDateIntStringSig{}
_ builtinFunc = &builtinSubDateIntIntSig{}
_ builtinFunc = &builtinSubDateIntRealSig{}
_ builtinFunc = &builtinSubDateIntDecimalSig{}
_ builtinFunc = &builtinSubDateDatetimeStringSig{}
_ builtinFunc = &builtinSubDateDatetimeIntSig{}
_ builtinFunc = &builtinSubDateDatetimeRealSig{}
_ builtinFunc = &builtinSubDateDatetimeDecimalSig{}
)

Expand Down Expand Up @@ -2703,6 +2709,14 @@ func (du *baseDateArithmitical) getIntervalFromInt(ctx sessionctx.Context, args
return strconv.FormatInt(interval, 10), false, nil
}

func (du *baseDateArithmitical) getIntervalFromReal(ctx sessionctx.Context, args []Expression, row chunk.Row, unit string) (string, bool, error) {
interval, isNull, err := args[1].EvalReal(ctx, row)
if isNull || err != nil {
return "", true, err
}
return strconv.FormatFloat(interval, 'f', -1, 64), false, nil
}

func (du *baseDateArithmitical) add(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {
year, month, day, dur, err := types.ExtractTimeValue(unit, interval)
if err != nil {
Expand Down Expand Up @@ -2783,7 +2797,7 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
}

intervalEvalTp := args[1].GetType().EvalType()
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {
intervalEvalTp = types.ETInt
}

Expand All @@ -2802,6 +2816,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETReal:
sig = &builtinAddDateStringRealSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
sig = &builtinAddDateStringDecimalSig{
baseBuiltinFunc: bf,
Expand All @@ -2817,6 +2836,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETReal:
sig = &builtinAddDateIntRealSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal:
sig = &builtinAddDateIntDecimalSig{
baseBuiltinFunc: bf,
Expand All @@ -2832,6 +2856,11 @@ func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETReal:
sig = &builtinAddDateDatetimeRealSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal:
sig = &builtinAddDateDatetimeDecimalSig{
baseBuiltinFunc: bf,
Expand Down Expand Up @@ -2907,6 +2936,39 @@ func (b *builtinAddDateStringIntSig) evalTime(row chunk.Row) (types.Time, bool,
return result, isNull || err != nil, err
}

type builtinAddDateStringRealSig struct {
baseBuiltinFunc
baseDateArithmitical
}

func (b *builtinAddDateStringRealSig) Clone() builtinFunc {
newSig := &builtinAddDateStringRealSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}

// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateStringRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, err
}

date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, err
}

type builtinAddDateStringDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
Expand Down Expand Up @@ -3006,6 +3068,39 @@ func (b *builtinAddDateIntIntSig) evalTime(row chunk.Row) (types.Time, bool, err
return result, isNull || err != nil, err
}

type builtinAddDateIntRealSig struct {
baseBuiltinFunc
baseDateArithmitical
}

func (b *builtinAddDateIntRealSig) Clone() builtinFunc {
newSig := &builtinAddDateIntRealSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}

// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateIntRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, err
}

date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, err
}

type builtinAddDateIntDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
Expand Down Expand Up @@ -3105,6 +3200,39 @@ func (b *builtinAddDateDatetimeIntSig) evalTime(row chunk.Row) (types.Time, bool
return result, isNull || err != nil, err
}

type builtinAddDateDatetimeRealSig struct {
baseBuiltinFunc
baseDateArithmitical
}

func (b *builtinAddDateDatetimeRealSig) Clone() builtinFunc {
newSig := &builtinAddDateDatetimeRealSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}

// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateDatetimeRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, err
}

date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, err
}

type builtinAddDateDatetimeDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
Expand Down Expand Up @@ -3153,7 +3281,7 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
}

intervalEvalTp := args[1].GetType().EvalType()
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal && intervalEvalTp != types.ETReal {
intervalEvalTp = types.ETInt
}

Expand All @@ -3172,6 +3300,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETReal:
sig = &builtinSubDateStringRealSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
sig = &builtinSubDateStringDecimalSig{
baseBuiltinFunc: bf,
Expand All @@ -3187,6 +3320,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETReal:
sig = &builtinSubDateIntRealSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETDecimal:
sig = &builtinSubDateIntDecimalSig{
baseBuiltinFunc: bf,
Expand All @@ -3202,6 +3340,11 @@ func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expres
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETReal:
sig = &builtinSubDateDatetimeRealSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETDecimal:
sig = &builtinSubDateDatetimeDecimalSig{
baseBuiltinFunc: bf,
Expand Down Expand Up @@ -3277,6 +3420,39 @@ func (b *builtinSubDateStringIntSig) evalTime(row chunk.Row) (types.Time, bool,
return result, isNull || err != nil, err
}

type builtinSubDateStringRealSig struct {
baseBuiltinFunc
baseDateArithmitical
}

func (b *builtinSubDateStringRealSig) Clone() builtinFunc {
newSig := &builtinSubDateStringRealSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}

// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateStringRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, err
}

date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, err
}

type builtinSubDateStringDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
Expand Down Expand Up @@ -3374,6 +3550,39 @@ func (b *builtinSubDateIntIntSig) evalTime(row chunk.Row) (types.Time, bool, err
return result, isNull || err != nil, err
}

type builtinSubDateIntRealSig struct {
baseBuiltinFunc
baseDateArithmitical
}

func (b *builtinSubDateIntRealSig) Clone() builtinFunc {
newSig := &builtinSubDateIntRealSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}

// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateIntRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, err
}

date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, err
}

type builtinSubDateDatetimeStringSig struct {
baseBuiltinFunc
baseDateArithmitical
Expand Down Expand Up @@ -3473,6 +3682,39 @@ func (b *builtinSubDateDatetimeIntSig) evalTime(row chunk.Row) (types.Time, bool
return result, isNull || err != nil, err
}

type builtinSubDateDatetimeRealSig struct {
baseBuiltinFunc
baseDateArithmitical
}

func (b *builtinSubDateDatetimeRealSig) Clone() builtinFunc {
newSig := &builtinSubDateDatetimeRealSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}

// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateDatetimeRealSig) evalTime(row chunk.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, err
}

date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

interval, isNull, err := b.getIntervalFromReal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, err
}

result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, err
}

type builtinSubDateDatetimeDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
Expand Down
22 changes: 22 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4267,3 +4267,25 @@ func (s *testIntegrationSuite) TestTimestampDatumEncode(c *C) {
))
tk.MustQuery(`select * from t where b = (select max(b) from t)`).Check(testkit.Rows(`1 2019-04-29 11:56:12`))
}

func (s *testIntegrationSuite) TestDateTimeAddReal(c *C) {
tk := testkit.NewTestKit(c, s.store)
defer s.cleanEnv(c)

cases := []struct {
sql string
result string
}{
{`SELECT "1900-01-01 00:00:00" + INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:18:43.456789"},
{`SELECT 19000101000000 + INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:18:43.456789"},
{`select date("1900-01-01") + interval 1.123456789e3 second;`, "1900-01-01 00:18:43.456789"},
{`SELECT "1900-01-01 00:18:43.456789" - INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:00:00"},
{`SELECT 19000101001843.456789 - INTERVAL 1.123456789e3 SECOND;`, "1900-01-01 00:00:00"},
{`select date("1900-01-01") - interval 1.123456789e3 second;`, "1899-12-31 23:41:16.543211"},
{`select 19000101000000 - interval 1.123456789e3 second;`, "1899-12-31 23:41:16.543211"},
}

for _, c := range cases {
tk.MustQuery(c.sql).Check(testkit.Rows(c.result))
}
}

0 comments on commit 5002d4d

Please sign in to comment.