Skip to content

Commit 868cf42

Browse files
committed
[SQL] Support transforming TreeNodes with Option children.
Thanks goes to @marmbrus for his implementation. Author: Michael Armbrust <michael@databricks.com> Author: Zongheng Yang <zongheng.y@gmail.com> Closes #1074 from concretevitamin/option-treenode and squashes the following commits: ef27b85 [Zongheng Yang] Merge pull request #1 from marmbrus/pr/1074 73133c2 [Michael Armbrust] TreeNodes can't be inner classes. ab78420 [Zongheng Yang] Add a test. 2ccb721 [Michael Armbrust] Add support for transformation of optional children. (cherry picked from commit 269fc62) Signed-off-by: Michael Armbrust <michael@databricks.com>
1 parent 05d85c8 commit 868cf42

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,14 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] {
187187
} else {
188188
arg
189189
}
190+
case Some(arg: TreeNode[_]) if children contains arg =>
191+
val newChild = arg.asInstanceOf[BaseType].transformDown(rule)
192+
if (!(newChild fastEquals arg)) {
193+
changed = true
194+
Some(newChild)
195+
} else {
196+
Some(arg)
197+
}
190198
case m: Map[_,_] => m
191199
case args: Traversable[_] => args.map {
192200
case arg: TreeNode[_] if children contains arg =>
@@ -231,6 +239,14 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] {
231239
} else {
232240
arg
233241
}
242+
case Some(arg: TreeNode[_]) if children contains arg =>
243+
val newChild = arg.asInstanceOf[BaseType].transformUp(rule)
244+
if (!(newChild fastEquals arg)) {
245+
changed = true
246+
Some(newChild)
247+
} else {
248+
Some(arg)
249+
}
234250
case m: Map[_,_] => m
235251
case args: Traversable[_] => args.map {
236252
case arg: TreeNode[_] if children contains arg =>
@@ -273,7 +289,8 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] {
273289
} catch {
274290
case e: java.lang.IllegalArgumentException =>
275291
throw new TreeNodeException(
276-
this, s"Failed to copy node. Is otherCopyArgs specified correctly for $nodeName?")
292+
this, s"Failed to copy node. Is otherCopyArgs specified correctly for $nodeName? "
293+
+ s"Exception message: ${e.getMessage}.")
277294
}
278295
}
279296

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/trees/TreeNodeSuite.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ import scala.collection.mutable.ArrayBuffer
2222
import org.scalatest.FunSuite
2323

2424
import org.apache.spark.sql.catalyst.expressions._
25+
import org.apache.spark.sql.catalyst.types.{StringType, NullType}
26+
27+
case class Dummy(optKey: Option[Expression]) extends Expression {
28+
def children = optKey.toSeq
29+
def references = Set.empty[Attribute]
30+
def nullable = true
31+
def dataType = NullType
32+
override lazy val resolved = true
33+
type EvaluatedType = Any
34+
def eval(input: Row) = null.asInstanceOf[Any]
35+
}
2536

2637
class TreeNodeSuite extends FunSuite {
2738
test("top node changed") {
@@ -75,4 +86,20 @@ class TreeNodeSuite extends FunSuite {
7586

7687
assert(expected === actual)
7788
}
89+
90+
test("transform works on nodes with Option children") {
91+
val dummy1 = Dummy(Some(Literal("1", StringType)))
92+
val dummy2 = Dummy(None)
93+
val toZero: PartialFunction[Expression, Expression] = { case Literal(_, _) => Literal(0) }
94+
95+
var actual = dummy1 transformDown toZero
96+
assert(actual === Dummy(Some(Literal(0))))
97+
98+
actual = dummy1 transformUp toZero
99+
assert(actual === Dummy(Some(Literal(0))))
100+
101+
actual = dummy2 transform toZero
102+
assert(actual === Dummy(None))
103+
}
104+
78105
}

0 commit comments

Comments
 (0)