Support add datetime with real interval (#10347)
This commit is contained in:
@ -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{}
|
||||
)
|
||||
|
||||
@ -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 {
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user