diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AnsiTypeCoercion.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AnsiTypeCoercion.scala index e23e7561f0e36..23c416dd4b383 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AnsiTypeCoercion.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/AnsiTypeCoercion.scala @@ -192,8 +192,8 @@ object AnsiTypeCoercion extends TypeCoercionBase { // Ideally the implicit cast rule should be the same as `Cast.canANSIStoreAssign` so that it's // consistent with table insertion. To avoid breaking too many existing Spark SQL queries, // we make the system to allow implicitly converting String type as other primitive types. - case (_: StringType, a @ (_: AtomicType | NumericType | DecimalType | AnyTimestampType)) => - Some(a.defaultConcreteType) + case (_: StringType, a @ (_: AtomicType | NumericType | DecimalType | AnyTimestampType | + AnyTimeType)) => Some(a.defaultConcreteType) case (ArrayType(fromType, _), AbstractArrayType(toType)) => implicitCast(fromType, toType).map(ArrayType(_, true)) diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala index ce387ef397aca..53de166e69edf 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercion.scala @@ -228,6 +228,7 @@ object TypeCoercion extends TypeCoercionBase { case (_: StringType, target: NumericType) => target case (_: StringType, datetime: DatetimeType) => datetime case (_: StringType, AnyTimestampType) => AnyTimestampType.defaultConcreteType + case (_: StringType, AnyTimeType) => AnyTimeType.defaultConcreteType case (_: StringType, BinaryType) => BinaryType // Cast any atomic type to string except if there are strings with different collations. case (any: AtomicType, st: StringType) if !any.isInstanceOf[StringType] => st diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercionSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercionSuite.scala index e6a9690ad7570..9b313511010f3 100644 --- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercionSuite.scala +++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/TypeCoercionSuite.scala @@ -217,6 +217,15 @@ abstract class TypeCoercionSuiteBase extends AnalysisTest { shouldNotCast(checkedType, IntegralType) } + test("SPARK-56152: implicit type cast - TimeType") { + val checkedType = TimeType() + checkTypeCasting(checkedType, castableTypes = Seq(checkedType, StringType) ++ datetimeTypes) + shouldCast(checkedType, AnyTimeType, AnyTimeType.defaultConcreteType) + shouldNotCast(checkedType, DecimalType) + shouldNotCast(checkedType, NumericType) + shouldNotCast(checkedType, IntegralType) + } + test("implicit type cast between two Map types") { val sourceType = MapType(IntegerType, IntegerType, true) val castableTypes = numericTypes ++ Seq(StringType).filter(!Cast.forceNullable(IntegerType, _)) @@ -1806,7 +1815,7 @@ object TypeCoercionSuite { val fractionalTypes: Seq[DataType] = Seq(DoubleType, FloatType, DecimalType.SYSTEM_DEFAULT, DecimalType(10, 2)) val numericTypes: Seq[DataType] = integralTypes ++ fractionalTypes - val datetimeTypes: Seq[DataType] = Seq(DateType, TimestampType, TimestampNTZType) + val datetimeTypes: Seq[DataType] = Seq(DateType, TimestampType, TimestampNTZType, TimeType()) val intervalTypes: Seq[DataType] = Seq(CalendarIntervalType, DayTimeIntervalType.defaultConcreteType, YearMonthIntervalType.defaultConcreteType) val atomicTypes: Seq[DataType] = diff --git a/sql/core/src/test/resources/sql-tests/analyzer-results/typeCoercion/native/implicitTypeCasts.sql.out b/sql/core/src/test/resources/sql-tests/analyzer-results/typeCoercion/native/implicitTypeCasts.sql.out index 977b1e1459c3e..910a320ae8772 100644 --- a/sql/core/src/test/resources/sql-tests/analyzer-results/typeCoercion/native/implicitTypeCasts.sql.out +++ b/sql/core/src/test/resources/sql-tests/analyzer-results/typeCoercion/native/implicitTypeCasts.sql.out @@ -359,6 +359,28 @@ Project [length(cast(cast(1996-09-10 10:11:12.4 as timestamp) as string)) AS len +- OneRowRelation +-- !query +SELECT '12:00:00' = TIME'12:00:00' FROM t +-- !query analysis +Project [(cast(12:00:00 as time(6)) = 12:00:00) AS (12:00:00 = TIME '12:00:00')#x] ++- SubqueryAlias t + +- View (`t`, [1#x]) + +- Project [cast(1#x as int) AS 1#x] + +- Project [1 AS 1#x] + +- OneRowRelation + + +-- !query +SELECT '12:00:01' > TIME'12:00:00' FROM t +-- !query analysis +Project [(cast(12:00:01 as time(6)) > 12:00:00) AS (12:00:01 > TIME '12:00:00')#x] ++- SubqueryAlias t + +- View (`t`, [1#x]) + +- Project [cast(1#x as int) AS 1#x] + +- Project [1 AS 1#x] + +- OneRowRelation + + -- !query SELECT year( '1996-01-10') FROM t -- !query analysis diff --git a/sql/core/src/test/resources/sql-tests/inputs/typeCoercion/native/implicitTypeCasts.sql b/sql/core/src/test/resources/sql-tests/inputs/typeCoercion/native/implicitTypeCasts.sql index 6de22b8b7c3de..21c4856d07397 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/typeCoercion/native/implicitTypeCasts.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/typeCoercion/native/implicitTypeCasts.sql @@ -56,6 +56,10 @@ SELECT length('four') FROM t; SELECT length(date('1996-09-10')) FROM t; SELECT length(timestamp('1996-09-10 10:11:12.4')) FROM t; +-- string to time +SELECT '12:00:00' = TIME'12:00:00' FROM t; +SELECT '12:00:01' > TIME'12:00:00' FROM t; + -- extract SELECT year( '1996-01-10') FROM t; SELECT month( '1996-01-10') FROM t; diff --git a/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/implicitTypeCasts.sql.out b/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/implicitTypeCasts.sql.out index bb75fe5991acf..726588623381c 100644 --- a/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/implicitTypeCasts.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/typeCoercion/native/implicitTypeCasts.sql.out @@ -263,6 +263,22 @@ struct 21 +-- !query +SELECT '12:00:00' = TIME'12:00:00' FROM t +-- !query schema +struct<(12:00:00 = TIME '12:00:00'):boolean> +-- !query output +true + + +-- !query +SELECT '12:00:01' > TIME'12:00:00' FROM t +-- !query schema +struct<(12:00:01 > TIME '12:00:00'):boolean> +-- !query output +true + + -- !query SELECT year( '1996-01-10') FROM t -- !query schema