diff --git a/core/src/main/resources/error/error-classes.json b/core/src/main/resources/error/error-classes.json index 3e1655d80e4e7..a3a2dff0e2744 100644 --- a/core/src/main/resources/error/error-classes.json +++ b/core/src/main/resources/error/error-classes.json @@ -86,6 +86,11 @@ "Cannot resolve due to data type mismatch:" ], "subClass" : { + "BINARY_ARRAY_DIFF_TYPES" : { + "message" : [ + "Input to function should have been two with same element type, but it's [, ]." + ] + }, "BINARY_OP_DIFF_TYPES" : { "message" : [ "the left and right operands of the binary operator have incompatible types ( and )." @@ -118,6 +123,11 @@ "To convert values from to , you can use the functions instead." ] }, + "DATA_DIFF_TYPES" : { + "message" : [ + "Input to should all be the same type, but it's ." + ] + }, "FRAME_LESS_OFFSET_WITHOUT_FOLDABLE" : { "message" : [ "Offset expression must be a literal." @@ -133,6 +143,31 @@ "Input schema must be a struct, an array or a map." ] }, + "INVALID_MAP_KEY_TYPE" : { + "message" : [ + "The key of map cannot be/contain ." + ] + }, + "INVALID_ORDERING_TYPE" : { + "message" : [ + "The does not support ordering on type ." + ] + }, + "MAP_CONCAT_DIFF_TYPES" : { + "message" : [ + "The should all be of type map, but it's ." + ] + }, + "MAP_CONTAINS_KEY_DIFF_TYPES" : { + "message" : [ + "Input to should have been followed by a value with same key type, but it's [, ]." + ] + }, + "MAP_FROM_ENTRIES_WRONG_TYPE" : { + "message" : [ + "The accepts only arrays of pair structs, but is of ." + ] + }, "NON_FOLDABLE_INPUT" : { "message" : [ "the input should be a foldable string expression and not null; however, got ." @@ -143,6 +178,11 @@ "all arguments must be strings." ] }, + "NULL_TYPE" : { + "message" : [ + "Null typed values cannot be used as arguments of ." + ] + }, "RANGE_FRAME_INVALID_TYPE" : { "message" : [ "The data type used in the order specification does not match the data type which is used in the range frame." diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collectionOperations.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collectionOperations.scala index cad833d66f68b..efaadac6ed1c8 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collectionOperations.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/collectionOperations.scala @@ -24,7 +24,9 @@ import scala.reflect.ClassTag import org.apache.spark.sql.catalyst.InternalRow import org.apache.spark.sql.catalyst.analysis.{TypeCheckResult, TypeCoercion, UnresolvedAttribute, UnresolvedSeed} +import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.DataTypeMismatch import org.apache.spark.sql.catalyst.expressions.ArraySortLike.NullOrder +import org.apache.spark.sql.catalyst.expressions.Cast.{toSQLExpr, toSQLType} import org.apache.spark.sql.catalyst.expressions.codegen._ import org.apache.spark.sql.catalyst.expressions.codegen.Block._ import org.apache.spark.sql.catalyst.trees.{BinaryLike, SQLQueryContext, UnaryLike} @@ -66,9 +68,16 @@ trait BinaryArrayExpressionWithImplicitCast extends BinaryExpression (left.dataType, right.dataType) match { case (ArrayType(e1, _), ArrayType(e2, _)) if e1.sameType(e2) => TypeCheckResult.TypeCheckSuccess - case _ => TypeCheckResult.TypeCheckFailure(s"input to function $prettyName should have " + - s"been two ${ArrayType.simpleString}s with same element type, but it's " + - s"[${left.dataType.catalogString}, ${right.dataType.catalogString}]") + case _ => + DataTypeMismatch( + errorSubClass = "BINARY_ARRAY_DIFF_TYPES", + messageParameters = Map( + "functionName" -> prettyName, + "arrayType" -> toSQLType(ArrayType), + "leftType" -> toSQLType(left.dataType), + "rightType" -> toSQLType(right.dataType) + ) + ) } } @@ -229,12 +238,21 @@ case class MapContainsKey(left: Expression, right: Expression) override def checkInputDataTypes(): TypeCheckResult = { (left.dataType, right.dataType) match { case (_, NullType) => - TypeCheckResult.TypeCheckFailure("Null typed values cannot be used as arguments") + DataTypeMismatch( + errorSubClass = "NULL_TYPE", + Map("functionName" -> prettyName)) case (MapType(kt, _, _), dt) if kt.sameType(dt) => TypeUtils.checkForOrderingExpr(kt, s"function $prettyName") - case _ => TypeCheckResult.TypeCheckFailure(s"Input to function $prettyName should have " + - s"been ${MapType.simpleString} followed by a value with same key type, but it's " + - s"[${left.dataType.catalogString}, ${right.dataType.catalogString}].") + case _ => + DataTypeMismatch( + errorSubClass = "MAP_CONTAINS_KEY_DIFF_TYPES", + messageParameters = Map( + "functionName" -> prettyName, + "dataType" -> toSQLType(MapType), + "leftType" -> toSQLType(left.dataType), + "rightType" -> toSQLType(right.dataType) + ) + ) } } @@ -663,9 +681,13 @@ case class MapConcat(children: Seq[Expression]) extends ComplexTypeMergingExpres override def checkInputDataTypes(): TypeCheckResult = { val funcName = s"function $prettyName" if (children.exists(!_.dataType.isInstanceOf[MapType])) { - TypeCheckResult.TypeCheckFailure( - s"input to $funcName should all be of type map, but it's " + - children.map(_.dataType.catalogString).mkString("[", ", ", "]")) + DataTypeMismatch( + errorSubClass = "MAP_CONCAT_DIFF_TYPES", + messageParameters = Map( + "functionName" -> funcName, + "dataType" -> children.map(_.dataType).map(toSQLType).mkString("[", ", ", "]") + ) + ) } else { val sameTypeCheck = TypeUtils.checkForSameTypeInputExpr(children.map(_.dataType), funcName) if (sameTypeCheck.isFailure) { @@ -801,8 +823,15 @@ case class MapFromEntries(child: Expression) extends UnaryExpression with NullIn override def checkInputDataTypes(): TypeCheckResult = dataTypeDetails match { case Some((mapType, _, _)) => TypeUtils.checkForMapKeyType(mapType.keyType) - case None => TypeCheckResult.TypeCheckFailure(s"'${child.sql}' is of " + - s"${child.dataType.catalogString} type. $prettyName accepts only arrays of pair structs.") + case None => + DataTypeMismatch( + errorSubClass = "MAP_FROM_ENTRIES_WRONG_TYPE", + messageParameters = Map( + "functionName" -> prettyName, + "childExpr" -> toSQLExpr(child), + "childType" -> toSQLType(child.dataType) + ) + ) } private lazy val mapBuilder = new ArrayBasedMapBuilder(dataType.keyType, dataType.valueType) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/TypeUtils.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/TypeUtils.scala index c7e42692d163c..7cb471d14bda4 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/TypeUtils.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/TypeUtils.scala @@ -18,6 +18,8 @@ package org.apache.spark.sql.catalyst.util import org.apache.spark.sql.catalyst.analysis.{TypeCheckResult, TypeCoercion} +import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.DataTypeMismatch +import org.apache.spark.sql.catalyst.expressions.Cast.toSQLType import org.apache.spark.sql.catalyst.expressions.RowOrdering import org.apache.spark.sql.errors.QueryCompilationErrors import org.apache.spark.sql.types._ @@ -31,8 +33,13 @@ object TypeUtils { if (RowOrdering.isOrderable(dt)) { TypeCheckResult.TypeCheckSuccess } else { - TypeCheckResult.TypeCheckFailure( - s"$caller does not support ordering on type ${dt.catalogString}") + DataTypeMismatch( + errorSubClass = "INVALID_ORDERING_TYPE", + Map( + "functionName" -> caller, + "dataType" -> toSQLType(dt) + ) + ) } } @@ -40,15 +47,24 @@ object TypeUtils { if (TypeCoercion.haveSameType(types)) { TypeCheckResult.TypeCheckSuccess } else { - TypeCheckResult.TypeCheckFailure( - s"input to $caller should all be the same type, but it's " + - types.map(_.catalogString).mkString("[", ", ", "]")) + DataTypeMismatch( + errorSubClass = "DATA_DIFF_TYPES", + messageParameters = Map( + "functionName" -> caller, + "dataType" -> types.map(toSQLType).mkString("(", " or ", ")") + ) + ) } } def checkForMapKeyType(keyType: DataType): TypeCheckResult = { if (keyType.existsRecursively(_.isInstanceOf[MapType])) { - TypeCheckResult.TypeCheckFailure("The key of map cannot be/contain map.") + DataTypeMismatch( + errorSubClass = "INVALID_MAP_KEY_TYPE", + messageParameters = Map( + "keyType" -> toSQLType(keyType) + ) + ) } else { TypeCheckResult.TypeCheckSuccess } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisErrorSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisErrorSuite.scala index dc007b5238648..d6a63dd0d0bf5 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisErrorSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/AnalysisErrorSuite.scala @@ -719,7 +719,17 @@ class AnalysisErrorSuite extends AnalysisTest { right, joinType = Cross, condition = Some($"b" === $"d")) - assertAnalysisError(plan2, "EqualTo does not support ordering on type map" :: Nil) + + assertAnalysisErrorClass( + inputPlan = plan2, + expectedErrorClass = "DATATYPE_MISMATCH.INVALID_ORDERING_TYPE", + expectedMessageParameters = Map( + "functionName" -> "EqualTo", + "dataType" -> "\"MAP\"", + "sqlExpr" -> "\"(b = d)\"" + ), + caseSensitive = true + ) } test("PredicateSubQuery is used outside of a allowed nodes") { diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ExpressionTypeCheckingSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ExpressionTypeCheckingSuite.scala index 933645a413540..633f9a648157d 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ExpressionTypeCheckingSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ExpressionTypeCheckingSuite.scala @@ -25,10 +25,11 @@ import org.apache.spark.sql.catalyst.expressions._ import org.apache.spark.sql.catalyst.expressions.aggregate._ import org.apache.spark.sql.catalyst.plans.SQLHelper import org.apache.spark.sql.catalyst.plans.logical.LocalRelation +import org.apache.spark.sql.errors.QueryErrorsBase import org.apache.spark.sql.internal.SQLConf import org.apache.spark.sql.types._ -class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { +class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper with QueryErrorsBase { val testRelation = LocalRelation( $"intField".int, @@ -52,7 +53,7 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { SimpleAnalyzer.checkAnalysis(analyzed) } - def assertErrorForDifferingTypes( + def assertErrorForBinaryDifferingTypes( expr: Expression, messageParameters: Map[String, String]): Unit = { checkError( exception = intercept[AnalysisException] { @@ -62,6 +63,26 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { parameters = messageParameters) } + def assertErrorForOrderingTypes( + expr: Expression, messageParameters: Map[String, String]): Unit = { + checkError( + exception = intercept[AnalysisException] { + assertSuccess(expr) + }, + errorClass = "DATATYPE_MISMATCH.INVALID_ORDERING_TYPE", + parameters = messageParameters) + } + + def assertErrorForDataDifferingTypes( + expr: Expression, messageParameters: Map[String, String]): Unit = { + checkError( + exception = intercept[AnalysisException] { + assertSuccess(expr) + }, + errorClass = "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + parameters = messageParameters) + } + def assertForWrongType(expr: Expression, messageParameters: Map[String, String]): Unit = { checkError( exception = intercept[AnalysisException] { @@ -94,49 +115,49 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { assertSuccess(Remainder($"intField", $"stringField")) // checkAnalysis(BitwiseAnd($"intField", $"stringField")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = Add($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField + booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = Subtract($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField - booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = Multiply($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField * booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = Divide($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField / booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = Remainder($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField % booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = BitwiseAnd($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField & booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = BitwiseOr($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField | booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = BitwiseXor($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField ^ booleanField)\"", @@ -211,13 +232,13 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { assertSuccess(EqualNullSafe($"intField", $"booleanField")) } withSQLConf(SQLConf.ANSI_ENABLED.key -> "true") { - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = EqualTo($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField = booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = EqualNullSafe($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField <=> booleanField)\"", @@ -225,55 +246,99 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { "right" -> "\"BOOLEAN\"")) } - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = EqualTo($"intField", $"mapField"), messageParameters = Map( "sqlExpr" -> "\"(intField = mapField)\"", "left" -> "\"INT\"", "right" -> "\"MAP\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = EqualNullSafe($"intField", $"mapField"), messageParameters = Map( "sqlExpr" -> "\"(intField <=> mapField)\"", "left" -> "\"INT\"", "right" -> "\"MAP\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = LessThan($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField < booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = LessThanOrEqual($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField <= booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = GreaterThan($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField > booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertErrorForDifferingTypes( + assertErrorForBinaryDifferingTypes( expr = GreaterThanOrEqual($"intField", $"booleanField"), messageParameters = Map( "sqlExpr" -> "\"(intField >= booleanField)\"", "left" -> "\"INT\"", "right" -> "\"BOOLEAN\"")) - assertError(EqualTo($"mapField", $"mapField"), - "EqualTo does not support ordering on type map") - assertError(EqualNullSafe($"mapField", $"mapField"), - "EqualNullSafe does not support ordering on type map") - assertError(LessThan($"mapField", $"mapField"), - "LessThan does not support ordering on type map") - assertError(LessThanOrEqual($"mapField", $"mapField"), - "LessThanOrEqual does not support ordering on type map") - assertError(GreaterThan($"mapField", $"mapField"), - "GreaterThan does not support ordering on type map") - assertError(GreaterThanOrEqual($"mapField", $"mapField"), - "GreaterThanOrEqual does not support ordering on type map") + assertErrorForOrderingTypes( + expr = EqualTo($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField = mapField)\"", + "functionName" -> "EqualTo", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = EqualTo($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField = mapField)\"", + "functionName" -> "EqualTo", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = EqualNullSafe($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField <=> mapField)\"", + "functionName" -> "EqualNullSafe", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = LessThan($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField < mapField)\"", + "functionName" -> "LessThan", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = LessThanOrEqual($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField <= mapField)\"", + "functionName" -> "LessThanOrEqual", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = GreaterThan($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField > mapField)\"", + "functionName" -> "GreaterThan", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = GreaterThanOrEqual($"mapField", $"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"(mapField >= mapField)\"", + "functionName" -> "GreaterThanOrEqual", + "dataType" -> "\"MAP\"" + ) + ) assertError(If($"intField", $"stringField", $"stringField"), "type of predicate expression in If should be boolean") @@ -305,18 +370,45 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { assertSuccess(new BoolAnd($"booleanField")) assertSuccess(new BoolOr($"booleanField")) - assertError(Min($"mapField"), "min does not support ordering on type") - assertError(Max($"mapField"), "max does not support ordering on type") + assertErrorForOrderingTypes( + expr = Min($"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"min(mapField)\"", + "functionName" -> "function min", + "dataType" -> "\"MAP\"" + ) + ) + assertErrorForOrderingTypes( + expr = Max($"mapField"), + messageParameters = Map( + "sqlExpr" -> "\"max(mapField)\"", + "functionName" -> "function max", + "dataType" -> "\"MAP\"" + ) + ) assertError(Sum($"booleanField"), "function sum requires numeric or interval types") assertError(Average($"booleanField"), "function average requires numeric or interval types") } test("check types for others") { - assertError(CreateArray(Seq($"intField", $"booleanField")), - "input to function array should all be the same type") - assertError(Coalesce(Seq($"intField", $"booleanField")), - "input to function coalesce should all be the same type") + assertErrorForDataDifferingTypes( + expr = CreateArray(Seq($"intField", $"booleanField")), + messageParameters = Map( + "sqlExpr" -> "\"array(intField, booleanField)\"", + "functionName" -> "function array", + "dataType" -> "(\"INT\" or \"BOOLEAN\")" + ) + ) + assertErrorForDataDifferingTypes( + expr = Coalesce(Seq($"intField", $"booleanField")), + messageParameters = Map( + "sqlExpr" -> "\"coalesce(intField, booleanField)\"", + "functionName" -> "function coalesce", + "dataType" -> "(\"INT\" or \"BOOLEAN\")" + ) + ) + assertError(Coalesce(Nil), "function coalesce requires at least one argument") assertError(new Murmur3Hash(Nil), "function hash requires at least one argument") assertError(new XxHash64(Nil), "function xxhash64 requires at least one argument") @@ -437,8 +529,15 @@ class ExpressionTypeCheckingSuite extends SparkFunSuite with SQLHelper { assertError(operator(Seq($"booleanField")), "requires at least two arguments") assertError(operator(Seq($"intField", $"stringField")), "should all have the same type") - assertError(operator(Seq($"mapField", $"mapField")), - "does not support ordering") + val expr3 = operator(Seq($"mapField", $"mapField")) + assertErrorForOrderingTypes( + expr = expr3, + messageParameters = Map( + "sqlExpr" -> toSQLExpr(expr3), + "functionName" -> s"function ${expr3.prettyName}", + "dataType" -> "\"MAP\"" + ) + ) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CollectionExpressionsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CollectionExpressionsSuite.scala index 9a6caea59bf03..9839b784e6059 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CollectionExpressionsSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CollectionExpressionsSuite.scala @@ -263,8 +263,9 @@ class CollectionExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper val map = MapConcat(Seq(mapOfMap, mapOfMap2)) map.checkInputDataTypes() match { case TypeCheckResult.TypeCheckSuccess => fail("should not allow map as map key") - case TypeCheckResult.TypeCheckFailure(msg) => - assert(msg.contains("The key of map cannot be/contain map")) + case TypeCheckResult.DataTypeMismatch(errorSubClass, messageParameters) => + assert(errorSubClass === "INVALID_MAP_KEY_TYPE") + assert(messageParameters === Map("keyType" -> "\"MAP\"")) } } @@ -341,8 +342,9 @@ class CollectionExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper arrayType(keyType = MapType(IntegerType, IntegerType), valueType = IntegerType))) map.checkInputDataTypes() match { case TypeCheckResult.TypeCheckSuccess => fail("should not allow map as map key") - case TypeCheckResult.TypeCheckFailure(msg) => - assert(msg.contains("The key of map cannot be/contain map")) + case TypeCheckResult.DataTypeMismatch(errorSubClass, messageParameters) => + assert(errorSubClass === "INVALID_MAP_KEY_TYPE") + assert(messageParameters === Map("keyType" -> "\"MAP\"")) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ComplexTypeSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ComplexTypeSuite.scala index 3d9416fda4596..fb6a23e3d776c 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ComplexTypeSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ComplexTypeSuite.scala @@ -310,8 +310,9 @@ class ComplexTypeSuite extends SparkFunSuite with ExpressionEvalHelper { )) map2.checkInputDataTypes() match { case TypeCheckResult.TypeCheckSuccess => fail("should not allow map as map key") - case TypeCheckResult.TypeCheckFailure(msg) => - assert(msg.contains("The key of map cannot be/contain map")) + case TypeCheckResult.DataTypeMismatch(errorSubClass, messageParameters) => + assert(errorSubClass == "INVALID_MAP_KEY_TYPE") + assert(messageParameters === Map("keyType" -> "\"MAP\"")) } } @@ -371,8 +372,9 @@ class ComplexTypeSuite extends SparkFunSuite with ExpressionEvalHelper { Literal.create(Seq(1), ArrayType(IntegerType))) map.checkInputDataTypes() match { case TypeCheckResult.TypeCheckSuccess => fail("should not allow map as map key") - case TypeCheckResult.TypeCheckFailure(msg) => - assert(msg.contains("The key of map cannot be/contain map")) + case TypeCheckResult.DataTypeMismatch(errorSubClass, messageParameters) => + assert(errorSubClass == "INVALID_MAP_KEY_TYPE") + assert(messageParameters === Map("keyType" -> "\"MAP\"")) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/HigherOrderFunctionsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/HigherOrderFunctionsSuite.scala index b1c4c4414274c..a6546d8a5dbb0 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/HigherOrderFunctionsSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/HigherOrderFunctionsSuite.scala @@ -524,8 +524,9 @@ class HigherOrderFunctionsSuite extends SparkFunSuite with ExpressionEvalHelper val map = transformKeys(ai0, makeMap) map.checkInputDataTypes() match { case TypeCheckResult.TypeCheckSuccess => fail("should not allow map as map key") - case TypeCheckResult.TypeCheckFailure(msg) => - assert(msg.contains("The key of map cannot be/contain map")) + case TypeCheckResult.DataTypeMismatch(errorSubClass, messageParameters) => + assert(errorSubClass == "INVALID_MAP_KEY_TYPE") + assert(messageParameters === Map("keyType" -> "\"MAP\"")) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/PredicateSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/PredicateSuite.scala index 0d1464ffdb029..5e5d0f7445e37 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/PredicateSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/PredicateSuite.scala @@ -239,7 +239,10 @@ class PredicateSuite extends SparkFunSuite with ExpressionEvalHelper { In(map, Seq(map)).checkInputDataTypes() match { case TypeCheckResult.TypeCheckFailure(msg) => assert(msg.contains("function in does not support ordering on type map")) - case _ => fail("In should not work on map type") + case TypeCheckResult.DataTypeMismatch(errorSubClass, messageParameters) => + assert(errorSubClass == "INVALID_ORDERING_TYPE") + assert(messageParameters === Map( + "functionName" -> "function in", "dataType" -> "\"MAP\"")) } } diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TypeUtilsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TypeUtilsSuite.scala index bc6852ca7e1fd..b209b93ce4d1c 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TypeUtilsSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/TypeUtilsSuite.scala @@ -18,7 +18,7 @@ package org.apache.spark.sql.catalyst.util import org.apache.spark.SparkFunSuite -import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.{TypeCheckFailure, TypeCheckSuccess} +import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.{DataTypeMismatch, TypeCheckSuccess} import org.apache.spark.sql.types._ class TypeUtilsSuite extends SparkFunSuite { @@ -28,7 +28,8 @@ class TypeUtilsSuite extends SparkFunSuite { } private def typeCheckFail(types: Seq[DataType]): Unit = { - assert(TypeUtils.checkForSameTypeInputExpr(types, "a").isInstanceOf[TypeCheckFailure]) + assert(TypeUtils.checkForSameTypeInputExpr(types, "a") + .isInstanceOf[DataTypeMismatch]) } test("checkForSameTypeInputExpr") { diff --git a/sql/core/src/test/resources/sql-tests/results/ansi/interval.sql.out b/sql/core/src/test/resources/sql-tests/results/ansi/interval.sql.out index 93fe7cf5956ac..2078d3d8eb686 100644 --- a/sql/core/src/test/resources/sql-tests/results/ansi/interval.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/ansi/interval.sql.out @@ -3605,7 +3605,21 @@ SELECT array(INTERVAL 1 MONTH, INTERVAL 20 DAYS) struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'array(INTERVAL '1' MONTH, INTERVAL '20' DAY)' due to data type mismatch: input to function array should all be the same type, but it's [interval month, interval day]; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"INTERVAL MONTH\" or \"INTERVAL DAY\")", + "functionName" : "function array", + "sqlExpr" : "\"array(INTERVAL '1' MONTH, INTERVAL '20' DAY)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 48, + "fragment" : "array(INTERVAL 1 MONTH, INTERVAL 20 DAYS)" + } ] +} -- !query @@ -3630,7 +3644,21 @@ SELECT coalesce(INTERVAL 1 MONTH, INTERVAL 20 DAYS) struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'coalesce(INTERVAL '1' MONTH, INTERVAL '20' DAY)' due to data type mismatch: input to function coalesce should all be the same type, but it's [interval month, interval day]; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"INTERVAL MONTH\" or \"INTERVAL DAY\")", + "functionName" : "function coalesce", + "sqlExpr" : "\"coalesce(INTERVAL '1' MONTH, INTERVAL '20' DAY)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 51, + "fragment" : "coalesce(INTERVAL 1 MONTH, INTERVAL 20 DAYS)" + } ] +} -- !query diff --git a/sql/core/src/test/resources/sql-tests/results/ansi/map.sql.out b/sql/core/src/test/resources/sql-tests/results/ansi/map.sql.out index cd7cf9a60ce37..c7c6f5578e76d 100644 --- a/sql/core/src/test/resources/sql-tests/results/ansi/map.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/ansi/map.sql.out @@ -69,7 +69,23 @@ select map_contains_key(map('1', 'a', '2', 'b'), 1) struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_contains_key(map('1', 'a', '2', 'b'), 1)' due to data type mismatch: Input to function map_contains_key should have been map followed by a value with same key type, but it's [map, int].; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.MAP_CONTAINS_KEY_DIFF_TYPES", + "messageParameters" : { + "dataType" : "\"MAP\"", + "functionName" : "map_contains_key", + "leftType" : "\"MAP\"", + "rightType" : "\"INT\"", + "sqlExpr" : "\"map_contains_key(map(1, a, 2, b), 1)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 51, + "fragment" : "map_contains_key(map('1', 'a', '2', 'b'), 1)" + } ] +} -- !query @@ -78,4 +94,20 @@ select map_contains_key(map(1, 'a', 2, 'b'), '1') struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_contains_key(map(1, 'a', 2, 'b'), '1')' due to data type mismatch: Input to function map_contains_key should have been map followed by a value with same key type, but it's [map, string].; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.MAP_CONTAINS_KEY_DIFF_TYPES", + "messageParameters" : { + "dataType" : "\"MAP\"", + "functionName" : "map_contains_key", + "leftType" : "\"MAP\"", + "rightType" : "\"STRING\"", + "sqlExpr" : "\"map_contains_key(map(1, a, 2, b), 1)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 49, + "fragment" : "map_contains_key(map(1, 'a', 2, 'b'), '1')" + } ] +} \ No newline at end of file diff --git a/sql/core/src/test/resources/sql-tests/results/interval.sql.out b/sql/core/src/test/resources/sql-tests/results/interval.sql.out index 88fd0f538514e..6eb5fb4ce8447 100644 --- a/sql/core/src/test/resources/sql-tests/results/interval.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/interval.sql.out @@ -3418,7 +3418,21 @@ SELECT array(INTERVAL 1 MONTH, INTERVAL 20 DAYS) struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'array(INTERVAL '1' MONTH, INTERVAL '20' DAY)' due to data type mismatch: input to function array should all be the same type, but it's [interval month, interval day]; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"INTERVAL MONTH\" or \"INTERVAL DAY\")", + "functionName" : "function array", + "sqlExpr" : "\"array(INTERVAL '1' MONTH, INTERVAL '20' DAY)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 48, + "fragment" : "array(INTERVAL 1 MONTH, INTERVAL 20 DAYS)" + } ] +} -- !query @@ -3443,7 +3457,21 @@ SELECT coalesce(INTERVAL 1 MONTH, INTERVAL 20 DAYS) struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'coalesce(INTERVAL '1' MONTH, INTERVAL '20' DAY)' due to data type mismatch: input to function coalesce should all be the same type, but it's [interval month, interval day]; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"INTERVAL MONTH\" or \"INTERVAL DAY\")", + "functionName" : "function coalesce", + "sqlExpr" : "\"coalesce(INTERVAL '1' MONTH, INTERVAL '20' DAY)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 51, + "fragment" : "coalesce(INTERVAL 1 MONTH, INTERVAL 20 DAYS)" + } ] +} -- !query diff --git a/sql/core/src/test/resources/sql-tests/results/map.sql.out b/sql/core/src/test/resources/sql-tests/results/map.sql.out index cd7cf9a60ce37..c7c6f5578e76d 100644 --- a/sql/core/src/test/resources/sql-tests/results/map.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/map.sql.out @@ -69,7 +69,23 @@ select map_contains_key(map('1', 'a', '2', 'b'), 1) struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_contains_key(map('1', 'a', '2', 'b'), 1)' due to data type mismatch: Input to function map_contains_key should have been map followed by a value with same key type, but it's [map, int].; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.MAP_CONTAINS_KEY_DIFF_TYPES", + "messageParameters" : { + "dataType" : "\"MAP\"", + "functionName" : "map_contains_key", + "leftType" : "\"MAP\"", + "rightType" : "\"INT\"", + "sqlExpr" : "\"map_contains_key(map(1, a, 2, b), 1)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 51, + "fragment" : "map_contains_key(map('1', 'a', '2', 'b'), 1)" + } ] +} -- !query @@ -78,4 +94,20 @@ select map_contains_key(map(1, 'a', 2, 'b'), '1') struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_contains_key(map(1, 'a', 2, 'b'), '1')' due to data type mismatch: Input to function map_contains_key should have been map followed by a value with same key type, but it's [map, string].; line 1 pos 7 +{ + "errorClass" : "DATATYPE_MISMATCH.MAP_CONTAINS_KEY_DIFF_TYPES", + "messageParameters" : { + "dataType" : "\"MAP\"", + "functionName" : "map_contains_key", + "leftType" : "\"MAP\"", + "rightType" : "\"STRING\"", + "sqlExpr" : "\"map_contains_key(map(1, a, 2, b), 1)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 8, + "stopIndex" : 49, + "fragment" : "map_contains_key(map(1, 'a', 2, 'b'), '1')" + } ] +} \ No newline at end of file diff --git a/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/mapconcat.sql.out b/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/mapconcat.sql.out index 916d32c5e35c7..5c1f5d4d917f5 100644 --- a/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/mapconcat.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/mapconcat.sql.out @@ -40,7 +40,6 @@ struct<> -- !query output - -- !query SELECT map_concat(boolean_map1, boolean_map2) boolean_map, @@ -91,7 +90,21 @@ FROM various_maps struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_concat(various_maps.tinyint_map1, various_maps.array_map1)' due to data type mismatch: input to function map_concat should all be the same type, but it's [map, map,array>]; line 2 pos 4 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"MAP\" or \"MAP, ARRAY>\")", + "functionName" : "function map_concat", + "sqlExpr" : "\"map_concat(tinyint_map1, array_map1)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 12, + "stopIndex" : 47, + "fragment" : "map_concat(tinyint_map1, array_map1)" + } ] +} -- !query @@ -102,7 +115,21 @@ FROM various_maps struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_concat(various_maps.boolean_map1, various_maps.int_map2)' due to data type mismatch: input to function map_concat should all be the same type, but it's [map, map]; line 2 pos 4 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"MAP\" or \"MAP\")", + "functionName" : "function map_concat", + "sqlExpr" : "\"map_concat(boolean_map1, int_map2)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 12, + "stopIndex" : 45, + "fragment" : "map_concat(boolean_map1, int_map2)" + } ] +} -- !query @@ -113,7 +140,21 @@ FROM various_maps struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_concat(various_maps.int_map1, various_maps.struct_map2)' due to data type mismatch: input to function map_concat should all be the same type, but it's [map, map,struct>]; line 2 pos 4 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"MAP\" or \"MAP, STRUCT>\")", + "functionName" : "function map_concat", + "sqlExpr" : "\"map_concat(int_map1, struct_map2)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 12, + "stopIndex" : 44, + "fragment" : "map_concat(int_map1, struct_map2)" + } ] +} -- !query @@ -124,7 +165,21 @@ FROM various_maps struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_concat(various_maps.struct_map1, various_maps.array_map2)' due to data type mismatch: input to function map_concat should all be the same type, but it's [map,struct>, map,array>]; line 2 pos 4 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"MAP, STRUCT>\" or \"MAP, ARRAY>\")", + "functionName" : "function map_concat", + "sqlExpr" : "\"map_concat(struct_map1, array_map2)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 12, + "stopIndex" : 46, + "fragment" : "map_concat(struct_map1, array_map2)" + } ] +} -- !query @@ -135,4 +190,18 @@ FROM various_maps struct<> -- !query output org.apache.spark.sql.AnalysisException -cannot resolve 'map_concat(various_maps.int_map1, various_maps.array_map2)' due to data type mismatch: input to function map_concat should all be the same type, but it's [map, map,array>]; line 2 pos 4 +{ + "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + "messageParameters" : { + "dataType" : "(\"MAP\" or \"MAP, ARRAY>\")", + "functionName" : "function map_concat", + "sqlExpr" : "\"map_concat(int_map1, array_map2)\"" + }, + "queryContext" : [ { + "objectType" : "", + "objectName" : "", + "startIndex" : 12, + "stopIndex" : 43, + "fragment" : "map_concat(int_map1, array_map2)" + } ] +} \ No newline at end of file diff --git a/sql/core/src/test/scala/org/apache/spark/sql/DataFrameAggregateSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/DataFrameAggregateSuite.scala index f58e30c71188f..90e2acfe5d688 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/DataFrameAggregateSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/DataFrameAggregateSuite.scala @@ -913,8 +913,17 @@ class DataFrameAggregateSuite extends QueryTest val error = intercept[AnalysisException] { sql("SELECT max_by(x, y) FROM tempView").show } - assert( - error.message.contains("function max_by does not support ordering on type map")) + checkError( + exception = error, + errorClass = "DATATYPE_MISMATCH.INVALID_ORDERING_TYPE", + sqlState = None, + parameters = Map( + "functionName" -> "function max_by", + "dataType" -> "\"MAP\"", + "sqlExpr" -> "\"max_by(x, y)\"" + ), + context = ExpectedContext(fragment = "max_by(x, y)", start = 7, stop = 18) + ) } } @@ -974,8 +983,17 @@ class DataFrameAggregateSuite extends QueryTest val error = intercept[AnalysisException] { sql("SELECT min_by(x, y) FROM tempView").show } - assert( - error.message.contains("function min_by does not support ordering on type map")) + checkError( + exception = error, + errorClass = "DATATYPE_MISMATCH.INVALID_ORDERING_TYPE", + sqlState = None, + parameters = Map( + "functionName" -> "function min_by", + "dataType" -> "\"MAP\"", + "sqlExpr" -> "\"min_by(x, y)\"" + ), + context = ExpectedContext(fragment = "min_by(x, y)", start = 7, stop = 18) + ) } } diff --git a/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala b/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala index 2b6ac9f6580d1..41af747a83e41 100644 --- a/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala +++ b/sql/core/src/test/scala/org/apache/spark/sql/DataFrameFunctionsSuite.scala @@ -1003,25 +1003,61 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession { checkAnswer(df3.selectExpr("map_concat(map1, map2)"), expected3) checkAnswer(df3.select(map_concat($"map1", $"map2")), expected3) - val expectedMessage1 = "input to function map_concat should all be the same type" - - assert(intercept[AnalysisException] { - df2.selectExpr("map_concat(map1, map2)").collect() - }.getMessage().contains(expectedMessage1)) - - assert(intercept[AnalysisException] { - df2.select(map_concat($"map1", $"map2")).collect() - }.getMessage().contains(expectedMessage1)) + checkError( + exception = intercept[AnalysisException] { + df2.selectExpr("map_concat(map1, map2)").collect() + }, + errorClass = "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + sqlState = None, + parameters = Map( + "sqlExpr" -> "\"map_concat(map1, map2)\"", + "dataType" -> "(\"MAP, INT>\" or \"MAP\")", + "functionName" -> "function map_concat"), + context = ExpectedContext( + fragment = "map_concat(map1, map2)", + start = 0, + stop = 21) + ) - val expectedMessage2 = "input to function map_concat should all be of type map" + checkError( + exception = intercept[AnalysisException] { + df2.select(map_concat($"map1", $"map2")).collect() + }, + errorClass = "DATATYPE_MISMATCH.DATA_DIFF_TYPES", + sqlState = None, + parameters = Map( + "sqlExpr" -> "\"map_concat(map1, map2)\"", + "dataType" -> "(\"MAP, INT>\" or \"MAP\")", + "functionName" -> "function map_concat") + ) - assert(intercept[AnalysisException] { - df2.selectExpr("map_concat(map1, 12)").collect() - }.getMessage().contains(expectedMessage2)) + checkError( + exception = intercept[AnalysisException] { + df2.selectExpr("map_concat(map1, 12)").collect() + }, + errorClass = "DATATYPE_MISMATCH.MAP_CONCAT_DIFF_TYPES", + sqlState = None, + parameters = Map( + "sqlExpr" -> "\"map_concat(map1, 12)\"", + "dataType" -> "[\"MAP, INT>\", \"INT\"]", + "functionName" -> "function map_concat"), + context = ExpectedContext( + fragment = "map_concat(map1, 12)", + start = 0, + stop = 19) + ) - assert(intercept[AnalysisException] { - df2.select(map_concat($"map1", lit(12))).collect() - }.getMessage().contains(expectedMessage2)) + checkError( + exception = intercept[AnalysisException] { + df2.select(map_concat($"map1", lit(12))).collect() + }, + errorClass = "DATATYPE_MISMATCH.MAP_CONCAT_DIFF_TYPES", + sqlState = None, + parameters = Map( + "sqlExpr" -> "\"map_concat(map1, 12)\"", + "dataType" -> "[\"MAP, INT>\", \"INT\"]", + "functionName" -> "function map_concat") + ) } test("map_from_entries function") { @@ -3606,10 +3642,20 @@ class DataFrameFunctionsSuite extends QueryTest with SharedSparkSession { "inputType" -> "\"INT\"", "requiredType" -> "\"MAP\"")) // scalastyle:on line.size.limit - val ex5 = intercept[AnalysisException] { - df.selectExpr("map_zip_with(mmi, mmi, (x, y, z) -> x)") - } - assert(ex5.getMessage.contains("function map_zip_with does not support ordering on type map")) + checkError( + exception = intercept[AnalysisException] { + df.selectExpr("map_zip_with(mmi, mmi, (x, y, z) -> x)") + }, + errorClass = "DATATYPE_MISMATCH.INVALID_ORDERING_TYPE", + sqlState = None, + parameters = Map( + "sqlExpr" -> "\"map_zip_with(mmi, mmi, lambdafunction(x, x, y, z))\"", + "dataType" -> "\"MAP\"", + "functionName" -> "function map_zip_with"), + context = ExpectedContext( + fragment = "map_zip_with(mmi, mmi, (x, y, z) -> x)", + start = 0, + stop = 37)) } test("transform keys function - primitive data types") {