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 06d8350db9891..e5230522b208b 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 @@ -150,9 +150,27 @@ object TypeCoercion { } private def findWiderCommonType(types: Seq[DataType]): Option[DataType] = { + var awaitingString = false types.foldLeft[Option[DataType]](Some(NullType))((r, c) => r match { - case Some(d) => findWiderTypeForTwo(d, c) - case None => None + case Some(d) => (d, c) match { + case (DateType, _: NumericType) | (_: NumericType, DateType) | + (TimestampType, _: NumericType) | (_: NumericType, TimestampType) => + awaitingString = true + None + case _ => findWiderTypeForTwo(d, c) + } + case None if awaitingString => c match { + case DateType => None + case TimestampType => None + case (_: NumericType) => None + case StringType => + awaitingString = false + Some(StringType) + case _ => + awaitingString = false + None + } + case _ => None }) } 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 d62e3b6dfe34f..07864e10468c1 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 @@ -528,6 +528,11 @@ class TypeCoercionSuite extends AnalysisTest { Coalesce(Seq(nullLit, floatNullLit, doubleLit, stringLit)), Coalesce(Seq(Cast(nullLit, StringType), Cast(floatNullLit, StringType), Cast(doubleLit, StringType), Cast(stringLit, StringType)))) + + ruleTest(rule, + Coalesce(Seq(timestampLit, intLit, stringLit)), + Coalesce(Seq(Cast(timestampLit, StringType), Cast(intLit, StringType), + Cast(stringLit, StringType)))) } test("CreateArray casts") { @@ -938,27 +943,32 @@ class TypeCoercionSuite extends AnalysisTest { AttributeReference("i", IntegerType)(), AttributeReference("u", DecimalType.SYSTEM_DEFAULT)(), AttributeReference("b", ByteType)(), - AttributeReference("d", DoubleType)()) + AttributeReference("d", DoubleType)(), + AttributeReference("a", DateType)()) val secondTable = LocalRelation( AttributeReference("s", StringType)(), AttributeReference("d", DecimalType(2, 1))(), AttributeReference("f", FloatType)(), - AttributeReference("l", LongType)()) + AttributeReference("l", LongType)(), + AttributeReference("t", TimestampType)()) val thirdTable = LocalRelation( AttributeReference("m", StringType)(), AttributeReference("n", DecimalType.SYSTEM_DEFAULT)(), AttributeReference("p", FloatType)(), - AttributeReference("q", DoubleType)()) - val forthTable = LocalRelation( + AttributeReference("q", DoubleType)(), + AttributeReference("l", LongType)()) + val fourthTable = LocalRelation( AttributeReference("m", StringType)(), AttributeReference("n", DecimalType.SYSTEM_DEFAULT)(), AttributeReference("p", ByteType)(), - AttributeReference("q", DoubleType)()) + AttributeReference("q", DoubleType)(), + AttributeReference("s", StringType)()) - val expectedTypes = Seq(StringType, DecimalType.SYSTEM_DEFAULT, FloatType, DoubleType) + val expectedTypes = Seq(StringType, DecimalType.SYSTEM_DEFAULT, FloatType, DoubleType, + StringType) val unionRelation = widenSetOperationTypes( - Union(firstTable :: secondTable :: thirdTable :: forthTable :: Nil)).asInstanceOf[Union] + Union(firstTable :: secondTable :: thirdTable :: fourthTable :: Nil)).asInstanceOf[Union] assert(unionRelation.children.length == 4) checkOutput(unionRelation.children.head, expectedTypes) checkOutput(unionRelation.children(1), expectedTypes)