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  }