github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/plan.go (about) 1 // Copyright 2015 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/clusterversion" 17 "github.com/cockroachdb/cockroach/pkg/kv" 18 "github.com/cockroachdb/cockroach/pkg/roachpb" 19 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 20 "github.com/cockroachdb/cockroach/pkg/sql/opt/exec" 21 "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" 22 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 23 "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" 24 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 25 "github.com/cockroachdb/cockroach/pkg/util/hlc" 26 ) 27 28 // runParams is a struct containing all parameters passed to planNode.Next() and 29 // startPlan. 30 type runParams struct { 31 // context.Context for this method call. 32 ctx context.Context 33 34 // extendedEvalCtx groups fields useful for this execution. 35 // Used during local execution and distsql physical planning. 36 extendedEvalCtx *extendedEvalContext 37 38 // planner associated with this execution. Only used during local 39 // execution. 40 p *planner 41 } 42 43 // EvalContext() gives convenient access to the runParam's EvalContext(). 44 func (r *runParams) EvalContext() *tree.EvalContext { 45 return &r.extendedEvalCtx.EvalContext 46 } 47 48 // SessionData gives convenient access to the runParam's SessionData. 49 func (r *runParams) SessionData() *sessiondata.SessionData { 50 return r.extendedEvalCtx.SessionData 51 } 52 53 // ExecCfg gives convenient access to the runParam's ExecutorConfig. 54 func (r *runParams) ExecCfg() *ExecutorConfig { 55 return r.extendedEvalCtx.ExecCfg 56 } 57 58 // Ann is a shortcut for the Annotations from the eval context. 59 func (r *runParams) Ann() *tree.Annotations { 60 return r.extendedEvalCtx.EvalContext.Annotations 61 } 62 63 // createTimeForNewTableDescriptor consults the cluster version to determine 64 // whether the CommitTimestamp() needs to be observed when creating a new 65 // TableDescriptor. See TableDescriptor.ModificationTime. 66 // 67 // TODO(ajwerner): remove in 20.1. 68 func (r *runParams) creationTimeForNewTableDescriptor() hlc.Timestamp { 69 // Before 19.2 we needed to observe the transaction CommitTimestamp to ensure 70 // that CreateAsOfTime and ModificationTime reflected the timestamp at which the 71 // creating transaction committed. Starting in 19.2 we use a zero-valued 72 // CreateAsOfTime and ModificationTime when creating a table descriptor and then 73 // upon reading use the MVCC timestamp to populate the values. 74 var ts hlc.Timestamp 75 if !r.ExecCfg().Settings.Version.IsActive( 76 r.ctx, clusterversion.VersionTableDescModificationTimeFromMVCC, 77 ) { 78 ts = r.p.txn.CommitTimestamp() 79 } 80 return ts 81 } 82 83 // planNode defines the interface for executing a query or portion of a query. 84 // 85 // The following methods apply to planNodes and contain special cases 86 // for each type; they thus need to be extended when adding/removing 87 // planNode instances: 88 // - planVisitor.visit() (walk.go) 89 // - planNodeNames (walk.go) 90 // - setLimitHint() (limit_hint.go) 91 // - planColumns() (plan_columns.go) 92 // 93 type planNode interface { 94 startExec(params runParams) error 95 96 // Next performs one unit of work, returning false if an error is 97 // encountered or if there is no more work to do. For statements 98 // that return a result set, the Values() method will return one row 99 // of results each time that Next() returns true. 100 // 101 // Available after startPlan(). It is illegal to call Next() after it returns 102 // false. It is legal to call Next() even if the node implements 103 // planNodeFastPath and the FastPathResults() method returns true. 104 Next(params runParams) (bool, error) 105 106 // Values returns the values at the current row. The result is only valid 107 // until the next call to Next(). 108 // 109 // Available after Next(). 110 Values() tree.Datums 111 112 // Close terminates the planNode execution and releases its resources. 113 // This method should be called if the node has been used in any way (any 114 // methods on it have been called) after it was constructed. Note that this 115 // doesn't imply that startExec() has been necessarily called. 116 // 117 // This method must not be called during execution - the planNode 118 // tree must remain "live" and readable via walk() even after 119 // execution completes. 120 // 121 // The node must not be used again after this method is called. Some nodes put 122 // themselves back into memory pools on Close. 123 Close(ctx context.Context) 124 } 125 126 // PlanNode is the exported name for planNode. Useful for CCL hooks. 127 type PlanNode = planNode 128 129 // planNodeFastPath is implemented by nodes that can perform all their 130 // work during startPlan(), possibly affecting even multiple rows. For 131 // example, DELETE can do this. 132 type planNodeFastPath interface { 133 // FastPathResults returns the affected row count and true if the 134 // node has no result set and has already executed when startPlan() completes. 135 // Note that Next() must still be valid even if this method returns 136 // true, although it may have nothing left to do. 137 FastPathResults() (int, bool) 138 } 139 140 // planNodeReadingOwnWrites can be implemented by planNodes which do 141 // not use the standard SQL principle of reading at the snapshot 142 // established at the start of the transaction. It requests that 143 // the top-level (shared) `startExec` function disable stepping 144 // mode for the duration of the node's `startExec()` call. 145 // 146 // This done e.g. for most DDL statements that perform multiple KV 147 // operations on descriptors, expecting to read their own writes. 148 // 149 // Note that only `startExec()` runs with the modified stepping mode, 150 // not the `Next()` methods. This interface (and the idea of 151 // temporarily disabling stepping mode) is neither sensical nor 152 // applicable to planNodes whose execution is interleaved with 153 // that of others. 154 type planNodeReadingOwnWrites interface { 155 // ReadingOwnWrites is a marker interface. 156 ReadingOwnWrites() 157 } 158 159 var _ planNode = &alterIndexNode{} 160 var _ planNode = &alterSequenceNode{} 161 var _ planNode = &alterTableNode{} 162 var _ planNode = &alterTypeNode{} 163 var _ planNode = &bufferNode{} 164 var _ planNode = &cancelQueriesNode{} 165 var _ planNode = &cancelSessionsNode{} 166 var _ planNode = &changePrivilegesNode{} 167 var _ planNode = &createDatabaseNode{} 168 var _ planNode = &createIndexNode{} 169 var _ planNode = &createSequenceNode{} 170 var _ planNode = &createStatsNode{} 171 var _ planNode = &createTableNode{} 172 var _ planNode = &createTypeNode{} 173 var _ planNode = &CreateRoleNode{} 174 var _ planNode = &createViewNode{} 175 var _ planNode = &delayedNode{} 176 var _ planNode = &deleteNode{} 177 var _ planNode = &deleteRangeNode{} 178 var _ planNode = &distinctNode{} 179 var _ planNode = &dropDatabaseNode{} 180 var _ planNode = &dropIndexNode{} 181 var _ planNode = &dropSequenceNode{} 182 var _ planNode = &dropTableNode{} 183 var _ planNode = &dropTypeNode{} 184 var _ planNode = &DropRoleNode{} 185 var _ planNode = &dropViewNode{} 186 var _ planNode = &errorIfRowsNode{} 187 var _ planNode = &explainDistSQLNode{} 188 var _ planNode = &explainPlanNode{} 189 var _ planNode = &explainVecNode{} 190 var _ planNode = &filterNode{} 191 var _ planNode = &GrantRoleNode{} 192 var _ planNode = &groupNode{} 193 var _ planNode = &hookFnNode{} 194 var _ planNode = &indexJoinNode{} 195 var _ planNode = &insertNode{} 196 var _ planNode = &insertFastPathNode{} 197 var _ planNode = &joinNode{} 198 var _ planNode = &limitNode{} 199 var _ planNode = &max1RowNode{} 200 var _ planNode = &ordinalityNode{} 201 var _ planNode = &projectSetNode{} 202 var _ planNode = &recursiveCTENode{} 203 var _ planNode = &relocateNode{} 204 var _ planNode = &renameColumnNode{} 205 var _ planNode = &renameDatabaseNode{} 206 var _ planNode = &renameIndexNode{} 207 var _ planNode = &renameTableNode{} 208 var _ planNode = &renderNode{} 209 var _ planNode = &RevokeRoleNode{} 210 var _ planNode = &rowCountNode{} 211 var _ planNode = &scanBufferNode{} 212 var _ planNode = &scanNode{} 213 var _ planNode = &scatterNode{} 214 var _ planNode = &serializeNode{} 215 var _ planNode = &sequenceSelectNode{} 216 var _ planNode = &showFingerprintsNode{} 217 var _ planNode = &showTraceNode{} 218 var _ planNode = &sortNode{} 219 var _ planNode = &splitNode{} 220 var _ planNode = &unsplitNode{} 221 var _ planNode = &unsplitAllNode{} 222 var _ planNode = &truncateNode{} 223 var _ planNode = &unaryNode{} 224 var _ planNode = &unionNode{} 225 var _ planNode = &updateNode{} 226 var _ planNode = &upsertNode{} 227 var _ planNode = &valuesNode{} 228 var _ planNode = &virtualTableNode{} 229 var _ planNode = &windowNode{} 230 var _ planNode = &zeroNode{} 231 232 var _ planNodeFastPath = &deleteRangeNode{} 233 var _ planNodeFastPath = &rowCountNode{} 234 var _ planNodeFastPath = &serializeNode{} 235 var _ planNodeFastPath = &setZoneConfigNode{} 236 var _ planNodeFastPath = &controlJobsNode{} 237 238 var _ planNodeReadingOwnWrites = &alterIndexNode{} 239 var _ planNodeReadingOwnWrites = &alterSequenceNode{} 240 var _ planNodeReadingOwnWrites = &alterTableNode{} 241 var _ planNodeReadingOwnWrites = &alterTypeNode{} 242 var _ planNodeReadingOwnWrites = &createIndexNode{} 243 var _ planNodeReadingOwnWrites = &createSequenceNode{} 244 var _ planNodeReadingOwnWrites = &createTableNode{} 245 var _ planNodeReadingOwnWrites = &createTypeNode{} 246 var _ planNodeReadingOwnWrites = &createViewNode{} 247 var _ planNodeReadingOwnWrites = &changePrivilegesNode{} 248 var _ planNodeReadingOwnWrites = &dropTypeNode{} 249 var _ planNodeReadingOwnWrites = &setZoneConfigNode{} 250 251 // planNodeRequireSpool serves as marker for nodes whose parent must 252 // ensure that the node is fully run to completion (and the results 253 // spooled) during the start phase. This is currently implemented by 254 // all mutation statements except for upsert. 255 type planNodeRequireSpool interface { 256 requireSpool() 257 } 258 259 var _ planNodeRequireSpool = &serializeNode{} 260 261 // planNodeSpool serves as marker for nodes that can perform all their 262 // execution during the start phase. This is different from the "fast 263 // path" interface because a node that performs all its execution 264 // during the start phase might still have some result rows and thus 265 // not implement the fast path. 266 // 267 // This interface exists for the following optimization: nodes 268 // that require spooling but are the children of a spooled node 269 // do not require the introduction of an explicit spool. 270 type planNodeSpooled interface { 271 spooled() 272 } 273 274 var _ planNodeSpooled = &spoolNode{} 275 276 // planTop is the struct that collects the properties 277 // of an entire plan. 278 // Note: some additional per-statement state is also stored in 279 // semaCtx (placeholders). 280 // TODO(jordan): investigate whether/how per-plan state like 281 // placeholder data can be concentrated in a single struct. 282 type planTop struct { 283 // stmt is a reference to the current statement (AST and other metadata). 284 stmt *Statement 285 286 planComponents 287 288 // mem/catalog retains the memo and catalog that were used to create the 289 // plan. 290 mem *memo.Memo 291 catalog *optCatalog 292 293 // auditEvents becomes non-nil if any of the descriptors used by 294 // current statement is causing an auditing event. See exec_log.go. 295 auditEvents []auditEvent 296 297 // flags is populated during planning and execution. 298 flags planFlags 299 300 // execErr retains the last execution error, if any. 301 execErr error 302 303 // avoidBuffering, when set, causes the execution to avoid buffering 304 // results. 305 avoidBuffering bool 306 307 instrumentation planInstrumentation 308 309 // If we are collecting query diagnostics, flow diagrams are saved here. 310 distSQLDiagrams []execinfrapb.FlowDiagram 311 } 312 313 // planMaybePhysical is a utility struct representing a plan. It can currently 314 // use either planNode or DistSQL spec representation, but eventually will be 315 // replaced by the latter representation directly. 316 type planMaybePhysical struct { 317 planNode planNode 318 // physPlan (when non-nil) contains the physical plan that has not yet 319 // been finalized. 320 physPlan *PhysicalPlan 321 // recommendation (when physPlan is non-nil) is the recommendation about 322 // the distribution of the physical plan. 323 recommendation distRecommendation 324 } 325 326 func (p planMaybePhysical) isPhysicalPlan() bool { 327 return p.physPlan != nil 328 } 329 330 func (p planMaybePhysical) planColumns() sqlbase.ResultColumns { 331 if p.isPhysicalPlan() { 332 // TODO(yuzefovich): update this once we support creating table reader 333 // specs directly in the optimizer (see #47474). 334 return nil 335 } 336 return planColumns(p.planNode) 337 } 338 339 func (p planMaybePhysical) Close(ctx context.Context) { 340 if p.planNode != nil { 341 p.planNode.Close(ctx) 342 } 343 } 344 345 // planComponents groups together the various components of the entire query 346 // plan. 347 type planComponents struct { 348 // subqueryPlans contains all the sub-query plans. 349 subqueryPlans []subquery 350 351 // plan for the main query. 352 main planMaybePhysical 353 354 // cascades contains metadata for all cascades. 355 cascades []cascadeMetadata 356 357 // checkPlans contains all the plans for queries that are to be executed after 358 // the main query (for example, foreign key checks). 359 checkPlans []checkPlan 360 } 361 362 type cascadeMetadata struct { 363 exec.Cascade 364 // plan for the cascade. This plan is not populated upfront; it is created 365 // only when it needs to run, after the main query (and previous cascades). 366 plan planMaybePhysical 367 } 368 369 // checkPlan is a query tree that is executed after the main one. It can only 370 // return an error (for example, foreign key violation). 371 type checkPlan struct { 372 plan planMaybePhysical 373 } 374 375 // close calls Close on all plan trees. 376 func (p *planComponents) close(ctx context.Context) { 377 if p.main.planNode != nil { 378 p.main.Close(ctx) 379 p.main.planNode = nil 380 } 381 382 for i := range p.subqueryPlans { 383 // Once a subquery plan has been evaluated, it already closes its 384 // plan. 385 if p.subqueryPlans[i].plan.planNode != nil { 386 p.subqueryPlans[i].plan.Close(ctx) 387 p.subqueryPlans[i].plan.planNode = nil 388 } 389 } 390 391 for i := range p.cascades { 392 if p.cascades[i].plan.planNode != nil { 393 p.cascades[i].plan.Close(ctx) 394 p.cascades[i].plan.planNode = nil 395 } 396 } 397 398 for i := range p.checkPlans { 399 if p.checkPlans[i].plan.planNode != nil { 400 p.checkPlans[i].plan.Close(ctx) 401 p.checkPlans[i].plan.planNode = nil 402 } 403 } 404 } 405 406 // init resets planTop to point to a given statement; used at the start of the 407 // planning process. 408 func (p *planTop) init(stmt *Statement, appStats *appStats) { 409 *p = planTop{stmt: stmt} 410 p.instrumentation.init(appStats) 411 } 412 413 // close ensures that the plan's resources have been deallocated. 414 func (p *planTop) close(ctx context.Context) { 415 if p.main.planNode != nil { 416 // TODO(yuzefovich): update this once we support creating table reader 417 // specs directly in the optimizer (see #47474). 418 p.instrumentation.savePlanInfo(ctx, p) 419 } 420 p.planComponents.close(ctx) 421 } 422 423 // formatOptPlan returns a visual representation of the optimizer plan that was 424 // used. 425 func (p *planTop) formatOptPlan(flags memo.ExprFmtFlags) string { 426 f := memo.MakeExprFmtCtx(flags, p.mem, p.catalog) 427 f.FormatExpr(p.mem.RootExpr()) 428 return f.Buffer.String() 429 } 430 431 // startExec calls startExec() on each planNode using a depth-first, post-order 432 // traversal. The subqueries, if any, are also started. 433 // 434 // If the planNode also implements the nodeReadingOwnWrites interface, 435 // the txn is temporarily reconfigured to use read-your-own-writes for 436 // the duration of the call to startExec. This is used e.g. by 437 // DDL statements. 438 // 439 // Reminder: walkPlan() ensures that subqueries and sub-plans are 440 // started before startExec() is called. 441 func startExec(params runParams, plan planNode) error { 442 o := planObserver{ 443 enterNode: func(ctx context.Context, _ string, p planNode) (bool, error) { 444 switch p.(type) { 445 case *explainPlanNode, *explainDistSQLNode, *explainVecNode: 446 // Do not recurse: we're not starting the plan if we just show its structure with EXPLAIN. 447 return false, nil 448 case *showTraceNode: 449 // showTrace needs to override the params struct, and does so in its startExec() method. 450 return false, nil 451 } 452 return true, nil 453 }, 454 leaveNode: func(_ string, n planNode) (err error) { 455 if _, ok := n.(planNodeReadingOwnWrites); ok { 456 prevMode := params.p.Txn().ConfigureStepping(params.ctx, kv.SteppingDisabled) 457 defer func() { _ = params.p.Txn().ConfigureStepping(params.ctx, prevMode) }() 458 } 459 return n.startExec(params) 460 }, 461 } 462 return walkPlan(params.ctx, plan, o) 463 } 464 465 func (p *planner) maybePlanHook(ctx context.Context, stmt tree.Statement) (planNode, error) { 466 // TODO(dan): This iteration makes the plan dispatch no longer constant 467 // time. We could fix that with a map of `reflect.Type` but including 468 // reflection in such a primary codepath is unfortunate. Instead, the 469 // upcoming IR work will provide unique numeric type tags, which will 470 // elegantly solve this. 471 for _, planHook := range planHooks { 472 if fn, header, subplans, avoidBuffering, err := planHook(ctx, stmt, p); err != nil { 473 return nil, err 474 } else if fn != nil { 475 if avoidBuffering { 476 p.curPlan.avoidBuffering = true 477 } 478 return &hookFnNode{f: fn, header: header, subplans: subplans}, nil 479 } 480 } 481 for _, planHook := range wrappedPlanHooks { 482 if node, err := planHook(ctx, stmt, p); err != nil { 483 return nil, err 484 } else if node != nil { 485 return node, err 486 } 487 } 488 489 return nil, nil 490 } 491 492 // Mark transaction as operating on the system DB if the descriptor id 493 // is within the SystemConfig range. 494 func (p *planner) maybeSetSystemConfig(id sqlbase.ID) error { 495 if !sqlbase.IsSystemConfigID(id) { 496 return nil 497 } 498 // Mark transaction as operating on the system DB. 499 return p.txn.SetSystemConfigTrigger() 500 } 501 502 // planFlags is used throughout the planning code to keep track of various 503 // events or decisions along the way. 504 type planFlags uint32 505 506 const ( 507 // planFlagOptCacheHit is set if a plan from the query plan cache was used (and 508 // re-optimized). 509 planFlagOptCacheHit = (1 << iota) 510 511 // planFlagOptCacheMiss is set if we looked for a plan in the query plan cache but 512 // did not find one. 513 planFlagOptCacheMiss 514 515 // planFlagDistributed is set if the plan is for the DistSQL engine, in 516 // distributed mode. 517 planFlagDistributed 518 519 // planFlagDistSQLLocal is set if the plan is for the DistSQL engine, 520 // but in local mode. 521 planFlagDistSQLLocal 522 523 // planFlagExecDone marks that execution has been completed. 524 planFlagExecDone 525 526 // planFlagImplicitTxn marks that the plan was run inside of an implicit 527 // transaction. 528 planFlagImplicitTxn 529 530 // planFlagIsDDL marks that the plan contains DDL. 531 planFlagIsDDL 532 ) 533 534 func (pf planFlags) IsSet(flag planFlags) bool { 535 return (pf & flag) != 0 536 } 537 538 func (pf *planFlags) Set(flag planFlags) { 539 *pf |= flag 540 } 541 542 // planInstrumentation handles collection of plan information before the plan is 543 // closed. 544 type planInstrumentation struct { 545 appStats *appStats 546 savedPlanForStats *roachpb.ExplainTreePlanNode 547 548 // If savePlanString is set to true, an EXPLAIN (VERBOSE)-style plan string 549 // will be saved in planString. 550 savePlanString bool 551 planString string 552 } 553 554 func (pi *planInstrumentation) init(appStats *appStats) { 555 pi.appStats = appStats 556 } 557 558 // savePlanInfo is called before the plan is closed. 559 func (pi *planInstrumentation) savePlanInfo(ctx context.Context, curPlan *planTop) { 560 if !curPlan.flags.IsSet(planFlagExecDone) { 561 return 562 } 563 if pi.appStats != nil && pi.appStats.shouldSaveLogicalPlanDescription( 564 curPlan.stmt, 565 curPlan.flags.IsSet(planFlagDistributed), 566 curPlan.flags.IsSet(planFlagImplicitTxn), 567 curPlan.execErr, 568 ) { 569 pi.savedPlanForStats = planToTree(ctx, curPlan) 570 } 571 572 if pi.savePlanString { 573 pi.planString = planToString(ctx, curPlan) 574 } 575 }