// evalDuration evals a builtinTimeSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time.
774851
func (b *builtinTimeSig) evalDuration(row chunk.Row) (res types.Duration, isNull bool, err error) {
	expr, isNull, err := b.args[0].EvalString(b.ctx, row)
	if isNull || err != nil {
		return res, isNull, err
	}

	fsp := 0
	if idx := strings.Index(expr, "."); idx != -1 {
		fsp = len(expr) - idx - 1
	}

	if fsp, err = types.CheckFsp(fsp); err != nil {
		return res, isNull, err
	}

	sc := b.ctx.GetSessionVars().StmtCtx
	res, err = types.ParseDuration(sc, expr, fsp)
	if types.ErrTruncatedWrongVal.Equal(err) {
		err = sc.HandleTruncate(err)
	}
	return res, isNull, err
}
83116
func (col *CorrelatedColumn) EvalDuration(ctx sessionctx.Context, row chunk.Row) (types.Duration, bool, error) {
	if col.Data.IsNull() {
		return types.Duration{}, true, nil
	}
	return col.Data.GetMysqlDuration(), false, nil
}
504738
func (b *builtinTruncateRealSig) evalReal(row chunk.Row) (float64, bool, error) {
	x, isNull, err := b.args[0].EvalReal(b.ctx, row)
	if isNull || err != nil {
		return 0, isNull, err
	}

	d, isNull, err := b.args[1].EvalInt(b.ctx, row)
	if isNull || err != nil {
		return 0, isNull, err
	}

	return types.Truncate(x, int(d)), false, nil
}
146655
func parseDuration(input string) (time.Duration, error) {
	d, err := time.ParseDuration(input)
	if err != nil {
		n, err := strconv.ParseFloat(input, 64)
		if err != nil {
			return 0, err
		}
		d = time.Duration(n*1000) * time.Millisecond
	}
	return d, nil
}
770442
func (b *builtinMakeTimeSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
	dur := types.ZeroDuration
	dur.Fsp = types.MaxFsp
	hour, isNull, err := b.getIntParam(b.args[0], row)
	if isNull || err != nil {
		return dur, isNull, err
	}
	minute, isNull, err := b.getIntParam(b.args[1], row)
	if isNull || err != nil {
		return dur, isNull, err
	}
	if minute < 0 || minute >= 60 {
		return dur, true, nil
	}
	second, isNull, err := b.args[2].EvalReal(b.ctx, row)
	if isNull || err != nil {
		return dur, isNull, err
	}
	if second < 0 || second >= 60 {
		return dur, true, nil
	}
	var overflow bool
	// MySQL TIME datatype: https://dev.mysql.com/doc/refman/5.7/en/time.html
	// ranges from '-838:59:59.000000' to '838:59:59.000000'
	if hour < 0 && mysql.HasUnsignedFlag(b.args[0].GetType().Flag) {
		hour = 838
		overflow = true
	}
	if hour < -838 {
		hour = -838
		overflow = true
	} else if hour > 838 {
		hour = 838
		overflow = true
	}
	if hour == -838 || hour == 838 {
		if second > 59 {
			second = 59
		}
	}
	if overflow {
		minute = 59
		second = 59
	}
	fsp := b.tp.Decimal
	dur, err = types.ParseDuration(b.ctx.GetSessionVars().StmtCtx, fmt.Sprintf("%02d:%02d:%v", hour, minute, second), fsp)
	if err != nil {
		return dur, true, err
	}
	return dur, false, nil
}
1105339
func (b *builtinDurationAnyValueSig) evalDuration(row chunk.Row) (types.Duration, bool, error) {
	return b.args[0].EvalDuration(b.ctx, row)
}
346185
func strDurationAddDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) {
	arg0, err := types.ParseDuration(sc, d, types.MaxFsp)
	if err != nil {
		return "", err
	}
	tmpDuration, err := arg0.Add(arg1)
	if err != nil {
		return "", err
	}
	tmpDuration.Fsp = types.MaxFsp
	if tmpDuration.MicroSecond() == 0 {
		tmpDuration.Fsp = types.MinFsp
	}
	return tmpDuration.String(), nil
}
600408
func (b *builtinTimeFormatSig) evalString(row chunk.Row) (string, bool, error) {
	dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
	// if err != nil, then dur is ZeroDuration, outputs 00:00:00 in this case which follows the behavior of mysql.
	if err != nil {
		logutil.Logger(context.Background()).Warn("time_format.args[0].EvalDuration failed", zap.Error(err))
	}
	if isNull {
		return "", isNull, err
	}
	formatMask, isNull, err := b.args[1].EvalString(b.ctx, row)
	if err != nil || isNull {
		return "", isNull, err
	}
	res, err := b.formatTime(b.ctx, dur, formatMask)
	return res, isNull, err
}
1056860
func (b *builtinSubDatetimeAndStringSig) evalTime(row chunk.Row) (types.Time, bool, error) {
	arg0, isNull, err := b.args[0].EvalTime(b.ctx, row)
	if isNull || err != nil {
		return types.ZeroDatetime, isNull, err
	}
	s, isNull, err := b.args[1].EvalString(b.ctx, row)
	if isNull || err != nil {
		return types.ZeroDatetime, isNull, err
	}
	if err != nil {
		return types.ZeroDatetime, true, err
	}
	if !isDuration(s) {
		return types.ZeroDatetime, true, nil
	}
	sc := b.ctx.GetSessionVars().StmtCtx
	arg1, err := types.ParseDuration(sc, s, types.GetFsp(s))
	if err != nil {
		return types.ZeroDatetime, true, err
	}
	arg1time, err := arg1.ConvertToTime(sc, mysql.TypeDatetime)
	if err != nil {
		return types.ZeroDatetime, true, err
	}
	tmpDuration := arg0.Sub(sc, &arg1time)
	result, err := tmpDuration.ConvertToTime(sc, mysql.TypeDatetime)
	return result, err != nil, err
}
224968
func (b *builtinTimeToSecSig) evalInt(row chunk.Row) (int64, bool, error) {
	duration, isNull, err := b.args[0].EvalDuration(b.ctx, row)
	if isNull || err != nil {
		return 0, isNull, err
	}
	var sign int
	if duration.Duration >= 0 {
		sign = 1
	} else {
		sign = -1
	}
	return int64(sign * (duration.Hour()*3600 + duration.Minute()*60 + duration.Second())), false, nil
}
797215
func (b *builtinTruncateDecimalSig) evalDecimal(row chunk.Row) (*types.MyDecimal, bool, error) {
	x, isNull, err := b.args[0].EvalDecimal(b.ctx, row)
	if isNull || err != nil {
		return nil, isNull, err
	}

	d, isNull, err := b.args[1].EvalInt(b.ctx, row)
	if isNull || err != nil {
		return nil, isNull, err
	}

	result := new(types.MyDecimal)
	if err := x.Round(result, mathutil.Min(int(d), b.getRetTp().Decimal), types.ModeTruncate); err != nil {
		return nil, true, err
	}
	return result, false, nil
}
409461
func (sf *ScalarFunction) EvalReal(ctx sessionctx.Context, row chunk.Row) (float64, bool, error) {
	return sf.Function.evalReal(row)
}
353638
func (b *builtinStringStringTimeDiffSig) evalDuration(row chunk.Row) (d types.Duration, isNull bool, err error) {
	lhs, isNull, err := b.args[0].EvalString(b.ctx, row)
	if isNull || err != nil {
		return d, isNull, err
	}

	rhs, isNull, err := b.args[1].EvalString(b.ctx, row)
	if isNull || err != nil {
		return d, isNull, err
	}

	sc := b.ctx.GetSessionVars().StmtCtx
	fsp := b.tp.Decimal
	lhsDur, lhsTime, lhsIsDuration, err := convertStringToDuration(sc, lhs, fsp)
	if err != nil {
		return d, true, err
	}

	rhsDur, rhsTime, rhsIsDuration, err := convertStringToDuration(sc, rhs, fsp)
	if err != nil {
		return d, true, err
	}

	if lhsIsDuration != rhsIsDuration {
		return d, true, nil
	}

	if lhsIsDuration {
		d, isNull, err = calculateDurationTimeDiff(b.ctx, lhsDur, rhsDur)
	} else {
		d, isNull, err = calculateTimeDiff(sc, lhsTime, rhsTime)
	}

	return d, isNull, err
}
853902
func (b *builtinLastDaySig) evalTime(row chunk.Row) (types.Time, bool, error) {
	arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
	if isNull || err != nil {
		return types.Time{}, true, handleInvalidTimeError(b.ctx, err)
	}
	tm := arg.Time
	var day int
	year, month := tm.Year(), tm.Month()
	if month == 0 {
		return types.Time{}, true, handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenWithStackByArgs(arg.String()))
	}
	day = types.GetLastDay(year, month)
	ret := types.Time{
		Time: types.FromDate(year, month, day, 0, 0, 0, 0),
		Type: mysql.TypeDate,
		Fsp:  types.DefaultFsp,
	}
	return ret, false, nil
}
837855
func ParseDuration(s string) (d time.Duration, err error) {
	r := strings.NewReader(s)

	switch {
	case strings.HasSuffix(s, "d"):
		var v float64
		_, err = fmt.Fscanf(r, "%fd", &v)
		d = time.Duration(v * float64(24*time.Hour))
	case strings.HasSuffix(s, "w"):
		var v float64
		_, err = fmt.Fscanf(r, "%fw", &v)
		d = time.Duration(v * float64(24*time.Hour*7))
	case strings.HasSuffix(s, "mo"):
		var v float64
		_, err = fmt.Fscanf(r, "%fmo", &v)
		d = time.Duration(v * float64(30*24*time.Hour))
	case strings.HasSuffix(s, "M"):
		var v float64
		_, err = fmt.Fscanf(r, "%fM", &v)
		d = time.Duration(v * float64(30*24*time.Hour))
	default:
		d, err = time.ParseDuration(s)
	}

	return
}
1281076
func ToDuration(ms time.Time) time.Duration {
	return Elapsed(ms, time.Now())
}
992074
func ParseDuration(sc *stmtctx.StatementContext, str string, fsp int) (Duration, error) {
	var (
		day, hour, minute, second int
		err                       error
		sign                      = 0
		dayExists                 = false
		origStr                   = str
	)

	fsp, err = CheckFsp(fsp)
	if err != nil {
		return ZeroDuration, errors.Trace(err)
	}

	if len(str) == 0 {
		return ZeroDuration, nil
	} else if str[0] == '-' {
		str = str[1:]
		sign = -1
	}

	// Time format may has day.
	if n := strings.IndexByte(str, ' '); n >= 0 {
		if day, err = strconv.Atoi(str[:n]); err == nil {
			dayExists = true
		}
		str = str[n+1:]
	}

	var (
		integeralPart = str
		fracPart      int
		overflow      bool
	)
	if n := strings.IndexByte(str, '.'); n >= 0 {
		// It has fractional precision parts.
		fracStr := str[n+1:]
		fracPart, overflow, err = ParseFrac(fracStr, fsp)
		if err != nil {
			return ZeroDuration, errors.Trace(err)
		}
		integeralPart = str[0:n]
	}

	// It tries to split integeralPart with delimiter, time delimiter must be :
	seps := strings.Split(integeralPart, ":")

	switch len(seps) {
	case 1:
		if dayExists {
			hour, err = strconv.Atoi(seps[0])
		} else {
			// No delimiter.
			switch len(integeralPart) {
			case 7: // HHHMMSS
				_, err = fmt.Sscanf(integeralPart, "%3d%2d%2d", &hour, &minute, &second)
			case 6: // HHMMSS
				_, err = fmt.Sscanf(integeralPart, "%2d%2d%2d", &hour, &minute, &second)
			case 5: // HMMSS
				_, err = fmt.Sscanf(integeralPart, "%1d%2d%2d", &hour, &minute, &second)
			case 4: // MMSS
				_, err = fmt.Sscanf(integeralPart, "%2d%2d", &minute, &second)
			case 3: // MSS
				_, err = fmt.Sscanf(integeralPart, "%1d%2d", &minute, &second)
			case 2: // SS
				_, err = fmt.Sscanf(integeralPart, "%2d", &second)
			case 1: // 0S
				_, err = fmt.Sscanf(integeralPart, "%1d", &second)
			default: // Maybe contains date.
				t, err1 := ParseDatetime(sc, str)
				if err1 != nil {
					return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
				}
				var dur Duration
				dur, err1 = t.ConvertToDuration()
				if err1 != nil {
					return ZeroDuration, errors.Trace(err)
				}
				return dur.RoundFrac(fsp)
			}
		}
	case 2:
		// HH:MM
		_, err = fmt.Sscanf(integeralPart, "%2d:%2d", &hour, &minute)
	case 3:
		// Time format maybe HH:MM:SS or HHH:MM:SS.
		// See https://dev.mysql.com/doc/refman/5.7/en/time.html
		if len(seps[0]) == 3 {
			_, err = fmt.Sscanf(integeralPart, "%3d:%2d:%2d", &hour, &minute, &second)
		} else {
			_, err = fmt.Sscanf(integeralPart, "%2d:%2d:%2d", &hour, &minute, &second)
		}
	default:
		return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
	}

	if err != nil {
		return ZeroDuration, errors.Trace(err)
	}

	if overflow {
		second++
		fracPart = 0
	}
	// Invalid TIME values are converted to '00:00:00'.
	// See https://dev.mysql.com/doc/refman/5.7/en/time.html
	if minute >= 60 || second > 60 || (!overflow && second == 60) {
		return ZeroDuration, ErrTruncatedWrongVal.GenWithStackByArgs("time", origStr)
	}
	d := gotime.Duration(day*24*3600+hour*3600+minute*60+second)*gotime.Second + gotime.Duration(fracPart)*gotime.Microsecond
	if sign == -1 {
		d = -d
	}

	d, err = TruncateOverflowMySQLTime(d)
	return Duration{Duration: d, Fsp: fsp}, errors.Trace(err)
}