github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/helper.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package memex
    15  
    16  import (
    17  	"math"
    18  	"strings"
    19  	"time"
    20  
    21  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    22  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    23  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    24  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    25  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    26  	"github.com/whtcorpsinc/milevadb/types"
    27  	driver "github.com/whtcorpsinc/milevadb/types/BerolinaSQL_driver"
    28  )
    29  
    30  func boolToInt64(v bool) int64 {
    31  	if v {
    32  		return 1
    33  	}
    34  	return 0
    35  }
    36  
    37  // IsValidCurrentTimestampExpr returns true if exprNode is a valid CurrentTimestamp memex.
    38  // Here `valid` means it is consistent with the given fieldType's Decimal.
    39  func IsValidCurrentTimestampExpr(exprNode ast.ExprNode, fieldType *types.FieldType) bool {
    40  	fn, isFuncCall := exprNode.(*ast.FuncCallExpr)
    41  	if !isFuncCall || fn.FnName.L != ast.CurrentTimestamp {
    42  		return false
    43  	}
    44  
    45  	containsArg := len(fn.Args) > 0
    46  	// Fsp represents fractional seconds precision.
    47  	containsFsp := fieldType != nil && fieldType.Decimal > 0
    48  	var isConsistent bool
    49  	if containsArg {
    50  		v, ok := fn.Args[0].(*driver.ValueExpr)
    51  		isConsistent = ok && fieldType != nil && v.Causet.GetInt64() == int64(fieldType.Decimal)
    52  	}
    53  
    54  	return (containsArg && isConsistent) || (!containsArg && !containsFsp)
    55  }
    56  
    57  // GetTimeValue gets the time value with type tp.
    58  func GetTimeValue(ctx stochastikctx.Context, v interface{}, tp byte, fsp int8) (d types.Causet, err error) {
    59  	value := types.NewTime(types.ZeroCoreTime, tp, fsp)
    60  
    61  	sc := ctx.GetStochastikVars().StmtCtx
    62  	switch x := v.(type) {
    63  	case string:
    64  		upperX := strings.ToUpper(x)
    65  		if upperX == strings.ToUpper(ast.CurrentTimestamp) {
    66  			defaultTime, err := getStmtTimestamp(ctx)
    67  			if err != nil {
    68  				return d, err
    69  			}
    70  			value.SetCoreTime(types.FromGoTime(defaultTime.Truncate(time.Duration(math.Pow10(9-int(fsp))) * time.Nanosecond)))
    71  			if tp == allegrosql.TypeTimestamp || tp == allegrosql.TypeDatetime {
    72  				err = value.ConvertTimeZone(time.Local, ctx.GetStochastikVars().Location())
    73  				if err != nil {
    74  					return d, err
    75  				}
    76  			}
    77  		} else if upperX == types.ZeroDatetimeStr {
    78  			value, err = types.ParseTimeFromNum(sc, 0, tp, fsp)
    79  			terror.Log(err)
    80  		} else {
    81  			value, err = types.ParseTime(sc, x, tp, fsp)
    82  			if err != nil {
    83  				return d, err
    84  			}
    85  		}
    86  	case *driver.ValueExpr:
    87  		switch x.HoTT() {
    88  		case types.HoTTString:
    89  			value, err = types.ParseTime(sc, x.GetString(), tp, fsp)
    90  			if err != nil {
    91  				return d, err
    92  			}
    93  		case types.HoTTInt64:
    94  			value, err = types.ParseTimeFromNum(sc, x.GetInt64(), tp, fsp)
    95  			if err != nil {
    96  				return d, err
    97  			}
    98  		case types.HoTTNull:
    99  			return d, nil
   100  		default:
   101  			return d, errDefaultValue
   102  		}
   103  	case *ast.FuncCallExpr:
   104  		if x.FnName.L == ast.CurrentTimestamp {
   105  			d.SetString(strings.ToUpper(ast.CurrentTimestamp), allegrosql.DefaultDefCauslationName)
   106  			return d, nil
   107  		}
   108  		return d, errDefaultValue
   109  	case *ast.UnaryOperationExpr:
   110  		// support some memex, like `-1`
   111  		v, err := EvalAstExpr(ctx, x)
   112  		if err != nil {
   113  			return d, err
   114  		}
   115  		ft := types.NewFieldType(allegrosql.TypeLonglong)
   116  		xval, err := v.ConvertTo(ctx.GetStochastikVars().StmtCtx, ft)
   117  		if err != nil {
   118  			return d, err
   119  		}
   120  
   121  		value, err = types.ParseTimeFromNum(sc, xval.GetInt64(), tp, fsp)
   122  		if err != nil {
   123  			return d, err
   124  		}
   125  	default:
   126  		return d, nil
   127  	}
   128  	d.SetMysqlTime(value)
   129  	return d, nil
   130  }
   131  
   132  // if timestamp stochastik variable set, use stochastik variable as current time, otherwise use cached time
   133  // during one allegrosql memex, the "current_time" should be the same
   134  func getStmtTimestamp(ctx stochastikctx.Context) (time.Time, error) {
   135  	now := time.Now()
   136  
   137  	if ctx == nil {
   138  		return now, nil
   139  	}
   140  
   141  	stochastikVars := ctx.GetStochastikVars()
   142  	timestampStr, err := variable.GetStochastikSystemVar(stochastikVars, "timestamp")
   143  	if err != nil {
   144  		return now, err
   145  	}
   146  
   147  	if timestampStr != "" {
   148  		timestamp, err := types.StrToInt(stochastikVars.StmtCtx, timestampStr, false)
   149  		if err != nil {
   150  			return time.Time{}, err
   151  		}
   152  		if timestamp <= 0 {
   153  			return now, nil
   154  		}
   155  		return time.Unix(timestamp, 0), nil
   156  	}
   157  	stmtCtx := ctx.GetStochastikVars().StmtCtx
   158  	return stmtCtx.GetNowTsCached(), nil
   159  }