dtenedor commented on code in PR #41007:
URL: https://github.com/apache/spark/pull/41007#discussion_r1194198592


##########
sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4:
##########
@@ -434,17 +434,31 @@ resource
 dmlStatementNoWith
     : insertInto query                                                         
    #singleInsertQuery
     | fromClause multiInsertQueryBody+                                         
    #multiInsertQuery
-    | DELETE FROM multipartIdentifier tableAlias whereClause?                  
    #deleteFromTable
-    | UPDATE multipartIdentifier tableAlias setClause whereClause?             
    #updateTable
-    | MERGE INTO target=multipartIdentifier targetAlias=tableAlias
-        USING (source=multipartIdentifier |
+    | DELETE FROM tableReference tableAlias whereClause?                       
    #deleteFromTable
+    | UPDATE tableReference tableAlias setClause whereClause?                  
    #updateTable
+    | MERGE INTO target=tableReference targetAlias=tableAlias
+        USING (source=tableReference |
           LEFT_PAREN sourceQuery=query RIGHT_PAREN) sourceAlias=tableAlias
         ON mergeCondition=booleanExpression
         matchedClause*
         notMatchedClause*
         notMatchedBySourceClause*                                              
    #mergeIntoTable
     ;
 
+tableReference
+    : IDENTIFIER_KW LEFT_PAREN expression RIGHT_PAREN
+    | multipartIdentifier
+    ;
+
+identifierReference
+    : IDENTIFIER_KW LEFT_PAREN expression RIGHT_PAREN
+    | multipartIdentifier
+    ;
+identifierReferenceAllowTemp

Review Comment:
   This does not seem any different than `identifierReference` above, or 
`tableReference`?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/IdentifierClauseUtil.scala:
##########
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.sql.catalyst.analysis
+
+import org.apache.spark.sql.catalyst.expressions.Expression
+import org.apache.spark.sql.types.StringType
+
+/**
+ * Resolves the catalog of the name parts for table/view/function/namespace.
+ */
+object IdentifierClauseUtil {
+  private def getNotNullFoldableSring(clauseName: String, expr: Expression): 
String = {
+    expr match {
+      case e if !e.foldable => expr.failAnalysis(
+        errorClass = "NOT_A_CONSTANT_STRING.NOT_CONSTANT",
+        messageParameters = Map(
+          "name" -> clauseName,
+          "expr" -> expr.sql))
+      case e if e.dataType != StringType => expr.failAnalysis(
+        errorClass = "NOT_A_CONSTANT_STRING.WRONG_TYPE",
+        messageParameters = Map(
+          "name" -> clauseName,
+          "expr" -> expr.sql,
+          "dataType" -> e.dataType.catalogString))
+      case e =>
+        e.eval() match {
+          case null => expr.failAnalysis(
+            errorClass = "NOT_A_CONSTANT_STRING.NULL",
+            messageParameters = Map(
+              "name" -> clauseName,
+              "expr" -> expr.sql))
+          case _ => e.eval().toString // OK

Review Comment:
   this makes us perform the `eval` again. I think we can just write `case 
other => other // OK` and it should work to reuse it instead.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,
+                               arguments: Seq[Expression],
+                               isDistinct: Boolean,
+                               filter: Option[Expression] = None,
+                               ignoreNulls: Boolean = false)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = arguments ++ filter.toSeq
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = identExpr.toString
+  override def toString: String = {
+    val distinct = if (isDistinct) "distinct " else ""
+    s"'${identExpr.toString}($distinct${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal
+  (newChildren: IndexedSeq[Expression]): UnresolvedFunctionIdentifierClause = {
+    if (filter.isDefined) {
+      copy(arguments = newChildren.dropRight(1), filter = 
Some(newChildren.last))
+    } else {
+      copy(arguments = newChildren)
+    }
+  }
+}
+
+object UnresolvedFunctionIdentifierClause {

Review Comment:
   optional: it might be simpler to just add this as another constructor inside 
the above case class instead of creating a separate helper object for this 
purpose?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,
+                               arguments: Seq[Expression],
+                               isDistinct: Boolean,
+                               filter: Option[Expression] = None,
+                               ignoreNulls: Boolean = false)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = arguments ++ filter.toSeq
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = identExpr.toString
+  override def toString: String = {
+    val distinct = if (isDistinct) "distinct " else ""
+    s"'${identExpr.toString}($distinct${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal
+  (newChildren: IndexedSeq[Expression]): UnresolvedFunctionIdentifierClause = {
+    if (filter.isDefined) {
+      copy(arguments = newChildren.dropRight(1), filter = 
Some(newChildren.last))
+    } else {
+      copy(arguments = newChildren)
+    }
+  }
+}
+
+object UnresolvedFunctionIdentifierClause {
+  def apply(
+             identExpr: Expression,
+             arguments: Seq[Expression],
+             isDistinct: Boolean): UnresolvedFunction = {
+    UnresolvedFunctionIdentifierClause(identExpr, arguments, isDistinct)
+  }
+}
+
+/**
+ * A table-valued function, e.g.
+ * {{{
+ *   select id from range(10);
+ * }}}
+ *
+ * @param identExpr user-specified expression with teh name of this 
table-value function
+ * @param functionArgs list of function arguments
+ */
+case class UnresolvedTableValuedFunctionIdentifierClause(
+                                          identExpr: Expression,
+                                          functionArgs: Seq[Expression])
+  extends LeafNode {
+
+  override def output: Seq[Attribute] = Nil
+
+  override lazy val resolved = false
+
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+}
+
+/**
+* A table-valued function with output column aliases, e.g.
+* {{{
+*   // Assign alias names
+*   select t.a from range(10) t(a);
+* }}}
+*
+* @param identExpr user-specified name of the table-valued function
+* @param child logical plan of the table-valued function
+* @param outputNames alias names of function output columns. The analyzer adds 
[[Project]]
+*                    to rename the output columns.
+*/
+case class UnresolvedTVFAliasesIdentifierClause(
+                                 identExpr: Expression,
+                                 child: LogicalPlan,
+                                 outputNames: Seq[String]) extends UnaryNode {
+
+  override def output: Seq[Attribute] = Nil
+
+  override lazy val resolved = false
+
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override protected def withNewChildInternal(newChild: LogicalPlan): 
LogicalPlan =
+    copy(child = newChild)
+}
+
+/**
+ * Holds the name of a relation that has yet to be looked up in a catalog.
+ *
+ * @param expr multipartIdentifier table name
+ */
+case class UnresolvedRelationIdentifierClause(expr: Expression)
+  extends UnresolvedRelationOrIdentifierClause {
+
+  /** Returns a `.` separated name for this relation. */
+  def tableName: String = throw new UnresolvedException("tableName")

Review Comment:
   QQ: why do we need this method if it just throws an exception and does not 
override anything?



##########
sql/catalyst/src/main/antlr4/org/apache/spark/sql/catalyst/parser/SqlBaseParser.g4:
##########
@@ -907,6 +922,7 @@ primaryExpression
     | qualifiedName DOT ASTERISK                                               
                #star
     | LEFT_PAREN namedExpression (COMMA namedExpression)+ RIGHT_PAREN          
                #rowConstructor
     | LEFT_PAREN query RIGHT_PAREN                                             
                #subqueryExpression
+    | IDENTIFIER_KW LEFT_PAREN expression RIGHT_PAREN                          
                #identifierClause

Review Comment:
   we might be OK with just this change in the grammar file to introduce the 
new IDENTIFIER clause feature, and not any of the other changes? We could 
always still do the other changes as well, but it could behoove us to split 
that into a separate PR?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,

Review Comment:
   please fix indentation?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,
+                               arguments: Seq[Expression],
+                               isDistinct: Boolean,
+                               filter: Option[Expression] = None,
+                               ignoreNulls: Boolean = false)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = arguments ++ filter.toSeq
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = identExpr.toString
+  override def toString: String = {
+    val distinct = if (isDistinct) "distinct " else ""
+    s"'${identExpr.toString}($distinct${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal
+  (newChildren: IndexedSeq[Expression]): UnresolvedFunctionIdentifierClause = {
+    if (filter.isDefined) {
+      copy(arguments = newChildren.dropRight(1), filter = 
Some(newChildren.last))
+    } else {
+      copy(arguments = newChildren)
+    }
+  }
+}
+
+object UnresolvedFunctionIdentifierClause {
+  def apply(
+             identExpr: Expression,
+             arguments: Seq[Expression],
+             isDistinct: Boolean): UnresolvedFunction = {
+    UnresolvedFunctionIdentifierClause(identExpr, arguments, isDistinct)
+  }
+}
+
+/**
+ * A table-valued function, e.g.
+ * {{{
+ *   select id from range(10);
+ * }}}
+ *
+ * @param identExpr user-specified expression with teh name of this 
table-value function
+ * @param functionArgs list of function arguments
+ */
+case class UnresolvedTableValuedFunctionIdentifierClause(
+                                          identExpr: Expression,
+                                          functionArgs: Seq[Expression])
+  extends LeafNode {
+
+  override def output: Seq[Attribute] = Nil
+
+  override lazy val resolved = false
+
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+}
+
+/**
+* A table-valued function with output column aliases, e.g.
+* {{{
+*   // Assign alias names
+*   select t.a from range(10) t(a);
+* }}}
+*
+* @param identExpr user-specified name of the table-valued function
+* @param child logical plan of the table-valued function
+* @param outputNames alias names of function output columns. The analyzer adds 
[[Project]]
+*                    to rename the output columns.
+*/
+case class UnresolvedTVFAliasesIdentifierClause(
+                                 identExpr: Expression,

Review Comment:
   please fix indentation?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/v2ResolutionPlans.scala:
##########
@@ -40,18 +40,34 @@ case class UnresolvedNamespace(multipartIdentifier: 
Seq[String]) extends LeafNod
   override def output: Seq[Attribute] = Nil
 }
 
+abstract class UnresolvedTableOrIdentifierClause extends LeafNode
+
 /**
  * Holds the name of a table that has yet to be looked up in a catalog. It 
will be resolved to
  * [[ResolvedTable]] during analysis.
  */
 case class UnresolvedTable(
     multipartIdentifier: Seq[String],
     commandName: String,
-    relationTypeMismatchHint: Option[String]) extends LeafNode {
+    relationTypeMismatchHint: Option[String]) extends 
UnresolvedTableOrIdentifierClause {
   override lazy val resolved: Boolean = false
 
   override def output: Seq[Attribute] = Nil
 }
+/**
+ * Holds the identifier of a tabl ein String form that has yet to be looked up 
in a catalog.
+ * It will be resolved to [[UnResolvedTable]] during analysis.
+ */
+case class UnresolvedTableIdentifierClause(

Review Comment:
   should this just be in `unresolved.scala` next to the other new unresolved 
identifier clause nodes? Same for the others below.



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/Analyzer.scala:
##########
@@ -2108,6 +2123,18 @@ class Analyzer(override val catalogManager: 
CatalogManager) extends RuleExecutor
           }
         }
 
+      // Resolve IDENTIFIER clause.
+      case u@UnresolvedRelationIdentifierClause(expr) if expr.resolved =>
+        UnresolvedRelation(IdentifierClauseUtil.evalIdentifierClause(expr))
+
+      // Resolve IDENTIFIER clause and reduce to a regular unresolved table 
function
+      case u@UnresolvedTableValuedFunctionIdentifierClause(expr, args) if 
expr.resolved =>
+        
UnresolvedTableValuedFunction(IdentifierClauseUtil.evalIdentifierClause(expr), 
args)
+
+      // Resolve IDENTIFIER clause and reduce to a regular unresolved TVF 
aliases

Review Comment:
   ```suggestion
         // Resolve IDENTIFIER clause and reduce to a regular unresolved TVF 
alias
   ```



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,
+                               arguments: Seq[Expression],
+                               isDistinct: Boolean,
+                               filter: Option[Expression] = None,
+                               ignoreNulls: Boolean = false)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = arguments ++ filter.toSeq
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = identExpr.toString
+  override def toString: String = {
+    val distinct = if (isDistinct) "distinct " else ""
+    s"'${identExpr.toString}($distinct${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal
+  (newChildren: IndexedSeq[Expression]): UnresolvedFunctionIdentifierClause = {
+    if (filter.isDefined) {
+      copy(arguments = newChildren.dropRight(1), filter = 
Some(newChildren.last))
+    } else {
+      copy(arguments = newChildren)
+    }
+  }
+}
+
+object UnresolvedFunctionIdentifierClause {
+  def apply(
+             identExpr: Expression,
+             arguments: Seq[Expression],
+             isDistinct: Boolean): UnresolvedFunction = {
+    UnresolvedFunctionIdentifierClause(identExpr, arguments, isDistinct)
+  }
+}
+
+/**
+ * A table-valued function, e.g.
+ * {{{
+ *   select id from range(10);
+ * }}}
+ *
+ * @param identExpr user-specified expression with teh name of this 
table-value function
+ * @param functionArgs list of function arguments
+ */
+case class UnresolvedTableValuedFunctionIdentifierClause(
+                                          identExpr: Expression,
+                                          functionArgs: Seq[Expression])
+  extends LeafNode {
+
+  override def output: Seq[Attribute] = Nil
+
+  override lazy val resolved = false
+
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)

Review Comment:
   optional: do we want to create separate patterns for each of these types of 
unresolved identifier clause? Or just combine them all into one? Having 
separate ones could grant more flexibility later if needed?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,
+                               arguments: Seq[Expression],
+                               isDistinct: Boolean,
+                               filter: Option[Expression] = None,
+                               ignoreNulls: Boolean = false)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = arguments ++ filter.toSeq
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = identExpr.toString
+  override def toString: String = {
+    val distinct = if (isDistinct) "distinct " else ""
+    s"'${identExpr.toString}($distinct${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal
+  (newChildren: IndexedSeq[Expression]): UnresolvedFunctionIdentifierClause = {
+    if (filter.isDefined) {
+      copy(arguments = newChildren.dropRight(1), filter = 
Some(newChildren.last))
+    } else {
+      copy(arguments = newChildren)
+    }
+  }
+}
+
+object UnresolvedFunctionIdentifierClause {
+  def apply(
+             identExpr: Expression,

Review Comment:
   please fix indentation?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/unresolved.scala:
##########
@@ -276,6 +279,138 @@ object UnresolvedAttribute {
   }
 }
 
+/**
+ * Holds an identifier clause for an attribute that has yet to be resolved.
+ */
+case class UnresolvedAttributeIdentifierClause(expr: Expression)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = Seq(expr)
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = "IDENTIFIER"
+  override def toString: String = {
+    s"'(${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal(newChildren: 
IndexedSeq[Expression]):
+  UnresolvedAttributeIdentifierClause = {
+      copy(expr = newChildren.head)
+  }
+}
+
+case class UnresolvedFunctionIdentifierClause(
+                               identExpr: Expression,
+                               arguments: Seq[Expression],
+                               isDistinct: Boolean,
+                               filter: Option[Expression] = None,
+                               ignoreNulls: Boolean = false)
+  extends Expression with Unevaluable {
+
+  override def children: Seq[Expression] = arguments ++ filter.toSeq
+
+  override def dataType: DataType = throw new UnresolvedException("dataType")
+  override def nullable: Boolean = throw new UnresolvedException("nullable")
+  override lazy val resolved = false
+  final override val nodePatterns: Seq[TreePattern] = 
Seq(UNRESOLVED_IDENTIFIER_CLAUSE)
+
+  override def prettyName: String = identExpr.toString
+  override def toString: String = {
+    val distinct = if (isDistinct) "distinct " else ""
+    s"'${identExpr.toString}($distinct${children.mkString(", ")})"
+  }
+
+  override protected def withNewChildrenInternal
+  (newChildren: IndexedSeq[Expression]): UnresolvedFunctionIdentifierClause = {
+    if (filter.isDefined) {
+      copy(arguments = newChildren.dropRight(1), filter = 
Some(newChildren.last))
+    } else {
+      copy(arguments = newChildren)
+    }
+  }
+}
+
+object UnresolvedFunctionIdentifierClause {
+  def apply(
+             identExpr: Expression,
+             arguments: Seq[Expression],
+             isDistinct: Boolean): UnresolvedFunction = {
+    UnresolvedFunctionIdentifierClause(identExpr, arguments, isDistinct)
+  }
+}
+
+/**
+ * A table-valued function, e.g.
+ * {{{
+ *   select id from range(10);
+ * }}}
+ *
+ * @param identExpr user-specified expression with teh name of this 
table-value function
+ * @param functionArgs list of function arguments
+ */
+case class UnresolvedTableValuedFunctionIdentifierClause(
+                                          identExpr: Expression,

Review Comment:
   please fix indentation?



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/v2ResolutionPlans.scala:
##########
@@ -40,18 +40,34 @@ case class UnresolvedNamespace(multipartIdentifier: 
Seq[String]) extends LeafNod
   override def output: Seq[Attribute] = Nil
 }
 
+abstract class UnresolvedTableOrIdentifierClause extends LeafNode
+
 /**
  * Holds the name of a table that has yet to be looked up in a catalog. It 
will be resolved to
  * [[ResolvedTable]] during analysis.
  */
 case class UnresolvedTable(
     multipartIdentifier: Seq[String],
     commandName: String,
-    relationTypeMismatchHint: Option[String]) extends LeafNode {
+    relationTypeMismatchHint: Option[String]) extends 
UnresolvedTableOrIdentifierClause {
   override lazy val resolved: Boolean = false
 
   override def output: Seq[Attribute] = Nil
 }
+/**
+ * Holds the identifier of a tabl ein String form that has yet to be looked up 
in a catalog.

Review Comment:
   ```suggestion
    * Holds the identifier of a table in string form that has yet to be looked 
up in a catalog.
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to