github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/common_plans.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 embedded 15 16 import ( 17 "bytes" 18 "context" 19 "fmt" 20 "strconv" 21 "strings" 22 23 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 24 "github.com/whtcorpsinc/BerolinaSQL/ast" 25 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 26 "github.com/whtcorpsinc/errors" 27 "github.com/whtcorpsinc/milevadb/causet" 28 "github.com/whtcorpsinc/milevadb/causet/blocks" 29 "github.com/whtcorpsinc/milevadb/ekv" 30 "github.com/whtcorpsinc/milevadb/memex" 31 "github.com/whtcorpsinc/milevadb/metrics" 32 "github.com/whtcorpsinc/milevadb/privilege" 33 "github.com/whtcorpsinc/milevadb/schemareplicant" 34 "github.com/whtcorpsinc/milevadb/soliton/chunk" 35 "github.com/whtcorpsinc/milevadb/soliton/ekvcache" 36 "github.com/whtcorpsinc/milevadb/soliton/hint" 37 "github.com/whtcorpsinc/milevadb/soliton/logutil" 38 "github.com/whtcorpsinc/milevadb/soliton/ranger" 39 "github.com/whtcorpsinc/milevadb/soliton/texttree" 40 "github.com/whtcorpsinc/milevadb/stochastikctx" 41 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 42 "github.com/whtcorpsinc/milevadb/types" 43 driver "github.com/whtcorpsinc/milevadb/types/BerolinaSQL_driver" 44 "go.uber.org/zap" 45 ) 46 47 var planCacheCounter = metrics.CausetCacheCounter.WithLabelValues("prepare") 48 49 // ShowDBS is for showing DBS information. 50 type ShowDBS struct { 51 baseSchemaProducer 52 } 53 54 // ShowSlow is for showing slow queries. 55 type ShowSlow struct { 56 baseSchemaProducer 57 58 *ast.ShowSlow 59 } 60 61 // ShowDBSJobQueries is for showing DBS job queries allegrosql. 62 type ShowDBSJobQueries struct { 63 baseSchemaProducer 64 65 JobIDs []int64 66 } 67 68 // ShowNextRowID is for showing the next global event ID. 69 type ShowNextRowID struct { 70 baseSchemaProducer 71 BlockName *ast.BlockName 72 } 73 74 // CheckBlock is used for checking causet data, built from the 'admin check causet' memex. 75 type CheckBlock struct { 76 baseSchemaProducer 77 78 DBName string 79 Block causet.Block 80 IndexInfos []*perceptron.IndexInfo 81 IndexLookUpReaders []*PhysicalIndexLookUpReader 82 ChecHoTTex bool 83 } 84 85 // RecoverIndex is used for backfilling corrupted index data. 86 type RecoverIndex struct { 87 baseSchemaProducer 88 89 Block *ast.BlockName 90 IndexName string 91 } 92 93 // CleanupIndex is used to delete dangling index data. 94 type CleanupIndex struct { 95 baseSchemaProducer 96 97 Block *ast.BlockName 98 IndexName string 99 } 100 101 // ChecHoTTexRange is used for checking index data, output the index values that handle within begin and end. 102 type ChecHoTTexRange struct { 103 baseSchemaProducer 104 105 Block *ast.BlockName 106 IndexName string 107 108 HandleRanges []ast.HandleRange 109 } 110 111 // ChecksumBlock is used for calculating causet checksum, built from the `admin checksum causet` memex. 112 type ChecksumBlock struct { 113 baseSchemaProducer 114 115 Blocks []*ast.BlockName 116 } 117 118 // CancelDBSJobs represents a cancel DBS jobs plan. 119 type CancelDBSJobs struct { 120 baseSchemaProducer 121 122 JobIDs []int64 123 } 124 125 // ReloadExprPushdownBlacklist reloads the data from expr_pushdown_blacklist causet. 126 type ReloadExprPushdownBlacklist struct { 127 baseSchemaProducer 128 } 129 130 // ReloadOptMemruleBlacklist reloads the data from opt_rule_blacklist causet. 131 type ReloadOptMemruleBlacklist struct { 132 baseSchemaProducer 133 } 134 135 // AdminPluginsCausetAction indicate action will be taken on plugins. 136 type AdminPluginsCausetAction int 137 138 const ( 139 // Enable indicates enable plugins. 140 Enable AdminPluginsCausetAction = iota + 1 141 // Disable indicates disable plugins. 142 Disable 143 ) 144 145 // AdminPlugins administrates milevadb plugins. 146 type AdminPlugins struct { 147 baseSchemaProducer 148 CausetAction AdminPluginsCausetAction 149 Plugins []string 150 } 151 152 // AdminShowTelemetry displays telemetry status including tracking ID, status and so on. 153 type AdminShowTelemetry struct { 154 baseSchemaProducer 155 } 156 157 // AdminResetTelemetryID regenerates a new telemetry tracking ID. 158 type AdminResetTelemetryID struct { 159 baseSchemaProducer 160 } 161 162 // Change represents a change plan. 163 type Change struct { 164 baseSchemaProducer 165 *ast.ChangeStmt 166 } 167 168 // Prepare represents prepare plan. 169 type Prepare struct { 170 baseSchemaProducer 171 172 Name string 173 ALLEGROSQLText string 174 } 175 176 // InterDircute represents prepare plan. 177 type InterDircute struct { 178 baseSchemaProducer 179 180 Name string 181 UsingVars []memex.Expression 182 PrepareParams []types.Causet 183 InterDircID uint32 184 Stmt ast.StmtNode 185 StmtType string 186 Causet Causet 187 } 188 189 // OptimizePreparedCauset optimizes the prepared memex. 190 func (e *InterDircute) OptimizePreparedCauset(ctx context.Context, sctx stochastikctx.Context, is schemareplicant.SchemaReplicant) error { 191 vars := sctx.GetStochastikVars() 192 if e.Name != "" { 193 e.InterDircID = vars.PreparedStmtNameToID[e.Name] 194 } 195 preparedPointer, ok := vars.PreparedStmts[e.InterDircID] 196 if !ok { 197 return errors.Trace(ErrStmtNotFound) 198 } 199 preparedObj, ok := preparedPointer.(*CachedPrepareStmt) 200 if !ok { 201 return errors.Errorf("invalid CachedPrepareStmt type") 202 } 203 prepared := preparedObj.PreparedAst 204 vars.StmtCtx.StmtType = prepared.StmtType 205 206 paramLen := len(e.PrepareParams) 207 if paramLen > 0 { 208 // for binary protocol execute, argument is placed in vars.PrepareParams 209 if len(prepared.Params) != paramLen { 210 return errors.Trace(ErrWrongParamCount) 211 } 212 vars.PreparedParams = e.PrepareParams 213 for i, val := range vars.PreparedParams { 214 param := prepared.Params[i].(*driver.ParamMarkerExpr) 215 param.Causet = val 216 param.InInterDircute = true 217 } 218 } else { 219 // for `execute stmt using @a, @b, @c`, using value in e.UsingVars 220 if len(prepared.Params) != len(e.UsingVars) { 221 return errors.Trace(ErrWrongParamCount) 222 } 223 224 for i, usingVar := range e.UsingVars { 225 val, err := usingVar.Eval(chunk.Row{}) 226 if err != nil { 227 return err 228 } 229 param := prepared.Params[i].(*driver.ParamMarkerExpr) 230 param.Causet = val 231 param.InInterDircute = true 232 vars.PreparedParams = append(vars.PreparedParams, val) 233 } 234 } 235 236 if prepared.SchemaVersion != is.SchemaMetaVersion() { 237 // In order to avoid some correctness issues, we have to clear the 238 // cached plan once the schemaReplicant version is changed. 239 // Cached plan in prepared struct does NOT have a "cache key" with 240 // schemaReplicant version like prepared plan cache key 241 prepared.CachedCauset = nil 242 preparedObj.InterlockingDirectorate = nil 243 // If the schemaReplicant version has changed we need to preprocess it again, 244 // if this time it failed, the real reason for the error is schemaReplicant changed. 245 err := Preprocess(sctx, prepared.Stmt, is, InPrepare) 246 if err != nil { 247 return ErrSchemaChanged.GenWithStack("Schema change caused error: %s", err.Error()) 248 } 249 prepared.SchemaVersion = is.SchemaMetaVersion() 250 } 251 err := e.getPhysicalCauset(ctx, sctx, is, preparedObj) 252 if err != nil { 253 return err 254 } 255 e.Stmt = prepared.Stmt 256 return nil 257 } 258 259 func (e *InterDircute) checkPreparedPriv(ctx context.Context, sctx stochastikctx.Context, 260 preparedObj *CachedPrepareStmt, is schemareplicant.SchemaReplicant) error { 261 if pm := privilege.GetPrivilegeManager(sctx); pm != nil { 262 if err := CheckPrivilege(sctx.GetStochastikVars().ActiveRoles, pm, preparedObj.VisitInfos); err != nil { 263 return err 264 } 265 } 266 err := CheckBlockLock(sctx, is, preparedObj.VisitInfos) 267 return err 268 } 269 270 func (e *InterDircute) setFoundInCausetCache(sctx stochastikctx.Context, opt bool) error { 271 vars := sctx.GetStochastikVars() 272 err := vars.SetSystemVar(variable.MilevaDBFoundInCausetCache, variable.BoolToIntStr(opt)) 273 return err 274 } 275 276 func (e *InterDircute) getPhysicalCauset(ctx context.Context, sctx stochastikctx.Context, is schemareplicant.SchemaReplicant, preparedStmt *CachedPrepareStmt) error { 277 stmtCtx := sctx.GetStochastikVars().StmtCtx 278 prepared := preparedStmt.PreparedAst 279 stmtCtx.UseCache = prepared.UseCache 280 var cacheKey ekvcache.Key 281 if prepared.UseCache { 282 cacheKey = NewPSTMTCausetCacheKey(sctx.GetStochastikVars(), e.InterDircID, prepared.SchemaVersion) 283 } 284 if prepared.CachedCauset != nil { 285 // Rewriting the memex in the select.where condition will convert its 286 // type from "paramMarker" to "Constant".When Point Select queries are executed, 287 // the memex in the where condition will not be evaluated, 288 // so you don't need to consider whether prepared.useCache is enabled. 289 plan := prepared.CachedCauset.(Causet) 290 names := prepared.CachedNames.(types.NameSlice) 291 err := e.rebuildRange(plan) 292 if err != nil { 293 logutil.BgLogger().Debug("rebuild range failed", zap.Error(err)) 294 goto REBUILD 295 } 296 if metrics.ResetblockCausetCacheCounterFortTest { 297 metrics.CausetCacheCounter.WithLabelValues("prepare").Inc() 298 } else { 299 planCacheCounter.Inc() 300 } 301 err = e.setFoundInCausetCache(sctx, true) 302 if err != nil { 303 return err 304 } 305 e.names = names 306 e.Causet = plan 307 stmtCtx.PointInterDirc = true 308 return nil 309 } 310 if prepared.UseCache { 311 if cacheValue, exists := sctx.PreparedCausetCache().Get(cacheKey); exists { 312 if err := e.checkPreparedPriv(ctx, sctx, preparedStmt, is); err != nil { 313 return err 314 } 315 cachedVal := cacheValue.(*PSTMTCausetCacheValue) 316 planValid := true 317 for tblInfo, unionScan := range cachedVal.TblInfo2UnionScan { 318 if !unionScan && blockHasDirtyContent(sctx, tblInfo) { 319 planValid = false 320 // TODO we can inject UnionScan into cached plan to avoid invalidating it, though 321 // rebuilding the filters in UnionScan is pretty trivial. 322 sctx.PreparedCausetCache().Delete(cacheKey) 323 break 324 } 325 } 326 if planValid { 327 err := e.rebuildRange(cachedVal.Causet) 328 if err != nil { 329 logutil.BgLogger().Debug("rebuild range failed", zap.Error(err)) 330 goto REBUILD 331 } 332 err = e.setFoundInCausetCache(sctx, true) 333 if err != nil { 334 return err 335 } 336 if metrics.ResetblockCausetCacheCounterFortTest { 337 metrics.CausetCacheCounter.WithLabelValues("prepare").Inc() 338 } else { 339 planCacheCounter.Inc() 340 } 341 e.names = cachedVal.OutPutNames 342 e.Causet = cachedVal.Causet 343 stmtCtx.SetCausetDigest(preparedStmt.NormalizedCauset, preparedStmt.CausetDigest) 344 return nil 345 } 346 } 347 } 348 349 REBUILD: 350 stmt := TryAddExtraLimit(sctx, prepared.Stmt) 351 p, names, err := OptimizeAstNode(ctx, sctx, stmt, is) 352 if err != nil { 353 return err 354 } 355 err = e.tryCachePointCauset(ctx, sctx, preparedStmt, is, p) 356 if err != nil { 357 return err 358 } 359 e.names = names 360 e.Causet = p 361 _, isBlockDual := p.(*PhysicalBlockDual) 362 if !isBlockDual && prepared.UseCache { 363 cached := NewPSTMTCausetCacheValue(p, names, stmtCtx.TblInfo2UnionScan) 364 preparedStmt.NormalizedCauset, preparedStmt.CausetDigest = NormalizeCauset(p) 365 stmtCtx.SetCausetDigest(preparedStmt.NormalizedCauset, preparedStmt.CausetDigest) 366 sctx.PreparedCausetCache().Put(cacheKey, cached) 367 } 368 err = e.setFoundInCausetCache(sctx, false) 369 return err 370 } 371 372 // tryCachePointCauset will try to cache point execution plan, there may be some 373 // short paths for these executions, currently "point select" and "point uFIDelate" 374 func (e *InterDircute) tryCachePointCauset(ctx context.Context, sctx stochastikctx.Context, 375 preparedStmt *CachedPrepareStmt, is schemareplicant.SchemaReplicant, p Causet) error { 376 var ( 377 prepared = preparedStmt.PreparedAst 378 ok bool 379 err error 380 names types.NameSlice 381 ) 382 switch p.(type) { 383 case *PointGetCauset: 384 ok, err = IsPointGetWithPKOrUniqueKeyByAutoCommit(sctx, p) 385 names = p.OutputNames() 386 if err != nil { 387 return err 388 } 389 case *UFIDelate: 390 ok, err = IsPointUFIDelateByAutoCommit(sctx, p) 391 if err != nil { 392 return err 393 } 394 if ok { 395 // make constant memex causetstore paramMarker 396 sctx.GetStochastikVars().StmtCtx.PointInterDirc = true 397 p, names, err = OptimizeAstNode(ctx, sctx, prepared.Stmt, is) 398 } 399 } 400 if ok { 401 // just cache point plan now 402 prepared.CachedCauset = p 403 prepared.CachedNames = names 404 preparedStmt.NormalizedCauset, preparedStmt.CausetDigest = NormalizeCauset(p) 405 sctx.GetStochastikVars().StmtCtx.SetCausetDigest(preparedStmt.NormalizedCauset, preparedStmt.CausetDigest) 406 } 407 return err 408 } 409 410 func (e *InterDircute) rebuildRange(p Causet) error { 411 sctx := p.SCtx() 412 sc := p.SCtx().GetStochastikVars().StmtCtx 413 var err error 414 switch x := p.(type) { 415 case *PhysicalBlockReader: 416 ts := x.BlockCausets[0].(*PhysicalBlockScan) 417 var pkDefCaus *memex.DeferredCauset 418 if ts.Block.IsCommonHandle { 419 pk := blocks.FindPrimaryIndex(ts.Block) 420 pkDefCauss := make([]*memex.DeferredCauset, 0, len(pk.DeferredCausets)) 421 pkDefCaussLen := make([]int, 0, len(pk.DeferredCausets)) 422 for _, colInfo := range pk.DeferredCausets { 423 pkDefCauss = append(pkDefCauss, memex.DefCausInfo2DefCaus(ts.schemaReplicant.DeferredCausets, ts.Block.DeferredCausets[colInfo.Offset])) 424 pkDefCaussLen = append(pkDefCaussLen, colInfo.Length) 425 } 426 res, err := ranger.DetachCondAndBuildRangeForIndex(p.SCtx(), ts.AccessCondition, pkDefCauss, pkDefCaussLen) 427 if err != nil { 428 return err 429 } 430 ts.Ranges = res.Ranges 431 } else { 432 if ts.Block.PKIsHandle { 433 if pkDefCausInfo := ts.Block.GetPkDefCausInfo(); pkDefCausInfo != nil { 434 pkDefCaus = memex.DefCausInfo2DefCaus(ts.schemaReplicant.DeferredCausets, pkDefCausInfo) 435 } 436 } 437 if pkDefCaus != nil { 438 ts.Ranges, err = ranger.BuildBlockRange(ts.AccessCondition, sc, pkDefCaus.RetType) 439 if err != nil { 440 return err 441 } 442 } else { 443 ts.Ranges = ranger.FullIntRange(false) 444 } 445 } 446 case *PhysicalIndexReader: 447 is := x.IndexCausets[0].(*PhysicalIndexScan) 448 is.Ranges, err = e.buildRangeForIndexScan(sctx, is) 449 if err != nil { 450 return err 451 } 452 case *PhysicalIndexLookUpReader: 453 is := x.IndexCausets[0].(*PhysicalIndexScan) 454 is.Ranges, err = e.buildRangeForIndexScan(sctx, is) 455 if err != nil { 456 return err 457 } 458 case *PointGetCauset: 459 // if access condition is not nil, which means it's a point get generated by cbo. 460 if x.AccessConditions != nil { 461 if x.IndexInfo != nil { 462 ranges, err := ranger.DetachCondAndBuildRangeForIndex(x.ctx, x.AccessConditions, x.IdxDefCauss, x.IdxDefCausLens) 463 if err != nil { 464 return err 465 } 466 for i := range x.IndexValues { 467 x.IndexValues[i] = ranges.Ranges[0].LowVal[i] 468 } 469 } else { 470 var pkDefCaus *memex.DeferredCauset 471 if x.TblInfo.PKIsHandle { 472 if pkDefCausInfo := x.TblInfo.GetPkDefCausInfo(); pkDefCausInfo != nil { 473 pkDefCaus = memex.DefCausInfo2DefCaus(x.schemaReplicant.DeferredCausets, pkDefCausInfo) 474 } 475 } 476 if pkDefCaus != nil { 477 ranges, err := ranger.BuildBlockRange(x.AccessConditions, x.ctx.GetStochastikVars().StmtCtx, pkDefCaus.RetType) 478 if err != nil { 479 return err 480 } 481 x.Handle = ekv.IntHandle(ranges[0].LowVal[0].GetInt64()) 482 } 483 } 484 } 485 // The code should never run here as long as we're not using point get for partition causet. 486 // And if we change the logic one day, here work as defensive programming to cache the error. 487 if x.PartitionInfo != nil { 488 return errors.New("point get for partition causet can not use plan cache") 489 } 490 if x.HandleParam != nil { 491 var iv int64 492 iv, err = x.HandleParam.Causet.ToInt64(sc) 493 if err != nil { 494 return err 495 } 496 x.Handle = ekv.IntHandle(iv) 497 return nil 498 } 499 for i, param := range x.IndexValueParams { 500 if param != nil { 501 x.IndexValues[i] = param.Causet 502 } 503 } 504 return nil 505 case *BatchPointGetCauset: 506 // if access condition is not nil, which means it's a point get generated by cbo. 507 if x.AccessConditions != nil { 508 if x.IndexInfo != nil { 509 ranges, err := ranger.DetachCondAndBuildRangeForIndex(x.ctx, x.AccessConditions, x.IdxDefCauss, x.IdxDefCausLens) 510 if err != nil { 511 return err 512 } 513 for i := range x.IndexValues { 514 for j := range ranges.Ranges[i].LowVal { 515 x.IndexValues[i][j] = ranges.Ranges[i].LowVal[j] 516 } 517 } 518 } else { 519 var pkDefCaus *memex.DeferredCauset 520 if x.TblInfo.PKIsHandle { 521 if pkDefCausInfo := x.TblInfo.GetPkDefCausInfo(); pkDefCausInfo != nil { 522 pkDefCaus = memex.DefCausInfo2DefCaus(x.schemaReplicant.DeferredCausets, pkDefCausInfo) 523 } 524 } 525 if pkDefCaus != nil { 526 ranges, err := ranger.BuildBlockRange(x.AccessConditions, x.ctx.GetStochastikVars().StmtCtx, pkDefCaus.RetType) 527 if err != nil { 528 return err 529 } 530 for i := range ranges { 531 x.Handles[i] = ekv.IntHandle(ranges[i].LowVal[0].GetInt64()) 532 } 533 } 534 } 535 } 536 for i, param := range x.HandleParams { 537 if param != nil { 538 var iv int64 539 iv, err = param.Causet.ToInt64(sc) 540 if err != nil { 541 return err 542 } 543 x.Handles[i] = ekv.IntHandle(iv) 544 } 545 } 546 for i, params := range x.IndexValueParams { 547 if len(params) < 1 { 548 continue 549 } 550 for j, param := range params { 551 if param != nil { 552 x.IndexValues[i][j] = param.Causet 553 } 554 } 555 } 556 case PhysicalCauset: 557 for _, child := range x.Children() { 558 err = e.rebuildRange(child) 559 if err != nil { 560 return err 561 } 562 } 563 case *Insert: 564 if x.SelectCauset != nil { 565 return e.rebuildRange(x.SelectCauset) 566 } 567 case *UFIDelate: 568 if x.SelectCauset != nil { 569 return e.rebuildRange(x.SelectCauset) 570 } 571 case *Delete: 572 if x.SelectCauset != nil { 573 return e.rebuildRange(x.SelectCauset) 574 } 575 } 576 return nil 577 } 578 579 func (e *InterDircute) buildRangeForIndexScan(sctx stochastikctx.Context, is *PhysicalIndexScan) ([]*ranger.Range, error) { 580 if len(is.IdxDefCauss) == 0 { 581 return ranger.FullRange(), nil 582 } 583 res, err := ranger.DetachCondAndBuildRangeForIndex(sctx, is.AccessCondition, is.IdxDefCauss, is.IdxDefCausLens) 584 if err != nil { 585 return nil, err 586 } 587 return res.Ranges, nil 588 } 589 590 // Deallocate represents deallocate plan. 591 type Deallocate struct { 592 baseSchemaProducer 593 594 Name string 595 } 596 597 // Set represents a plan for set stmt. 598 type Set struct { 599 baseSchemaProducer 600 601 VarAssigns []*memex.VarAssignment 602 } 603 604 // SetConfig represents a plan for set config stmt. 605 type SetConfig struct { 606 baseSchemaProducer 607 608 Type string 609 Instance string 610 Name string 611 Value memex.Expression 612 } 613 614 // ALLEGROSQLBindOpType repreents the ALLEGROALLEGROSQL bind type 615 type ALLEGROSQLBindOpType int 616 617 const ( 618 // OpALLEGROSQLBindCreate represents the operation to create a ALLEGROALLEGROSQL bind. 619 OpALLEGROSQLBindCreate ALLEGROSQLBindOpType = iota 620 // OpALLEGROSQLBindDrop represents the operation to drop a ALLEGROALLEGROSQL bind. 621 OpALLEGROSQLBindDrop 622 // OpFlushBindings is used to flush plan bindings. 623 OpFlushBindings 624 // OpCaptureBindings is used to capture plan bindings. 625 OpCaptureBindings 626 // OpEvolveBindings is used to evolve plan binding. 627 OpEvolveBindings 628 // OpReloadBindings is used to reload plan binding. 629 OpReloadBindings 630 ) 631 632 // ALLEGROSQLBindCauset represents a plan for ALLEGROALLEGROSQL bind. 633 type ALLEGROSQLBindCauset struct { 634 baseSchemaProducer 635 636 ALLEGROSQLBindOp ALLEGROSQLBindOpType 637 NormdOrigALLEGROSQL string 638 BindALLEGROSQL string 639 IsGlobal bool 640 BindStmt ast.StmtNode 641 EDB string 642 Charset string 643 DefCauslation string 644 } 645 646 // Simple represents a simple memex plan which doesn't need any optimization. 647 type Simple struct { 648 baseSchemaProducer 649 650 Statement ast.StmtNode 651 } 652 653 // InsertGeneratedDeferredCausets is for completing generated columns in Insert. 654 // We resolve generation memexs in plan, and eval those in interlock. 655 type InsertGeneratedDeferredCausets struct { 656 DeferredCausets []*ast.DeferredCausetName 657 Exprs []memex.Expression 658 OnDuplicates []*memex.Assignment 659 } 660 661 // Insert represents an insert plan. 662 type Insert struct { 663 baseSchemaProducer 664 665 Block causet.Block 666 blockSchema *memex.Schema 667 blockDefCausNames types.NameSlice 668 DeferredCausets []*ast.DeferredCausetName 669 Lists [][]memex.Expression 670 SetList []*memex.Assignment 671 672 OnDuplicate []*memex.Assignment 673 Schema4OnDuplicate *memex.Schema 674 names4OnDuplicate types.NameSlice 675 676 GenDefCauss InsertGeneratedDeferredCausets 677 678 SelectCauset PhysicalCauset 679 680 IsReplace bool 681 682 // NeedFillDefaultValue is true when expr in value list reference other column. 683 NeedFillDefaultValue bool 684 685 AllAssignmentsAreConstant bool 686 } 687 688 // UFIDelate represents UFIDelate plan. 689 type UFIDelate struct { 690 baseSchemaProducer 691 692 OrderedList []*memex.Assignment 693 694 AllAssignmentsAreConstant bool 695 696 SelectCauset PhysicalCauset 697 698 TblDefCausPosInfos TblDefCausPosInfoSlice 699 700 // Used when partition sets are given. 701 // e.g. uFIDelate t partition(p0) set a = 1; 702 PartitionedBlock []causet.PartitionedBlock 703 } 704 705 // Delete represents a delete plan. 706 type Delete struct { 707 baseSchemaProducer 708 709 IsMultiBlock bool 710 711 SelectCauset PhysicalCauset 712 713 TblDefCausPosInfos TblDefCausPosInfoSlice 714 } 715 716 // AnalyzeBlockID is hybrid causet id used to analyze causet. 717 type AnalyzeBlockID struct { 718 PersistID int64 719 DefCauslectIDs []int64 720 } 721 722 // StoreAsDefCauslectID indicates whether collect causet id is same as persist causet id. 723 // for new partition implementation is TRUE but FALSE for old partition implementation 724 func (h *AnalyzeBlockID) StoreAsDefCauslectID() bool { 725 return h.PersistID == h.DefCauslectIDs[0] 726 } 727 728 func (h *AnalyzeBlockID) String() string { 729 return fmt.Sprintf("%d => %v", h.DefCauslectIDs, h.PersistID) 730 } 731 732 // Equals indicates whether two causet id is equal. 733 func (h *AnalyzeBlockID) Equals(t *AnalyzeBlockID) bool { 734 if h == t { 735 return true 736 } 737 if h == nil || t == nil { 738 return false 739 } 740 if h.PersistID != t.PersistID { 741 return false 742 } 743 if len(h.DefCauslectIDs) != len(t.DefCauslectIDs) { 744 return false 745 } 746 if len(h.DefCauslectIDs) == 1 { 747 return h.DefCauslectIDs[0] == t.DefCauslectIDs[0] 748 } 749 for _, hp := range h.DefCauslectIDs { 750 var matchOne bool 751 for _, tp := range t.DefCauslectIDs { 752 if tp == hp { 753 matchOne = true 754 break 755 } 756 } 757 if !matchOne { 758 return false 759 } 760 } 761 return true 762 } 763 764 // analyzeInfo is used to causetstore the database name, causet name and partition name of analyze task. 765 type analyzeInfo struct { 766 DBName string 767 BlockName string 768 PartitionName string 769 BlockID AnalyzeBlockID 770 Incremental bool 771 } 772 773 // AnalyzeDeferredCausetsTask is used for analyze columns. 774 type AnalyzeDeferredCausetsTask struct { 775 HandleDefCauss HandleDefCauss 776 DefCaussInfo []*perceptron.DeferredCausetInfo 777 TblInfo *perceptron.BlockInfo 778 analyzeInfo 779 } 780 781 // AnalyzeIndexTask is used for analyze index. 782 type AnalyzeIndexTask struct { 783 IndexInfo *perceptron.IndexInfo 784 TblInfo *perceptron.BlockInfo 785 analyzeInfo 786 } 787 788 // Analyze represents an analyze plan 789 type Analyze struct { 790 baseSchemaProducer 791 792 DefCausTasks []AnalyzeDeferredCausetsTask 793 IdxTasks []AnalyzeIndexTask 794 Opts map[ast.AnalyzeOptionType]uint64 795 } 796 797 // LoadData represents a loaddata plan. 798 type LoadData struct { 799 baseSchemaProducer 800 801 IsLocal bool 802 OnDuplicate ast.OnDuplicateKeyHandlingType 803 Path string 804 Block *ast.BlockName 805 DeferredCausets []*ast.DeferredCausetName 806 FieldsInfo *ast.FieldsClause 807 LinesInfo *ast.LinesClause 808 IgnoreLines uint64 809 810 DeferredCausetAssignments []*ast.Assignment 811 DeferredCausetsAndUserVars []*ast.DeferredCausetNameOrUserVar 812 813 GenDefCauss InsertGeneratedDeferredCausets 814 } 815 816 // LoadStats represents a load stats plan. 817 type LoadStats struct { 818 baseSchemaProducer 819 820 Path string 821 } 822 823 // IndexAdvise represents a index advise plan. 824 type IndexAdvise struct { 825 baseSchemaProducer 826 827 IsLocal bool 828 Path string 829 MaxMinutes uint64 830 MaxIndexNum *ast.MaxIndexNumClause 831 LinesInfo *ast.LinesClause 832 } 833 834 // SplitRegion represents a split regions plan. 835 type SplitRegion struct { 836 baseSchemaProducer 837 838 BlockInfo *perceptron.BlockInfo 839 PartitionNames []perceptron.CIStr 840 IndexInfo *perceptron.IndexInfo 841 Lower []types.Causet 842 Upper []types.Causet 843 Num int 844 ValueLists [][]types.Causet 845 } 846 847 // SplitRegionStatus represents a split regions status plan. 848 type SplitRegionStatus struct { 849 baseSchemaProducer 850 851 Block causet.Block 852 IndexInfo *perceptron.IndexInfo 853 } 854 855 // DBS represents a DBS memex plan. 856 type DBS struct { 857 baseSchemaProducer 858 859 Statement ast.DBSNode 860 } 861 862 // SelectInto represents a select-into plan. 863 type SelectInto struct { 864 baseSchemaProducer 865 866 TargetCauset Causet 867 IntoOpt *ast.SelectIntoOption 868 } 869 870 // Explain represents a explain plan. 871 type Explain struct { 872 baseSchemaProducer 873 874 TargetCauset Causet 875 Format string 876 Analyze bool 877 InterDircStmt ast.StmtNode 878 879 Rows [][]string 880 explainedCausets map[int]bool 881 } 882 883 // GetExplainRowsForCauset get explain rows for plan. 884 func GetExplainRowsForCauset(plan Causet) (rows [][]string) { 885 explain := &Explain{ 886 TargetCauset: plan, 887 Format: ast.ExplainFormatROW, 888 Analyze: false, 889 } 890 if err := explain.RenderResult(); err != nil { 891 return rows 892 } 893 return explain.Rows 894 } 895 896 // prepareSchema prepares explain's result schemaReplicant. 897 func (e *Explain) prepareSchema() error { 898 var fieldNames []string 899 format := strings.ToLower(e.Format) 900 901 switch { 902 case format == ast.ExplainFormatROW && !e.Analyze: 903 fieldNames = []string{"id", "estRows", "task", "access object", "operator info"} 904 case format == ast.ExplainFormatROW && e.Analyze: 905 fieldNames = []string{"id", "estRows", "actRows", "task", "access object", "execution info", "operator info", "memory", "disk"} 906 case format == ast.ExplainFormatDOT: 907 fieldNames = []string{"dot contents"} 908 case format == ast.ExplainFormatHint: 909 fieldNames = []string{"hint"} 910 default: 911 return errors.Errorf("explain format '%s' is not supported now", e.Format) 912 } 913 914 cwn := &columnsWithNames{ 915 defcaus: make([]*memex.DeferredCauset, 0, len(fieldNames)), 916 names: make([]*types.FieldName, 0, len(fieldNames)), 917 } 918 919 for _, fieldName := range fieldNames { 920 cwn.Append(buildDeferredCausetWithName("", fieldName, allegrosql.TypeString, allegrosql.MaxBlobWidth)) 921 } 922 e.SetSchema(cwn.col2Schema()) 923 e.names = cwn.names 924 return nil 925 } 926 927 // RenderResult renders the explain result as specified format. 928 func (e *Explain) RenderResult() error { 929 if e.TargetCauset == nil { 930 return nil 931 } 932 switch strings.ToLower(e.Format) { 933 case ast.ExplainFormatROW: 934 if e.Rows == nil || e.Analyze { 935 e.explainedCausets = map[int]bool{} 936 err := e.explainCausetInRowFormat(e.TargetCauset, "root", "", "", true) 937 if err != nil { 938 return err 939 } 940 } 941 case ast.ExplainFormatDOT: 942 if physicalCauset, ok := e.TargetCauset.(PhysicalCauset); ok { 943 e.prepareDotInfo(physicalCauset) 944 } 945 case ast.ExplainFormatHint: 946 hints := GenHintsFromPhysicalCauset(e.TargetCauset) 947 hints = append(hints, hint.ExtractBlockHintsFromStmtNode(e.InterDircStmt, nil)...) 948 e.Rows = append(e.Rows, []string{hint.RestoreOptimizerHints(hints)}) 949 default: 950 return errors.Errorf("explain format '%s' is not supported now", e.Format) 951 } 952 return nil 953 } 954 955 // explainCausetInRowFormat generates explain information for root-tasks. 956 func (e *Explain) explainCausetInRowFormat(p Causet, taskType, driverSide, indent string, isLastChild bool) (err error) { 957 e.prepareOperatorInfo(p, taskType, driverSide, indent, isLastChild) 958 e.explainedCausets[p.ID()] = true 959 960 // For every child we create a new sub-tree rooted by it. 961 childIndent := texttree.Indent4Child(indent, isLastChild) 962 963 if physCauset, ok := p.(PhysicalCauset); ok { 964 // indicate driven side and driving side of 'join' and 'apply' 965 // See issue https://github.com/whtcorpsinc/milevadb/issues/14602. 966 driverSideInfo := make([]string, len(physCauset.Children())) 967 buildSide := -1 968 969 switch plan := physCauset.(type) { 970 case *PhysicalApply: 971 buildSide = plan.InnerChildIdx ^ 1 972 case *PhysicalHashJoin: 973 if plan.UseOuterToBuild { 974 buildSide = plan.InnerChildIdx ^ 1 975 } else { 976 buildSide = plan.InnerChildIdx 977 } 978 case *PhysicalMergeJoin: 979 if plan.JoinType == RightOuterJoin { 980 buildSide = 0 981 } else { 982 buildSide = 1 983 } 984 case *PhysicalIndexJoin: 985 buildSide = plan.InnerChildIdx ^ 1 986 case *PhysicalIndexMergeJoin: 987 buildSide = plan.InnerChildIdx ^ 1 988 case *PhysicalIndexHashJoin: 989 buildSide = plan.InnerChildIdx ^ 1 990 case *PhysicalBroadCastJoin: 991 buildSide = plan.InnerChildIdx 992 } 993 994 if buildSide != -1 { 995 driverSideInfo[0], driverSideInfo[1] = "(Build)", "(Probe)" 996 } else { 997 buildSide = 0 998 } 999 1000 // Always put the Build above the Probe. 1001 for i := range physCauset.Children() { 1002 pchild := &physCauset.Children()[i^buildSide] 1003 if e.explainedCausets[(*pchild).ID()] { 1004 continue 1005 } 1006 err = e.explainCausetInRowFormat(*pchild, taskType, driverSideInfo[i], childIndent, i == len(physCauset.Children())-1) 1007 if err != nil { 1008 return 1009 } 1010 } 1011 } 1012 1013 switch x := p.(type) { 1014 case *PhysicalBlockReader: 1015 var storeType string 1016 switch x.StoreType { 1017 case ekv.EinsteinDB, ekv.TiFlash, ekv.MilevaDB: 1018 // expected do nothing 1019 default: 1020 return errors.Errorf("the causetstore type %v is unknown", x.StoreType) 1021 } 1022 storeType = x.StoreType.Name() 1023 err = e.explainCausetInRowFormat(x.blockCauset, "cop["+storeType+"]", "", childIndent, true) 1024 case *PhysicalIndexReader: 1025 err = e.explainCausetInRowFormat(x.indexCauset, "cop[einsteindb]", "", childIndent, true) 1026 case *PhysicalIndexLookUpReader: 1027 err = e.explainCausetInRowFormat(x.indexCauset, "cop[einsteindb]", "(Build)", childIndent, false) 1028 err = e.explainCausetInRowFormat(x.blockCauset, "cop[einsteindb]", "(Probe)", childIndent, true) 1029 case *PhysicalIndexMergeReader: 1030 for _, pchild := range x.partialCausets { 1031 err = e.explainCausetInRowFormat(pchild, "cop[einsteindb]", "(Build)", childIndent, false) 1032 } 1033 err = e.explainCausetInRowFormat(x.blockCauset, "cop[einsteindb]", "(Probe)", childIndent, true) 1034 case *Insert: 1035 if x.SelectCauset != nil { 1036 err = e.explainCausetInRowFormat(x.SelectCauset, "root", "", childIndent, true) 1037 } 1038 case *UFIDelate: 1039 if x.SelectCauset != nil { 1040 err = e.explainCausetInRowFormat(x.SelectCauset, "root", "", childIndent, true) 1041 } 1042 case *Delete: 1043 if x.SelectCauset != nil { 1044 err = e.explainCausetInRowFormat(x.SelectCauset, "root", "", childIndent, true) 1045 } 1046 case *InterDircute: 1047 if x.Causet != nil { 1048 err = e.explainCausetInRowFormat(x.Causet, "root", "", indent, true) 1049 } 1050 } 1051 return 1052 } 1053 1054 func getRuntimeInfo(ctx stochastikctx.Context, p Causet) (actRows, analyzeInfo, memoryInfo, diskInfo string) { 1055 runtimeStatsDefCausl := ctx.GetStochastikVars().StmtCtx.RuntimeStatsDefCausl 1056 if runtimeStatsDefCausl == nil { 1057 return 1058 } 1059 explainID := p.ID() 1060 1061 // There maybe some mock information for cop task to let runtimeStatsDefCausl.Exists(p.ExplainID()) is true. 1062 // So check copTaskEkxecDetail first and print the real cop task information if it's not empty. 1063 if runtimeStatsDefCausl.ExistsCopStats(explainID) { 1064 copstats := runtimeStatsDefCausl.GetCopStats(explainID) 1065 analyzeInfo = copstats.String() 1066 actRows = fmt.Sprint(copstats.GetActRows()) 1067 } else if runtimeStatsDefCausl.ExistsRootStats(explainID) { 1068 rootstats := runtimeStatsDefCausl.GetRootStats(explainID) 1069 analyzeInfo = rootstats.String() 1070 actRows = fmt.Sprint(rootstats.GetActRows()) 1071 } else { 1072 analyzeInfo = "time:0ns, loops:0" 1073 actRows = "0" 1074 } 1075 1076 memoryInfo = "N/A" 1077 memTracker := ctx.GetStochastikVars().StmtCtx.MemTracker.SearchTrackerWithoutLock(p.ID()) 1078 if memTracker != nil { 1079 memoryInfo = memTracker.BytesToString(memTracker.MaxConsumed()) 1080 } 1081 1082 diskInfo = "N/A" 1083 diskTracker := ctx.GetStochastikVars().StmtCtx.DiskTracker.SearchTrackerWithoutLock(p.ID()) 1084 if diskTracker != nil { 1085 diskInfo = diskTracker.BytesToString(diskTracker.MaxConsumed()) 1086 } 1087 return 1088 } 1089 1090 // prepareOperatorInfo generates the following information for every plan: 1091 // operator id, estimated rows, task type, access object and other operator info. 1092 func (e *Explain) prepareOperatorInfo(p Causet, taskType, driverSide, indent string, isLastChild bool) { 1093 if p.ExplainID().String() == "_0" { 1094 return 1095 } 1096 1097 id := texttree.PrettyIdentifier(p.ExplainID().String()+driverSide, indent, isLastChild) 1098 1099 estRows := "N/A" 1100 if si := p.statsInfo(); si != nil { 1101 estRows = strconv.FormatFloat(si.RowCount, 'f', 2, 64) 1102 } 1103 1104 var accessObject, operatorInfo string 1105 if plan, ok := p.(dataAccesser); ok { 1106 accessObject = plan.AccessObject() 1107 operatorInfo = plan.OperatorInfo(false) 1108 } else { 1109 if pa, ok := p.(partitionAccesser); ok && e.ctx != nil { 1110 accessObject = pa.accessObject(e.ctx) 1111 } 1112 operatorInfo = p.ExplainInfo() 1113 } 1114 1115 var event []string 1116 if e.Analyze { 1117 actRows, analyzeInfo, memoryInfo, diskInfo := getRuntimeInfo(e.ctx, p) 1118 event = []string{id, estRows, actRows, taskType, accessObject, analyzeInfo, operatorInfo, memoryInfo, diskInfo} 1119 } else { 1120 event = []string{id, estRows, taskType, accessObject, operatorInfo} 1121 } 1122 e.Rows = append(e.Rows, event) 1123 } 1124 1125 func (e *Explain) prepareDotInfo(p PhysicalCauset) { 1126 buffer := bytes.NewBufferString("") 1127 fmt.Fprintf(buffer, "\ndigraph %s {\n", p.ExplainID()) 1128 e.prepareTaskDot(p, "root", buffer) 1129 buffer.WriteString("}\n") 1130 1131 e.Rows = append(e.Rows, []string{buffer.String()}) 1132 } 1133 1134 func (e *Explain) prepareTaskDot(p PhysicalCauset, taskTp string, buffer *bytes.Buffer) { 1135 fmt.Fprintf(buffer, "subgraph cluster%v{\n", p.ID()) 1136 buffer.WriteString("node [style=filled, color=lightgrey]\n") 1137 buffer.WriteString("color=black\n") 1138 fmt.Fprintf(buffer, "label = \"%s\"\n", taskTp) 1139 1140 if len(p.Children()) == 0 { 1141 if taskTp == "cop" { 1142 fmt.Fprintf(buffer, "\"%s\"\n}\n", p.ExplainID()) 1143 return 1144 } 1145 fmt.Fprintf(buffer, "\"%s\"\n", p.ExplainID()) 1146 } 1147 1148 var CausetTasks []PhysicalCauset 1149 var pipelines []string 1150 1151 for planQueue := []PhysicalCauset{p}; len(planQueue) > 0; planQueue = planQueue[1:] { 1152 curCauset := planQueue[0] 1153 switch copCauset := curCauset.(type) { 1154 case *PhysicalBlockReader: 1155 pipelines = append(pipelines, fmt.Sprintf("\"%s\" -> \"%s\"\n", copCauset.ExplainID(), copCauset.blockCauset.ExplainID())) 1156 CausetTasks = append(CausetTasks, copCauset.blockCauset) 1157 case *PhysicalIndexReader: 1158 pipelines = append(pipelines, fmt.Sprintf("\"%s\" -> \"%s\"\n", copCauset.ExplainID(), copCauset.indexCauset.ExplainID())) 1159 CausetTasks = append(CausetTasks, copCauset.indexCauset) 1160 case *PhysicalIndexLookUpReader: 1161 pipelines = append(pipelines, fmt.Sprintf("\"%s\" -> \"%s\"\n", copCauset.ExplainID(), copCauset.blockCauset.ExplainID())) 1162 pipelines = append(pipelines, fmt.Sprintf("\"%s\" -> \"%s\"\n", copCauset.ExplainID(), copCauset.indexCauset.ExplainID())) 1163 CausetTasks = append(CausetTasks, copCauset.blockCauset) 1164 CausetTasks = append(CausetTasks, copCauset.indexCauset) 1165 case *PhysicalIndexMergeReader: 1166 for i := 0; i < len(copCauset.partialCausets); i++ { 1167 pipelines = append(pipelines, fmt.Sprintf("\"%s\" -> \"%s\"\n", copCauset.ExplainID(), copCauset.partialCausets[i].ExplainID())) 1168 CausetTasks = append(CausetTasks, copCauset.partialCausets[i]) 1169 } 1170 if copCauset.blockCauset != nil { 1171 pipelines = append(pipelines, fmt.Sprintf("\"%s\" -> \"%s\"\n", copCauset.ExplainID(), copCauset.blockCauset.ExplainID())) 1172 CausetTasks = append(CausetTasks, copCauset.blockCauset) 1173 } 1174 } 1175 for _, child := range curCauset.Children() { 1176 fmt.Fprintf(buffer, "\"%s\" -> \"%s\"\n", curCauset.ExplainID(), child.ExplainID()) 1177 planQueue = append(planQueue, child) 1178 } 1179 } 1180 buffer.WriteString("}\n") 1181 1182 for _, cop := range CausetTasks { 1183 e.prepareTaskDot(cop.(PhysicalCauset), "cop", buffer) 1184 } 1185 1186 for i := range pipelines { 1187 buffer.WriteString(pipelines[i]) 1188 } 1189 } 1190 1191 // IsPointGetWithPKOrUniqueKeyByAutoCommit returns true when meets following conditions: 1192 // 1. ctx is auto commit tagged 1193 // 2. stochastik is not InTxn 1194 // 3. plan is point get by pk, or point get by unique index (no double read) 1195 func IsPointGetWithPKOrUniqueKeyByAutoCommit(ctx stochastikctx.Context, p Causet) (bool, error) { 1196 if !IsAutoCommitTxn(ctx) { 1197 return false, nil 1198 } 1199 1200 // check plan 1201 if proj, ok := p.(*PhysicalProjection); ok { 1202 p = proj.Children()[0] 1203 } 1204 1205 switch v := p.(type) { 1206 case *PhysicalIndexReader: 1207 indexScan := v.IndexCausets[0].(*PhysicalIndexScan) 1208 return indexScan.IsPointGetByUniqueKey(ctx.GetStochastikVars().StmtCtx), nil 1209 case *PhysicalBlockReader: 1210 blockScan := v.BlockCausets[0].(*PhysicalBlockScan) 1211 isPointRange := len(blockScan.Ranges) == 1 && blockScan.Ranges[0].IsPoint(ctx.GetStochastikVars().StmtCtx) 1212 if !isPointRange { 1213 return false, nil 1214 } 1215 pkLength := 1 1216 if blockScan.Block.IsCommonHandle { 1217 pkIdx := blocks.FindPrimaryIndex(blockScan.Block) 1218 pkLength = len(pkIdx.DeferredCausets) 1219 } 1220 return len(blockScan.Ranges[0].LowVal) == pkLength, nil 1221 case *PointGetCauset: 1222 // If the PointGetCauset needs to read data using unique index (double read), we 1223 // can't use max uint64, because using math.MaxUint64 can't guarantee repeablock-read 1224 // and the data and index would be inconsistent! 1225 isPointGet := v.IndexInfo == nil || (v.IndexInfo.Primary && v.TblInfo.IsCommonHandle) 1226 return isPointGet, nil 1227 default: 1228 return false, nil 1229 } 1230 } 1231 1232 // IsAutoCommitTxn checks if stochastik is in autocommit mode and not InTxn 1233 // used for fast plan like point get 1234 func IsAutoCommitTxn(ctx stochastikctx.Context) bool { 1235 return ctx.GetStochastikVars().IsAutocommit() && !ctx.GetStochastikVars().InTxn() 1236 } 1237 1238 // IsPointUFIDelateByAutoCommit checks if plan p is point uFIDelate and is in autocommit context 1239 func IsPointUFIDelateByAutoCommit(ctx stochastikctx.Context, p Causet) (bool, error) { 1240 if !IsAutoCommitTxn(ctx) { 1241 return false, nil 1242 } 1243 1244 // check plan 1245 uFIDelCauset, ok := p.(*UFIDelate) 1246 if !ok { 1247 return false, nil 1248 } 1249 if _, isFastSel := uFIDelCauset.SelectCauset.(*PointGetCauset); isFastSel { 1250 return true, nil 1251 } 1252 return false, nil 1253 } 1254 1255 func buildSchemaAndNameFromIndex(defcaus []*memex.DeferredCauset, dbName perceptron.CIStr, tblInfo *perceptron.BlockInfo, idxInfo *perceptron.IndexInfo) (*memex.Schema, types.NameSlice) { 1256 schemaReplicant := memex.NewSchema(defcaus...) 1257 idxDefCauss := idxInfo.DeferredCausets 1258 names := make([]*types.FieldName, 0, len(idxDefCauss)) 1259 tblName := tblInfo.Name 1260 for _, col := range idxDefCauss { 1261 names = append(names, &types.FieldName{ 1262 OrigTblName: tblName, 1263 OrigDefCausName: col.Name, 1264 DBName: dbName, 1265 TblName: tblName, 1266 DefCausName: col.Name, 1267 }) 1268 } 1269 return schemaReplicant, names 1270 } 1271 1272 func buildSchemaAndNameFromPKDefCaus(pkDefCaus *memex.DeferredCauset, dbName perceptron.CIStr, tblInfo *perceptron.BlockInfo) (*memex.Schema, types.NameSlice) { 1273 schemaReplicant := memex.NewSchema([]*memex.DeferredCauset{pkDefCaus}...) 1274 names := make([]*types.FieldName, 0, 1) 1275 tblName := tblInfo.Name 1276 col := tblInfo.GetPkDefCausInfo() 1277 names = append(names, &types.FieldName{ 1278 OrigTblName: tblName, 1279 OrigDefCausName: col.Name, 1280 DBName: dbName, 1281 TblName: tblName, 1282 DefCausName: col.Name, 1283 }) 1284 return schemaReplicant, names 1285 } 1286 1287 func locateHashPartition(ctx stochastikctx.Context, expr memex.Expression, pi *perceptron.PartitionInfo, r []types.Causet) (int, error) { 1288 ret, isNull, err := expr.EvalInt(ctx, chunk.MutRowFromCausets(r).ToRow()) 1289 if err != nil { 1290 return 0, err 1291 } 1292 if isNull { 1293 return 0, nil 1294 } 1295 if ret < 0 { 1296 ret = 0 - ret 1297 } 1298 return int(ret % int64(pi.Num)), nil 1299 }