@@ -20,20 +20,16 @@ package org.apache.spark.sql.catalyst.trees
20
20
import java .util .UUID
21
21
22
22
import scala .collection .Map
23
- import scala .collection .mutable .Stack
24
23
import scala .reflect .ClassTag
25
24
26
25
import org .apache .commons .lang3 .ClassUtils
27
26
import org .json4s .JsonAST ._
28
27
import org .json4s .JsonDSL ._
29
28
import org .json4s .jackson .JsonMethods ._
30
29
31
- import org .apache .spark .SparkContext
32
- import org .apache .spark .rdd .{EmptyRDD , RDD }
33
30
import org .apache .spark .sql .catalyst .catalog .{BucketSpec , CatalogStorageFormat , CatalogTable , CatalogTableType , FunctionResource }
34
31
import org .apache .spark .sql .catalyst .FunctionIdentifier
35
32
import org .apache .spark .sql .catalyst .ScalaReflection ._
36
- import org .apache .spark .sql .catalyst .ScalaReflectionLock
37
33
import org .apache .spark .sql .catalyst .TableIdentifier
38
34
import org .apache .spark .sql .catalyst .errors ._
39
35
import org .apache .spark .sql .catalyst .expressions ._
@@ -493,25 +489,35 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
493
489
494
490
/**
495
491
* Returns a string representation of the nodes in this tree, where each operator is numbered.
496
- * The numbers can be used with [[trees.TreeNode.apply apply ]] to easily access specific subtrees.
492
+ * The numbers can be used with [[TreeNode.apply ]] to easily access specific subtrees.
493
+ *
494
+ * The numbers are based on depth-first traversal of the tree (with innerChildren traversed first
495
+ * before children).
497
496
*/
498
497
def numberedTreeString : String =
499
498
treeString.split(" \n " ).zipWithIndex.map { case (line, i) => f " $i%02d $line" }.mkString(" \n " )
500
499
501
500
/**
502
501
* Returns the tree node at the specified number.
503
502
* Numbers for each node can be found in the [[numberedTreeString ]].
503
+ *
504
+ * Note that this cannot return BaseType because logical plan's plan node might return
505
+ * physical plan for innerChildren, e.g. in-memory relation logical plan node has a reference
506
+ * to the physical plan node it is referencing.
504
507
*/
505
- def apply (number : Int ): BaseType = getNodeNumbered(new MutableInt (number))
508
+ def apply (number : Int ): TreeNode [_] = getNodeNumbered(new MutableInt (number)).orNull
506
509
507
- protected def getNodeNumbered (number : MutableInt ): BaseType = {
510
+ private def getNodeNumbered (number : MutableInt ): Option [ TreeNode [_]] = {
508
511
if (number.i < 0 ) {
509
- null . asInstanceOf [ BaseType ]
512
+ None
510
513
} else if (number.i == 0 ) {
511
- this
514
+ Some ( this )
512
515
} else {
513
516
number.i -= 1
514
- children.map(_.getNodeNumbered(number)).find(_ != null ).getOrElse(null .asInstanceOf [BaseType ])
517
+ // Note that this traversal order must be the same as numberedTreeString.
518
+ innerChildren.map(_.getNodeNumbered(number)).find(_ != None ).getOrElse {
519
+ children.map(_.getNodeNumbered(number)).find(_ != None ).flatten
520
+ }
515
521
}
516
522
}
517
523
@@ -527,26 +533,25 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
527
533
* The `i`-th element in `lastChildren` indicates whether the ancestor of the current node at
528
534
* depth `i + 1` is the last child of its own parent node. The depth of the root node is 0, and
529
535
* `lastChildren` for the root node should be empty.
536
+ *
537
+ * Note that this traversal (numbering) order must be the same as [[getNodeNumbered ]].
530
538
*/
531
539
def generateTreeString (
532
540
depth : Int ,
533
541
lastChildren : Seq [Boolean ],
534
542
builder : StringBuilder ,
535
543
verbose : Boolean ,
536
544
prefix : String = " " ): StringBuilder = {
545
+
537
546
if (depth > 0 ) {
538
547
lastChildren.init.foreach { isLast =>
539
- val prefixFragment = if (isLast) " " else " : "
540
- builder.append(prefixFragment)
548
+ builder.append(if (isLast) " " else " : " )
541
549
}
542
-
543
- val branch = if (lastChildren.last) " +- " else " :- "
544
- builder.append(branch)
550
+ builder.append(if (lastChildren.last) " +- " else " :- " )
545
551
}
546
552
547
553
builder.append(prefix)
548
- val headline = if (verbose) verboseString else simpleString
549
- builder.append(headline)
554
+ builder.append(if (verbose) verboseString else simpleString)
550
555
builder.append(" \n " )
551
556
552
557
if (innerChildren.nonEmpty) {
@@ -557,9 +562,10 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
557
562
}
558
563
559
564
if (children.nonEmpty) {
560
- children.init.foreach(
561
- _.generateTreeString(depth + 1 , lastChildren :+ false , builder, verbose, prefix))
562
- children.last.generateTreeString(depth + 1 , lastChildren :+ true , builder, verbose, prefix)
565
+ children.init.foreach(_.generateTreeString(
566
+ depth + 1 , lastChildren :+ false , builder, verbose, prefix))
567
+ children.last.generateTreeString(
568
+ depth + 1 , lastChildren :+ true , builder, verbose, prefix)
563
569
}
564
570
565
571
builder
0 commit comments