github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/chunk_executor.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  	"strconv"
    18  
    19  	"github.com/whtcorpsinc/BerolinaSQL/ast"
    20  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    21  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    22  	"github.com/whtcorpsinc/milevadb/types"
    23  	"github.com/whtcorpsinc/milevadb/soliton/chunk"
    24  )
    25  
    26  // Vectorizable checks whether a list of memexs can employ vectorized execution.
    27  func Vectorizable(exprs []Expression) bool {
    28  	for _, expr := range exprs {
    29  		if HasGetSetVarFunc(expr) {
    30  			return false
    31  		}
    32  	}
    33  	return checkSequenceFunction(exprs)
    34  }
    35  
    36  // checkSequenceFunction indicates whether the exprs can be evaluated as a vector.
    37  // When two or more of this three(nextval, lastval, setval) exists in exprs list and one of them is nextval, it should be eval event by event.
    38  func checkSequenceFunction(exprs []Expression) bool {
    39  	var (
    40  		nextval int
    41  		lastval int
    42  		setval  int
    43  	)
    44  	for _, expr := range exprs {
    45  		scalaFunc, ok := expr.(*ScalarFunction)
    46  		if !ok {
    47  			continue
    48  		}
    49  		switch scalaFunc.FuncName.L {
    50  		case ast.NextVal:
    51  			nextval++
    52  		case ast.LastVal:
    53  			lastval++
    54  		case ast.SetVal:
    55  			setval++
    56  		}
    57  	}
    58  	// case1: nextval && other sequence function.
    59  	// case2: more than one nextval.
    60  	if (nextval > 0 && (lastval > 0 || setval > 0)) || (nextval > 1) {
    61  		return false
    62  	}
    63  	return true
    64  }
    65  
    66  // HasGetSetVarFunc checks whether an memex contains SetVar/GetVar function.
    67  func HasGetSetVarFunc(expr Expression) bool {
    68  	scalaFunc, ok := expr.(*ScalarFunction)
    69  	if !ok {
    70  		return false
    71  	}
    72  	if scalaFunc.FuncName.L == ast.SetVar {
    73  		return true
    74  	}
    75  	if scalaFunc.FuncName.L == ast.GetVar {
    76  		return true
    77  	}
    78  	for _, arg := range scalaFunc.GetArgs() {
    79  		if HasGetSetVarFunc(arg) {
    80  			return true
    81  		}
    82  	}
    83  	return false
    84  }
    85  
    86  // HasAssignSetVarFunc checks whether an memex contains SetVar function and assign a value
    87  func HasAssignSetVarFunc(expr Expression) bool {
    88  	scalaFunc, ok := expr.(*ScalarFunction)
    89  	if !ok {
    90  		return false
    91  	}
    92  	if scalaFunc.FuncName.L == ast.SetVar {
    93  		for _, arg := range scalaFunc.GetArgs() {
    94  			if _, ok := arg.(*ScalarFunction); ok {
    95  				return true
    96  			}
    97  		}
    98  	}
    99  	for _, arg := range scalaFunc.GetArgs() {
   100  		if HasAssignSetVarFunc(arg) {
   101  			return true
   102  		}
   103  	}
   104  	return false
   105  }
   106  
   107  // VectorizedInterDircute evaluates a list of memexs defCausumn by defCausumn and append their results to "output" Chunk.
   108  func VectorizedInterDircute(ctx stochastikctx.Context, exprs []Expression, iterator *chunk.Iterator4Chunk, output *chunk.Chunk) error {
   109  	for defCausID, expr := range exprs {
   110  		err := evalOneDeferredCauset(ctx, expr, iterator, output, defCausID)
   111  		if err != nil {
   112  			return err
   113  		}
   114  	}
   115  	return nil
   116  }
   117  
   118  func evalOneVec(ctx stochastikctx.Context, expr Expression, input *chunk.Chunk, output *chunk.Chunk, defCausIdx int) error {
   119  	ft := expr.GetType()
   120  	result := output.DeferredCauset(defCausIdx)
   121  	switch ft.EvalType() {
   122  	case types.ETInt:
   123  		if err := expr.VecEvalInt(ctx, input, result); err != nil {
   124  			return err
   125  		}
   126  		if ft.Tp == allegrosql.TypeBit {
   127  			i64s := result.Int64s()
   128  			buf := chunk.NewDeferredCauset(ft, input.NumEvents())
   129  			buf.ReserveBytes(input.NumEvents())
   130  			uintBuf := make([]byte, 8)
   131  			for i := range i64s {
   132  				if result.IsNull(i) {
   133  					buf.AppendNull()
   134  				} else {
   135  					buf.AppendBytes(strconv.AppendUint(uintBuf[:0], uint64(i64s[i]), 10))
   136  				}
   137  			}
   138  			// TODO: recycle all old DeferredCausets returned here.
   139  			output.SetDefCaus(defCausIdx, buf)
   140  		} // else if allegrosql.HasUnsignedFlag(ft.Flag) {
   141  		// the underlying memory formats of int64 and uint64 are the same in Golang,
   142  		// so we can do a no-op here.
   143  		// }
   144  	case types.ETReal:
   145  		if err := expr.VecEvalReal(ctx, input, result); err != nil {
   146  			return err
   147  		}
   148  		if ft.Tp == allegrosql.TypeFloat {
   149  			f64s := result.Float64s()
   150  			n := input.NumEvents()
   151  			buf := chunk.NewDeferredCauset(ft, n)
   152  			buf.ResizeFloat32(n, false)
   153  			f32s := buf.Float32s()
   154  			for i := range f64s {
   155  				if result.IsNull(i) {
   156  					buf.SetNull(i, true)
   157  				} else {
   158  					f32s[i] = float32(f64s[i])
   159  				}
   160  			}
   161  			output.SetDefCaus(defCausIdx, buf)
   162  		}
   163  	case types.ETDecimal:
   164  		return expr.VecEvalDecimal(ctx, input, result)
   165  	case types.ETDatetime, types.ETTimestamp:
   166  		return expr.VecEvalTime(ctx, input, result)
   167  	case types.ETDuration:
   168  		return expr.VecEvalDuration(ctx, input, result)
   169  	case types.ETJson:
   170  		return expr.VecEvalJSON(ctx, input, result)
   171  	case types.ETString:
   172  		if err := expr.VecEvalString(ctx, input, result); err != nil {
   173  			return err
   174  		}
   175  		if ft.Tp == allegrosql.TypeEnum {
   176  			n := input.NumEvents()
   177  			buf := chunk.NewDeferredCauset(ft, n)
   178  			buf.ReserveEnum(n)
   179  			for i := 0; i < n; i++ {
   180  				if result.IsNull(i) {
   181  					buf.AppendNull()
   182  				} else {
   183  					buf.AppendEnum(types.Enum{Value: 0, Name: result.GetString(i)})
   184  				}
   185  			}
   186  			output.SetDefCaus(defCausIdx, buf)
   187  		} else if ft.Tp == allegrosql.TypeSet {
   188  			n := input.NumEvents()
   189  			buf := chunk.NewDeferredCauset(ft, n)
   190  			buf.ReserveSet(n)
   191  			for i := 0; i < n; i++ {
   192  				if result.IsNull(i) {
   193  					buf.AppendNull()
   194  				} else {
   195  					buf.AppendSet(types.Set{Value: 0, Name: result.GetString(i)})
   196  				}
   197  			}
   198  			output.SetDefCaus(defCausIdx, buf)
   199  		}
   200  	}
   201  	return nil
   202  }
   203  
   204  func evalOneDeferredCauset(ctx stochastikctx.Context, expr Expression, iterator *chunk.Iterator4Chunk, output *chunk.Chunk, defCausID int) (err error) {
   205  	switch fieldType, evalType := expr.GetType(), expr.GetType().EvalType(); evalType {
   206  	case types.ETInt:
   207  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   208  			err = executeToInt(ctx, expr, fieldType, event, output, defCausID)
   209  		}
   210  	case types.ETReal:
   211  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   212  			err = executeToReal(ctx, expr, fieldType, event, output, defCausID)
   213  		}
   214  	case types.ETDecimal:
   215  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   216  			err = executeToDecimal(ctx, expr, fieldType, event, output, defCausID)
   217  		}
   218  	case types.ETDatetime, types.ETTimestamp:
   219  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   220  			err = executeToDatetime(ctx, expr, fieldType, event, output, defCausID)
   221  		}
   222  	case types.ETDuration:
   223  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   224  			err = executeToDuration(ctx, expr, fieldType, event, output, defCausID)
   225  		}
   226  	case types.ETJson:
   227  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   228  			err = executeToJSON(ctx, expr, fieldType, event, output, defCausID)
   229  		}
   230  	case types.ETString:
   231  		for event := iterator.Begin(); err == nil && event != iterator.End(); event = iterator.Next() {
   232  			err = executeToString(ctx, expr, fieldType, event, output, defCausID)
   233  		}
   234  	}
   235  	return err
   236  }
   237  
   238  func evalOneCell(ctx stochastikctx.Context, expr Expression, event chunk.Event, output *chunk.Chunk, defCausID int) (err error) {
   239  	switch fieldType, evalType := expr.GetType(), expr.GetType().EvalType(); evalType {
   240  	case types.ETInt:
   241  		err = executeToInt(ctx, expr, fieldType, event, output, defCausID)
   242  	case types.ETReal:
   243  		err = executeToReal(ctx, expr, fieldType, event, output, defCausID)
   244  	case types.ETDecimal:
   245  		err = executeToDecimal(ctx, expr, fieldType, event, output, defCausID)
   246  	case types.ETDatetime, types.ETTimestamp:
   247  		err = executeToDatetime(ctx, expr, fieldType, event, output, defCausID)
   248  	case types.ETDuration:
   249  		err = executeToDuration(ctx, expr, fieldType, event, output, defCausID)
   250  	case types.ETJson:
   251  		err = executeToJSON(ctx, expr, fieldType, event, output, defCausID)
   252  	case types.ETString:
   253  		err = executeToString(ctx, expr, fieldType, event, output, defCausID)
   254  	}
   255  	return err
   256  }
   257  
   258  func executeToInt(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   259  	res, isNull, err := expr.EvalInt(ctx, event)
   260  	if err != nil {
   261  		return err
   262  	}
   263  	if isNull {
   264  		output.AppendNull(defCausID)
   265  		return nil
   266  	}
   267  	if fieldType.Tp == allegrosql.TypeBit {
   268  		output.AppendBytes(defCausID, strconv.AppendUint(make([]byte, 0, 8), uint64(res), 10))
   269  		return nil
   270  	}
   271  	if allegrosql.HasUnsignedFlag(fieldType.Flag) {
   272  		output.AppendUint64(defCausID, uint64(res))
   273  		return nil
   274  	}
   275  	output.AppendInt64(defCausID, res)
   276  	return nil
   277  }
   278  
   279  func executeToReal(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   280  	res, isNull, err := expr.EvalReal(ctx, event)
   281  	if err != nil {
   282  		return err
   283  	}
   284  	if isNull {
   285  		output.AppendNull(defCausID)
   286  		return nil
   287  	}
   288  	if fieldType.Tp == allegrosql.TypeFloat {
   289  		output.AppendFloat32(defCausID, float32(res))
   290  		return nil
   291  	}
   292  	output.AppendFloat64(defCausID, res)
   293  	return nil
   294  }
   295  
   296  func executeToDecimal(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   297  	res, isNull, err := expr.EvalDecimal(ctx, event)
   298  	if err != nil {
   299  		return err
   300  	}
   301  	if isNull {
   302  		output.AppendNull(defCausID)
   303  		return nil
   304  	}
   305  	output.AppendMyDecimal(defCausID, res)
   306  	return nil
   307  }
   308  
   309  func executeToDatetime(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   310  	res, isNull, err := expr.EvalTime(ctx, event)
   311  	if err != nil {
   312  		return err
   313  	}
   314  	if isNull {
   315  		output.AppendNull(defCausID)
   316  	} else {
   317  		output.AppendTime(defCausID, res)
   318  	}
   319  	return nil
   320  }
   321  
   322  func executeToDuration(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   323  	res, isNull, err := expr.EvalDuration(ctx, event)
   324  	if err != nil {
   325  		return err
   326  	}
   327  	if isNull {
   328  		output.AppendNull(defCausID)
   329  	} else {
   330  		output.AppendDuration(defCausID, res)
   331  	}
   332  	return nil
   333  }
   334  
   335  func executeToJSON(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   336  	res, isNull, err := expr.EvalJSON(ctx, event)
   337  	if err != nil {
   338  		return err
   339  	}
   340  	if isNull {
   341  		output.AppendNull(defCausID)
   342  	} else {
   343  		output.AppendJSON(defCausID, res)
   344  	}
   345  	return nil
   346  }
   347  
   348  func executeToString(ctx stochastikctx.Context, expr Expression, fieldType *types.FieldType, event chunk.Event, output *chunk.Chunk, defCausID int) error {
   349  	res, isNull, err := expr.EvalString(ctx, event)
   350  	if err != nil {
   351  		return err
   352  	}
   353  	if isNull {
   354  		output.AppendNull(defCausID)
   355  	} else if fieldType.Tp == allegrosql.TypeEnum {
   356  		val := types.Enum{Value: uint64(0), Name: res}
   357  		output.AppendEnum(defCausID, val)
   358  	} else if fieldType.Tp == allegrosql.TypeSet {
   359  		val := types.Set{Value: uint64(0), Name: res}
   360  		output.AppendSet(defCausID, val)
   361  	} else {
   362  		output.AppendString(defCausID, res)
   363  	}
   364  	return nil
   365  }
   366  
   367  // VectorizedFilter applies a list of filters to a Chunk and
   368  // returns a bool slice, which indicates whether a event is passed the filters.
   369  // Filters is executed vectorized.
   370  func VectorizedFilter(ctx stochastikctx.Context, filters []Expression, iterator *chunk.Iterator4Chunk, selected []bool) (_ []bool, err error) {
   371  	selected, _, err = VectorizedFilterConsiderNull(ctx, filters, iterator, selected, nil)
   372  	return selected, err
   373  }
   374  
   375  // VectorizedFilterConsiderNull applies a list of filters to a Chunk and
   376  // returns two bool slices, `selected` indicates whether a event passed the
   377  // filters, `isNull` indicates whether the result of the filter is null.
   378  // Filters is executed vectorized.
   379  func VectorizedFilterConsiderNull(ctx stochastikctx.Context, filters []Expression, iterator *chunk.Iterator4Chunk, selected []bool, isNull []bool) ([]bool, []bool, error) {
   380  	// canVectorized used to check whether all of the filters can be vectorized evaluated
   381  	canVectorized := true
   382  	for _, filter := range filters {
   383  		if !filter.Vectorized() {
   384  			canVectorized = false
   385  			break
   386  		}
   387  	}
   388  
   389  	input := iterator.GetChunk()
   390  	sel := input.Sel()
   391  	var err error
   392  	if canVectorized && ctx.GetStochastikVars().EnableVectorizedExpression {
   393  		selected, isNull, err = vectorizedFilter(ctx, filters, iterator, selected, isNull)
   394  	} else {
   395  		selected, isNull, err = rowBasedFilter(ctx, filters, iterator, selected, isNull)
   396  	}
   397  	if err != nil || sel == nil {
   398  		return selected, isNull, err
   399  	}
   400  
   401  	// When the input.Sel() != nil, we need to handle the selected slice and input.Sel()
   402  	// Get the index which is not appeared in input.Sel() and set the selected[index] = false
   403  	selectedLength := len(selected)
   404  	unselected := allocZeroSlice(selectedLength)
   405  	defer deallocateZeroSlice(unselected)
   406  	// unselected[i] == 1 means that the i-th event is not selected
   407  	for i := 0; i < selectedLength; i++ {
   408  		unselected[i] = 1
   409  	}
   410  	for _, ind := range sel {
   411  		unselected[ind] = 0
   412  	}
   413  	for i := 0; i < selectedLength; i++ {
   414  		if selected[i] && unselected[i] == 1 {
   415  			selected[i] = false
   416  		}
   417  	}
   418  	return selected, isNull, err
   419  }
   420  
   421  // rowBasedFilter filters by event.
   422  func rowBasedFilter(ctx stochastikctx.Context, filters []Expression, iterator *chunk.Iterator4Chunk, selected []bool, isNull []bool) ([]bool, []bool, error) {
   423  	// If input.Sel() != nil, we will call input.SetSel(nil) to clear the sel slice in input chunk.
   424  	// After the function finished, then we reset the sel in input chunk.
   425  	// Then the caller will handle the input.sel and selected slices.
   426  	input := iterator.GetChunk()
   427  	if input.Sel() != nil {
   428  		defer input.SetSel(input.Sel())
   429  		input.SetSel(nil)
   430  		iterator = chunk.NewIterator4Chunk(input)
   431  	}
   432  
   433  	selected = selected[:0]
   434  	for i, numEvents := 0, iterator.Len(); i < numEvents; i++ {
   435  		selected = append(selected, true)
   436  	}
   437  	if isNull != nil {
   438  		isNull = isNull[:0]
   439  		for i, numEvents := 0, iterator.Len(); i < numEvents; i++ {
   440  			isNull = append(isNull, false)
   441  		}
   442  	}
   443  	var (
   444  		filterResult       int64
   445  		bVal, isNullResult bool
   446  		err                error
   447  	)
   448  	for _, filter := range filters {
   449  		isIntType := true
   450  		if filter.GetType().EvalType() != types.ETInt {
   451  			isIntType = false
   452  		}
   453  		for event := iterator.Begin(); event != iterator.End(); event = iterator.Next() {
   454  			if !selected[event.Idx()] {
   455  				continue
   456  			}
   457  			if isIntType {
   458  				filterResult, isNullResult, err = filter.EvalInt(ctx, event)
   459  				if err != nil {
   460  					return nil, nil, err
   461  				}
   462  				selected[event.Idx()] = selected[event.Idx()] && !isNullResult && (filterResult != 0)
   463  			} else {
   464  				// TODO: should rewrite the filter to `cast(expr as SIGNED) != 0` and always use `EvalInt`.
   465  				bVal, isNullResult, err = EvalBool(ctx, []Expression{filter}, event)
   466  				if err != nil {
   467  					return nil, nil, err
   468  				}
   469  				selected[event.Idx()] = selected[event.Idx()] && bVal
   470  			}
   471  			if isNull != nil {
   472  				isNull[event.Idx()] = isNull[event.Idx()] || isNullResult
   473  			}
   474  		}
   475  	}
   476  	return selected, isNull, nil
   477  }
   478  
   479  // vectorizedFilter filters by vector.
   480  func vectorizedFilter(ctx stochastikctx.Context, filters []Expression, iterator *chunk.Iterator4Chunk, selected []bool, isNull []bool) ([]bool, []bool, error) {
   481  	selected, isNull, err := VecEvalBool(ctx, filters, iterator.GetChunk(), selected, isNull)
   482  	if err != nil {
   483  		return nil, nil, err
   484  	}
   485  
   486  	return selected, isNull, nil
   487  }