Files
tidb/expression/builtin_time.go

1865 lines
52 KiB
Go

// Copyright 2013 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSES/QL-LICENSE file.
// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package expression
import (
"fmt"
"math"
"regexp"
"strings"
"time"
"github.com/juju/errors"
"github.com/pingcap/tidb/ast"
"github.com/pingcap/tidb/context"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/util/types"
)
var (
_ functionClass = &dateFunctionClass{}
_ functionClass = &dateDiffFunctionClass{}
_ functionClass = &timeDiffFunctionClass{}
_ functionClass = &dateFormatFunctionClass{}
_ functionClass = &hourFunctionClass{}
_ functionClass = &minuteFunctionClass{}
_ functionClass = &secondFunctionClass{}
_ functionClass = &microSecondFunctionClass{}
_ functionClass = &monthFunctionClass{}
_ functionClass = &monthNameFunctionClass{}
_ functionClass = &nowFunctionClass{}
_ functionClass = &dayNameFunctionClass{}
_ functionClass = &dayOfMonthFunctionClass{}
_ functionClass = &dayOfWeekFunctionClass{}
_ functionClass = &dayOfYearFunctionClass{}
_ functionClass = &weekFunctionClass{}
_ functionClass = &weekDayFunctionClass{}
_ functionClass = &weekOfYearFunctionClass{}
_ functionClass = &yearFunctionClass{}
_ functionClass = &yearWeekFunctionClass{}
_ functionClass = &fromUnixTimeFunctionClass{}
_ functionClass = &strToDateFunctionClass{}
_ functionClass = &sysDateFunctionClass{}
_ functionClass = &currentDateFunctionClass{}
_ functionClass = &currentTimeFunctionClass{}
_ functionClass = &timeFunctionClass{}
_ functionClass = &utcDateFunctionClass{}
_ functionClass = &utcTimestampFunctionClass{}
_ functionClass = &extractFunctionClass{}
_ functionClass = &arithmeticFunctionClass{}
_ functionClass = &unixTimestampFunctionClass{}
_ functionClass = &addTimeFunctionClass{}
_ functionClass = &convertTzFunctionClass{}
_ functionClass = &makeDateFunctionClass{}
_ functionClass = &makeTimeFunctionClass{}
_ functionClass = &periodAddFunctionClass{}
_ functionClass = &periodDiffFunctionClass{}
_ functionClass = &quarterFunctionClass{}
_ functionClass = &secToTimeFunctionClass{}
_ functionClass = &subTimeFunctionClass{}
_ functionClass = &timeFormatFunctionClass{}
_ functionClass = &timeToSecFunctionClass{}
_ functionClass = &timestampAddFunctionClass{}
_ functionClass = &toDaysFunctionClass{}
_ functionClass = &toSecondsFunctionClass{}
_ functionClass = &utcTimeFunctionClass{}
_ functionClass = &timestampFunctionClass{}
)
var (
_ builtinFunc = &builtinDateSig{}
_ builtinFunc = &builtinDateDiffSig{}
_ builtinFunc = &builtinTimeDiffSig{}
_ builtinFunc = &builtinDateFormatSig{}
_ builtinFunc = &builtinHourSig{}
_ builtinFunc = &builtinMinuteSig{}
_ builtinFunc = &builtinSecondSig{}
_ builtinFunc = &builtinMicroSecondSig{}
_ builtinFunc = &builtinMonthSig{}
_ builtinFunc = &builtinMonthNameSig{}
_ builtinFunc = &builtinNowSig{}
_ builtinFunc = &builtinDayNameSig{}
_ builtinFunc = &builtinDayOfMonthSig{}
_ builtinFunc = &builtinDayOfWeekSig{}
_ builtinFunc = &builtinDayOfYearSig{}
_ builtinFunc = &builtinWeekSig{}
_ builtinFunc = &builtinWeekDaySig{}
_ builtinFunc = &builtinWeekOfYearSig{}
_ builtinFunc = &builtinYearSig{}
_ builtinFunc = &builtinYearWeekSig{}
_ builtinFunc = &builtinFromUnixTimeSig{}
_ builtinFunc = &builtinStrToDateSig{}
_ builtinFunc = &builtinSysDateSig{}
_ builtinFunc = &builtinCurrentDateSig{}
_ builtinFunc = &builtinCurrentTimeSig{}
_ builtinFunc = &builtinTimeSig{}
_ builtinFunc = &builtinUTCDateSig{}
_ builtinFunc = &builtinUTCTimestampSig{}
_ builtinFunc = &builtinExtractSig{}
_ builtinFunc = &builtinArithmeticSig{}
_ builtinFunc = &builtinUnixTimestampSig{}
_ builtinFunc = &builtinAddTimeSig{}
_ builtinFunc = &builtinConvertTzSig{}
_ builtinFunc = &builtinMakeDateSig{}
_ builtinFunc = &builtinMakeTimeSig{}
_ builtinFunc = &builtinPeriodAddSig{}
_ builtinFunc = &builtinPeriodDiffSig{}
_ builtinFunc = &builtinQuarterSig{}
_ builtinFunc = &builtinSecToTimeSig{}
_ builtinFunc = &builtinSubTimeSig{}
_ builtinFunc = &builtinTimeFormatSig{}
_ builtinFunc = &builtinTimeToSecSig{}
_ builtinFunc = &builtinTimestampAddSig{}
_ builtinFunc = &builtinToDaysSig{}
_ builtinFunc = &builtinToSecondsSig{}
_ builtinFunc = &builtinUTCTimeSig{}
_ builtinFunc = &builtinTimestampSig{}
)
func convertTimeToMysqlTime(t time.Time, fsp int) (types.Time, error) {
tr, err := types.RoundFrac(t, int(fsp))
if err != nil {
return types.Time{}, errors.Trace(err)
}
return types.Time{
Time: types.FromGoTime(tr),
Type: mysql.TypeDatetime,
Fsp: fsp,
}, nil
}
func convertToTime(sc *variable.StatementContext, arg types.Datum, tp byte) (d types.Datum, err error) {
f := types.NewFieldType(tp)
f.Decimal = types.MaxFsp
d, err = arg.ConvertTo(sc, f)
if err != nil {
d.SetNull()
return d, errors.Trace(err)
}
if d.IsNull() {
return d, nil
}
if d.Kind() != types.KindMysqlTime {
d.SetNull()
return d, errors.Errorf("need time type, but got %T", d.GetValue())
}
return d, nil
}
func convertToDuration(sc *variable.StatementContext, arg types.Datum, fsp int) (d types.Datum, err error) {
f := types.NewFieldType(mysql.TypeDuration)
f.Decimal = fsp
d, err = arg.ConvertTo(sc, f)
if err != nil {
d.SetNull()
return d, errors.Trace(err)
}
if d.IsNull() {
return d, nil
}
if d.Kind() != types.KindMysqlDuration {
d.SetNull()
return d, errors.Errorf("need duration type, but got %T", d.GetValue())
}
return d, nil
}
type dateFunctionClass struct {
baseFunctionClass
}
func (c *dateFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDateSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDateSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date
func (b *builtinDateSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return convertToTime(b.ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
}
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)
if err != nil {
return t, errors.Trace(err)
}
}
return d.GetMysqlTime(), nil
}
type dateDiffFunctionClass struct {
baseFunctionClass
}
func (c *dateDiffFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDateDiffSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDateDiffSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_datediff
func (b *builtinDateDiffSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
if args[0].IsNull() || args[1].IsNull() {
return d, nil
}
sc := b.ctx.GetSessionVars().StmtCtx
t1, err := convertDatumToTime(sc, args[0])
if err != nil {
return d, errors.Trace(err)
}
t2, err := convertDatumToTime(sc, args[1])
if err != nil {
return d, errors.Trace(err)
}
if t1.Time.Month() == 0 || t1.Time.Day() == 0 || t2.Time.Month() == 0 || t2.Time.Day() == 0 {
return d, nil
}
r := types.DateDiff(t1.Time, t2.Time)
d.SetInt64(int64(r))
return d, nil
}
type timeDiffFunctionClass struct {
baseFunctionClass
}
func (c *timeDiffFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimeDiffSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimeDiffSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinTimeDiffSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
if args[0].IsNull() || args[1].IsNull() {
return d, nil
}
sc := b.ctx.GetSessionVars().StmtCtx
t1, err := convertDatumToTime(sc, args[0])
if err != nil {
return d, errors.Trace(err)
}
t2, err := convertDatumToTime(sc, args[1])
if err != nil {
return d, errors.Trace(err)
}
t := t1.Sub(&t2)
d.SetMysqlDuration(t)
return d, nil
}
type dateFormatFunctionClass struct {
baseFunctionClass
}
func (c *dateFormatFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDateFormatSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDateFormatSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
func (b *builtinDateFormatSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return builtinDateFormat(args, b.ctx)
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
func builtinDateFormat(args []types.Datum, ctx context.Context) (types.Datum, error) {
var d types.Datum
date, err := convertToTime(ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDatetime)
if err != nil {
return d, errors.Trace(err)
}
t := date.GetMysqlTime()
str, err := t.DateFormat(args[1].GetString())
if err != nil {
return d, errors.Trace(err)
}
d.SetString(str)
return d, nil
}
type fromDaysFunctionClass struct {
baseFunctionClass
}
func (c *fromDaysFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinFromDaysSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinFromDaysSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-days
func (b *builtinFromDaysSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
days, err := args[0].ToInt64(b.ctx.GetSessionVars().StmtCtx)
d.SetMysqlTime(types.TimeFromDays(days))
return d, nil
}
type hourFunctionClass struct {
baseFunctionClass
}
func (c *hourFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinHourSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinHourSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_hour
func (b *builtinHourSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToDuration(b.ctx.GetSessionVars().StmtCtx, args[0], types.MaxFsp)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
h := int64(d.GetMysqlDuration().Hour())
d.SetInt64(h)
return d, nil
}
type minuteFunctionClass struct {
baseFunctionClass
}
func (c *minuteFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMinuteSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinMinuteSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_minute
func (b *builtinMinuteSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToDuration(b.ctx.GetSessionVars().StmtCtx, args[0], types.MaxFsp)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
m := int64(d.GetMysqlDuration().Minute())
d.SetInt64(m)
return d, nil
}
type secondFunctionClass struct {
baseFunctionClass
}
func (c *secondFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinSecondSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinSecondSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_second
func (b *builtinSecondSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToDuration(b.ctx.GetSessionVars().StmtCtx, args[0], types.MaxFsp)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
s := int64(d.GetMysqlDuration().Second())
d.SetInt64(s)
return d, nil
}
type microSecondFunctionClass struct {
baseFunctionClass
}
func (c *microSecondFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMicroSecondSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinMicroSecondSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_microsecond
func (b *builtinMicroSecondSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToDuration(b.ctx.GetSessionVars().StmtCtx, args[0], types.MaxFsp)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
m := int64(d.GetMysqlDuration().MicroSecond())
d.SetInt64(m)
return d, nil
}
type monthFunctionClass struct {
baseFunctionClass
}
func (c *monthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMonthSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinMonthSig struct {
baseBuiltinFunc
}
func (b *builtinMonthSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return builtinMonth(args, b.ctx)
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_month
func builtinMonth(args []types.Datum, ctx context.Context) (types.Datum, error) {
d, err := convertToTime(ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
i := int64(0)
if t.IsZero() {
d.SetInt64(i)
return d, nil
}
i = int64(t.Time.Month())
d.SetInt64(i)
return d, nil
}
type monthNameFunctionClass struct {
baseFunctionClass
}
func (c *monthNameFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMonthNameSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinMonthNameSig struct {
baseBuiltinFunc
}
func (b *builtinMonthNameSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return builtinMonthName(args, b.ctx)
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_monthname
func builtinMonthName(args []types.Datum, ctx context.Context) (types.Datum, error) {
d, err := builtinMonth(args, ctx)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
mon := int(d.GetInt64())
if mon <= 0 || mon > len(types.MonthNames) {
d.SetNull()
if mon == 0 {
return d, nil
}
return d, errors.Errorf("no name for invalid month: %d.", mon)
}
d.SetString(types.MonthNames[mon-1])
return d, nil
}
type nowFunctionClass struct {
baseFunctionClass
}
func (c *nowFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinNowSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinNowSig struct {
baseBuiltinFunc
}
func (b *builtinNowSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return builtinNow(args, b.ctx)
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_now
func builtinNow(args []types.Datum, ctx context.Context) (d types.Datum, err error) {
// TODO: if NOW is used in stored function or trigger, NOW will return the beginning time
// of the execution.
fsp := 0
sc := ctx.GetSessionVars().StmtCtx
if len(args) == 1 && !args[0].IsNull() {
if fsp, err = checkFsp(sc, args[0]); err != nil {
return d, errors.Trace(err)
}
}
t, err := convertTimeToMysqlTime(time.Now(), fsp)
if err != nil {
return d, errors.Trace(err)
}
d.SetMysqlTime(t)
return d, nil
}
type dayNameFunctionClass struct {
baseFunctionClass
}
func (c *dayNameFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDayNameSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDayNameSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayname
func (b *builtinDayNameSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := builtinWeekDay(args, b.ctx)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
weekday := d.GetInt64()
if (weekday < 0) || (weekday >= int64(len(types.WeekdayNames))) {
d.SetNull()
return d, errors.Errorf("no name for invalid weekday: %d.", weekday)
}
d.SetString(types.WeekdayNames[weekday])
return d, nil
}
type dayOfMonthFunctionClass struct {
baseFunctionClass
}
func (c *dayOfMonthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDayOfMonthSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDayOfMonthSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofmonth
func (b *builtinDayOfMonthSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
// TODO: some invalid format like 2000-00-00 will return 0 too.
d, err = convertToTime(b.ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
if t.IsZero() {
d.SetInt64(int64(0))
return d, nil
}
d.SetInt64(int64(t.Time.Day()))
return d, nil
}
type dayOfWeekFunctionClass struct {
baseFunctionClass
}
func (c *dayOfWeekFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDayOfWeekSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDayOfWeekSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofweek
func (b *builtinDayOfWeekSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err = convertToTime(b.ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
if t.IsZero() {
d.SetNull()
// TODO: log warning or return error?
return d, nil
}
// 1 is Sunday, 2 is Monday, .... 7 is Saturday
d.SetInt64(int64(t.Time.Weekday() + 1))
return d, nil
}
type dayOfYearFunctionClass struct {
baseFunctionClass
}
func (c *dayOfYearFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDayOfYearSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinDayOfYearSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofyear
func (b *builtinDayOfYearSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToTime(b.ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
t := d.GetMysqlTime()
if t.InvalidZero() {
// TODO: log warning or return error?
d.SetNull()
return d, nil
}
yd := int64(t.Time.YearDay())
d.SetInt64(yd)
return d, nil
}
type weekFunctionClass struct {
baseFunctionClass
}
func (c *weekFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinWeekSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinWeekSig struct {
baseBuiltinFunc
}
func (b *builtinWeekSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return builtinWeek(args, b.ctx)
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_week
func builtinWeek(args []types.Datum, ctx context.Context) (types.Datum, error) {
d, err := convertToTime(ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
if t.IsZero() {
// TODO: log warning or return error?
d.SetNull()
return d, nil
}
var mode int
if len(args) > 1 {
v, err := args[1].ToInt64(ctx.GetSessionVars().StmtCtx)
if err != nil {
return d, errors.Trace(err)
}
mode = int(v)
}
week := t.Time.Week(mode)
wi := int64(week)
d.SetInt64(wi)
return d, nil
}
type weekDayFunctionClass struct {
baseFunctionClass
}
func (c *weekDayFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinWeekDaySig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinWeekDaySig struct {
baseBuiltinFunc
}
func (b *builtinWeekDaySig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
return builtinWeekDay(args, b.ctx)
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_weekday
func builtinWeekDay(args []types.Datum, ctx context.Context) (types.Datum, error) {
d, err := convertToTime(ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
if t.IsZero() {
// TODO: log warning or return error?
d.SetNull()
return d, nil
}
// Monday is 0, ... Sunday = 6 in MySQL
// but in go, Sunday is 0, ... Saturday is 6
// w will do a conversion.
w := (int64(t.Time.Weekday()) + 6) % 7
d.SetInt64(w)
return d, nil
}
type weekOfYearFunctionClass struct {
baseFunctionClass
}
func (c *weekOfYearFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinWeekOfYearSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinWeekOfYearSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_weekofyear
func (b *builtinWeekOfYearSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
// WeekOfYear is equivalent to to Week(date, 3)
d := types.Datum{}
d.SetInt64(3)
return builtinWeek([]types.Datum{args[0], d}, b.ctx)
}
type yearFunctionClass struct {
baseFunctionClass
}
func (c *yearFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinYearSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinYearSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_year
func (b *builtinYearSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToTime(b.ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
if t.IsZero() {
d.SetInt64(0)
return d, nil
}
d.SetInt64(int64(t.Time.Year()))
return d, nil
}
type yearWeekFunctionClass struct {
baseFunctionClass
}
func (c *yearWeekFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinYearWeekSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinYearWeekSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_yearweek
func (b *builtinYearWeekSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
d, err := convertToTime(b.ctx.GetSessionVars().StmtCtx, args[0], mysql.TypeDate)
if err != nil || d.IsNull() {
return d, errors.Trace(err)
}
// No need to check type here.
t := d.GetMysqlTime()
if t.InvalidZero() {
d.SetNull()
// TODO: log warning or return error?
return d, nil
}
var mode int64
if len(args) > 1 {
v, err := args[1].ToInt64(b.ctx.GetSessionVars().StmtCtx)
if err != nil {
return d, errors.Trace(err)
}
mode = v
}
year, week := t.Time.YearWeek(int(mode))
d.SetInt64(int64(week + year*100))
if d.GetInt64() < 0 {
d.SetInt64(math.MaxUint32)
}
return d, nil
}
type fromUnixTimeFunctionClass struct {
baseFunctionClass
}
func (c *fromUnixTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinFromUnixTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinFromUnixTimeSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime
func (b *builtinFromUnixTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
unixTimeStamp, err := args[0].ToDecimal(sc)
if err != nil {
return d, errors.Trace(err)
}
// 0 <= unixTimeStamp <= INT32_MAX
if unixTimeStamp.IsNegative() {
return
}
integralPart, err := unixTimeStamp.ToInt()
if err == types.ErrTruncated {
err = nil
}
if err != nil {
return d, errors.Trace(err)
}
if integralPart > int64(math.MaxInt32) {
return
}
// Split the integral part and fractional part of a decimal timestamp.
// e.g. for timestamp 12345.678,
// first get the integral part 12345,
// then (12345.678 - 12345) * (10^9) to get the decimal part and convert it to nanosecond precision.
integerDecimalTp := new(types.MyDecimal).FromInt(integralPart)
fracDecimalTp := new(types.MyDecimal)
err = types.DecimalSub(unixTimeStamp, integerDecimalTp, fracDecimalTp)
if err != nil {
return d, errors.Trace(err)
}
nano := new(types.MyDecimal).FromInt(int64(time.Second))
x := new(types.MyDecimal)
err = types.DecimalMul(fracDecimalTp, nano, x)
if err != nil {
return d, errors.Trace(err)
}
fractionalPart, err := x.ToInt() // here fractionalPart is result multiplying the original fractional part by 10^9.
if err == types.ErrTruncated {
err = nil
}
if err != nil {
return d, errors.Trace(err)
}
_, fracDigitsNumber := unixTimeStamp.PrecisionAndFrac()
fsp := fracDigitsNumber
if fracDigitsNumber > types.MaxFsp {
fsp = types.MaxFsp
}
t, err := convertTimeToMysqlTime(time.Unix(integralPart, fractionalPart), fsp)
if err != nil {
return d, errors.Trace(err)
}
if args[0].Kind() == types.KindString { // Keep consistent with MySQL.
t.Fsp = types.MaxFsp
}
d.SetMysqlTime(t)
if len(args) == 1 {
return
}
return builtinDateFormat([]types.Datum{d, args[1]}, b.ctx)
}
type strToDateFunctionClass struct {
baseFunctionClass
}
func (c *strToDateFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinStrToDateSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinStrToDateSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
func (b *builtinStrToDateSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
date := args[0].GetString()
format := args[1].GetString()
var (
d types.Datum
t types.Time
)
succ := t.StrToDate(date, format)
if !succ {
d.SetNull()
return d, nil
}
d.SetMysqlTime(t)
return d, nil
}
type sysDateFunctionClass struct {
baseFunctionClass
}
func (c *sysDateFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinSysDateSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinSysDateSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate
func (b *builtinSysDateSig) eval(row []types.Datum) (types.Datum, error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
// SYSDATE is not the same as NOW if NOW is used in a stored function or trigger.
// But here we can just think they are the same because we don't support stored function
// and trigger now.
return builtinNow(args, b.ctx)
}
type currentDateFunctionClass struct {
baseFunctionClass
}
func (c *currentDateFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinCurrentDateSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinCurrentDateSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_curdate
func (b *builtinCurrentDateSig) eval(_ []types.Datum) (d types.Datum, err error) {
year, month, day := time.Now().Date()
t := types.Time{
Time: types.FromDate(year, int(month), day, 0, 0, 0, 0),
Type: mysql.TypeDate, Fsp: 0}
d.SetMysqlTime(t)
return d, nil
}
type currentTimeFunctionClass struct {
baseFunctionClass
}
func (c *currentTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinCurrentTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinCurrentTimeSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_curtime
func (b *builtinCurrentTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
fsp := 0
sc := b.ctx.GetSessionVars().StmtCtx
if len(args) == 1 && !args[0].IsNull() {
if fsp, err = checkFsp(sc, args[0]); err != nil {
d.SetNull()
return d, errors.Trace(err)
}
}
d.SetString(time.Now().Format("15:04:05.000000"))
return convertToDuration(b.ctx.GetSessionVars().StmtCtx, d, fsp)
}
type timeFunctionClass struct {
baseFunctionClass
}
func (c *timeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimeSig struct {
baseBuiltinFunc
}
// See http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time
func (b *builtinTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
if args[0].IsNull() {
return
}
str, err := args[0].ToString()
if err != nil {
return d, errors.Trace(err)
}
idx := strings.Index(str, ".")
fsp := 0
if idx != -1 {
fsp = len(str) - idx - 1
}
sc := b.ctx.GetSessionVars().StmtCtx
fspD := types.NewIntDatum(int64(fsp))
if fsp, err = checkFsp(sc, fspD); err != nil {
return d, errors.Trace(err)
}
return convertToDuration(sc, args[0], fsp)
}
type utcDateFunctionClass struct {
baseFunctionClass
}
func (c *utcDateFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinUTCDateSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinUTCDateSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-date
func (b *builtinUTCDateSig) eval(_ []types.Datum) (d types.Datum, err error) {
year, month, day := time.Now().UTC().Date()
t := types.Time{
Time: types.FromGoTime(time.Date(year, month, day, 0, 0, 0, 0, time.UTC)),
Type: mysql.TypeDate, Fsp: types.UnspecifiedFsp}
d.SetMysqlTime(t)
return d, nil
}
type utcTimestampFunctionClass struct {
baseFunctionClass
}
func (c *utcTimestampFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinUTCTimestampSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinUTCTimestampSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-timestamp
func (b *builtinUTCTimestampSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
fsp := 0
sc := b.ctx.GetSessionVars().StmtCtx
if len(args) == 1 && !args[0].IsNull() {
if fsp, err = checkFsp(sc, args[0]); err != nil {
return d, errors.Trace(err)
}
}
t, err := convertTimeToMysqlTime(time.Now().UTC(), fsp)
if err != nil {
return d, errors.Trace(err)
}
d.SetMysqlTime(t)
return d, nil
}
type extractFunctionClass struct {
baseFunctionClass
}
func (c *extractFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinExtractSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinExtractSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_extract
func (b *builtinExtractSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
unit := args[0].GetString()
vd := args[1]
if vd.IsNull() {
d.SetNull()
return d, nil
}
f := types.NewFieldType(mysql.TypeDatetime)
f.Decimal = types.MaxFsp
val, err := vd.ConvertTo(b.ctx.GetSessionVars().StmtCtx, f)
if err != nil {
d.SetNull()
return d, errors.Trace(err)
}
if val.IsNull() {
d.SetNull()
return d, nil
}
if val.Kind() != types.KindMysqlTime {
d.SetNull()
return d, errors.Errorf("need time type, but got %T", val)
}
t := val.GetMysqlTime()
n, err1 := types.ExtractTimeNum(unit, t)
if err1 != nil {
d.SetNull()
return d, errors.Trace(err1)
}
d.SetInt64(n)
return d, nil
}
func checkFsp(sc *variable.StatementContext, arg types.Datum) (int, error) {
fsp, err := arg.ToInt64(sc)
if err != nil {
return 0, errors.Trace(err)
}
if int(fsp) > types.MaxFsp {
return 0, errors.Errorf("Too big precision %d specified. Maximum is 6.", fsp)
} else if fsp < 0 {
return 0, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp)
}
return int(fsp), nil
}
type dateArithFunctionClass struct {
baseFunctionClass
op ast.DateArithType
}
func (c *dateArithFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinDateArithSig{newBaseBuiltinFunc(args, ctx), c.op}, errors.Trace(c.verifyArgs(args))
}
type builtinDateArithSig struct {
baseBuiltinFunc
op ast.DateArithType
}
func (b *builtinDateArithSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
// args[0] -> Date
// args[1] -> Interval Value
// args[2] -> Interval Unit
// health check for date and interval
if args[0].IsNull() || args[1].IsNull() {
return d, nil
}
nodeDate := args[0]
nodeIntervalValue := args[1]
nodeIntervalUnit := args[2].GetString()
if nodeIntervalValue.IsNull() {
return d, nil
}
// parse date
fieldType := mysql.TypeDate
var resultField *types.FieldType
switch nodeDate.Kind() {
case types.KindMysqlTime:
x := nodeDate.GetMysqlTime()
if (x.Type == mysql.TypeDatetime) || (x.Type == mysql.TypeTimestamp) {
fieldType = mysql.TypeDatetime
}
case types.KindString:
x := nodeDate.GetString()
if !types.IsDateFormat(x) {
fieldType = mysql.TypeDatetime
}
case types.KindInt64:
x := nodeDate.GetInt64()
if t, err1 := types.ParseTimeFromInt64(x); err1 == nil {
if (t.Type == mysql.TypeDatetime) || (t.Type == mysql.TypeTimestamp) {
fieldType = mysql.TypeDatetime
}
}
}
sc := b.ctx.GetSessionVars().StmtCtx
if types.IsClockUnit(nodeIntervalUnit) {
fieldType = mysql.TypeDatetime
}
resultField = types.NewFieldType(fieldType)
resultField.Decimal = types.MaxFsp
value, err := nodeDate.ConvertTo(b.ctx.GetSessionVars().StmtCtx, resultField)
if err != nil {
return d, errInvalidOperation.Gen("DateArith invalid args, need date but get %T", nodeDate)
}
if value.IsNull() {
return d, errInvalidOperation.Gen("DateArith invalid args, need date but get %v", value.GetValue())
}
if value.Kind() != types.KindMysqlTime {
return d, errInvalidOperation.Gen("DateArith need time type, but got %T", value.GetValue())
}
result := value.GetMysqlTime()
// parse interval
var interval string
if strings.ToLower(nodeIntervalUnit) == "day" {
day, err1 := parseDayInterval(sc, nodeIntervalValue)
if err1 != nil {
return d, errInvalidOperation.Gen("DateArith invalid day interval, need int but got %T", nodeIntervalValue.GetString())
}
interval = fmt.Sprintf("%d", day)
} else {
if nodeIntervalValue.Kind() == types.KindString {
interval = fmt.Sprintf("%v", nodeIntervalValue.GetString())
} else {
ii, err1 := nodeIntervalValue.ToInt64(sc)
if err1 != nil {
return d, errors.Trace(err1)
}
interval = fmt.Sprintf("%v", ii)
}
}
year, month, day, duration, err := types.ExtractTimeValue(nodeIntervalUnit, interval)
if err != nil {
return d, errors.Trace(err)
}
if b.op == ast.DateArithSub {
year, month, day, duration = -year, -month, -day, -duration
}
// TODO: Consider time_zone variable.
t, err := result.Time.GoTime(time.Local)
if err != nil {
return d, errors.Trace(err)
}
t = t.Add(duration)
t = t.AddDate(int(year), int(month), int(day))
if t.Nanosecond() == 0 {
result.Fsp = 0
}
result.Time = types.FromGoTime(t)
d.SetMysqlTime(result)
return d, nil
}
var reg = regexp.MustCompile(`[\d]+`)
func parseDayInterval(sc *variable.StatementContext, value types.Datum) (int64, error) {
switch value.Kind() {
case types.KindString:
vs := value.GetString()
s := strings.ToLower(vs)
if s == "false" {
return 0, nil
} else if s == "true" {
return 1, nil
}
value.SetString(reg.FindString(vs))
}
return value.ToInt64(sc)
}
type timestampDiffFunctionClass struct {
baseFunctionClass
}
func (c *timestampDiffFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimestampDiffSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimestampDiffSig struct {
baseBuiltinFunc
}
// https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampdiff
func (b *builtinTimestampDiffSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
if args[1].IsNull() || args[2].IsNull() {
return d, nil
}
sc := b.ctx.GetSessionVars().StmtCtx
t1, err := convertDatumToTime(sc, args[1])
if err != nil {
return d, errorOrWarning(err, b.ctx)
}
t2, err := convertDatumToTime(sc, args[2])
if err != nil {
return d, errorOrWarning(err, b.ctx)
}
if t1.InvalidZero() || t2.InvalidZero() {
return d, errorOrWarning(types.ErrInvalidTimeFormat, b.ctx)
}
v := types.TimestampDiff(args[0].GetString(), t1, t2)
d.SetInt64(v)
return
}
// errorOrWarning reports error or warning depend on the context.
func errorOrWarning(err error, ctx context.Context) error {
sc := ctx.GetSessionVars().StmtCtx
// TODO: Use better name, such as sc.IsInsert instead of sc.IgnoreTruncate.
if ctx.GetSessionVars().StrictSQLMode && !sc.IgnoreTruncate {
return errors.Trace(types.ErrInvalidTimeFormat)
}
sc.AppendWarning(err)
return nil
}
type unixTimestampFunctionClass struct {
baseFunctionClass
}
func (c *unixTimestampFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinUnixTimestampSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinUnixTimestampSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
if len(args) == 0 {
now := time.Now().Unix()
d.SetInt64(now)
return
}
var (
t types.Time
t1 time.Time
)
switch args[0].Kind() {
case types.KindString:
t, err = types.ParseTime(args[0].GetString(), mysql.TypeDatetime, types.MaxFsp)
if err != nil {
return d, errors.Trace(err)
}
case types.KindInt64, types.KindUint64:
t, err = types.ParseTimeFromInt64(args[0].GetInt64())
if err != nil {
return d, errors.Trace(err)
}
case types.KindMysqlTime:
t = args[0].GetMysqlTime()
default:
return d, errors.Errorf("Unkonwn args type for unix_timestamp %d", args[0].Kind())
}
t1, err = t.Time.GoTime(getTimeZone(b.ctx))
if err != nil {
d.SetInt64(0)
return d, nil
}
if t.Time.Microsecond() > 0 {
var dec types.MyDecimal
dec.FromFloat64(float64(t1.Unix()) + float64(t.Time.Microsecond())/1e6)
d.SetMysqlDecimal(&dec)
} else {
d.SetInt64(t1.Unix())
}
return
}
type timestampFunctionClass struct {
baseFunctionClass
}
func (c *timestampFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimestampSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimestampSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_timestamp
func (b *builtinTimestampSig) eval(row []types.Datum) (d types.Datum, err error) {
args, err := b.evalArgs(row)
if err != nil {
return types.Datum{}, errors.Trace(err)
}
if args[0].IsNull() {
return
}
var arg0 types.Time
switch tp := args[0].Kind(); tp {
case types.KindInt64, types.KindUint64:
arg0, err = types.ParseDatetimeFromNum(args[0].GetInt64())
if err != nil {
return d, errors.Trace(err)
}
case types.KindString, types.KindBytes, types.KindMysqlDecimal, types.KindFloat32, types.KindFloat64:
s, err := args[0].ToString()
if err != nil {
return d, errors.Trace(err)
}
arg0, err = types.ParseTime(s, mysql.TypeDatetime, getFsp(s))
if err != nil {
return d, errors.Trace(err)
}
case types.KindMysqlTime:
arg0 = args[0].GetMysqlTime()
default:
return d, errors.Errorf("Unkonwn args type for timestamp %d", tp)
}
if len(args) == 1 {
d.SetMysqlTime(arg0)
return
}
// If exists args[1].
s, err := args[1].ToString()
if err != nil {
return d, errors.Trace(err)
}
arg1, err := types.ParseDuration(s, getFsp(s))
if err != nil {
return d, errors.Trace(err)
}
tmpDuration := arg0.Add(&arg1)
result, err := tmpDuration.ConvertToTime(arg0.Type)
if err != nil {
return d, errors.Trace(err)
}
d.SetMysqlTime(result)
return
}
func getFsp(s string) (fsp int) {
fsp = len(s) - strings.Index(s, ".") - 1
if fsp == len(s) {
fsp = 0
} else if fsp > 6 {
fsp = 6
}
return
}
func getTimeZone(ctx context.Context) *time.Location {
ret := ctx.GetSessionVars().TimeZone
if ret == nil {
ret = time.Local
}
return ret
}
type addTimeFunctionClass struct {
baseFunctionClass
}
func (c *addTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinAddTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinAddTimeSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("ADDTIME")
}
type convertTzFunctionClass struct {
baseFunctionClass
}
func (c *convertTzFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinConvertTzSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinConvertTzSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_convert-tz
func (b *builtinConvertTzSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("CONVERT_TZ")
}
type makeDateFunctionClass struct {
baseFunctionClass
}
func (c *makeDateFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMakeDateSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinMakeDateSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_makedate
func (b *builtinMakeDateSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("MAKEDATE")
}
type makeTimeFunctionClass struct {
baseFunctionClass
}
func (c *makeTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinMakeTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinMakeTimeSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_maketime
func (b *builtinMakeTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("MAKETIME")
}
type periodAddFunctionClass struct {
baseFunctionClass
}
func (c *periodAddFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinPeriodAddSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinPeriodAddSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_period-add
func (b *builtinPeriodAddSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("PERIOD_ADD")
}
type periodDiffFunctionClass struct {
baseFunctionClass
}
func (c *periodDiffFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinPeriodDiffSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinPeriodDiffSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_period-diff
func (b *builtinPeriodDiffSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("PERIOD_DIFF")
}
type quarterFunctionClass struct {
baseFunctionClass
}
func (c *quarterFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinQuarterSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinQuarterSig struct {
baseBuiltinFunc
}
// 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")
}
type secToTimeFunctionClass struct {
baseFunctionClass
}
func (c *secToTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinSecToTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinSecToTimeSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sec-to-time
func (b *builtinSecToTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("SEC_TO_TIME")
}
type subTimeFunctionClass struct {
baseFunctionClass
}
func (c *subTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinSubTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinSubTimeSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("SUB_TIME")
}
type timeFormatFunctionClass struct {
baseFunctionClass
}
func (c *timeFormatFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimeFormatSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimeFormatSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time-format
func (b *builtinTimeFormatSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("TIME_FORMAT")
}
type timeToSecFunctionClass struct {
baseFunctionClass
}
func (c *timeToSecFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimeToSecSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimeToSecSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time-to-sec
func (b *builtinTimeToSecSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("TIME_TO_SEC")
}
type timestampAddFunctionClass struct {
baseFunctionClass
}
func (c *timestampAddFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinTimestampAddSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinTimestampAddSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampadd
func (b *builtinTimestampAddSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("TIMESTAMPADD")
}
type toDaysFunctionClass struct {
baseFunctionClass
}
func (c *toDaysFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinToDaysSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinToDaysSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-days
func (b *builtinToDaysSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("to_days")
}
type toSecondsFunctionClass struct {
baseFunctionClass
}
func (c *toSecondsFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinToSecondsSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinToSecondsSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-seconds
func (b *builtinToSecondsSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("TO_SECONDS")
}
type utcTimeFunctionClass struct {
baseFunctionClass
}
func (c *utcTimeFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {
return &builtinUTCTimeSig{newBaseBuiltinFunc(args, ctx)}, errors.Trace(c.verifyArgs(args))
}
type builtinUTCTimeSig struct {
baseBuiltinFunc
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-time
func (b *builtinUTCTimeSig) eval(row []types.Datum) (d types.Datum, err error) {
return d, errFunctionNotExists.GenByArgs("UTC_TIME")
}