Skip to content

Commit c2a6b8a

Browse files
authored
feat: Cast date to Numeric (No Op) (#3544)
1 parent 7022983 commit c2a6b8a

2 files changed

Lines changed: 60 additions & 35 deletions

File tree

spark/src/main/scala/org/apache/comet/expressions/CometCast.scala

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,36 @@ object CometCast extends CometExpressionSerde[Cast] with CometExprShim {
6767
case _: Literal =>
6868
exprToProtoInternal(Literal.create(cast.eval(), cast.dataType), inputs, binding)
6969
case _ =>
70-
val childExpr = exprToProtoInternal(cast.child, inputs, binding)
71-
if (childExpr.isDefined) {
72-
castToProto(cast, cast.timeZoneId, cast.dataType, childExpr.get, evalMode(cast))
70+
if (isAlwaysCastToNull(cast.child.dataType, cast.dataType, evalMode(cast))) {
71+
exprToProtoInternal(Literal.create(null, cast.dataType), inputs, binding)
7372
} else {
74-
withInfo(cast, cast.child)
75-
None
73+
val childExpr = exprToProtoInternal(cast.child, inputs, binding)
74+
if (childExpr.isDefined) {
75+
castToProto(cast, cast.timeZoneId, cast.dataType, childExpr.get, evalMode(cast))
76+
} else {
77+
withInfo(cast, cast.child)
78+
None
79+
}
7680
}
7781
}
7882
}
7983

84+
// Some casts like date -> int/byte / long are always null. Terminate early in planning
85+
private def isAlwaysCastToNull(
86+
fromType: DataType,
87+
toType: DataType,
88+
evalMode: CometEvalMode.Value): Boolean = {
89+
(fromType, toType) match {
90+
case (
91+
DataTypes.DateType,
92+
DataTypes.BooleanType | DataTypes.ByteType | DataTypes.ShortType |
93+
DataTypes.IntegerType | DataTypes.LongType | DataTypes.FloatType |
94+
DataTypes.DoubleType | _: DecimalType) if evalMode == CometEvalMode.LEGACY =>
95+
true
96+
case _ => false
97+
}
98+
}
99+
80100
/**
81101
* Wrap an already serialized expression in a cast.
82102
*/
@@ -168,7 +188,7 @@ object CometCast extends CometExpressionSerde[Cast] with CometExprShim {
168188
}
169189
}
170190
Compatible()
171-
case (DataTypes.DateType, toType) => canCastFromDate(toType)
191+
case (DataTypes.DateType, toType) => canCastFromDate(toType, evalMode)
172192
case _ => unsupported(fromType, toType)
173193
}
174194
}
@@ -355,11 +375,16 @@ object CometCast extends CometExpressionSerde[Cast] with CometExprShim {
355375
case _ => Unsupported(Some(s"Cast from DecimalType to $toType is not supported"))
356376
}
357377

358-
private def canCastFromDate(toType: DataType): SupportLevel = toType match {
359-
case DataTypes.TimestampType =>
360-
Compatible()
361-
case _ => Unsupported(Some(s"Cast from DateType to $toType is not supported"))
362-
}
378+
private def canCastFromDate(toType: DataType, evalMode: CometEvalMode.Value): SupportLevel =
379+
toType match {
380+
case DataTypes.TimestampType =>
381+
Compatible()
382+
case DataTypes.BooleanType | DataTypes.ByteType | DataTypes.ShortType |
383+
DataTypes.IntegerType | DataTypes.LongType | DataTypes.FloatType |
384+
DataTypes.DoubleType | _: DecimalType if evalMode == CometEvalMode.LEGACY =>
385+
Compatible()
386+
case _ => Unsupported(Some(s"Cast from DateType to $toType is not supported"))
387+
}
363388

364389
private def unsupported(fromType: DataType, toType: DataType): Unsupported = {
365390
Unsupported(Some(s"Cast from $fromType to $toType is not supported"))

spark/src/test/scala/org/apache/comet/CometCastSuite.scala

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -960,44 +960,44 @@ class CometCastSuite extends CometTestBase with AdaptiveSparkPlanHelper {
960960

961961
// CAST from DateType
962962

963-
ignore("cast DateType to BooleanType") {
964-
// Arrow error: Cast error: Casting from Date32 to Boolean not supported
965-
castTest(generateDates(), DataTypes.BooleanType)
963+
// Date to Boolean/Byte/Short/Int/Long/Float/Double/Decimal casts always return NULL
964+
// in LEGACY mode. In ANSI and TRY mode, Spark throws AnalysisException at
965+
// query parsing time. Hence, ANSI and Try mode are disabled in tests
966+
967+
test("cast DateType to BooleanType") {
968+
castTest(generateDates(), DataTypes.BooleanType, testAnsi = false, testTry = false)
966969
}
967970

968-
ignore("cast DateType to ByteType") {
969-
// Arrow error: Cast error: Casting from Date32 to Int8 not supported
970-
castTest(generateDates(), DataTypes.ByteType)
971+
test("cast DateType to ByteType") {
972+
castTest(generateDates(), DataTypes.ByteType, testAnsi = false, testTry = false)
971973
}
972974

973-
ignore("cast DateType to ShortType") {
974-
// Arrow error: Cast error: Casting from Date32 to Int16 not supported
975-
castTest(generateDates(), DataTypes.ShortType)
975+
test("cast DateType to ShortType") {
976+
castTest(generateDates(), DataTypes.ShortType, testAnsi = false, testTry = false)
976977
}
977978

978-
ignore("cast DateType to IntegerType") {
979-
// input: 2345-01-01, expected: null, actual: 3789391
980-
castTest(generateDates(), DataTypes.IntegerType)
979+
test("cast DateType to IntegerType") {
980+
castTest(generateDates(), DataTypes.IntegerType, testAnsi = false, testTry = false)
981981
}
982982

983-
ignore("cast DateType to LongType") {
984-
// input: 2024-01-01, expected: null, actual: 19723
985-
castTest(generateDates(), DataTypes.LongType)
983+
test("cast DateType to LongType") {
984+
castTest(generateDates(), DataTypes.LongType, testAnsi = false, testTry = false)
986985
}
987986

988-
ignore("cast DateType to FloatType") {
989-
// Arrow error: Cast error: Casting from Date32 to Float32 not supported
990-
castTest(generateDates(), DataTypes.FloatType)
987+
test("cast DateType to FloatType") {
988+
castTest(generateDates(), DataTypes.FloatType, testAnsi = false, testTry = false)
991989
}
992990

993-
ignore("cast DateType to DoubleType") {
994-
// Arrow error: Cast error: Casting from Date32 to Float64 not supported
995-
castTest(generateDates(), DataTypes.DoubleType)
991+
test("cast DateType to DoubleType") {
992+
castTest(generateDates(), DataTypes.DoubleType, testAnsi = false, testTry = false)
996993
}
997994

998-
ignore("cast DateType to DecimalType(10,2)") {
999-
// Arrow error: Cast error: Casting from Date32 to Decimal128(10, 2) not supported
1000-
castTest(generateDates(), DataTypes.createDecimalType(10, 2))
995+
test("cast DateType to DecimalType(10,2)") {
996+
castTest(
997+
generateDates(),
998+
DataTypes.createDecimalType(10, 2),
999+
testAnsi = false,
1000+
testTry = false)
10011001
}
10021002

10031003
test("cast DateType to StringType") {

0 commit comments

Comments
 (0)