Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package org.apache.spark.sql.catalyst.analysis

import java.util.Locale

import org.apache.spark.sql.AnalysisException
import org.apache.spark.sql.catalyst.expressions.{Alias, Expression}
import org.apache.spark.sql.catalyst.plans.logical.{LogicalPlan, Project, Range}
import org.apache.spark.sql.catalyst.rules._
Expand Down Expand Up @@ -68,9 +69,11 @@ object ResolveTableValuedFunctions extends Rule[LogicalPlan] {
: (ArgumentList, Seq[Any] => LogicalPlan) = {
(ArgumentList(args: _*),
pf orElse {
case args =>
throw new IllegalArgumentException(
"Invalid arguments for resolved function: " + args.mkString(", "))
case arguments =>
// This is caught again by the apply function and rethrow with richer information about
// position, etc, for a better error message.
throw new AnalysisException(
"Invalid arguments for resolved function: " + arguments.mkString(", "))
})
}

Expand Down Expand Up @@ -105,22 +108,35 @@ object ResolveTableValuedFunctions extends Rule[LogicalPlan] {

override def apply(plan: LogicalPlan): LogicalPlan = plan resolveOperators {
case u: UnresolvedTableValuedFunction if u.functionArgs.forall(_.resolved) =>
// The whole resolution is somewhat difficult to understand here due to too much abstractions.
// We should probably rewrite the following at some point. Reynold was just here to improve
// error messages and didn't have time to do a proper rewrite.
val resolvedFunc = builtinFunctions.get(u.functionName.toLowerCase(Locale.ROOT)) match {
case Some(tvf) =>

def failAnalysis(): Nothing = {
val argTypes = u.functionArgs.map(_.dataType.typeName).mkString(", ")
u.failAnalysis(
s"""error: table-valued function ${u.functionName} with alternatives:
|${tvf.keys.map(_.toString).toSeq.sorted.map(x => s" ($x)").mkString("\n")}
|cannot be applied to: ($argTypes)""".stripMargin)
}

val resolved = tvf.flatMap { case (argList, resolver) =>
argList.implicitCast(u.functionArgs) match {
case Some(casted) =>
Some(resolver(casted.map(_.eval())))
try {
Some(resolver(casted.map(_.eval())))
} catch {
case e: AnalysisException =>
failAnalysis()
}
case _ =>
None
}
}
resolved.headOption.getOrElse {
val argTypes = u.functionArgs.map(_.dataType.typeName).mkString(", ")
u.failAnalysis(
s"""error: table-valued function ${u.functionName} with alternatives:
|${tvf.keys.map(_.toString).toSeq.sorted.map(x => s" ($x)").mkString("\n")}
|cannot be applied to: (${argTypes})""".stripMargin)
failAnalysis()
}
case _ =>
u.failAnalysis(s"could not resolve `${u.functionName}` to a table-valued function")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,13 @@ select * from range(1, null)
-- !query 6 schema
struct<>
-- !query 6 output
java.lang.IllegalArgumentException
Invalid arguments for resolved function: 1, null
org.apache.spark.sql.AnalysisException
error: table-valued function range with alternatives:
Copy link
Contributor

@dilipbiswal dilipbiswal Jul 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: @rxin will it be better to display the function name within single quotes ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably could go either way

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rxin Ok.

(end: long)
(start: long, end: long)
(start: long, end: long, step: long)
(start: long, end: long, step: long, numPartitions: integer)
cannot be applied to: (integer, null); line 1 pos 14


-- !query 7
Expand Down