github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/constant.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  	"fmt"
    18  
    19  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    20  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    21  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    22  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    23  	"github.com/whtcorpsinc/milevadb/types"
    24  	"github.com/whtcorpsinc/milevadb/types/json"
    25  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    26  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    27  )
    28  
    29  // NewOne stands for a number 1.
    30  func NewOne() *Constant {
    31  	return &Constant{
    32  		Value:   types.NewCauset(1),
    33  		RetType: types.NewFieldType(allegrosql.TypeTiny),
    34  	}
    35  }
    36  
    37  // NewZero stands for a number 0.
    38  func NewZero() *Constant {
    39  	return &Constant{
    40  		Value:   types.NewCauset(0),
    41  		RetType: types.NewFieldType(allegrosql.TypeTiny),
    42  	}
    43  }
    44  
    45  // NewNull stands for null constant.
    46  func NewNull() *Constant {
    47  	return &Constant{
    48  		Value:   types.NewCauset(nil),
    49  		RetType: types.NewFieldType(allegrosql.TypeTiny),
    50  	}
    51  }
    52  
    53  // Constant stands for a constant value.
    54  type Constant struct {
    55  	Value   types.Causet
    56  	RetType *types.FieldType
    57  	// DeferredExpr holds deferred function in CausetCache cached plan.
    58  	// it's only used to represent non-deterministic functions(see memex.DeferredFunctions)
    59  	// in CausetCache cached plan, so let them can be evaluated until cached item be used.
    60  	DeferredExpr Expression
    61  	// ParamMarker holds param index inside stochastikVars.PreparedParams.
    62  	// It's only used to reference a user variable provided in the `EXECUTE` memex or `COM_EXECUTE` binary protodefCaus.
    63  	ParamMarker *ParamMarker
    64  	hashcode    []byte
    65  
    66  	defCauslationInfo
    67  }
    68  
    69  // ParamMarker indicates param provided by COM_STMT_EXECUTE.
    70  type ParamMarker struct {
    71  	ctx   stochastikctx.Context
    72  	order int
    73  }
    74  
    75  // GetUserVar returns the corresponding user variable presented in the `EXECUTE` memex or `COM_EXECUTE` command.
    76  func (d *ParamMarker) GetUserVar() types.Causet {
    77  	stochastikVars := d.ctx.GetStochastikVars()
    78  	return stochastikVars.PreparedParams[d.order]
    79  }
    80  
    81  // String implements fmt.Stringer interface.
    82  func (c *Constant) String() string {
    83  	if c.ParamMarker != nil {
    84  		dt := c.ParamMarker.GetUserVar()
    85  		c.Value.SetValue(dt.GetValue(), c.RetType)
    86  	} else if c.DeferredExpr != nil {
    87  		return c.DeferredExpr.String()
    88  	}
    89  	return fmt.Sprintf("%v", c.Value.GetValue())
    90  }
    91  
    92  // MarshalJSON implements json.Marshaler interface.
    93  func (c *Constant) MarshalJSON() ([]byte, error) {
    94  	return []byte(fmt.Sprintf("%q", c)), nil
    95  }
    96  
    97  // Clone implements Expression interface.
    98  func (c *Constant) Clone() Expression {
    99  	con := *c
   100  	return &con
   101  }
   102  
   103  // GetType implements Expression interface.
   104  func (c *Constant) GetType() *types.FieldType {
   105  	if c.ParamMarker != nil {
   106  		// GetType() may be called in multi-threaded context, e.g, in building inner interlocks of IndexJoin,
   107  		// so it should avoid data race. We achieve this by returning different FieldType pointer for each call.
   108  		tp := types.NewFieldType(allegrosql.TypeUnspecified)
   109  		dt := c.ParamMarker.GetUserVar()
   110  		types.DefaultParamTypeForValue(dt.GetValue(), tp)
   111  		return tp
   112  	}
   113  	return c.RetType
   114  }
   115  
   116  // VecEvalInt evaluates this memex in a vectorized manner.
   117  func (c *Constant) VecEvalInt(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   118  	if c.DeferredExpr == nil {
   119  		return genVecFromConstExpr(ctx, c, types.ETInt, input, result)
   120  	}
   121  	return c.DeferredExpr.VecEvalInt(ctx, input, result)
   122  }
   123  
   124  // VecEvalReal evaluates this memex in a vectorized manner.
   125  func (c *Constant) VecEvalReal(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   126  	if c.DeferredExpr == nil {
   127  		return genVecFromConstExpr(ctx, c, types.ETReal, input, result)
   128  	}
   129  	return c.DeferredExpr.VecEvalReal(ctx, input, result)
   130  }
   131  
   132  // VecEvalString evaluates this memex in a vectorized manner.
   133  func (c *Constant) VecEvalString(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   134  	if c.DeferredExpr == nil {
   135  		return genVecFromConstExpr(ctx, c, types.ETString, input, result)
   136  	}
   137  	return c.DeferredExpr.VecEvalString(ctx, input, result)
   138  }
   139  
   140  // VecEvalDecimal evaluates this memex in a vectorized manner.
   141  func (c *Constant) VecEvalDecimal(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   142  	if c.DeferredExpr == nil {
   143  		return genVecFromConstExpr(ctx, c, types.ETDecimal, input, result)
   144  	}
   145  	return c.DeferredExpr.VecEvalDecimal(ctx, input, result)
   146  }
   147  
   148  // VecEvalTime evaluates this memex in a vectorized manner.
   149  func (c *Constant) VecEvalTime(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   150  	if c.DeferredExpr == nil {
   151  		return genVecFromConstExpr(ctx, c, types.ETTimestamp, input, result)
   152  	}
   153  	return c.DeferredExpr.VecEvalTime(ctx, input, result)
   154  }
   155  
   156  // VecEvalDuration evaluates this memex in a vectorized manner.
   157  func (c *Constant) VecEvalDuration(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   158  	if c.DeferredExpr == nil {
   159  		return genVecFromConstExpr(ctx, c, types.ETDuration, input, result)
   160  	}
   161  	return c.DeferredExpr.VecEvalDuration(ctx, input, result)
   162  }
   163  
   164  // VecEvalJSON evaluates this memex in a vectorized manner.
   165  func (c *Constant) VecEvalJSON(ctx stochastikctx.Context, input *chunk.Chunk, result *chunk.DeferredCauset) error {
   166  	if c.DeferredExpr == nil {
   167  		return genVecFromConstExpr(ctx, c, types.ETJson, input, result)
   168  	}
   169  	return c.DeferredExpr.VecEvalJSON(ctx, input, result)
   170  }
   171  
   172  func (c *Constant) getLazyCauset(event chunk.Event) (dt types.Causet, isLazy bool, err error) {
   173  	if c.ParamMarker != nil {
   174  		return c.ParamMarker.GetUserVar(), true, nil
   175  	} else if c.DeferredExpr != nil {
   176  		dt, err = c.DeferredExpr.Eval(event)
   177  		return dt, true, err
   178  	}
   179  	return types.Causet{}, false, nil
   180  }
   181  
   182  // Eval implements Expression interface.
   183  func (c *Constant) Eval(event chunk.Event) (types.Causet, error) {
   184  	if dt, lazy, err := c.getLazyCauset(event); lazy {
   185  		if err != nil {
   186  			return c.Value, err
   187  		}
   188  		if dt.IsNull() {
   189  			c.Value.SetNull()
   190  			return c.Value, nil
   191  		}
   192  		if c.DeferredExpr != nil {
   193  			sf, sfOk := c.DeferredExpr.(*ScalarFunction)
   194  			if sfOk {
   195  				val, err := dt.ConvertTo(sf.GetCtx().GetStochastikVars().StmtCtx, c.RetType)
   196  				if err != nil {
   197  					return dt, err
   198  				}
   199  				return val, nil
   200  			}
   201  		}
   202  		return dt, nil
   203  	}
   204  	return c.Value, nil
   205  }
   206  
   207  // EvalInt returns int representation of Constant.
   208  func (c *Constant) EvalInt(ctx stochastikctx.Context, event chunk.Event) (int64, bool, error) {
   209  	dt, lazy, err := c.getLazyCauset(event)
   210  	if err != nil {
   211  		return 0, false, err
   212  	}
   213  	if !lazy {
   214  		dt = c.Value
   215  	}
   216  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   217  		return 0, true, nil
   218  	} else if dt.HoTT() == types.HoTTBinaryLiteral {
   219  		val, err := dt.GetBinaryLiteral().ToInt(ctx.GetStochastikVars().StmtCtx)
   220  		return int64(val), err != nil, err
   221  	} else if c.GetType().Hybrid() || dt.HoTT() == types.HoTTString {
   222  		res, err := dt.ToInt64(ctx.GetStochastikVars().StmtCtx)
   223  		return res, false, err
   224  	}
   225  	return dt.GetInt64(), false, nil
   226  }
   227  
   228  // EvalReal returns real representation of Constant.
   229  func (c *Constant) EvalReal(ctx stochastikctx.Context, event chunk.Event) (float64, bool, error) {
   230  	dt, lazy, err := c.getLazyCauset(event)
   231  	if err != nil {
   232  		return 0, false, err
   233  	}
   234  	if !lazy {
   235  		dt = c.Value
   236  	}
   237  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   238  		return 0, true, nil
   239  	}
   240  	if c.GetType().Hybrid() || dt.HoTT() == types.HoTTBinaryLiteral || dt.HoTT() == types.HoTTString {
   241  		res, err := dt.ToFloat64(ctx.GetStochastikVars().StmtCtx)
   242  		return res, false, err
   243  	}
   244  	return dt.GetFloat64(), false, nil
   245  }
   246  
   247  // EvalString returns string representation of Constant.
   248  func (c *Constant) EvalString(ctx stochastikctx.Context, event chunk.Event) (string, bool, error) {
   249  	dt, lazy, err := c.getLazyCauset(event)
   250  	if err != nil {
   251  		return "", false, err
   252  	}
   253  	if !lazy {
   254  		dt = c.Value
   255  	}
   256  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   257  		return "", true, nil
   258  	}
   259  	res, err := dt.ToString()
   260  	return res, false, err
   261  }
   262  
   263  // EvalDecimal returns decimal representation of Constant.
   264  func (c *Constant) EvalDecimal(ctx stochastikctx.Context, event chunk.Event) (*types.MyDecimal, bool, error) {
   265  	dt, lazy, err := c.getLazyCauset(event)
   266  	if err != nil {
   267  		return nil, false, err
   268  	}
   269  	if !lazy {
   270  		dt = c.Value
   271  	}
   272  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   273  		return nil, true, nil
   274  	}
   275  	res, err := dt.ToDecimal(ctx.GetStochastikVars().StmtCtx)
   276  	return res, false, err
   277  }
   278  
   279  // EvalTime returns DATE/DATETIME/TIMESTAMP representation of Constant.
   280  func (c *Constant) EvalTime(ctx stochastikctx.Context, event chunk.Event) (val types.Time, isNull bool, err error) {
   281  	dt, lazy, err := c.getLazyCauset(event)
   282  	if err != nil {
   283  		return types.ZeroTime, false, err
   284  	}
   285  	if !lazy {
   286  		dt = c.Value
   287  	}
   288  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   289  		return types.ZeroTime, true, nil
   290  	}
   291  	return dt.GetMysqlTime(), false, nil
   292  }
   293  
   294  // EvalDuration returns Duration representation of Constant.
   295  func (c *Constant) EvalDuration(ctx stochastikctx.Context, event chunk.Event) (val types.Duration, isNull bool, err error) {
   296  	dt, lazy, err := c.getLazyCauset(event)
   297  	if err != nil {
   298  		return types.Duration{}, false, err
   299  	}
   300  	if !lazy {
   301  		dt = c.Value
   302  	}
   303  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   304  		return types.Duration{}, true, nil
   305  	}
   306  	return dt.GetMysqlDuration(), false, nil
   307  }
   308  
   309  // EvalJSON returns JSON representation of Constant.
   310  func (c *Constant) EvalJSON(ctx stochastikctx.Context, event chunk.Event) (json.BinaryJSON, bool, error) {
   311  	dt, lazy, err := c.getLazyCauset(event)
   312  	if err != nil {
   313  		return json.BinaryJSON{}, false, err
   314  	}
   315  	if !lazy {
   316  		dt = c.Value
   317  	}
   318  	if c.GetType().Tp == allegrosql.TypeNull || dt.IsNull() {
   319  		return json.BinaryJSON{}, true, nil
   320  	}
   321  	return dt.GetMysqlJSON(), false, nil
   322  }
   323  
   324  // Equal implements Expression interface.
   325  func (c *Constant) Equal(ctx stochastikctx.Context, b Expression) bool {
   326  	y, ok := b.(*Constant)
   327  	if !ok {
   328  		return false
   329  	}
   330  	_, err1 := y.Eval(chunk.Event{})
   331  	_, err2 := c.Eval(chunk.Event{})
   332  	if err1 != nil || err2 != nil {
   333  		return false
   334  	}
   335  	con, err := c.Value.CompareCauset(ctx.GetStochastikVars().StmtCtx, &y.Value)
   336  	if err != nil || con != 0 {
   337  		return false
   338  	}
   339  	return true
   340  }
   341  
   342  // IsCorrelated implements Expression interface.
   343  func (c *Constant) IsCorrelated() bool {
   344  	return false
   345  }
   346  
   347  // ConstItem implements Expression interface.
   348  func (c *Constant) ConstItem(sc *stmtctx.StatementContext) bool {
   349  	return !sc.UseCache || (c.DeferredExpr == nil && c.ParamMarker == nil)
   350  }
   351  
   352  // Decorrelate implements Expression interface.
   353  func (c *Constant) Decorrelate(_ *Schema) Expression {
   354  	return c
   355  }
   356  
   357  // HashCode implements Expression interface.
   358  func (c *Constant) HashCode(sc *stmtctx.StatementContext) []byte {
   359  	if len(c.hashcode) > 0 {
   360  		return c.hashcode
   361  	}
   362  	_, err := c.Eval(chunk.Event{})
   363  	if err != nil {
   364  		terror.Log(err)
   365  	}
   366  	c.hashcode = append(c.hashcode, constantFlag)
   367  	c.hashcode, err = codec.EncodeValue(sc, c.hashcode, c.Value)
   368  	if err != nil {
   369  		terror.Log(err)
   370  	}
   371  	return c.hashcode
   372  }
   373  
   374  // ResolveIndices implements Expression interface.
   375  func (c *Constant) ResolveIndices(_ *Schema) (Expression, error) {
   376  	return c, nil
   377  }
   378  
   379  func (c *Constant) resolveIndices(_ *Schema) error {
   380  	return nil
   381  }
   382  
   383  // Vectorized returns if this memex supports vectorized evaluation.
   384  func (c *Constant) Vectorized() bool {
   385  	if c.DeferredExpr != nil {
   386  		return c.DeferredExpr.Vectorized()
   387  	}
   388  	return true
   389  }
   390  
   391  // SupportReverseEval checks whether the builtinFunc support reverse evaluation.
   392  func (c *Constant) SupportReverseEval() bool {
   393  	if c.DeferredExpr != nil {
   394  		return c.DeferredExpr.SupportReverseEval()
   395  	}
   396  	return true
   397  }
   398  
   399  // ReverseEval evaluates the only one defCausumn value with given function result.
   400  func (c *Constant) ReverseEval(sc *stmtctx.StatementContext, res types.Causet, rType types.RoundingType) (val types.Causet, err error) {
   401  	return c.Value, nil
   402  }
   403  
   404  // Coercibility returns the coercibility value which is used to check defCauslations.
   405  func (c *Constant) Coercibility() Coercibility {
   406  	if c.HasCoercibility() {
   407  		return c.defCauslationInfo.Coercibility()
   408  	}
   409  
   410  	c.SetCoercibility(deriveCoercibilityForConstant(c))
   411  	return c.defCauslationInfo.Coercibility()
   412  }