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 }