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  }