github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/walk.go (about)

     1  // Copyright 2016 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  	"bytes"
    15  	"context"
    16  	"fmt"
    17  	"reflect"
    18  	"strings"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    23  	"github.com/cockroachdb/cockroach/pkg/util"
    24  	"github.com/cockroachdb/cockroach/pkg/util/encoding"
    25  	"github.com/cockroachdb/errors"
    26  )
    27  
    28  type observeVerbosity int
    29  
    30  const (
    31  	observeMetadata observeVerbosity = iota
    32  	observeAlways
    33  )
    34  
    35  // planObserver is the interface to implement by components that need
    36  // to visit a planNode tree.
    37  // Used mainly by EXPLAIN, but also for the collector of back-references
    38  // for view definitions.
    39  type planObserver struct {
    40  	// replaceNode is invoked upon entering a tree node. It can replace the
    41  	// current planNode in the tree by returning a non-nil planNode. Returning
    42  	// nil will continue the recursion and not modify the current node.
    43  	replaceNode func(ctx context.Context, nodeName string, plan planNode) (planNode, error)
    44  
    45  	// enterNode is invoked upon entering a tree node. It can return false to
    46  	// stop the recursion at this node.
    47  	enterNode func(ctx context.Context, nodeName string, plan planNode) (bool, error)
    48  
    49  	// expr is invoked for each expression field in each node.
    50  	expr func(verbosity observeVerbosity, nodeName, fieldName string, n int, expr tree.Expr)
    51  
    52  	// spans is invoked for spans embedded in each node. hardLimitSet indicates
    53  	// whether the node will "touch" a limited number of rows.
    54  	spans func(nodeName, fieldName string, index *sqlbase.IndexDescriptor, spans []roachpb.Span, hardLimitSet bool)
    55  
    56  	// attr is invoked for non-expression metadata in each node.
    57  	attr func(nodeName, fieldName, attr string)
    58  
    59  	// leaveNode is invoked upon leaving a tree node.
    60  	leaveNode func(nodeName string, plan planNode) error
    61  
    62  	// followRowSourceToPlanNode controls whether the tree walker continues
    63  	// walking when it encounters a rowSourceToPlanNode, which indicates that the
    64  	// logical plan has been mutated for distribution. This should normally be
    65  	// set to false, as normally the planNodeToRowSource on the other end will
    66  	// take care of propagating signals via its own walker.
    67  	followRowSourceToPlanNode bool
    68  }
    69  
    70  // walkPlan performs a depth-first traversal of the plan given as
    71  // argument, informing the planObserver of the node details at each
    72  // level.
    73  func walkPlan(ctx context.Context, plan planNode, observer planObserver) error {
    74  	v := makePlanVisitor(ctx, observer)
    75  	v.visit(plan)
    76  	return v.err
    77  }
    78  
    79  // planVisitor is the support structure for walkPlan().
    80  type planVisitor struct {
    81  	observer planObserver
    82  	ctx      context.Context
    83  	err      error
    84  }
    85  
    86  // makePlanVisitor creates a planVisitor instance.
    87  // ctx will be stored in the planVisitor and used when visiting planNode's and
    88  // expressions..
    89  func makePlanVisitor(ctx context.Context, observer planObserver) planVisitor {
    90  	return planVisitor{observer: observer, ctx: ctx}
    91  }
    92  
    93  // visit is the recursive function that supports walkPlan().
    94  func (v *planVisitor) visit(plan planNode) planNode {
    95  	if v.err != nil {
    96  		return plan
    97  	}
    98  
    99  	name := nodeName(plan)
   100  
   101  	if v.observer.replaceNode != nil {
   102  		newNode, err := v.observer.replaceNode(v.ctx, name, plan)
   103  		if err != nil {
   104  			v.err = err
   105  			return plan
   106  		}
   107  		if newNode != nil {
   108  			return newNode
   109  		}
   110  	}
   111  	v.visitInternal(plan, name)
   112  	return plan
   113  }
   114  
   115  // visitConcrete is like visit, but provided for the case where a planNode is
   116  // trying to recurse into a concrete planNode type, and not a planNode
   117  // interface.
   118  func (v *planVisitor) visitConcrete(plan planNode) {
   119  	if v.err != nil {
   120  		return
   121  	}
   122  
   123  	name := nodeName(plan)
   124  	v.visitInternal(plan, name)
   125  }
   126  
   127  func (v *planVisitor) visitInternal(plan planNode, name string) {
   128  	if v.err != nil {
   129  		return
   130  	}
   131  	recurse := true
   132  
   133  	if v.observer.enterNode != nil {
   134  		recurse, v.err = v.observer.enterNode(v.ctx, name, plan)
   135  		if v.err != nil {
   136  			return
   137  		}
   138  	}
   139  	if v.observer.leaveNode != nil {
   140  		defer func() {
   141  			if v.err != nil {
   142  				return
   143  			}
   144  			v.err = v.observer.leaveNode(name, plan)
   145  		}()
   146  	}
   147  
   148  	if !recurse {
   149  		return
   150  	}
   151  
   152  	switch n := plan.(type) {
   153  	case *valuesNode:
   154  		if v.observer.attr != nil {
   155  			numRows := len(n.tuples)
   156  			if n.rows != nil {
   157  				numRows = n.rows.Len()
   158  			}
   159  			v.observer.attr(name, "size", formatValuesSize(numRows, len(n.columns)))
   160  		}
   161  
   162  		if v.observer.expr != nil {
   163  			v.metadataTuples(name, n.tuples)
   164  		}
   165  
   166  	case *scanNode:
   167  		if v.observer.attr != nil {
   168  			v.observer.attr(name, "table", fmt.Sprintf("%s@%s", n.desc.Name, n.index.Name))
   169  			if n.noIndexJoin {
   170  				v.observer.attr(name, "hint", "no index join")
   171  			}
   172  			if n.specifiedIndex != nil {
   173  				v.observer.attr(name, "hint", fmt.Sprintf("force index @%s", n.specifiedIndex.Name))
   174  			}
   175  		}
   176  		if v.observer.spans != nil {
   177  			v.observer.spans(name, "spans", n.index, n.spans, n.hardLimit != 0)
   178  		}
   179  		if v.observer.attr != nil {
   180  			// Only print out "parallel" when it makes sense. i.e. don't print if
   181  			// we know we will get only one result from the scan. There are cases
   182  			// in which "parallel" will be printed out even though the spans cover
   183  			// a single range, but there is nothing we can do about that.
   184  			if n.canParallelize() && (len(n.spans) > 1 || n.maxResults > 1) {
   185  				v.observer.attr(name, "parallel", "")
   186  			}
   187  			if n.hardLimit > 0 && isFilterTrue(n.filter) {
   188  				v.observer.attr(name, "limit", fmt.Sprintf("%d", n.hardLimit))
   189  			}
   190  			if n.lockingStrength != sqlbase.ScanLockingStrength_FOR_NONE {
   191  				strength := ""
   192  				switch n.lockingStrength {
   193  				case sqlbase.ScanLockingStrength_FOR_KEY_SHARE:
   194  					strength = "for key share"
   195  				case sqlbase.ScanLockingStrength_FOR_SHARE:
   196  					strength = "for share"
   197  				case sqlbase.ScanLockingStrength_FOR_NO_KEY_UPDATE:
   198  					strength = "for no key update"
   199  				case sqlbase.ScanLockingStrength_FOR_UPDATE:
   200  					strength = "for update"
   201  				default:
   202  					panic(errors.AssertionFailedf("unexpected strength"))
   203  				}
   204  				v.observer.attr(name, "locking strength", strength)
   205  			}
   206  			if n.lockingWaitPolicy != sqlbase.ScanLockingWaitPolicy_BLOCK {
   207  				wait := ""
   208  				switch n.lockingWaitPolicy {
   209  				case sqlbase.ScanLockingWaitPolicy_SKIP:
   210  					wait = "skip locked"
   211  				case sqlbase.ScanLockingWaitPolicy_ERROR:
   212  					wait = "nowait"
   213  				default:
   214  					panic(errors.AssertionFailedf("unexpected wait policy"))
   215  				}
   216  				v.observer.attr(name, "locking wait policy", wait)
   217  			}
   218  		}
   219  		if v.observer.expr != nil {
   220  			v.expr(name, "filter", -1, n.filter)
   221  		}
   222  
   223  	case *filterNode:
   224  		if v.observer.expr != nil {
   225  			v.expr(name, "filter", -1, n.filter)
   226  		}
   227  		n.source.plan = v.visit(n.source.plan)
   228  
   229  	case *renderNode:
   230  		if v.observer.expr != nil {
   231  			for i, r := range n.render {
   232  				v.metadataExpr(name, "render", i, r)
   233  			}
   234  		}
   235  		n.source.plan = v.visit(n.source.plan)
   236  
   237  	case *indexJoinNode:
   238  		if v.observer.attr != nil {
   239  			v.observer.attr(name, "table", fmt.Sprintf("%s@%s", n.table.desc.Name, n.table.index.Name))
   240  			inputCols := planColumns(n.input)
   241  			cols := make([]string, len(n.keyCols))
   242  			for i, c := range n.keyCols {
   243  				cols[i] = inputCols[c].Name
   244  			}
   245  			v.observer.attr(name, "key columns", strings.Join(cols, ", "))
   246  			v.expr(name, "filter", -1, n.table.filter)
   247  		}
   248  		n.input = v.visit(n.input)
   249  
   250  	case *lookupJoinNode:
   251  		if v.observer.attr != nil {
   252  			v.observer.attr(name, "table", fmt.Sprintf("%s@%s", n.table.desc.Name, n.table.index.Name))
   253  			v.observer.attr(name, "type", joinTypeStr(n.joinType))
   254  		}
   255  		var b bytes.Buffer
   256  		b.WriteByte('(')
   257  		inputCols := planColumns(n.input)
   258  		for i, c := range n.eqCols {
   259  			if i > 0 {
   260  				b.WriteString(", ")
   261  			}
   262  			b.WriteString(inputCols[c].Name)
   263  		}
   264  		b.WriteString(") = (")
   265  		for i := range n.eqCols {
   266  			if i > 0 {
   267  				b.WriteString(", ")
   268  			}
   269  			if i < len(n.table.index.ColumnNames) {
   270  				b.WriteString(n.table.index.ColumnNames[i])
   271  			} else {
   272  				id := n.table.index.ExtraColumnIDs[i-len(n.table.index.ColumnNames)]
   273  				col, err := n.table.desc.FindColumnByID(id)
   274  				if err != nil {
   275  					fmt.Fprintf(&b, "<error: %v>", err)
   276  				} else {
   277  					b.WriteString(col.Name)
   278  				}
   279  			}
   280  		}
   281  		b.WriteByte(')')
   282  		v.observer.attr(name, "equality", b.String())
   283  		if n.eqColsAreKey {
   284  			v.observer.attr(name, "equality cols are key", "")
   285  		}
   286  		if n.CanParallelize() {
   287  			v.observer.attr(name, "parallel", "")
   288  		}
   289  		if v.observer.expr != nil && n.onCond != nil && n.onCond != tree.DBoolTrue {
   290  			v.expr(name, "pred", -1, n.onCond)
   291  		}
   292  		n.input = v.visit(n.input)
   293  
   294  	case *vTableLookupJoinNode:
   295  		if v.observer.attr != nil {
   296  			v.observer.attr(name, "table", fmt.Sprintf("%s@%s", n.table.Name, n.index.Name))
   297  			v.observer.attr(name, "type", joinTypeStr(n.joinType))
   298  			var b bytes.Buffer
   299  			b.WriteByte('(')
   300  			inputCols := planColumns(n.input)
   301  			b.WriteString(inputCols[n.eqCol].Name)
   302  			b.WriteString(") = (")
   303  			b.WriteString(n.index.ColumnNames[0])
   304  			b.WriteByte(')')
   305  			v.observer.attr(name, "equality", b.String())
   306  		}
   307  		if v.observer.expr != nil && n.pred.onCond != nil && n.pred.onCond != tree.DBoolTrue {
   308  			v.expr(name, "pred", -1, n.pred.onCond)
   309  		}
   310  		n.input = v.visit(n.input)
   311  
   312  	case *zigzagJoinNode:
   313  		if v.observer.attr != nil {
   314  			v.observer.attr(name, "type", joinTypeStr(sqlbase.InnerJoin))
   315  			if v.observer.expr != nil && n.onCond != nil && n.onCond != tree.DBoolTrue {
   316  				v.expr(name, "pred", -1, n.onCond)
   317  			}
   318  			for _, side := range n.sides {
   319  				v.visitConcrete(side.scan)
   320  				if side.fixedVals != nil {
   321  					description := fmt.Sprintf(
   322  						"%d column%s",
   323  						len(side.fixedVals.columns),
   324  						util.Pluralize(int64(len(side.fixedVals.columns))),
   325  					)
   326  					v.observer.attr(name, "fixedvals", description)
   327  				}
   328  			}
   329  		}
   330  
   331  	case *applyJoinNode:
   332  		if v.observer.attr != nil {
   333  			v.observer.attr(name, "type", joinTypeStr(n.joinType))
   334  		}
   335  		if v.observer.expr != nil {
   336  			v.expr(name, "pred", -1, n.pred.onCond)
   337  		}
   338  		n.input.plan = v.visit(n.input.plan)
   339  
   340  	case *joinNode:
   341  		if v.observer.attr != nil {
   342  			jType := joinTypeStr(n.joinType)
   343  			if n.joinType == sqlbase.InnerJoin && len(n.pred.leftColNames) == 0 && n.pred.onCond == nil {
   344  				jType = "cross"
   345  			}
   346  			v.observer.attr(name, "type", jType)
   347  
   348  			if len(n.pred.leftColNames) > 0 {
   349  				f := tree.NewFmtCtx(tree.FmtSimple)
   350  				f.WriteByte('(')
   351  				f.FormatNode(&n.pred.leftColNames)
   352  				f.WriteString(") = (")
   353  				f.FormatNode(&n.pred.rightColNames)
   354  				f.WriteByte(')')
   355  				v.observer.attr(name, "equality", f.CloseAndGetString())
   356  				if n.pred.leftEqKey {
   357  					v.observer.attr(name, "left cols are key", "")
   358  				}
   359  				if n.pred.rightEqKey {
   360  					v.observer.attr(name, "right cols are key", "")
   361  				}
   362  			}
   363  			if len(n.mergeJoinOrdering) > 0 {
   364  				// The ordering refers to equality columns
   365  				eqCols := make(sqlbase.ResultColumns, len(n.pred.leftEqualityIndices))
   366  				for i := range eqCols {
   367  					eqCols[i].Name = fmt.Sprintf("(%s=%s)", n.pred.leftColNames[i], n.pred.rightColNames[i])
   368  				}
   369  				v.observer.attr(name, "mergeJoinOrder", formatOrdering(n.mergeJoinOrdering, eqCols))
   370  			}
   371  		}
   372  		if v.observer.expr != nil {
   373  			v.expr(name, "pred", -1, n.pred.onCond)
   374  		}
   375  		n.left.plan = v.visit(n.left.plan)
   376  		n.right.plan = v.visit(n.right.plan)
   377  
   378  	case *limitNode:
   379  		if v.observer.expr != nil {
   380  			v.expr(name, "count", -1, n.countExpr)
   381  			v.expr(name, "offset", -1, n.offsetExpr)
   382  		}
   383  		n.plan = v.visit(n.plan)
   384  
   385  	case *max1RowNode:
   386  		n.plan = v.visit(n.plan)
   387  
   388  	case *distinctNode:
   389  		if v.observer.attr == nil {
   390  			n.plan = v.visit(n.plan)
   391  			break
   392  		}
   393  
   394  		if !n.distinctOnColIdxs.Empty() {
   395  			var buf bytes.Buffer
   396  			prefix := ""
   397  			columns := planColumns(n.plan)
   398  			n.distinctOnColIdxs.ForEach(func(col int) {
   399  				buf.WriteString(prefix)
   400  				buf.WriteString(columns[col].Name)
   401  				prefix = ", "
   402  			})
   403  			v.observer.attr(name, "distinct on", buf.String())
   404  			if n.nullsAreDistinct {
   405  				v.observer.attr(name, "nulls are distinct", "")
   406  			}
   407  			if n.errorOnDup != "" {
   408  				v.observer.attr(name, "error on duplicate", "")
   409  			}
   410  		}
   411  
   412  		if !n.columnsInOrder.Empty() {
   413  			var buf bytes.Buffer
   414  			prefix := ""
   415  			columns := planColumns(n.plan)
   416  			for i, ok := n.columnsInOrder.Next(0); ok; i, ok = n.columnsInOrder.Next(i + 1) {
   417  				buf.WriteString(prefix)
   418  				buf.WriteString(columns[i].Name)
   419  				prefix = ", "
   420  			}
   421  			v.observer.attr(name, "order key", buf.String())
   422  		}
   423  
   424  		n.plan = v.visit(n.plan)
   425  
   426  	case *sortNode:
   427  		if v.observer.attr != nil {
   428  			columns := planColumns(n.plan)
   429  			v.observer.attr(name, "order", formatOrdering(n.ordering, columns))
   430  			if p := n.alreadyOrderedPrefix; p > 0 {
   431  				v.observer.attr(name, "already ordered", formatOrdering(n.ordering[:p], columns))
   432  			}
   433  		}
   434  		n.plan = v.visit(n.plan)
   435  
   436  	case *groupNode:
   437  		if v.observer.attr != nil {
   438  			inputCols := planColumns(n.plan)
   439  			for i, agg := range n.funcs {
   440  				var buf bytes.Buffer
   441  				if groupingCol, ok := n.aggIsGroupingColumn(i); ok {
   442  					buf.WriteString(inputCols[groupingCol].Name)
   443  				} else {
   444  					fmt.Fprintf(&buf, "%s(", agg.funcName)
   445  					if len(agg.argRenderIdxs) > 0 {
   446  						if agg.isDistinct() {
   447  							buf.WriteString("DISTINCT ")
   448  						}
   449  
   450  						for i, idx := range agg.argRenderIdxs {
   451  							if i != 0 {
   452  								buf.WriteString(", ")
   453  							}
   454  							buf.WriteString(inputCols[idx].Name)
   455  						}
   456  					}
   457  					buf.WriteByte(')')
   458  					if agg.filterRenderIdx != noRenderIdx {
   459  						fmt.Fprintf(&buf, " FILTER (WHERE %s)", inputCols[agg.filterRenderIdx].Name)
   460  					}
   461  				}
   462  				v.observer.attr(name, fmt.Sprintf("aggregate %d", i), buf.String())
   463  			}
   464  			if len(n.groupCols) > 0 {
   465  				var cols []string
   466  				for _, c := range n.groupCols {
   467  					cols = append(cols, inputCols[c].Name)
   468  				}
   469  				v.observer.attr(name, "group by", strings.Join(cols, ", "))
   470  			}
   471  			if len(n.groupColOrdering) > 0 {
   472  				v.observer.attr(name, "ordered", formatOrdering(n.groupColOrdering, inputCols))
   473  			}
   474  			if n.isScalar {
   475  				v.observer.attr(name, "scalar", "")
   476  			}
   477  		}
   478  
   479  		n.plan = v.visit(n.plan)
   480  
   481  	case *windowNode:
   482  		if v.observer.expr != nil {
   483  			for i, agg := range n.funcs {
   484  				v.metadataExpr(name, "window", i, agg.expr)
   485  			}
   486  			for i, rexpr := range n.windowRender {
   487  				v.metadataExpr(name, "render", i, rexpr)
   488  			}
   489  		}
   490  		n.plan = v.visit(n.plan)
   491  
   492  	case *unionNode:
   493  		n.left = v.visit(n.left)
   494  		n.right = v.visit(n.right)
   495  
   496  	case *splitNode:
   497  		n.rows = v.visit(n.rows)
   498  
   499  	case *unsplitNode:
   500  		n.rows = v.visit(n.rows)
   501  
   502  	case *relocateNode:
   503  		n.rows = v.visit(n.rows)
   504  
   505  	case *insertNode, *insertFastPathNode:
   506  		var run *insertRun
   507  		if ins, ok := n.(*insertNode); ok {
   508  			run = &ins.run
   509  		} else {
   510  			run = &n.(*insertFastPathNode).run.insertRun
   511  		}
   512  
   513  		if v.observer.attr != nil {
   514  			var buf bytes.Buffer
   515  			buf.WriteString(run.ti.tableDesc().Name)
   516  			buf.WriteByte('(')
   517  			for i := range run.insertCols {
   518  				if i > 0 {
   519  					buf.WriteString(", ")
   520  				}
   521  				buf.WriteString(run.insertCols[i].Name)
   522  			}
   523  			buf.WriteByte(')')
   524  			v.observer.attr(name, "into", buf.String())
   525  			v.observer.attr(name, "strategy", run.ti.desc())
   526  			if run.ti.autoCommit == autoCommitEnabled {
   527  				v.observer.attr(name, "auto commit", "")
   528  			}
   529  		}
   530  
   531  		if ins, ok := n.(*insertNode); ok {
   532  			ins.source = v.visit(ins.source)
   533  		} else {
   534  			ins := n.(*insertFastPathNode)
   535  			if v.observer.attr != nil {
   536  				for i := range ins.run.fkChecks {
   537  					c := &ins.run.fkChecks[i]
   538  					tabDesc := c.ReferencedTable.(*optTable).desc
   539  					idxDesc := c.ReferencedIndex.(*optIndex).desc
   540  					v.observer.attr(name, "FK check", fmt.Sprintf("%s@%s", tabDesc.Name, idxDesc.Name))
   541  				}
   542  			}
   543  			if len(ins.input) != 0 {
   544  				if v.observer.attr != nil {
   545  					v.observer.attr(name, "size", formatValuesSize(len(ins.input), len(ins.input[0])))
   546  				}
   547  
   548  				if v.observer.expr != nil {
   549  					v.metadataTuples(name, ins.input)
   550  				}
   551  			}
   552  		}
   553  
   554  	case *upsertNode:
   555  		if v.observer.attr != nil {
   556  			var buf bytes.Buffer
   557  			buf.WriteString(n.run.tw.tableDesc().Name)
   558  			buf.WriteByte('(')
   559  			for i := range n.run.insertCols {
   560  				if i > 0 {
   561  					buf.WriteString(", ")
   562  				}
   563  				buf.WriteString(n.run.insertCols[i].Name)
   564  			}
   565  			buf.WriteByte(')')
   566  			v.observer.attr(name, "into", buf.String())
   567  			v.observer.attr(name, "strategy", n.run.tw.desc())
   568  			if n.run.tw.autoCommit == autoCommitEnabled {
   569  				v.observer.attr(name, "auto commit", "")
   570  			}
   571  		}
   572  
   573  		n.source = v.visit(n.source)
   574  
   575  	case *updateNode:
   576  		if v.observer.attr != nil {
   577  			v.observer.attr(name, "table", n.run.tu.tableDesc().Name)
   578  			if len(n.run.tu.ru.UpdateCols) > 0 {
   579  				var buf bytes.Buffer
   580  				for i := range n.run.tu.ru.UpdateCols {
   581  					if i > 0 {
   582  						buf.WriteString(", ")
   583  					}
   584  					buf.WriteString(n.run.tu.ru.UpdateCols[i].Name)
   585  				}
   586  				v.observer.attr(name, "set", buf.String())
   587  			}
   588  			v.observer.attr(name, "strategy", n.run.tu.desc())
   589  			if n.run.tu.autoCommit == autoCommitEnabled {
   590  				v.observer.attr(name, "auto commit", "")
   591  			}
   592  		}
   593  		if v.observer.expr != nil {
   594  			for i, cexpr := range n.run.computeExprs {
   595  				v.metadataExpr(name, "computed", i, cexpr)
   596  			}
   597  		}
   598  		// An updater has no sub-expressions, so nothing special to do here.
   599  		n.source = v.visit(n.source)
   600  
   601  	case *deleteNode:
   602  		if v.observer.attr != nil {
   603  			v.observer.attr(name, "from", n.run.td.tableDesc().Name)
   604  			v.observer.attr(name, "strategy", n.run.td.desc())
   605  			if n.run.td.autoCommit == autoCommitEnabled {
   606  				v.observer.attr(name, "auto commit", "")
   607  			}
   608  		}
   609  		// A deleter has no sub-expressions, so nothing special to do here.
   610  		n.source = v.visit(n.source)
   611  
   612  	case *deleteRangeNode:
   613  		if v.observer.attr != nil {
   614  			v.observer.attr(name, "from", n.desc.Name)
   615  			if n.autoCommitEnabled {
   616  				v.observer.attr(name, "auto commit", "")
   617  			}
   618  		}
   619  		if v.observer.spans != nil {
   620  			v.observer.spans(name, "spans", &n.desc.PrimaryIndex, n.spans, false /* hardLimitSet */)
   621  		}
   622  
   623  	case *serializeNode:
   624  		v.visitConcrete(n.source)
   625  
   626  	case *rowCountNode:
   627  		v.visitConcrete(n.source)
   628  
   629  	case *createTableNode:
   630  		if n.n.As() {
   631  			n.sourcePlan = v.visit(n.sourcePlan)
   632  		}
   633  
   634  	case *createViewNode:
   635  		if v.observer.attr != nil {
   636  			v.observer.attr(name, "query", n.viewQuery)
   637  		}
   638  
   639  	case *setVarNode:
   640  		if v.observer.expr != nil {
   641  			for i, texpr := range n.typedValues {
   642  				v.metadataExpr(name, "value", i, texpr)
   643  			}
   644  		}
   645  
   646  	case *setClusterSettingNode:
   647  		if v.observer.expr != nil && n.value != nil {
   648  			v.metadataExpr(name, "value", -1, n.value)
   649  		}
   650  
   651  	case *delayedNode:
   652  		if v.observer.attr != nil {
   653  			v.observer.attr(name, "source", n.name)
   654  			if n.indexConstraint != nil {
   655  				v.observer.attr(name, "constraint", n.indexConstraint.String())
   656  			}
   657  		}
   658  		if n.plan != nil {
   659  			n.plan = v.visit(n.plan)
   660  		}
   661  
   662  	case *explainDistSQLNode:
   663  		n.plan.main.planNode = v.visit(n.plan.main.planNode)
   664  
   665  	case *explainVecNode:
   666  		n.plan.planNode = v.visit(n.plan.planNode)
   667  
   668  	case *ordinalityNode:
   669  		n.source = v.visit(n.source)
   670  
   671  	case *spoolNode:
   672  		if n.hardLimit > 0 && v.observer.attr != nil {
   673  			v.observer.attr(name, "limit", fmt.Sprintf("%d", n.hardLimit))
   674  		}
   675  		n.source = v.visit(n.source)
   676  
   677  	case *saveTableNode:
   678  		if v.observer.attr != nil {
   679  			v.observer.attr(name, "target", n.target.String())
   680  		}
   681  		n.source = v.visit(n.source)
   682  
   683  	case *showTraceReplicaNode:
   684  		n.plan = v.visit(n.plan)
   685  
   686  	case *explainPlanNode:
   687  		n.plan.main.planNode = v.visit(n.plan.main.planNode)
   688  
   689  	case *cancelQueriesNode:
   690  		n.rows = v.visit(n.rows)
   691  
   692  	case *cancelSessionsNode:
   693  		n.rows = v.visit(n.rows)
   694  
   695  	case *controlJobsNode:
   696  		n.rows = v.visit(n.rows)
   697  
   698  	case *setZoneConfigNode:
   699  		if v.observer.expr != nil {
   700  			v.metadataExpr(name, "yaml", -1, n.yamlConfig)
   701  		}
   702  
   703  	case *projectSetNode:
   704  		if v.observer.expr != nil {
   705  			for i, texpr := range n.exprs {
   706  				v.metadataExpr(name, "render", i, texpr)
   707  			}
   708  		}
   709  		n.source = v.visit(n.source)
   710  
   711  	case *rowSourceToPlanNode:
   712  		if v.observer.followRowSourceToPlanNode && n.originalPlanNode != nil {
   713  			v.visit(n.originalPlanNode)
   714  		}
   715  
   716  	case *errorIfRowsNode:
   717  		n.plan = v.visit(n.plan)
   718  
   719  	case *scanBufferNode:
   720  		if v.observer.attr != nil {
   721  			v.observer.attr(name, "label", n.label)
   722  		}
   723  
   724  	case *bufferNode:
   725  		if v.observer.attr != nil {
   726  			v.observer.attr(name, "label", n.label)
   727  		}
   728  		n.plan = v.visit(n.plan)
   729  
   730  	case *recursiveCTENode:
   731  		if v.observer.attr != nil {
   732  			v.observer.attr(name, "label", n.label)
   733  		}
   734  		n.initial = v.visit(n.initial)
   735  
   736  	case *exportNode:
   737  		if v.observer.attr != nil {
   738  			v.observer.attr(name, "destination", n.fileName)
   739  		}
   740  		n.source = v.visit(n.source)
   741  	}
   742  }
   743  
   744  // expr wraps observer.expr() and provides it with the current node's
   745  // name.
   746  func (v *planVisitor) expr(nodeName string, fieldName string, n int, expr tree.Expr) {
   747  	if v.err != nil {
   748  		return
   749  	}
   750  	v.observer.expr(observeAlways, nodeName, fieldName, n, expr)
   751  }
   752  
   753  // metadataExpr wraps observer.expr() and provides it with the current node's
   754  // name, with verbosity = metadata.
   755  func (v *planVisitor) metadataExpr(nodeName string, fieldName string, n int, expr tree.Expr) {
   756  	if v.err != nil {
   757  		return
   758  	}
   759  	v.observer.expr(observeMetadata, nodeName, fieldName, n, expr)
   760  }
   761  
   762  // metadataTuples calls metadataExpr for each expression in a matrix.
   763  func (v *planVisitor) metadataTuples(nodeName string, tuples [][]tree.TypedExpr) {
   764  	for i := range tuples {
   765  		for j, expr := range tuples[i] {
   766  			var fieldName string
   767  			if v.observer.attr != nil {
   768  				fieldName = fmt.Sprintf("row %d, expr", i)
   769  			}
   770  			v.metadataExpr(nodeName, fieldName, j, expr)
   771  		}
   772  	}
   773  }
   774  
   775  func formatOrdering(ordering sqlbase.ColumnOrdering, columns sqlbase.ResultColumns) string {
   776  	var buf bytes.Buffer
   777  	fmtCtx := tree.NewFmtCtx(tree.FmtSimple)
   778  	for i, o := range ordering {
   779  		if i > 0 {
   780  			buf.WriteByte(',')
   781  		}
   782  		prefix := byte('+')
   783  		if o.Direction == encoding.Descending {
   784  			prefix = byte('-')
   785  		}
   786  		buf.WriteByte(prefix)
   787  
   788  		fmtCtx.FormatNameP(&columns[o.ColIdx].Name)
   789  		_, _ = fmtCtx.WriteTo(&buf)
   790  	}
   791  	fmtCtx.Close()
   792  	return buf.String()
   793  }
   794  
   795  // formatValuesSize returns a string of the form "5 columns, 1 row".
   796  func formatValuesSize(numRows, numCols int) string {
   797  	return fmt.Sprintf(
   798  		"%d column%s, %d row%s",
   799  		numCols, util.Pluralize(int64(numCols)),
   800  		numRows, util.Pluralize(int64(numRows)),
   801  	)
   802  }
   803  
   804  // nodeName returns the name of the given planNode as string.  The
   805  // node's current state is taken into account, e.g. sortNode has
   806  // either name "sort" or "nosort" depending on whether sorting is
   807  // needed.
   808  func nodeName(plan planNode) string {
   809  	// Some nodes have custom names depending on attributes.
   810  	switch n := plan.(type) {
   811  	case *scanNode:
   812  		if n.reverse {
   813  			return "revscan"
   814  		}
   815  	case *unionNode:
   816  		if n.emitAll {
   817  			return "append"
   818  		}
   819  
   820  	case *joinNode:
   821  		if len(n.mergeJoinOrdering) > 0 {
   822  			return "merge-join"
   823  		}
   824  		if len(n.pred.leftEqualityIndices) == 0 {
   825  			return "cross-join"
   826  		}
   827  		return "hash-join"
   828  	}
   829  
   830  	name, ok := planNodeNames[reflect.TypeOf(plan)]
   831  	if !ok {
   832  		panic(fmt.Sprintf("name missing for type %T", plan))
   833  	}
   834  
   835  	return name
   836  }
   837  
   838  func joinTypeStr(t sqlbase.JoinType) string {
   839  	switch t {
   840  	case sqlbase.InnerJoin:
   841  		return "inner"
   842  	case sqlbase.LeftOuterJoin:
   843  		return "left outer"
   844  	case sqlbase.RightOuterJoin:
   845  		return "right outer"
   846  	case sqlbase.FullOuterJoin:
   847  		return "full outer"
   848  	case sqlbase.LeftSemiJoin:
   849  		return "semi"
   850  	case sqlbase.LeftAntiJoin:
   851  		return "anti"
   852  	}
   853  	panic(fmt.Sprintf("unknown join type %s", t))
   854  }
   855  
   856  // planNodeNames is the mapping from node type to strings.  The
   857  // strings are constant and not precomputed so that the type names can
   858  // be changed without changing the output of "EXPLAIN".
   859  var planNodeNames = map[reflect.Type]string{
   860  	reflect.TypeOf(&alterIndexNode{}):        "alter index",
   861  	reflect.TypeOf(&alterSequenceNode{}):     "alter sequence",
   862  	reflect.TypeOf(&alterTableNode{}):        "alter table",
   863  	reflect.TypeOf(&alterTypeNode{}):         "alter type",
   864  	reflect.TypeOf(&alterRoleNode{}):         "alter role",
   865  	reflect.TypeOf(&applyJoinNode{}):         "apply-join",
   866  	reflect.TypeOf(&bufferNode{}):            "buffer node",
   867  	reflect.TypeOf(&cancelQueriesNode{}):     "cancel queries",
   868  	reflect.TypeOf(&cancelSessionsNode{}):    "cancel sessions",
   869  	reflect.TypeOf(&changePrivilegesNode{}):  "change privileges",
   870  	reflect.TypeOf(&commentOnColumnNode{}):   "comment on column",
   871  	reflect.TypeOf(&commentOnDatabaseNode{}): "comment on database",
   872  	reflect.TypeOf(&commentOnIndexNode{}):    "comment on index",
   873  	reflect.TypeOf(&commentOnTableNode{}):    "comment on table",
   874  	reflect.TypeOf(&controlJobsNode{}):       "control jobs",
   875  	reflect.TypeOf(&createDatabaseNode{}):    "create database",
   876  	reflect.TypeOf(&createIndexNode{}):       "create index",
   877  	reflect.TypeOf(&createSequenceNode{}):    "create sequence",
   878  	reflect.TypeOf(&createSchemaNode{}):      "create schema",
   879  	reflect.TypeOf(&createStatsNode{}):       "create statistics",
   880  	reflect.TypeOf(&createTableNode{}):       "create table",
   881  	reflect.TypeOf(&createTypeNode{}):        "create type",
   882  	reflect.TypeOf(&CreateRoleNode{}):        "create user/role",
   883  	reflect.TypeOf(&createViewNode{}):        "create view",
   884  	reflect.TypeOf(&delayedNode{}):           "virtual table",
   885  	reflect.TypeOf(&deleteNode{}):            "delete",
   886  	reflect.TypeOf(&deleteRangeNode{}):       "delete range",
   887  	reflect.TypeOf(&distinctNode{}):          "distinct",
   888  	reflect.TypeOf(&dropDatabaseNode{}):      "drop database",
   889  	reflect.TypeOf(&dropIndexNode{}):         "drop index",
   890  	reflect.TypeOf(&dropSequenceNode{}):      "drop sequence",
   891  	reflect.TypeOf(&dropTableNode{}):         "drop table",
   892  	reflect.TypeOf(&dropTypeNode{}):          "drop type",
   893  	reflect.TypeOf(&DropRoleNode{}):          "drop user/role",
   894  	reflect.TypeOf(&dropViewNode{}):          "drop view",
   895  	reflect.TypeOf(&errorIfRowsNode{}):       "error if rows",
   896  	reflect.TypeOf(&explainDistSQLNode{}):    "explain distsql",
   897  	reflect.TypeOf(&explainPlanNode{}):       "explain plan",
   898  	reflect.TypeOf(&explainVecNode{}):        "explain vectorized",
   899  	reflect.TypeOf(&exportNode{}):            "export",
   900  	reflect.TypeOf(&filterNode{}):            "filter",
   901  	reflect.TypeOf(&GrantRoleNode{}):         "grant role",
   902  	reflect.TypeOf(&groupNode{}):             "group",
   903  	reflect.TypeOf(&hookFnNode{}):            "plugin",
   904  	reflect.TypeOf(&indexJoinNode{}):         "index-join",
   905  	reflect.TypeOf(&insertNode{}):            "insert",
   906  	reflect.TypeOf(&insertFastPathNode{}):    "insert-fast-path",
   907  	reflect.TypeOf(&joinNode{}):              "join",
   908  	reflect.TypeOf(&limitNode{}):             "limit",
   909  	reflect.TypeOf(&lookupJoinNode{}):        "lookup-join",
   910  	reflect.TypeOf(&max1RowNode{}):           "max1row",
   911  	reflect.TypeOf(&ordinalityNode{}):        "ordinality",
   912  	reflect.TypeOf(&projectSetNode{}):        "project set",
   913  	reflect.TypeOf(&recursiveCTENode{}):      "recursive cte node",
   914  	reflect.TypeOf(&relocateNode{}):          "relocate",
   915  	reflect.TypeOf(&renameColumnNode{}):      "rename column",
   916  	reflect.TypeOf(&renameDatabaseNode{}):    "rename database",
   917  	reflect.TypeOf(&renameIndexNode{}):       "rename index",
   918  	reflect.TypeOf(&renameTableNode{}):       "rename table",
   919  	reflect.TypeOf(&renderNode{}):            "render",
   920  	reflect.TypeOf(&RevokeRoleNode{}):        "revoke role",
   921  	reflect.TypeOf(&rowCountNode{}):          "count",
   922  	reflect.TypeOf(&rowSourceToPlanNode{}):   "row source to plan node",
   923  	reflect.TypeOf(&saveTableNode{}):         "save table",
   924  	reflect.TypeOf(&scanBufferNode{}):        "scan buffer node",
   925  	reflect.TypeOf(&scanNode{}):              "scan",
   926  	reflect.TypeOf(&scatterNode{}):           "scatter",
   927  	reflect.TypeOf(&scrubNode{}):             "scrub",
   928  	reflect.TypeOf(&sequenceSelectNode{}):    "sequence select",
   929  	reflect.TypeOf(&serializeNode{}):         "run",
   930  	reflect.TypeOf(&setClusterSettingNode{}): "set cluster setting",
   931  	reflect.TypeOf(&setVarNode{}):            "set",
   932  	reflect.TypeOf(&setZoneConfigNode{}):     "configure zone",
   933  	reflect.TypeOf(&showFingerprintsNode{}):  "showFingerprints",
   934  	reflect.TypeOf(&showTraceNode{}):         "show trace for",
   935  	reflect.TypeOf(&showTraceReplicaNode{}):  "replica trace",
   936  	reflect.TypeOf(&sortNode{}):              "sort",
   937  	reflect.TypeOf(&splitNode{}):             "split",
   938  	reflect.TypeOf(&unsplitNode{}):           "unsplit",
   939  	reflect.TypeOf(&unsplitAllNode{}):        "unsplit all",
   940  	reflect.TypeOf(&spoolNode{}):             "spool",
   941  	reflect.TypeOf(&truncateNode{}):          "truncate",
   942  	reflect.TypeOf(&unaryNode{}):             "emptyrow",
   943  	reflect.TypeOf(&unionNode{}):             "union",
   944  	reflect.TypeOf(&updateNode{}):            "update",
   945  	reflect.TypeOf(&upsertNode{}):            "upsert",
   946  	reflect.TypeOf(&valuesNode{}):            "values",
   947  	reflect.TypeOf(&virtualTableNode{}):      "virtual table values",
   948  	reflect.TypeOf(&vTableLookupJoinNode{}):  "virtual-table-lookup-join",
   949  	reflect.TypeOf(&windowNode{}):            "window",
   950  	reflect.TypeOf(&zeroNode{}):              "norows",
   951  	reflect.TypeOf(&zigzagJoinNode{}):        "zigzag-join",
   952  }