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 }