Skip to content
8 changes: 4 additions & 4 deletions common/utils/src/main/resources/error/error-classes.json
Original file line number Diff line number Diff line change
Expand Up @@ -804,12 +804,12 @@
"subClass" : {
"BOTH_POSITIONAL_AND_NAMED" : {
"message" : [
"A positional argument and named argument both referred to the same parameter."
"A positional argument and named argument both referred to the same parameter. Please remove the named argument referring to this parameter."
Copy link
Contributor

Choose a reason for hiding this comment

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

These error message changes are specific to SQL named arguments, can you please update the PR title and description to indicate that?

]
},
"DOUBLE_NAMED_ARGUMENT_REFERENCE" : {
"message" : [
"More than one named argument referred to the same parameter."
"More than one named argument referred to the same parameter. Please assign a value only once."
]
}
},
Expand Down Expand Up @@ -2398,7 +2398,7 @@
},
"REQUIRED_PARAMETER_NOT_FOUND" : {
"message" : [
"Cannot invoke function <functionName> because the parameter named <parameterName> is required, but the function call did not supply a value. Please update the function call to supply an argument value (either positionally or by name) and retry the query again."
"Cannot invoke function <functionName> because the parameter named <parameterName> is required, but the function call did not supply a value. Please update the function call to supply an argument value (either positionally at index <index> or by name) and retry the query again."
],
"sqlState" : "4274K"
},
Expand Down Expand Up @@ -2599,7 +2599,7 @@
},
"UNEXPECTED_POSITIONAL_ARGUMENT" : {
"message" : [
"Cannot invoke function <functionName> because it contains positional argument(s) following named argument(s); please rearrange them so the positional arguments come first and then retry the query again."
"Cannot invoke function <functionName> because it contains positional argument(s) following the named argument assigned to <parameterName>; please rearrange them so the positional arguments come first and then retry the query again."
],
"sqlState" : "4274K"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ This error class has the following derived error classes:

## BOTH_POSITIONAL_AND_NAMED

A positional argument and named argument both referred to the same parameter.
A positional argument and named argument both referred to the same parameter. Please remove the named argument referring to this parameter.

## DOUBLE_NAMED_ARGUMENT_REFERENCE

More than one named argument referred to the same parameter.
More than one named argument referred to the same parameter. Please assign a value only once.


4 changes: 2 additions & 2 deletions docs/sql-error-conditions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1555,7 +1555,7 @@ The `<clause>` clause may be used at most once per `<operation>` operation.

[SQLSTATE: 4274K](sql-error-conditions-sqlstates.html#class-42-syntax-error-or-access-rule-violation)

Cannot invoke function `<functionName>` because the parameter named `<parameterName>` is required, but the function call did not supply a value. Please update the function call to supply an argument value (either positionally or by name) and retry the query again.
Cannot invoke function `<functionName>` because the parameter named `<parameterName>` is required, but the function call did not supply a value. Please update the function call to supply an argument value (either positionally at index `<index>` or by name) and retry the query again.

### REQUIRES_SINGLE_PART_NAMESPACE

Expand Down Expand Up @@ -1770,7 +1770,7 @@ Parameter `<paramIndex>` of function `<functionName>` requires the `<requiredTyp

[SQLSTATE: 4274K](sql-error-conditions-sqlstates.html#class-42-syntax-error-or-access-rule-violation)

Cannot invoke function `<functionName>` because it contains positional argument(s) following named argument(s); please rearrange them so the positional arguments come first and then retry the query again.
Cannot invoke function `<functionName>` because it contains positional argument(s) following the named argument assigned to `<parameterName>`; please rearrange them so the positional arguments come first and then retry the query again.

### UNKNOWN_PROTOBUF_MESSAGE_TYPE

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ object NamedParametersSupport {
val positionalParametersSet = allParameterNames.take(positionalArgs.size).toSet
val namedParametersSet = collection.mutable.Set[String]()

for (arg <- namedArgs) {
namedArgs.zipWithIndex.foreach { case (arg, index) =>
arg match {
case namedArg: NamedArgumentExpression =>
val parameterName = namedArg.key
Expand All @@ -122,7 +122,8 @@ object NamedParametersSupport {
}
namedParametersSet.add(namedArg.key)
case _ =>
throw QueryCompilationErrors.unexpectedPositionalArgument(functionName)
throw QueryCompilationErrors.unexpectedPositionalArgument(
functionName, namedArgs(index - 1).asInstanceOf[NamedArgumentExpression].key)
}
}

Expand All @@ -141,15 +142,16 @@ object NamedParametersSupport {
}.toMap

// We rearrange named arguments to match their positional order.
val rearrangedNamedArgs: Seq[Expression] = namedParameters.map { param =>
namedArgMap.getOrElse(
param.name,
if (param.default.isEmpty) {
throw QueryCompilationErrors.requiredParameterNotFound(functionName, param.name)
} else {
param.default.get
}
)
val rearrangedNamedArgs: Seq[Expression] = namedParameters.zipWithIndex.map {
case (param, index) =>
namedArgMap.getOrElse(
param.name,
if (param.default.isEmpty) {
throw QueryCompilationErrors.requiredParameterNotFound(functionName, param.name, index)
} else {
param.default.get
}
)
}
val rearrangedArgs = positionalArgs ++ rearrangedNamedArgs
assert(rearrangedArgs.size == parameters.size)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ private[sql] object QueryCompilationErrors extends QueryErrorsBase {
}

def requiredParameterNotFound(
functionName: String, parameterName: String) : Throwable = {
functionName: String, parameterName: String, index: Int) : Throwable = {
new AnalysisException(
errorClass = "REQUIRED_PARAMETER_NOT_FOUND",
messageParameters = Map(
"functionName" -> toSQLId(functionName),
"parameterName" -> toSQLId(parameterName))
"parameterName" -> toSQLId(parameterName),
"index" -> index.toString)
)
}

Expand All @@ -115,10 +116,14 @@ private[sql] object QueryCompilationErrors extends QueryErrorsBase {
)
}

def unexpectedPositionalArgument(functionName: String): Throwable = {
def unexpectedPositionalArgument(
functionName: String,
precedingNamedArgument: String): Throwable = {
new AnalysisException(
errorClass = "UNEXPECTED_POSITIONAL_ARGUMENT",
messageParameters = Map("functionName" -> toSQLId(functionName))
messageParameters = Map(
"functionName" -> toSQLId(functionName),
"parameterName" -> toSQLId(precedingNamedArgument))
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ case class DummyExpression(
}

object DummyExpressionBuilder extends ExpressionBuilder {

def defaultFunctionSignature: FunctionSignature = {
FunctionSignature(Seq(InputParameter("k1"),
InputParameter("k2"),
Expand All @@ -49,18 +50,20 @@ object DummyExpressionBuilder extends ExpressionBuilder {

override def functionSignature: Option[FunctionSignature] =
Some(defaultFunctionSignature)

override def build(funcName: String, expressions: Seq[Expression]): Expression =
DummyExpression(expressions(0), expressions(1), expressions(2), expressions(3))
}

class NamedArgumentFunctionSuite extends AnalysisTest {
class NamedParameterFunctionSuite extends AnalysisTest {

final val k1Arg = Literal("v1")
final val k2Arg = NamedArgumentExpression("k2", Literal("v2"))
final val k3Arg = NamedArgumentExpression("k3", Literal("v3"))
final val k4Arg = NamedArgumentExpression("k4", Literal("v4"))
final val namedK1Arg = NamedArgumentExpression("k1", Literal("v1-2"))
final val args = Seq(k1Arg, k4Arg, k2Arg, k3Arg)

final val expectedSeq = Seq(Literal("v1"), Literal("v2"), Literal("v3"), Literal("v4"))
final val signature = DummyExpressionBuilder.defaultFunctionSignature
final val illegalSignature = FunctionSignature(Seq(
Expand Down Expand Up @@ -115,8 +118,8 @@ class NamedArgumentFunctionSuite extends AnalysisTest {
checkError(
exception = parseRearrangeException(signature, Seq(k1Arg, k2Arg, k3Arg), "foo"),
errorClass = "REQUIRED_PARAMETER_NOT_FOUND",
parameters = Map("functionName" -> toSQLId("foo"), "parameterName" -> toSQLId("k4"))
)
parameters = Map(
"functionName" -> toSQLId("foo"), "parameterName" -> toSQLId("k4"), "index" -> "2"))
}

test("UNRECOGNIZED_PARAMETER_NAME") {
Expand All @@ -134,7 +137,7 @@ class NamedArgumentFunctionSuite extends AnalysisTest {
exception = parseRearrangeException(signature,
Seq(k2Arg, k3Arg, k1Arg, k4Arg), "foo"),
errorClass = "UNEXPECTED_POSITIONAL_ARGUMENT",
parameters = Map("functionName" -> toSQLId("foo"))
parameters = Map("functionName" -> toSQLId("foo"), "parameterName" -> toSQLId("k3"))
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ org.apache.spark.sql.AnalysisException
"errorClass" : "UNEXPECTED_POSITIONAL_ARGUMENT",
"sqlState" : "4274K",
"messageParameters" : {
"functionName" : "`mask`"
"functionName" : "`mask`",
"parameterName" : "`lowerChar`"
},
"queryContext" : [ {
"objectType" : "",
Expand Down Expand Up @@ -292,6 +293,7 @@ org.apache.spark.sql.AnalysisException
"sqlState" : "4274K",
"messageParameters" : {
"functionName" : "`mask`",
"index" : "0",
"parameterName" : "`str`"
},
"queryContext" : [ {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ org.apache.spark.sql.AnalysisException
"errorClass" : "UNEXPECTED_POSITIONAL_ARGUMENT",
"sqlState" : "4274K",
"messageParameters" : {
"functionName" : "`mask`"
"functionName" : "`mask`",
"parameterName" : "`lowerChar`"
},
"queryContext" : [ {
"objectType" : "",
Expand Down Expand Up @@ -283,6 +284,7 @@ org.apache.spark.sql.AnalysisException
"sqlState" : "4274K",
"messageParameters" : {
"functionName" : "`mask`",
"index" : "0",
"parameterName" : "`str`"
},
"queryContext" : [ {
Expand Down