github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/evaluator/helper.go (about) 1 package evaluator 2 3 import ( 4 "strconv" 5 "strings" 6 "time" 7 8 "github.com/insionng/yougam/libraries/juju/errors" 9 "github.com/insionng/yougam/libraries/pingcap/tidb/ast" 10 "github.com/insionng/yougam/libraries/pingcap/tidb/context" 11 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 12 "github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx/variable" 13 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 14 ) 15 16 var ( 17 // CurrentTimestamp is the keyword getting default value for datetime and timestamp type. 18 CurrentTimestamp = "CURRENT_TIMESTAMP" 19 currentTimestampL = "current_timestamp" 20 // ZeroTimestamp shows the zero datetime and timestamp. 21 ZeroTimestamp = "0000-00-00 00:00:00" 22 ) 23 24 var ( 25 errDefaultValue = errors.New("invalid default value") 26 ) 27 28 // GetTimeValue gets the time value with type tp. 29 func GetTimeValue(ctx context.Context, v interface{}, tp byte, fsp int) (types.Datum, error) { 30 return getTimeValue(ctx, v, tp, fsp) 31 } 32 33 func getTimeValue(ctx context.Context, v interface{}, tp byte, fsp int) (d types.Datum, err error) { 34 value := mysql.Time{ 35 Type: tp, 36 Fsp: fsp, 37 } 38 39 defaultTime, err := getSystemTimestamp(ctx) 40 if err != nil { 41 return d, errors.Trace(err) 42 } 43 44 switch x := v.(type) { 45 case string: 46 upperX := strings.ToUpper(x) 47 if upperX == CurrentTimestamp { 48 value.Time = defaultTime 49 } else if upperX == ZeroTimestamp { 50 value, _ = mysql.ParseTimeFromNum(0, tp, fsp) 51 } else { 52 value, err = mysql.ParseTime(x, tp, fsp) 53 if err != nil { 54 return d, errors.Trace(err) 55 } 56 } 57 case *ast.ValueExpr: 58 switch x.Kind() { 59 case types.KindString: 60 value, err = mysql.ParseTime(x.GetString(), tp, fsp) 61 if err != nil { 62 return d, errors.Trace(err) 63 } 64 case types.KindInt64: 65 value, err = mysql.ParseTimeFromNum(x.GetInt64(), tp, fsp) 66 if err != nil { 67 return d, errors.Trace(err) 68 } 69 case types.KindNull: 70 return d, nil 71 default: 72 return d, errors.Trace(errDefaultValue) 73 } 74 case *ast.FuncCallExpr: 75 if x.FnName.L == currentTimestampL { 76 d.SetString(CurrentTimestamp) 77 return d, nil 78 } 79 return d, errors.Trace(errDefaultValue) 80 case *ast.UnaryOperationExpr: 81 // support some expression, like `-1` 82 v, err := Eval(ctx, x) 83 if err != nil { 84 return d, errors.Trace(err) 85 } 86 ft := types.NewFieldType(mysql.TypeLonglong) 87 xval, err := v.ConvertTo(ft) 88 if err != nil { 89 return d, errors.Trace(err) 90 } 91 92 value, err = mysql.ParseTimeFromNum(xval.GetInt64(), tp, fsp) 93 if err != nil { 94 return d, errors.Trace(err) 95 } 96 default: 97 return d, nil 98 } 99 100 d.SetMysqlTime(value) 101 return d, nil 102 } 103 104 // IsCurrentTimeExpr returns whether e is CurrentTimeExpr. 105 func IsCurrentTimeExpr(e ast.ExprNode) bool { 106 x, ok := e.(*ast.FuncCallExpr) 107 if !ok { 108 return false 109 } 110 return x.FnName.L == currentTimestampL 111 } 112 113 func getSystemTimestamp(ctx context.Context) (time.Time, error) { 114 value := time.Now() 115 116 if ctx == nil { 117 return value, nil 118 } 119 120 // check whether use timestamp varibale 121 sessionVars := variable.GetSessionVars(ctx) 122 if v, ok := sessionVars.Systems["timestamp"]; ok { 123 if v != "" { 124 timestamp, err := strconv.ParseInt(v, 10, 64) 125 if err != nil { 126 return time.Time{}, errors.Trace(err) 127 } 128 129 if timestamp <= 0 { 130 return value, nil 131 } 132 133 return time.Unix(timestamp, 0), nil 134 } 135 } 136 137 return value, nil 138 }