github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/causet/embedded/logical_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 "math" 18 19 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 20 "github.com/whtcorpsinc/BerolinaSQL/ast" 21 "github.com/whtcorpsinc/BerolinaSQL/auth" 22 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 23 "github.com/whtcorpsinc/milevadb/causet" 24 "github.com/whtcorpsinc/milevadb/causet/property" 25 "github.com/whtcorpsinc/milevadb/causet/soliton" 26 "github.com/whtcorpsinc/milevadb/memex" 27 "github.com/whtcorpsinc/milevadb/memex/aggregation" 28 "github.com/whtcorpsinc/milevadb/soliton/logutil" 29 "github.com/whtcorpsinc/milevadb/soliton/ranger" 30 "github.com/whtcorpsinc/milevadb/statistics" 31 "github.com/whtcorpsinc/milevadb/types" 32 "go.uber.org/zap" 33 ) 34 35 var ( 36 _ LogicalCauset = &LogicalJoin{} 37 _ LogicalCauset = &LogicalAggregation{} 38 _ LogicalCauset = &LogicalProjection{} 39 _ LogicalCauset = &LogicalSelection{} 40 _ LogicalCauset = &LogicalApply{} 41 _ LogicalCauset = &LogicalMaxOneRow{} 42 _ LogicalCauset = &LogicalBlockDual{} 43 _ LogicalCauset = &DataSource{} 44 _ LogicalCauset = &EinsteinDBSingleGather{} 45 _ LogicalCauset = &LogicalBlockScan{} 46 _ LogicalCauset = &LogicalIndexScan{} 47 _ LogicalCauset = &LogicalUnionAll{} 48 _ LogicalCauset = &LogicalSort{} 49 _ LogicalCauset = &LogicalLock{} 50 _ LogicalCauset = &LogicalLimit{} 51 _ LogicalCauset = &LogicalWindow{} 52 ) 53 54 // JoinType contains CrossJoin, InnerJoin, LeftOuterJoin, RightOuterJoin, FullOuterJoin, SemiJoin. 55 type JoinType int 56 57 const ( 58 // InnerJoin means inner join. 59 InnerJoin JoinType = iota 60 // LeftOuterJoin means left join. 61 LeftOuterJoin 62 // RightOuterJoin means right join. 63 RightOuterJoin 64 // SemiJoin means if event a in causet A matches some rows in B, just output a. 65 SemiJoin 66 // AntiSemiJoin means if event a in causet A does not match any event in B, then output a. 67 AntiSemiJoin 68 // LeftOuterSemiJoin means if event a in causet A matches some rows in B, output (a, true), otherwise, output (a, false). 69 LeftOuterSemiJoin 70 // AntiLeftOuterSemiJoin means if event a in causet A matches some rows in B, output (a, false), otherwise, output (a, true). 71 AntiLeftOuterSemiJoin 72 ) 73 74 // IsOuterJoin returns if this joiner is a outer joiner 75 func (tp JoinType) IsOuterJoin() bool { 76 return tp == LeftOuterJoin || tp == RightOuterJoin || 77 tp == LeftOuterSemiJoin || tp == AntiLeftOuterSemiJoin 78 } 79 80 func (tp JoinType) String() string { 81 switch tp { 82 case InnerJoin: 83 return "inner join" 84 case LeftOuterJoin: 85 return "left outer join" 86 case RightOuterJoin: 87 return "right outer join" 88 case SemiJoin: 89 return "semi join" 90 case AntiSemiJoin: 91 return "anti semi join" 92 case LeftOuterSemiJoin: 93 return "left outer semi join" 94 case AntiLeftOuterSemiJoin: 95 return "anti left outer semi join" 96 } 97 return "unsupported join type" 98 } 99 100 const ( 101 preferLeftAsINLJInner uint = 1 << iota 102 preferRightAsINLJInner 103 preferLeftAsINLHJInner 104 preferRightAsINLHJInner 105 preferLeftAsINLMJInner 106 preferRightAsINLMJInner 107 preferHashJoin 108 preferMergeJoin 109 preferBCJoin 110 preferHashAgg 111 preferStreamAgg 112 ) 113 114 const ( 115 preferEinsteinDB = 1 << iota 116 preferTiFlash 117 ) 118 119 // LogicalJoin is the logical join plan. 120 type LogicalJoin struct { 121 logicalSchemaProducer 122 123 JoinType JoinType 124 reordered bool 125 cartesianJoin bool 126 StraightJoin bool 127 128 // hintInfo stores the join algorithm hint information specified by client. 129 hintInfo *blockHintInfo 130 preferJoinType uint 131 132 EqualConditions []*memex.ScalarFunction 133 LeftConditions memex.CNFExprs 134 RightConditions memex.CNFExprs 135 OtherConditions memex.CNFExprs 136 137 leftProperties [][]*memex.DeferredCauset 138 rightProperties [][]*memex.DeferredCauset 139 140 // DefaultValues is only used for left/right outer join, which is values the inner event's should be when the outer causet 141 // doesn't match any inner causet's event. 142 // That it's nil just means the default values is a slice of NULL. 143 // Currently, only `aggregation push down` phase will set this. 144 DefaultValues []types.Causet 145 146 // redundantSchema contains columns which are eliminated in join. 147 // For select * from a join b using (c); a.c will in output schemaReplicant, and b.c will in redundantSchema. 148 redundantSchema *memex.Schema 149 redundantNames types.NameSlice 150 151 // equalCondOutCnt indicates the estimated count of joined rows after evaluating `EqualConditions`. 152 equalCondOutCnt float64 153 } 154 155 // Shallow shallow copies a LogicalJoin struct. 156 func (p *LogicalJoin) Shallow() *LogicalJoin { 157 join := *p 158 return join.Init(p.ctx, p.blockOffset) 159 } 160 161 // GetJoinKeys extracts join keys(columns) from EqualConditions. It returns left join keys, right 162 // join keys and an `isNullEQ` array which means the `joinKey[i]` is a `NullEQ` function. The `hasNullEQ` 163 // means whether there is a `NullEQ` of a join key. 164 func (p *LogicalJoin) GetJoinKeys() (leftKeys, rightKeys []*memex.DeferredCauset, isNullEQ []bool, hasNullEQ bool) { 165 for _, expr := range p.EqualConditions { 166 leftKeys = append(leftKeys, expr.GetArgs()[0].(*memex.DeferredCauset)) 167 rightKeys = append(rightKeys, expr.GetArgs()[1].(*memex.DeferredCauset)) 168 isNullEQ = append(isNullEQ, expr.FuncName.L == ast.NullEQ) 169 hasNullEQ = hasNullEQ || expr.FuncName.L == ast.NullEQ 170 } 171 return 172 } 173 174 func (p *LogicalJoin) columnSubstitute(schemaReplicant *memex.Schema, exprs []memex.Expression) { 175 for i, cond := range p.LeftConditions { 176 p.LeftConditions[i] = memex.DeferredCausetSubstitute(cond, schemaReplicant, exprs) 177 } 178 179 for i, cond := range p.RightConditions { 180 p.RightConditions[i] = memex.DeferredCausetSubstitute(cond, schemaReplicant, exprs) 181 } 182 183 for i, cond := range p.OtherConditions { 184 p.OtherConditions[i] = memex.DeferredCausetSubstitute(cond, schemaReplicant, exprs) 185 } 186 187 for i := len(p.EqualConditions) - 1; i >= 0; i-- { 188 newCond := memex.DeferredCausetSubstitute(p.EqualConditions[i], schemaReplicant, exprs).(*memex.ScalarFunction) 189 190 // If the columns used in the new filter all come from the left child, 191 // we can push this filter to it. 192 if memex.ExprFromSchema(newCond, p.children[0].Schema()) { 193 p.LeftConditions = append(p.LeftConditions, newCond) 194 p.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...) 195 continue 196 } 197 198 // If the columns used in the new filter all come from the right 199 // child, we can push this filter to it. 200 if memex.ExprFromSchema(newCond, p.children[1].Schema()) { 201 p.RightConditions = append(p.RightConditions, newCond) 202 p.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...) 203 continue 204 } 205 206 _, lhsIsDefCaus := newCond.GetArgs()[0].(*memex.DeferredCauset) 207 _, rhsIsDefCaus := newCond.GetArgs()[1].(*memex.DeferredCauset) 208 209 // If the columns used in the new filter are not all memex.DeferredCauset, 210 // we can not use it as join's equal condition. 211 if !(lhsIsDefCaus && rhsIsDefCaus) { 212 p.OtherConditions = append(p.OtherConditions, newCond) 213 p.EqualConditions = append(p.EqualConditions[:i], p.EqualConditions[i+1:]...) 214 continue 215 } 216 217 p.EqualConditions[i] = newCond 218 } 219 } 220 221 // AttachOnConds extracts on conditions for join and set the `EqualConditions`, `LeftConditions`, `RightConditions` and 222 // `OtherConditions` by the result of extract. 223 func (p *LogicalJoin) AttachOnConds(onConds []memex.Expression) { 224 eq, left, right, other := p.extractOnCondition(onConds, false, false) 225 p.AppendJoinConds(eq, left, right, other) 226 } 227 228 // AppendJoinConds appends new join conditions. 229 func (p *LogicalJoin) AppendJoinConds(eq []*memex.ScalarFunction, left, right, other []memex.Expression) { 230 p.EqualConditions = append(eq, p.EqualConditions...) 231 p.LeftConditions = append(left, p.LeftConditions...) 232 p.RightConditions = append(right, p.RightConditions...) 233 p.OtherConditions = append(other, p.OtherConditions...) 234 } 235 236 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 237 func (p *LogicalJoin) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 238 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.EqualConditions)+len(p.LeftConditions)+len(p.RightConditions)+len(p.OtherConditions)) 239 for _, fun := range p.EqualConditions { 240 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...) 241 } 242 for _, fun := range p.LeftConditions { 243 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...) 244 } 245 for _, fun := range p.RightConditions { 246 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...) 247 } 248 for _, fun := range p.OtherConditions { 249 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(fun)...) 250 } 251 return corDefCauss 252 } 253 254 // ExtractJoinKeys extract join keys as a schemaReplicant for child with childIdx. 255 func (p *LogicalJoin) ExtractJoinKeys(childIdx int) *memex.Schema { 256 joinKeys := make([]*memex.DeferredCauset, 0, len(p.EqualConditions)) 257 for _, eqCond := range p.EqualConditions { 258 joinKeys = append(joinKeys, eqCond.GetArgs()[childIdx].(*memex.DeferredCauset)) 259 } 260 return memex.NewSchema(joinKeys...) 261 } 262 263 // LogicalProjection represents a select fields plan. 264 type LogicalProjection struct { 265 logicalSchemaProducer 266 267 Exprs []memex.Expression 268 269 // calculateGenDefCauss indicates the projection is for calculating generated columns. 270 // In *UFIDelATE*, we should know this to tell different projections. 271 calculateGenDefCauss bool 272 273 // CalculateNoDelay indicates this Projection is the root Causet and should be 274 // calculated without delay and will not return any result to client. 275 // Currently it is "true" only when the current allegrosql query is a "DO" memex. 276 // See "https://dev.allegrosql.com/doc/refman/5.7/en/do.html" for more detail. 277 CalculateNoDelay bool 278 279 // AvoidDeferredCausetEvaluator is a temporary variable which is ONLY used to avoid 280 // building columnEvaluator for the memexs of Projection which is 281 // built by buildProjection4Union. 282 // This can be removed after column pool being supported. 283 // Related issue: MilevaDB#8141(https://github.com/whtcorpsinc/milevadb/issues/8141) 284 AvoidDeferredCausetEvaluator bool 285 } 286 287 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 288 func (p *LogicalProjection) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 289 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.Exprs)) 290 for _, expr := range p.Exprs { 291 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...) 292 } 293 return corDefCauss 294 } 295 296 // GetUsedDefCauss extracts all of the DeferredCausets used by proj. 297 func (p *LogicalProjection) GetUsedDefCauss() (usedDefCauss []*memex.DeferredCauset) { 298 for _, expr := range p.Exprs { 299 usedDefCauss = append(usedDefCauss, memex.ExtractDeferredCausets(expr)...) 300 } 301 return usedDefCauss 302 } 303 304 // LogicalAggregation represents an aggregate plan. 305 type LogicalAggregation struct { 306 logicalSchemaProducer 307 308 AggFuncs []*aggregation.AggFuncDesc 309 GroupByItems []memex.Expression 310 // groupByDefCauss stores the columns that are group-by items. 311 groupByDefCauss []*memex.DeferredCauset 312 313 // aggHints stores aggregation hint information. 314 aggHints aggHintInfo 315 316 possibleProperties [][]*memex.DeferredCauset 317 inputCount float64 // inputCount is the input count of this plan. 318 } 319 320 // HasDistinct shows whether LogicalAggregation has functions with distinct. 321 func (la *LogicalAggregation) HasDistinct() bool { 322 for _, aggFunc := range la.AggFuncs { 323 if aggFunc.HasDistinct { 324 return true 325 } 326 } 327 return false 328 } 329 330 // CopyAggHints copies the aggHints from another LogicalAggregation. 331 func (la *LogicalAggregation) CopyAggHints(agg *LogicalAggregation) { 332 // TODO: Copy the hint may make the un-applicable hint throw the 333 // same warning message more than once. We'd better add a flag for 334 // `HaveThrownWarningMessage` to avoid this. Besides, finalAgg and 335 // partialAgg (in cascades causet) should share the same hint, instead 336 // of a copy. 337 la.aggHints = agg.aggHints 338 } 339 340 // IsPartialModeAgg returns if all of the AggFuncs are partialMode. 341 func (la *LogicalAggregation) IsPartialModeAgg() bool { 342 // Since all of the AggFunc share the same AggMode, we only need to check the first one. 343 return la.AggFuncs[0].Mode == aggregation.Partial1Mode 344 } 345 346 // IsCompleteModeAgg returns if all of the AggFuncs are CompleteMode. 347 func (la *LogicalAggregation) IsCompleteModeAgg() bool { 348 // Since all of the AggFunc share the same AggMode, we only need to check the first one. 349 return la.AggFuncs[0].Mode == aggregation.CompleteMode 350 } 351 352 // GetGroupByDefCauss returns the groupByDefCauss. If the groupByDefCauss haven't be collected, 353 // this method would collect them at first. If the GroupByItems have been changed, 354 // we should explicitly collect GroupByDeferredCausets before this method. 355 func (la *LogicalAggregation) GetGroupByDefCauss() []*memex.DeferredCauset { 356 if la.groupByDefCauss == nil { 357 la.collectGroupByDeferredCausets() 358 } 359 return la.groupByDefCauss 360 } 361 362 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 363 func (la *LogicalAggregation) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 364 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(la.GroupByItems)+len(la.AggFuncs)) 365 for _, expr := range la.GroupByItems { 366 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...) 367 } 368 for _, fun := range la.AggFuncs { 369 for _, arg := range fun.Args { 370 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(arg)...) 371 } 372 } 373 return corDefCauss 374 } 375 376 // GetUsedDefCauss extracts all of the DeferredCausets used by agg including GroupByItems and AggFuncs. 377 func (la *LogicalAggregation) GetUsedDefCauss() (usedDefCauss []*memex.DeferredCauset) { 378 for _, groupByItem := range la.GroupByItems { 379 usedDefCauss = append(usedDefCauss, memex.ExtractDeferredCausets(groupByItem)...) 380 } 381 for _, aggDesc := range la.AggFuncs { 382 for _, expr := range aggDesc.Args { 383 usedDefCauss = append(usedDefCauss, memex.ExtractDeferredCausets(expr)...) 384 } 385 } 386 return usedDefCauss 387 } 388 389 // LogicalSelection represents a where or having predicate. 390 type LogicalSelection struct { 391 baseLogicalCauset 392 393 // Originally the WHERE or ON condition is parsed into a single memex, 394 // but after we converted to CNF(Conjunctive normal form), it can be 395 // split into a list of AND conditions. 396 Conditions []memex.Expression 397 } 398 399 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 400 func (p *LogicalSelection) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 401 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.Conditions)) 402 for _, cond := range p.Conditions { 403 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(cond)...) 404 } 405 return corDefCauss 406 } 407 408 // LogicalApply gets one event from outer interlock and gets one event from inner interlock according to outer event. 409 type LogicalApply struct { 410 LogicalJoin 411 412 CorDefCauss []*memex.CorrelatedDeferredCauset 413 } 414 415 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 416 func (la *LogicalApply) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 417 corDefCauss := la.LogicalJoin.ExtractCorrelatedDefCauss() 418 for i := len(corDefCauss) - 1; i >= 0; i-- { 419 if la.children[0].Schema().Contains(&corDefCauss[i].DeferredCauset) { 420 corDefCauss = append(corDefCauss[:i], corDefCauss[i+1:]...) 421 } 422 } 423 return corDefCauss 424 } 425 426 // LogicalMaxOneRow checks if a query returns no more than one event. 427 type LogicalMaxOneRow struct { 428 baseLogicalCauset 429 } 430 431 // LogicalBlockDual represents a dual causet plan. 432 type LogicalBlockDual struct { 433 logicalSchemaProducer 434 435 RowCount int 436 } 437 438 // LogicalMemBlock represents a memory causet or virtual causet 439 // Some memory blocks wants to take the tenantship of some predications 440 // e.g 441 // SELECT * FROM cluster_log WHERE type='einsteindb' AND address='192.16.5.32' 442 // Assume that the causet `cluster_log` is a memory causet, which is used 443 // to retrieve logs from remote components. In the above situation we should 444 // send log search request to the target EinsteinDB (192.16.5.32) directly instead of 445 // requesting all cluster components log search gRPC interface to retrieve 446 // log message and filtering them in MilevaDB node. 447 type LogicalMemBlock struct { 448 logicalSchemaProducer 449 450 Extractor MemBlockPredicateExtractor 451 DBName perceptron.CIStr 452 BlockInfo *perceptron.BlockInfo 453 // QueryTimeRange is used to specify the time range for metrics summary blocks and inspection blocks 454 // e.g: select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from metrics_summary; 455 // select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from metrics_summary_by_label; 456 // select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from inspection_summary; 457 // select /*+ time_range('2020-02-02 12:10:00', '2020-02-02 13:00:00') */ from inspection_result; 458 QueryTimeRange QueryTimeRange 459 } 460 461 // LogicalUnionScan is only used in non read-only txn. 462 type LogicalUnionScan struct { 463 baseLogicalCauset 464 465 conditions []memex.Expression 466 467 handleDefCauss HandleDefCauss 468 } 469 470 // DataSource represents a blockScan without condition push down. 471 type DataSource struct { 472 logicalSchemaProducer 473 474 astIndexHints []*ast.IndexHint 475 IndexHints []indexHintInfo 476 causet causet.Block 477 blockInfo *perceptron.BlockInfo 478 DeferredCausets []*perceptron.DeferredCausetInfo 479 DBName perceptron.CIStr 480 481 BlockAsName *perceptron.CIStr 482 // indexMergeHints are the hint for indexmerge. 483 indexMergeHints []indexHintInfo 484 // pushedDownConds are the conditions that will be pushed down to interlock. 485 pushedDownConds []memex.Expression 486 // allConds contains all the filters on this causet. For now it's maintained 487 // in predicate push down and used only in partition pruning. 488 allConds []memex.Expression 489 490 statisticBlock *statistics.Block 491 blockStats *property.StatsInfo 492 493 // possibleAccessPaths stores all the possible access path for physical plan, including causet scan. 494 possibleAccessPaths []*soliton.AccessPath 495 496 // The data source may be a partition, rather than a real causet. 497 isPartition bool 498 physicalBlockID int64 499 partitionNames []perceptron.CIStr 500 501 // handleDefCaus represents the handle column for the datasource, either the 502 // int primary key column or extra handle column. 503 //handleDefCaus *memex.DeferredCauset 504 handleDefCauss HandleDefCauss 505 // TblDefCauss contains the original columns of causet before being pruned, and it 506 // is used for estimating causet scan cost. 507 TblDefCauss []*memex.DeferredCauset 508 // commonHandleDefCauss and commonHandleLens save the info of primary key which is the clustered index. 509 commonHandleDefCauss []*memex.DeferredCauset 510 commonHandleLens []int 511 // TblDefCausHists contains the Histogram of all original causet columns, 512 // it is converted from statisticBlock, and used for IO/network cost estimating. 513 TblDefCausHists *statistics.HistDefCausl 514 // preferStoreType means the DataSource is enforced to which storage. 515 preferStoreType int 516 // preferPartitions causetstore the map, the key represents causetstore type, the value represents the partition name list. 517 preferPartitions map[int][]perceptron.CIStr 518 } 519 520 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 521 func (ds *DataSource) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 522 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(ds.pushedDownConds)) 523 for _, expr := range ds.pushedDownConds { 524 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...) 525 } 526 return corDefCauss 527 } 528 529 // EinsteinDBSingleGather is a leaf logical operator of MilevaDB layer to gather 530 // tuples from EinsteinDB regions. 531 type EinsteinDBSingleGather struct { 532 logicalSchemaProducer 533 Source *DataSource 534 // IsIndexGather marks if this EinsteinDBSingleGather gathers tuples from an IndexScan. 535 // in implementation phase, we need this flag to determine whether to generate 536 // PhysicalBlockReader or PhysicalIndexReader. 537 IsIndexGather bool 538 Index *perceptron.IndexInfo 539 } 540 541 // LogicalBlockScan is the logical causet scan operator for EinsteinDB. 542 type LogicalBlockScan struct { 543 logicalSchemaProducer 544 Source *DataSource 545 HandleDefCauss HandleDefCauss 546 AccessConds memex.CNFExprs 547 Ranges []*ranger.Range 548 } 549 550 // LogicalIndexScan is the logical index scan operator for EinsteinDB. 551 type LogicalIndexScan struct { 552 logicalSchemaProducer 553 // DataSource should be read-only here. 554 Source *DataSource 555 IsDoubleRead bool 556 557 EqCondCount int 558 AccessConds memex.CNFExprs 559 Ranges []*ranger.Range 560 561 Index *perceptron.IndexInfo 562 DeferredCausets []*perceptron.DeferredCausetInfo 563 FullIdxDefCauss []*memex.DeferredCauset 564 FullIdxDefCausLens []int 565 IdxDefCauss []*memex.DeferredCauset 566 IdxDefCausLens []int 567 } 568 569 // MatchIndexProp checks if the indexScan can match the required property. 570 func (p *LogicalIndexScan) MatchIndexProp(prop *property.PhysicalProperty) (match bool) { 571 if prop.IsEmpty() { 572 return true 573 } 574 if all, _ := prop.AllSameOrder(); !all { 575 return false 576 } 577 for i, col := range p.IdxDefCauss { 578 if col.Equal(nil, prop.Items[0].DefCaus) { 579 return matchIndicesProp(p.IdxDefCauss[i:], p.IdxDefCausLens[i:], prop.Items) 580 } else if i >= p.EqCondCount { 581 break 582 } 583 } 584 return false 585 } 586 587 // getBlockPath finds the BlockPath from a group of accessPaths. 588 func getBlockPath(paths []*soliton.AccessPath) *soliton.AccessPath { 589 for _, path := range paths { 590 if path.IsBlockPath() { 591 return path 592 } 593 } 594 return nil 595 } 596 597 func (ds *DataSource) buildBlockGather() LogicalCauset { 598 ts := LogicalBlockScan{Source: ds, HandleDefCauss: ds.handleDefCauss}.Init(ds.ctx, ds.blockOffset) 599 ts.SetSchema(ds.Schema()) 600 sg := EinsteinDBSingleGather{Source: ds, IsIndexGather: false}.Init(ds.ctx, ds.blockOffset) 601 sg.SetSchema(ds.Schema()) 602 sg.SetChildren(ts) 603 return sg 604 } 605 606 func (ds *DataSource) buildIndexGather(path *soliton.AccessPath) LogicalCauset { 607 is := LogicalIndexScan{ 608 Source: ds, 609 IsDoubleRead: false, 610 Index: path.Index, 611 FullIdxDefCauss: path.FullIdxDefCauss, 612 FullIdxDefCausLens: path.FullIdxDefCausLens, 613 IdxDefCauss: path.IdxDefCauss, 614 IdxDefCausLens: path.IdxDefCausLens, 615 }.Init(ds.ctx, ds.blockOffset) 616 617 is.DeferredCausets = make([]*perceptron.DeferredCausetInfo, len(ds.DeferredCausets)) 618 copy(is.DeferredCausets, ds.DeferredCausets) 619 is.SetSchema(ds.Schema()) 620 is.IdxDefCauss, is.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(is.DeferredCausets, is.schemaReplicant.DeferredCausets, is.Index) 621 622 sg := EinsteinDBSingleGather{ 623 Source: ds, 624 IsIndexGather: true, 625 Index: path.Index, 626 }.Init(ds.ctx, ds.blockOffset) 627 sg.SetSchema(ds.Schema()) 628 sg.SetChildren(is) 629 return sg 630 } 631 632 // Convert2Gathers builds logical EinsteinDBSingleGathers from DataSource. 633 func (ds *DataSource) Convert2Gathers() (gathers []LogicalCauset) { 634 tg := ds.buildBlockGather() 635 gathers = append(gathers, tg) 636 for _, path := range ds.possibleAccessPaths { 637 if !path.IsIntHandlePath { 638 path.FullIdxDefCauss, path.FullIdxDefCausLens = memex.IndexInfo2DefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index) 639 path.IdxDefCauss, path.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index) 640 // If index columns can cover all of the needed columns, we can use a IndexGather + IndexScan. 641 if ds.isCoveringIndex(ds.schemaReplicant.DeferredCausets, path.FullIdxDefCauss, path.FullIdxDefCausLens, ds.blockInfo) { 642 gathers = append(gathers, ds.buildIndexGather(path)) 643 } 644 // TODO: If index columns can not cover the schemaReplicant, use IndexLookUpGather. 645 } 646 } 647 return gathers 648 } 649 650 func (ds *DataSource) deriveCommonHandleBlockPathStats(path *soliton.AccessPath, conds []memex.Expression, isIm bool) (bool, error) { 651 path.CountAfterAccess = float64(ds.statisticBlock.Count) 652 path.Ranges = ranger.FullNotNullRange() 653 path.IdxDefCauss, path.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index) 654 path.FullIdxDefCauss, path.FullIdxDefCausLens = memex.IndexInfo2DefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index) 655 if len(conds) == 0 { 656 return false, nil 657 } 658 sc := ds.ctx.GetStochastikVars().StmtCtx 659 if len(path.IdxDefCauss) != 0 { 660 res, err := ranger.DetachCondAndBuildRangeForIndex(ds.ctx, conds, path.IdxDefCauss, path.IdxDefCausLens) 661 if err != nil { 662 return false, err 663 } 664 path.Ranges = res.Ranges 665 path.AccessConds = res.AccessConds 666 path.BlockFilters = res.RemainedConds 667 path.EqCondCount = res.EqCondCount 668 path.EqOrInCondCount = res.EqOrInCount 669 path.IsDNFCond = res.IsDNFCond 670 path.CountAfterAccess, err = ds.blockStats.HistDefCausl.GetRowCountByIndexRanges(sc, path.Index.ID, path.Ranges) 671 if err != nil { 672 return false, err 673 } 674 } else { 675 path.BlockFilters = conds 676 } 677 if path.EqOrInCondCount == len(path.AccessConds) { 678 accesses, remained := path.SplitCorDefCausAccessCondFromFilters(ds.ctx, path.EqOrInCondCount) 679 path.AccessConds = append(path.AccessConds, accesses...) 680 path.BlockFilters = remained 681 if len(accesses) > 0 && ds.statisticBlock.Pseudo { 682 path.CountAfterAccess = ds.statisticBlock.PseudoAvgCountPerValue() 683 } else { 684 selectivity := path.CountAfterAccess / float64(ds.statisticBlock.Count) 685 for i := range accesses { 686 col := path.IdxDefCauss[path.EqOrInCondCount+i] 687 ndv := ds.getDeferredCausetNDV(col.ID) 688 ndv *= selectivity 689 if ndv < 1 { 690 ndv = 1.0 691 } 692 path.CountAfterAccess = path.CountAfterAccess / ndv 693 } 694 } 695 } 696 // If the `CountAfterAccess` is less than `stats.RowCount`, there must be some inconsistent stats info. 697 // We prefer the `stats.RowCount` because it could use more stats info to calculate the selectivity. 698 if path.CountAfterAccess < ds.stats.RowCount && !isIm { 699 path.CountAfterAccess = math.Min(ds.stats.RowCount/SelectionFactor, float64(ds.statisticBlock.Count)) 700 } 701 // Check whether there's only point query. 702 noIntervalRanges := true 703 haveNullVal := false 704 for _, ran := range path.Ranges { 705 // Not point or the not full matched. 706 if !ran.IsPoint(sc) || len(ran.HighVal) != len(path.Index.DeferredCausets) { 707 noIntervalRanges = false 708 break 709 } 710 // Check whether there's null value. 711 for i := 0; i < len(path.Index.DeferredCausets); i++ { 712 if ran.HighVal[i].IsNull() { 713 haveNullVal = true 714 break 715 } 716 } 717 if haveNullVal { 718 break 719 } 720 } 721 return noIntervalRanges && !haveNullVal, nil 722 } 723 724 // deriveBlockPathStats will fulfill the information that the AccessPath need. 725 // And it will check whether the primary key is covered only by point query. 726 // isIm indicates whether this function is called to generate the partial path for IndexMerge. 727 func (ds *DataSource) deriveBlockPathStats(path *soliton.AccessPath, conds []memex.Expression, isIm bool) (bool, error) { 728 if path.IsCommonHandlePath { 729 return ds.deriveCommonHandleBlockPathStats(path, conds, isIm) 730 } 731 var err error 732 sc := ds.ctx.GetStochastikVars().StmtCtx 733 path.CountAfterAccess = float64(ds.statisticBlock.Count) 734 path.BlockFilters = conds 735 var pkDefCaus *memex.DeferredCauset 736 columnLen := len(ds.schemaReplicant.DeferredCausets) 737 isUnsigned := false 738 if ds.blockInfo.PKIsHandle { 739 if pkDefCausInfo := ds.blockInfo.GetPkDefCausInfo(); pkDefCausInfo != nil { 740 isUnsigned = allegrosql.HasUnsignedFlag(pkDefCausInfo.Flag) 741 pkDefCaus = memex.DefCausInfo2DefCaus(ds.schemaReplicant.DeferredCausets, pkDefCausInfo) 742 } 743 } else if columnLen > 0 && ds.schemaReplicant.DeferredCausets[columnLen-1].ID == perceptron.ExtraHandleID { 744 pkDefCaus = ds.schemaReplicant.DeferredCausets[columnLen-1] 745 } 746 if pkDefCaus == nil { 747 path.Ranges = ranger.FullIntRange(isUnsigned) 748 return false, nil 749 } 750 751 path.Ranges = ranger.FullIntRange(isUnsigned) 752 if len(conds) == 0 { 753 return false, nil 754 } 755 path.AccessConds, path.BlockFilters = ranger.DetachCondsForDeferredCauset(ds.ctx, conds, pkDefCaus) 756 // If there's no access cond, we try to find that whether there's memex containing correlated column that 757 // can be used to access data. 758 corDefCausInAccessConds := false 759 if len(path.AccessConds) == 0 { 760 for i, filter := range path.BlockFilters { 761 eqFunc, ok := filter.(*memex.ScalarFunction) 762 if !ok || eqFunc.FuncName.L != ast.EQ { 763 continue 764 } 765 lDefCaus, lOk := eqFunc.GetArgs()[0].(*memex.DeferredCauset) 766 if lOk && lDefCaus.Equal(ds.ctx, pkDefCaus) { 767 _, rOk := eqFunc.GetArgs()[1].(*memex.CorrelatedDeferredCauset) 768 if rOk { 769 path.AccessConds = append(path.AccessConds, filter) 770 path.BlockFilters = append(path.BlockFilters[:i], path.BlockFilters[i+1:]...) 771 corDefCausInAccessConds = true 772 break 773 } 774 } 775 rDefCaus, rOk := eqFunc.GetArgs()[1].(*memex.DeferredCauset) 776 if rOk && rDefCaus.Equal(ds.ctx, pkDefCaus) { 777 _, lOk := eqFunc.GetArgs()[0].(*memex.CorrelatedDeferredCauset) 778 if lOk { 779 path.AccessConds = append(path.AccessConds, filter) 780 path.BlockFilters = append(path.BlockFilters[:i], path.BlockFilters[i+1:]...) 781 corDefCausInAccessConds = true 782 break 783 } 784 } 785 } 786 } 787 if corDefCausInAccessConds { 788 path.CountAfterAccess = 1 789 return true, nil 790 } 791 path.Ranges, err = ranger.BuildBlockRange(path.AccessConds, sc, pkDefCaus.RetType) 792 if err != nil { 793 return false, err 794 } 795 path.CountAfterAccess, err = ds.statisticBlock.GetRowCountByIntDeferredCausetRanges(sc, pkDefCaus.ID, path.Ranges) 796 // If the `CountAfterAccess` is less than `stats.RowCount`, there must be some inconsistent stats info. 797 // We prefer the `stats.RowCount` because it could use more stats info to calculate the selectivity. 798 if path.CountAfterAccess < ds.stats.RowCount && !isIm { 799 path.CountAfterAccess = math.Min(ds.stats.RowCount/SelectionFactor, float64(ds.statisticBlock.Count)) 800 } 801 // Check whether the primary key is covered by point query. 802 noIntervalRange := true 803 for _, ran := range path.Ranges { 804 if !ran.IsPoint(sc) { 805 noIntervalRange = false 806 break 807 } 808 } 809 return noIntervalRange, err 810 } 811 812 func (ds *DataSource) fillIndexPath(path *soliton.AccessPath, conds []memex.Expression) error { 813 sc := ds.ctx.GetStochastikVars().StmtCtx 814 path.Ranges = ranger.FullRange() 815 path.CountAfterAccess = float64(ds.statisticBlock.Count) 816 path.IdxDefCauss, path.IdxDefCausLens = memex.IndexInfo2PrefixDefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index) 817 path.FullIdxDefCauss, path.FullIdxDefCausLens = memex.IndexInfo2DefCauss(ds.DeferredCausets, ds.schemaReplicant.DeferredCausets, path.Index) 818 if !path.Index.Unique && !path.Index.Primary && len(path.Index.DeferredCausets) == len(path.IdxDefCauss) { 819 handleDefCaus := ds.getPKIsHandleDefCaus() 820 if handleDefCaus != nil && !allegrosql.HasUnsignedFlag(handleDefCaus.RetType.Flag) { 821 alreadyHandle := false 822 for _, col := range path.IdxDefCauss { 823 if col.ID == perceptron.ExtraHandleID || col.Equal(nil, handleDefCaus) { 824 alreadyHandle = true 825 } 826 } 827 // Don't add one column twice to the index. May cause unexpected errors. 828 if !alreadyHandle { 829 path.IdxDefCauss = append(path.IdxDefCauss, handleDefCaus) 830 path.IdxDefCausLens = append(path.IdxDefCausLens, types.UnspecifiedLength) 831 } 832 } 833 } 834 if len(path.IdxDefCauss) != 0 { 835 res, err := ranger.DetachCondAndBuildRangeForIndex(ds.ctx, conds, path.IdxDefCauss, path.IdxDefCausLens) 836 if err != nil { 837 return err 838 } 839 path.Ranges = res.Ranges 840 path.AccessConds = res.AccessConds 841 path.BlockFilters = res.RemainedConds 842 path.EqCondCount = res.EqCondCount 843 path.EqOrInCondCount = res.EqOrInCount 844 path.IsDNFCond = res.IsDNFCond 845 path.CountAfterAccess, err = ds.blockStats.HistDefCausl.GetRowCountByIndexRanges(sc, path.Index.ID, path.Ranges) 846 if err != nil { 847 return err 848 } 849 } else { 850 path.BlockFilters = conds 851 } 852 return nil 853 } 854 855 // deriveIndexPathStats will fulfill the information that the AccessPath need. 856 // And it will check whether this index is full matched by point query. We will use this check to 857 // determine whether we remove other paths or not. 858 // conds is the conditions used to generate the DetachRangeResult for path. 859 // isIm indicates whether this function is called to generate the partial path for IndexMerge. 860 func (ds *DataSource) deriveIndexPathStats(path *soliton.AccessPath, conds []memex.Expression, isIm bool) bool { 861 sc := ds.ctx.GetStochastikVars().StmtCtx 862 if path.EqOrInCondCount == len(path.AccessConds) { 863 accesses, remained := path.SplitCorDefCausAccessCondFromFilters(ds.ctx, path.EqOrInCondCount) 864 path.AccessConds = append(path.AccessConds, accesses...) 865 path.BlockFilters = remained 866 if len(accesses) > 0 && ds.statisticBlock.Pseudo { 867 path.CountAfterAccess = ds.statisticBlock.PseudoAvgCountPerValue() 868 } else { 869 selectivity := path.CountAfterAccess / float64(ds.statisticBlock.Count) 870 for i := range accesses { 871 col := path.IdxDefCauss[path.EqOrInCondCount+i] 872 ndv := ds.getDeferredCausetNDV(col.ID) 873 ndv *= selectivity 874 if ndv < 1 { 875 ndv = 1.0 876 } 877 path.CountAfterAccess = path.CountAfterAccess / ndv 878 } 879 } 880 } 881 var indexFilters []memex.Expression 882 indexFilters, path.BlockFilters = ds.splitIndexFilterConditions(path.BlockFilters, path.FullIdxDefCauss, path.FullIdxDefCausLens, ds.blockInfo) 883 path.IndexFilters = append(path.IndexFilters, indexFilters...) 884 // If the `CountAfterAccess` is less than `stats.RowCount`, there must be some inconsistent stats info. 885 // We prefer the `stats.RowCount` because it could use more stats info to calculate the selectivity. 886 if path.CountAfterAccess < ds.stats.RowCount && !isIm { 887 path.CountAfterAccess = math.Min(ds.stats.RowCount/SelectionFactor, float64(ds.statisticBlock.Count)) 888 } 889 if path.IndexFilters != nil { 890 selectivity, _, err := ds.blockStats.HistDefCausl.Selectivity(ds.ctx, path.IndexFilters, nil) 891 if err != nil { 892 logutil.BgLogger().Debug("calculate selectivity failed, use selection factor", zap.Error(err)) 893 selectivity = SelectionFactor 894 } 895 if isIm { 896 path.CountAfterIndex = path.CountAfterAccess * selectivity 897 } else { 898 path.CountAfterIndex = math.Max(path.CountAfterAccess*selectivity, ds.stats.RowCount) 899 } 900 } 901 // Check whether there's only point query. 902 noIntervalRanges := true 903 haveNullVal := false 904 for _, ran := range path.Ranges { 905 // Not point or the not full matched. 906 if !ran.IsPoint(sc) || len(ran.HighVal) != len(path.Index.DeferredCausets) { 907 noIntervalRanges = false 908 break 909 } 910 // Check whether there's null value. 911 for i := 0; i < len(path.Index.DeferredCausets); i++ { 912 if ran.HighVal[i].IsNull() { 913 haveNullVal = true 914 break 915 } 916 } 917 if haveNullVal { 918 break 919 } 920 } 921 return noIntervalRanges && !haveNullVal 922 } 923 924 func getPKIsHandleDefCausFromSchema(defcaus []*perceptron.DeferredCausetInfo, schemaReplicant *memex.Schema, pkIsHandle bool) *memex.DeferredCauset { 925 if !pkIsHandle { 926 // If the PKIsHandle is false, return the ExtraHandleDeferredCauset. 927 for i, col := range defcaus { 928 if col.ID == perceptron.ExtraHandleID { 929 return schemaReplicant.DeferredCausets[i] 930 } 931 } 932 return nil 933 } 934 for i, col := range defcaus { 935 if allegrosql.HasPriKeyFlag(col.Flag) { 936 return schemaReplicant.DeferredCausets[i] 937 } 938 } 939 return nil 940 } 941 942 func (ds *DataSource) getPKIsHandleDefCaus() *memex.DeferredCauset { 943 return getPKIsHandleDefCausFromSchema(ds.DeferredCausets, ds.schemaReplicant, ds.blockInfo.PKIsHandle) 944 } 945 946 func (p *LogicalIndexScan) getPKIsHandleDefCaus(schemaReplicant *memex.Schema) *memex.DeferredCauset { 947 // We cannot use p.Source.getPKIsHandleDefCaus() here, 948 // Because we may re-prune p.DeferredCausets and p.schemaReplicant during the transformation. 949 // That will make p.DeferredCausets different from p.Source.DeferredCausets. 950 return getPKIsHandleDefCausFromSchema(p.DeferredCausets, schemaReplicant, p.Source.blockInfo.PKIsHandle) 951 } 952 953 // BlockInfo returns the *BlockInfo of data source. 954 func (ds *DataSource) BlockInfo() *perceptron.BlockInfo { 955 return ds.blockInfo 956 } 957 958 // LogicalUnionAll represents LogicalUnionAll plan. 959 type LogicalUnionAll struct { 960 logicalSchemaProducer 961 } 962 963 // LogicalPartitionUnionAll represents the LogicalUnionAll plan is for partition causet. 964 type LogicalPartitionUnionAll struct { 965 LogicalUnionAll 966 } 967 968 // LogicalSort stands for the order by plan. 969 type LogicalSort struct { 970 baseLogicalCauset 971 972 ByItems []*soliton.ByItems 973 } 974 975 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 976 func (ls *LogicalSort) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 977 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(ls.ByItems)) 978 for _, item := range ls.ByItems { 979 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(item.Expr)...) 980 } 981 return corDefCauss 982 } 983 984 // LogicalTopN represents a top-n plan. 985 type LogicalTopN struct { 986 baseLogicalCauset 987 988 ByItems []*soliton.ByItems 989 Offset uint64 990 Count uint64 991 limitHints limitHintInfo 992 } 993 994 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 995 func (lt *LogicalTopN) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 996 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(lt.ByItems)) 997 for _, item := range lt.ByItems { 998 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(item.Expr)...) 999 } 1000 return corDefCauss 1001 } 1002 1003 // isLimit checks if TopN is a limit plan. 1004 func (lt *LogicalTopN) isLimit() bool { 1005 return len(lt.ByItems) == 0 1006 } 1007 1008 // LogicalLimit represents offset and limit plan. 1009 type LogicalLimit struct { 1010 baseLogicalCauset 1011 1012 Offset uint64 1013 Count uint64 1014 limitHints limitHintInfo 1015 } 1016 1017 // LogicalLock represents a select dagger plan. 1018 type LogicalLock struct { 1019 baseLogicalCauset 1020 1021 Lock *ast.SelectLockInfo 1022 tblID2Handle map[int64][]HandleDefCauss 1023 partitionedBlock []causet.PartitionedBlock 1024 } 1025 1026 // WindowFrame represents a window function frame. 1027 type WindowFrame struct { 1028 Type ast.FrameType 1029 Start *FrameBound 1030 End *FrameBound 1031 } 1032 1033 // FrameBound is the boundary of a frame. 1034 type FrameBound struct { 1035 Type ast.BoundType 1036 UnBounded bool 1037 Num uint64 1038 // CalcFuncs is used for range framed windows. 1039 // We will build the date_add or date_sub functions for frames like `INTERVAL '2:30' MINUTE_SECOND FOLLOWING`, 1040 // and plus or minus for frames like `1 preceding`. 1041 CalcFuncs []memex.Expression 1042 // CmpFuncs is used to decide whether one event is included in the current frame. 1043 CmpFuncs []memex.CompareFunc 1044 } 1045 1046 // LogicalWindow represents a logical window function plan. 1047 type LogicalWindow struct { 1048 logicalSchemaProducer 1049 1050 WindowFuncDescs []*aggregation.WindowFuncDesc 1051 PartitionBy []property.Item 1052 OrderBy []property.Item 1053 Frame *WindowFrame 1054 } 1055 1056 // ExtractCorrelatedDefCauss implements LogicalCauset interface. 1057 func (p *LogicalWindow) ExtractCorrelatedDefCauss() []*memex.CorrelatedDeferredCauset { 1058 corDefCauss := make([]*memex.CorrelatedDeferredCauset, 0, len(p.WindowFuncDescs)) 1059 for _, windowFunc := range p.WindowFuncDescs { 1060 for _, arg := range windowFunc.Args { 1061 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(arg)...) 1062 } 1063 } 1064 if p.Frame != nil { 1065 if p.Frame.Start != nil { 1066 for _, expr := range p.Frame.Start.CalcFuncs { 1067 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...) 1068 } 1069 } 1070 if p.Frame.End != nil { 1071 for _, expr := range p.Frame.End.CalcFuncs { 1072 corDefCauss = append(corDefCauss, memex.ExtractCorDeferredCausets(expr)...) 1073 } 1074 } 1075 } 1076 return corDefCauss 1077 } 1078 1079 // GetWindowResultDeferredCausets returns the columns storing the result of the window function. 1080 func (p *LogicalWindow) GetWindowResultDeferredCausets() []*memex.DeferredCauset { 1081 return p.schemaReplicant.DeferredCausets[p.schemaReplicant.Len()-len(p.WindowFuncDescs):] 1082 } 1083 1084 // ExtractCorDeferredCausetsBySchema only extracts the correlated columns that match the specified schemaReplicant. 1085 // e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schemaReplicant is [t2.a, t2.b, t2.c], 1086 // only [t2.a] is returned. 1087 func ExtractCorDeferredCausetsBySchema(corDefCauss []*memex.CorrelatedDeferredCauset, schemaReplicant *memex.Schema, resolveIndex bool) []*memex.CorrelatedDeferredCauset { 1088 resultCorDefCauss := make([]*memex.CorrelatedDeferredCauset, schemaReplicant.Len()) 1089 for _, corDefCaus := range corDefCauss { 1090 idx := schemaReplicant.DeferredCausetIndex(&corDefCaus.DeferredCauset) 1091 if idx != -1 { 1092 if resultCorDefCauss[idx] == nil { 1093 resultCorDefCauss[idx] = &memex.CorrelatedDeferredCauset{ 1094 DeferredCauset: *schemaReplicant.DeferredCausets[idx], 1095 Data: new(types.Causet), 1096 } 1097 } 1098 corDefCaus.Data = resultCorDefCauss[idx].Data 1099 } 1100 } 1101 // Shrink slice. e.g. [col1, nil, col2, nil] will be changed to [col1, col2]. 1102 length := 0 1103 for _, col := range resultCorDefCauss { 1104 if col != nil { 1105 resultCorDefCauss[length] = col 1106 length++ 1107 } 1108 } 1109 resultCorDefCauss = resultCorDefCauss[:length] 1110 1111 if resolveIndex { 1112 for _, corDefCaus := range resultCorDefCauss { 1113 corDefCaus.Index = schemaReplicant.DeferredCausetIndex(&corDefCaus.DeferredCauset) 1114 } 1115 } 1116 1117 return resultCorDefCauss 1118 } 1119 1120 // extractCorDeferredCausetsBySchema4LogicalCauset only extracts the correlated columns that match the specified schemaReplicant. 1121 // e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schemaReplicant is [t2.a, t2.b, t2.c], 1122 // only [t2.a] is returned. 1123 func extractCorDeferredCausetsBySchema4LogicalCauset(p LogicalCauset, schemaReplicant *memex.Schema) []*memex.CorrelatedDeferredCauset { 1124 corDefCauss := ExtractCorrelatedDefCauss4LogicalCauset(p) 1125 return ExtractCorDeferredCausetsBySchema(corDefCauss, schemaReplicant, false) 1126 } 1127 1128 // ExtractCorDeferredCausetsBySchema4PhysicalCauset only extracts the correlated columns that match the specified schemaReplicant. 1129 // e.g. If the correlated columns from plan are [t1.a, t2.a, t3.a] and specified schemaReplicant is [t2.a, t2.b, t2.c], 1130 // only [t2.a] is returned. 1131 func ExtractCorDeferredCausetsBySchema4PhysicalCauset(p PhysicalCauset, schemaReplicant *memex.Schema) []*memex.CorrelatedDeferredCauset { 1132 corDefCauss := ExtractCorrelatedDefCauss4PhysicalCauset(p) 1133 return ExtractCorDeferredCausetsBySchema(corDefCauss, schemaReplicant, true) 1134 } 1135 1136 // ShowContents stores the contents for the `SHOW` memex. 1137 type ShowContents struct { 1138 Tp ast.ShowStmtType // Databases/Blocks/DeferredCausets/.... 1139 DBName string 1140 Block *ast.BlockName // Used for showing columns. 1141 DeferredCauset *ast.DeferredCausetName // Used for `desc causet column`. 1142 IndexName perceptron.CIStr 1143 Flag int // Some flag parsed from allegrosql, such as FULL. 1144 User *auth.UserIdentity // Used for show grants. 1145 Roles []*auth.RoleIdentity // Used for show grants. 1146 1147 Full bool 1148 IfNotExists bool // Used for `show create database if not exists`. 1149 GlobalScope bool // Used by show variables. 1150 Extended bool // Used for `show extended columns from ...` 1151 } 1152 1153 // LogicalShow represents a show plan. 1154 type LogicalShow struct { 1155 logicalSchemaProducer 1156 ShowContents 1157 } 1158 1159 // LogicalShowDBSJobs is for showing DBS job list. 1160 type LogicalShowDBSJobs struct { 1161 logicalSchemaProducer 1162 1163 JobNumber int64 1164 }