Example #1
0
// Eval implements the Expression Eval interface.
func (da *DateAdd) Eval(ctx context.Context, args map[interface{}]interface{}) (interface{}, error) {
	dv, err := da.Date.Eval(ctx, args)
	if dv == nil || err != nil {
		return nil, errors.Trace(err)
	}

	sv, err := types.ToString(dv)
	if err != nil {
		return nil, errors.Trace(err)
	}

	f := types.NewFieldType(mysql.TypeDatetime)
	f.Decimal = mysql.MaxFsp

	dv, err = types.Convert(sv, f)
	if dv == nil || err != nil {
		return nil, errors.Trace(err)
	}

	t, ok := dv.(mysql.Time)
	if !ok {
		return nil, errors.Errorf("need time type, but got %T", dv)
	}

	iv, err := da.Interval.Eval(ctx, args)
	if iv == nil || err != nil {
		return nil, errors.Trace(err)
	}

	format, err := types.ToString(iv)
	if err != nil {
		return nil, errors.Trace(err)
	}

	years, months, days, durations, err := mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(format))
	if err != nil {
		return nil, errors.Trace(err)
	}

	t.Time = t.Time.Add(durations)
	t.Time = t.Time.AddDate(int(years), int(months), int(days))

	// "2011-11-11 10:10:20.000000" outputs "2011-11-11 10:10:20".
	if t.Time.Nanosecond() == 0 {
		t.Fsp = 0
	}

	return t, nil
}
Example #2
0
func (da *DateArith) evalArgs(ctx context.Context, args map[interface{}]interface{}) (
	*evalArgsResult, error) {
	ret := &evalArgsResult{time: mysql.ZeroTimestamp}

	dVal, err := da.Date.Eval(ctx, args)
	if dVal == nil || err != nil {
		return ret, errors.Trace(err)
	}
	dValStr, err := types.ToString(dVal)
	if err != nil {
		return ret, errors.Trace(err)
	}
	f := types.NewFieldType(mysql.TypeDatetime)
	f.Decimal = mysql.MaxFsp
	dVal, err = types.Convert(dValStr, f)
	if dVal == nil || err != nil {
		return ret, errors.Trace(err)
	}

	var ok bool
	ret.time, ok = dVal.(mysql.Time)
	if !ok {
		return ret, errors.Errorf("need time type, but got %T", dVal)
	}

	iVal, err := da.Interval.Eval(ctx, args)
	if iVal == nil || err != nil {
		ret.time = mysql.ZeroTimestamp
		return ret, errors.Trace(err)
	}
	// handle adddate(expr,days) or subdate(expr,days) form
	if da.Form == DateArithDaysForm {
		if iVal, err = da.evalDaysForm(iVal); err != nil {
			return ret, errors.Trace(err)
		}
	}

	iValStr, err := types.ToString(iVal)
	if err != nil {
		return ret, errors.Trace(err)
	}
	ret.year, ret.month, ret.day, ret.duration, err = mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(iValStr))
	if err != nil {
		return ret, errors.Trace(err)
	}

	return ret, nil
}
Example #3
0
func (da *DateArith) evalArgs(ctx context.Context, args map[interface{}]interface{}) (
	mysql.Time, int64, int64, int64, time.Duration, error) {
	dVal, err := da.Date.Eval(ctx, args)
	if dVal == nil || err != nil {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err)
	}
	dValStr, err := types.ToString(dVal)
	if err != nil {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err)
	}
	f := types.NewFieldType(mysql.TypeDatetime)
	f.Decimal = mysql.MaxFsp
	dVal, err = types.Convert(dValStr, f)
	if dVal == nil || err != nil {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err)
	}
	t, ok := dVal.(mysql.Time)
	if !ok {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Errorf("need time type, but got %T", dVal)
	}

	iVal, err := da.Interval.Eval(ctx, args)
	if iVal == nil || err != nil {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err)
	}
	iValStr, err := types.ToString(iVal)
	if err != nil {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err)
	}
	years, months, days, durations, err := mysql.ExtractTimeValue(da.Unit, strings.TrimSpace(iValStr))
	if err != nil {
		return mysql.ZeroTimestamp, 0, 0, 0, 0, errors.Trace(err)
	}

	return t, years, months, days, durations, nil
}
Example #4
0
func (e *Evaluator) funcDateArith(v *ast.FuncDateArithExpr) bool {
	// health check for date and interval
	nodeDate := v.Date.GetValue()
	if types.IsNil(nodeDate) {
		v.SetValue(nil)
		return true
	}
	nodeInterval := v.Interval.GetValue()
	if types.IsNil(nodeInterval) {
		v.SetValue(nil)
		return true
	}
	// parse date
	fieldType := mysql.TypeDate
	var resultField *types.FieldType
	switch x := nodeDate.(type) {
	case mysql.Time:
		if (x.Type == mysql.TypeDatetime) || (x.Type == mysql.TypeTimestamp) {
			fieldType = mysql.TypeDatetime
		}
	case string:
		if !mysql.IsDateFormat(x) {
			fieldType = mysql.TypeDatetime
		}
	case int64:
		if t, err := mysql.ParseTimeFromInt64(x); err == nil {
			if (t.Type == mysql.TypeDatetime) || (t.Type == mysql.TypeTimestamp) {
				fieldType = mysql.TypeDatetime
			}
		}
	}
	if mysql.IsClockUnit(v.Unit) {
		fieldType = mysql.TypeDatetime
	}
	resultField = types.NewFieldType(fieldType)
	resultField.Decimal = mysql.MaxFsp
	value, err := types.Convert(nodeDate, resultField)
	if err != nil {
		e.err = ErrInvalidOperation.Gen("DateArith invalid args, need date but get %T", nodeDate)
		return false
	}
	if types.IsNil(value) {
		e.err = ErrInvalidOperation.Gen("DateArith invalid args, need date but get %v", value)
		return false
	}
	result, ok := value.(mysql.Time)
	if !ok {
		e.err = ErrInvalidOperation.Gen("DateArith need time type, but got %T", value)
		return false
	}
	// parse interval
	var interval string
	if strings.ToLower(v.Unit) == "day" {
		day, err2 := parseDayInterval(nodeInterval)
		if err2 != nil {
			e.err = ErrInvalidOperation.Gen("DateArith invalid day interval, need int but got %T", nodeInterval)
			return false
		}
		interval = fmt.Sprintf("%d", day)
	} else {
		interval = fmt.Sprintf("%v", nodeInterval)
	}
	year, month, day, duration, err := mysql.ExtractTimeValue(v.Unit, interval)
	if err != nil {
		e.err = errors.Trace(err)
		return false
	}
	if v.Op == ast.DateSub {
		year, month, day, duration = -year, -month, -day, -duration
	}
	result.Time = result.Time.Add(duration)
	result.Time = result.Time.AddDate(int(year), int(month), int(day))
	if result.Time.Nanosecond() == 0 {
		result.Fsp = 0
	}
	v.SetValue(result)
	return true
}
Example #5
0
func builtinDateArith(args []types.Datum, ctx context.Context) (d types.Datum, err error) {
	// Op is used for distinguishing date_add and date_sub.
	// args[0] -> Op
	// args[1] -> Date
	// args[2] -> DateArithInterval
	// health check for date and interval
	if args[1].Kind() == types.KindNull {
		d.SetNull()
		return d, nil
	}
	nodeDate := args[1]
	nodeInterval := args[2].GetInterface().(ast.DateArithInterval)
	nodeIntervalIntervalDatum := nodeInterval.Interval.GetDatum()
	if nodeIntervalIntervalDatum.Kind() == types.KindNull {
		d.SetNull()
		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 !mysql.IsDateFormat(x) {
			fieldType = mysql.TypeDatetime
		}
	case types.KindInt64:
		x := nodeDate.GetInt64()
		if t, err1 := mysql.ParseTimeFromInt64(x); err1 == nil {
			if (t.Type == mysql.TypeDatetime) || (t.Type == mysql.TypeTimestamp) {
				fieldType = mysql.TypeDatetime
			}
		}
	}
	if mysql.IsClockUnit(nodeInterval.Unit) {
		fieldType = mysql.TypeDatetime
	}
	resultField = types.NewFieldType(fieldType)
	resultField.Decimal = mysql.MaxFsp
	value, err := nodeDate.ConvertTo(resultField)
	if err != nil {
		d.SetNull()
		return d, ErrInvalidOperation.Gen("DateArith invalid args, need date but get %T", nodeDate)
	}
	if value.Kind() == types.KindNull {
		d.SetNull()
		return d, ErrInvalidOperation.Gen("DateArith invalid args, need date but get %v", value.GetValue())
	}
	if value.Kind() != types.KindMysqlTime {
		d.SetNull()
		return d, ErrInvalidOperation.Gen("DateArith need time type, but got %T", value.GetValue())
	}
	result := value.GetMysqlTime()
	// parse interval
	var interval string
	if strings.ToLower(nodeInterval.Unit) == "day" {
		day, err1 := parseDayInterval(*nodeIntervalIntervalDatum)
		if err1 != nil {
			d.SetNull()
			return d, ErrInvalidOperation.Gen("DateArith invalid day interval, need int but got %T", nodeIntervalIntervalDatum.GetString())
		}
		interval = fmt.Sprintf("%d", day)
	} else {
		if nodeIntervalIntervalDatum.Kind() == types.KindString {
			interval = fmt.Sprintf("%v", nodeIntervalIntervalDatum.GetString())
		} else {
			ii, err1 := nodeIntervalIntervalDatum.ToInt64()
			if err1 != nil {
				d.SetNull()
				return d, errors.Trace(err1)
			}
			interval = fmt.Sprintf("%v", ii)
		}
	}
	year, month, day, duration, err := mysql.ExtractTimeValue(nodeInterval.Unit, interval)
	if err != nil {
		d.SetNull()
		return d, errors.Trace(err)
	}
	op := args[0].GetInterface().(ast.DateArithType)
	if op == ast.DateSub {
		year, month, day, duration = -year, -month, -day, -duration
	}
	result.Time = result.Time.Add(duration)
	result.Time = result.Time.AddDate(int(year), int(month), int(day))
	if result.Time.Nanosecond() == 0 {
		result.Fsp = 0
	}
	d.SetMysqlTime(result)
	return d, nil
}