diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala
index 76ede87e4e6c0a69ae6646f3811e6726e1a96094..37e557441dc63f2b93a7320e4254f6d8dab1690a 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/trees/TreeNode.scala
@@ -336,6 +336,21 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] {
     children.foreach(_.generateTreeString(depth + 1, builder))
     builder
   }
+
+  /**
+   * Returns a 'scala code' representation of this `TreeNode` and its children.  Intended for use
+   * when debugging where the prettier toString function is obfuscating the actual structure. In the
+   * case of 'pure' `TreeNodes` that only contain primitives and other TreeNodes, the result can be
+   * pasted in the REPL to build an equivalent Tree.
+   */
+  def asCode: String = {
+    val args = productIterator.map {
+      case tn: TreeNode[_] => tn.asCode
+      case s: String => "\"" + s + "\""
+      case other => other.toString
+    }
+    s"$nodeName(${args.mkString(",")})"
+  }
 }
 
 /**