Skip to content
Merged
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
47 changes: 31 additions & 16 deletions core/src/main/resources/error/error-classes.json
Original file line number Diff line number Diff line change
Expand Up @@ -263,9 +263,14 @@
"The <exprName> must be between <valueRange> (current value = <currentValue>)"
]
},
"WRONG_NUM_ENDPOINTS" : {
"message" : [
"The number of endpoints must be >= 2 to construct intervals but the actual number is <actualNumber>."
]
},
"WRONG_NUM_PARAMS" : {
"message" : [
"wrong number of parameters: <actualNum>."
"The <functionName> requires <expectedNum> parameters but the actual number is <actualNum>."
]
}
}
Expand All @@ -276,6 +281,11 @@
],
"sqlState" : "22008"
},
"DECIMAL_PRECISION_EXCEEDS_MAX_PRECISION" : {
"message" : [
"Decimal precision <precision> exceeds max precision <maxPrecision>."
]
},
"DEFAULT_DATABASE_NOT_EXISTS" : {
"message" : [
"Default database <defaultDatabase> does not exist, please create it first or change default database to 'default'."
Expand Down Expand Up @@ -416,6 +426,16 @@
}
}
},
"INCORRECT_END_OFFSET" : {
"message" : [
"Max offset with <rowsPerSecond> rowsPerSecond is <maxSeconds>, but it's <endSeconds> now."
]
},
"INCORRECT_RUMP_UP_RATE" : {
"message" : [
"Max offset with <rowsPerSecond> rowsPerSecond is <maxSeconds>, but 'rampUpTimeSeconds' is <rampUpTimeSeconds>."
]
},
"INDEX_ALREADY_EXISTS" : {
"message" : [
"Cannot create the index because it already exists. <message>."
Expand Down Expand Up @@ -605,6 +625,11 @@
],
"sqlState" : "22005"
},
"OUT_OF_DECIMAL_TYPE_RANGE" : {
"message" : [
"Out of decimal type range: <value>."
]
},
"PARSE_CHAR_MISSING_LENGTH" : {
"message" : [
"DataType <type> requires a length parameter, for example <type>(10). Please specify the length."
Expand Down Expand Up @@ -814,6 +839,11 @@
},
"sqlState" : "42000"
},
"UNSCALED_VALUE_TOO_LARGE_FOR_PRECISION" : {
"message" : [
"Unscaled value too large for precision. If necessary set <ansiConfig> to false to bypass this error."
]
},
"UNSUPPORTED_DATATYPE" : {
"message" : [
"Unsupported data type <typeName>"
Expand Down Expand Up @@ -3707,21 +3737,6 @@
"Unexpected: <o>"
]
},
"_LEGACY_ERROR_TEMP_2117" : {
"message" : [
"Unscaled value too large for precision. If necessary set <ansiConfig> to false to bypass this error."
]
},
"_LEGACY_ERROR_TEMP_2118" : {
"message" : [
"Decimal precision <precision> exceeds max precision <maxPrecision>"
]
},
"_LEGACY_ERROR_TEMP_2119" : {
"message" : [
"out of decimal type range: <str>"
]
},
"_LEGACY_ERROR_TEMP_2120" : {
"message" : [
"Do not support array of type <clazz>."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ case class CallMethodViaReflection(children: Seq[Expression])
if (children.size < 2) {
DataTypeMismatch(
errorSubClass = "WRONG_NUM_PARAMS",
messageParameters = Map("actualNum" -> children.length.toString))
messageParameters = Map(
"functionName" -> prettyName,
"expectedNum" -> "> 1",
"actualNum" -> children.length.toString))
} else {
val unexpectedParameter = children.zipWithIndex.collectFirst {
case (e, 0) if !(e.dataType == StringType && e.foldable) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ import java.util

import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult
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.catalyst.expressions.{ExpectsInputTypes, Expression, GenericInternalRow}
import org.apache.spark.sql.catalyst.trees.BinaryLike
import org.apache.spark.sql.catalyst.util.{ArrayData, GenericArrayData, HyperLogLogPlusPlusHelper}
import org.apache.spark.sql.errors.QueryErrorsBase
import org.apache.spark.sql.types._
import org.apache.spark.unsafe.Platform

Expand All @@ -49,7 +50,10 @@ case class ApproxCountDistinctForIntervals(
relativeSD: Double = 0.05,
mutableAggBufferOffset: Int = 0,
inputAggBufferOffset: Int = 0)
extends TypedImperativeAggregate[Array[Long]] with ExpectsInputTypes with BinaryLike[Expression] {
extends TypedImperativeAggregate[Array[Long]]
with ExpectsInputTypes
with BinaryLike[Expression]
with QueryErrorsBase {

def this(child: Expression, endpointsExpression: Expression, relativeSD: Expression) = {
this(
Expand Down Expand Up @@ -77,19 +81,32 @@ case class ApproxCountDistinctForIntervals(
if (defaultCheck.isFailure) {
defaultCheck
} else if (!endpointsExpression.foldable) {
TypeCheckFailure("The endpoints provided must be constant literals")
DataTypeMismatch(
errorSubClass = "NON_FOLDABLE_INPUT",
messageParameters = Map(
"inputName" -> "endpointsExpression",
"inputType" -> toSQLType(endpointsExpression.dataType)))
} else {
endpointsExpression.dataType match {
case ArrayType(_: NumericType | DateType | TimestampType | TimestampNTZType |
_: AnsiIntervalType, _) =>
if (endpoints.length < 2) {
TypeCheckFailure("The number of endpoints must be >= 2 to construct intervals")
DataTypeMismatch(
errorSubClass = "WRONG_NUM_ENDPOINTS",
messageParameters = Map("actualNumber" -> endpoints.length.toString))
} else {
TypeCheckSuccess
}
case _ =>
TypeCheckFailure("Endpoints require (numeric or timestamp or date or timestamp_ntz or " +
"interval year to month or interval day to second) type")
case inputType =>
val requiredElemTypes = toSQLType(TypeCollection(
NumericType, DateType, TimestampType, TimestampNTZType, AnsiIntervalType))
DataTypeMismatch(
errorSubClass = "UNEXPECTED_INPUT_TYPE",
messageParameters = Map(
"paramIndex" -> "2",
"requiredType" -> s"ARRAY OF $requiredElemTypes",
"inputSql" -> toSQLExpr(endpointsExpression),
"inputType" -> toSQLType(inputType)))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ case class Average(
Seq(TypeCollection(NumericType, YearMonthIntervalType, DayTimeIntervalType))

override def checkInputDataTypes(): TypeCheckResult =
TypeUtils.checkForAnsiIntervalOrNumericType(child.dataType, "average")
TypeUtils.checkForAnsiIntervalOrNumericType(child)

override def nullable: Boolean = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ case class Sum(
Seq(TypeCollection(NumericType, YearMonthIntervalType, DayTimeIntervalType))

override def checkInputDataTypes(): TypeCheckResult =
TypeUtils.checkForAnsiIntervalOrNumericType(child.dataType, prettyName)
TypeUtils.checkForAnsiIntervalOrNumericType(child)

final override val nodePatterns: Seq[TreePattern] = Seq(SUM)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,10 @@ case class Least(children: Seq[Expression]) extends ComplexTypeMergingExpression
if (children.length <= 1) {
DataTypeMismatch(
errorSubClass = "WRONG_NUM_PARAMS",
messageParameters = Map("actualNum" -> children.length.toString))
messageParameters = Map(
"functionName" -> prettyName,
"expectedNum" -> "> 1",
"actualNum" -> children.length.toString))
} else if (!TypeCoercion.haveSameType(inputTypesForMerging)) {
DataTypeMismatch(
errorSubClass = "DATA_DIFF_TYPES",
Expand Down Expand Up @@ -1290,7 +1293,10 @@ case class Greatest(children: Seq[Expression]) extends ComplexTypeMergingExpress
if (children.length <= 1) {
DataTypeMismatch(
errorSubClass = "WRONG_NUM_PARAMS",
messageParameters = Map("actualNum" -> children.length.toString))
messageParameters = Map(
"functionName" -> prettyName,
"expectedNum" -> "> 1",
"actualNum" -> children.length.toString))
} else if (!TypeCoercion.haveSameType(inputTypesForMerging)) {
DataTypeMismatch(
errorSubClass = "DATA_DIFF_TYPES",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,10 @@ case class JsonTuple(children: Seq[Expression])
if (children.length < 2) {
DataTypeMismatch(
errorSubClass = "WRONG_NUM_PARAMS",
messageParameters = Map("actualNum" -> children.length.toString))
messageParameters = Map(
"functionName" -> prettyName,
"expectedNum" -> "> 1",
"actualNum" -> children.length.toString))
} else if (children.forall(child => StringType.acceptsType(child.dataType))) {
TypeCheckResult.TypeCheckSuccess
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import org.apache.commons.text.StringEscapeUtils

import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult
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.catalyst.expressions.Cast._
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
Expand All @@ -37,7 +38,6 @@ import org.apache.spark.sql.errors.QueryExecutionErrors
import org.apache.spark.sql.types._
import org.apache.spark.unsafe.types.UTF8String


abstract class StringRegexExpression extends BinaryExpression
with ImplicitCastInputTypes with NullIntolerant with Predicate {

Expand Down Expand Up @@ -594,14 +594,28 @@ case class RegExpReplace(subject: Expression, regexp: Expression, rep: Expressio
return defaultCheck
}
if (!pos.foldable) {
return TypeCheckFailure(s"Position expression must be foldable, but got $pos")
return DataTypeMismatch(
errorSubClass = "NON_FOLDABLE_INPUT",
messageParameters = Map(
"inputName" -> "position",
"inputType" -> toSQLType(pos.dataType),
"inputExpr" -> toSQLExpr(pos)
)
)
}

val posEval = pos.eval()
if (posEval == null || posEval.asInstanceOf[Int] > 0) {
TypeCheckSuccess
} else {
TypeCheckFailure(s"Position expression must be positive, but got: $posEval")
DataTypeMismatch(
errorSubClass = "VALUE_OUT_OF_RANGE",
messageParameters = Map(
"exprName" -> "position",
"valueRange" -> s"(0, ${Int.MaxValue}]",
"currentValue" -> toSQLValue(posEval, pos.dataType)
)
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import scala.collection.mutable.ArrayBuffer

import org.apache.spark.sql.catalyst.InternalRow
import org.apache.spark.sql.catalyst.analysis.{ExpressionBuilder, FunctionRegistry, TypeCheckResult}
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.DataTypeMismatch
import org.apache.spark.sql.catalyst.expressions.Cast._
import org.apache.spark.sql.catalyst.expressions.codegen._
import org.apache.spark.sql.catalyst.expressions.codegen.Block._
import org.apache.spark.sql.catalyst.expressions.objects.StaticInvoke
Expand Down Expand Up @@ -273,18 +275,35 @@ case class Elt(

override def checkInputDataTypes(): TypeCheckResult = {
if (children.size < 2) {
TypeCheckResult.TypeCheckFailure("elt function requires at least two arguments")
DataTypeMismatch(
errorSubClass = "WRONG_NUM_PARAMS",
messageParameters = Map(
"functionName" -> "elt",
"expectedNum" -> "> 1",
"actualNum" -> children.length.toString
)
)
} else {
val (indexType, inputTypes) = (indexExpr.dataType, inputExprs.map(_.dataType))
if (indexType != IntegerType) {
return TypeCheckResult.TypeCheckFailure(s"first input to function $prettyName should " +
s"have ${IntegerType.catalogString}, but it's ${indexType.catalogString}")
return DataTypeMismatch(
errorSubClass = "UNEXPECTED_INPUT_TYPE",
messageParameters = Map(
"paramIndex" -> "1",
"requiredType" -> toSQLType(IntegerType),
"inputSql" -> toSQLExpr(indexExpr),
"inputType" -> toSQLType(indexType)))
}
if (inputTypes.exists(tpe => !Seq(StringType, BinaryType).contains(tpe))) {
return TypeCheckResult.TypeCheckFailure(
s"input to function $prettyName should have ${StringType.catalogString} or " +
s"${BinaryType.catalogString}, but it's " +
inputTypes.map(_.catalogString).mkString("[", ", ", "]"))
return DataTypeMismatch(
errorSubClass = "UNEXPECTED_INPUT_TYPE",
messageParameters = Map(
"paramIndex" -> "2...",
"requiredType" -> (toSQLType(StringType) + " or " + toSQLType(BinaryType)),
"inputSql" -> inputExprs.map(toSQLExpr(_)).mkString(","),
"inputType" -> inputTypes.map(toSQLType(_)).mkString(",")
)
)
}
TypeUtils.checkForSameTypeInputExpr(inputTypes, s"function $prettyName")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ 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.catalyst.expressions.{Expression, RowOrdering}
import org.apache.spark.sql.errors.{QueryCompilationErrors, QueryErrorsBase}
import org.apache.spark.sql.types._

/**
* Functions to help with checking for valid data types and value comparison of various types.
*/
object TypeUtils {
object TypeUtils extends QueryErrorsBase {

def checkForOrderingExpr(dt: DataType, caller: String): TypeCheckResult = {
if (RowOrdering.isOrderable(dt)) {
Expand Down Expand Up @@ -70,13 +69,18 @@ object TypeUtils {
}
}

def checkForAnsiIntervalOrNumericType(
dt: DataType, funcName: String): TypeCheckResult = dt match {
def checkForAnsiIntervalOrNumericType(input: Expression): TypeCheckResult = input.dataType match {
case _: AnsiIntervalType | NullType =>
TypeCheckResult.TypeCheckSuccess
case dt if dt.isInstanceOf[NumericType] => TypeCheckResult.TypeCheckSuccess
case other => TypeCheckResult.TypeCheckFailure(
s"function $funcName requires numeric or interval types, not ${other.catalogString}")
case other =>
DataTypeMismatch(
errorSubClass = "UNEXPECTED_INPUT_TYPE",
messageParameters = Map(
"paramIndex" -> "1",
"requiredType" -> Seq(NumericType, AnsiIntervalType).map(toSQLType).mkString(" or "),
"inputSql" -> toSQLExpr(input),
"inputType" -> toSQLType(other)))
}

def getNumeric(t: DataType, exactNumericRequired: Boolean = false): Numeric[Any] = {
Expand Down
Loading