-
Notifications
You must be signed in to change notification settings - Fork 338
feat: support Spark 4.1 TIME type and expressions via codegen dispatch #4821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,7 +28,7 @@ import org.apache.spark.sql.catalyst.expressions.codegen._ | |
| import org.apache.spark.sql.internal.SQLConf | ||
| import org.apache.spark.sql.types._ | ||
|
|
||
| import org.apache.comet.shims.CometExprTraitShim | ||
| import org.apache.comet.shims.{CometExprTraitShim, CometTypeShim} | ||
|
|
||
| /** | ||
| * Compiles a bound [[Expression]] plus an Arrow input schema into a [[CometBatchKernel]] that | ||
|
|
@@ -49,7 +49,7 @@ import org.apache.comet.shims.CometExprTraitShim | |
| * The generated kernel is the `InternalRow` that Spark's `BoundReference.genCode` reads from. See | ||
| * [[generateSource]] for how the wiring is set up. | ||
| */ | ||
| object CometBatchKernelCodegen extends Logging with CometExprTraitShim { | ||
| object CometBatchKernelCodegen extends Logging with CometExprTraitShim with CometTypeShim { | ||
|
|
||
| /** | ||
| * Resolve an Arrow vector class by simple name through the codegen object's own classloader. | ||
|
|
@@ -69,6 +69,7 @@ object CometBatchKernelCodegen extends Logging with CometExprTraitShim { | |
| case "DateDayVector" => classOf[DateDayVector] | ||
| case "TimeStampMicroVector" => classOf[TimeStampMicroVector] | ||
| case "TimeStampMicroTZVector" => classOf[TimeStampMicroTZVector] | ||
| case "TimeNanoVector" => classOf[TimeNanoVector] | ||
| case "VarCharVector" => classOf[VarCharVector] | ||
| case "VarBinaryVector" => classOf[VarBinaryVector] | ||
| case "IntervalYearVector" => classOf[IntervalYearVector] | ||
|
|
@@ -87,6 +88,7 @@ object CometBatchKernelCodegen extends Logging with CometExprTraitShim { | |
| case _: StringType | _: BinaryType => true | ||
| case DateType | TimestampType | TimestampNTZType => true | ||
| case _: YearMonthIntervalType | _: DayTimeIntervalType => true | ||
| case dt if isTimeType(dt) => true | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This also makes arrays, structs, and maps containing
now passes validation and throws during kernel generation instead of falling back. Could we add |
||
| case ArrayType(inner, _) => isSupportedDataType(inner) | ||
| case st: StructType => st.fields.forall(f => isSupportedDataType(f.dataType)) | ||
| case mt: MapType => isSupportedDataType(mt.keyType) && isSupportedDataType(mt.valueType) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,7 @@ import org.apache.spark.sql.internal.SQLConf | |
| import org.apache.spark.sql.types.TimeType | ||
|
|
||
| import org.apache.comet.expressions.CometEvalMode | ||
| import org.apache.comet.serde.CometScalaUDF | ||
| import org.apache.comet.serde.ExprOuterClass.{BinaryOutputStyle, Expr} | ||
| import org.apache.comet.serde.QueryPlanSerde.{exprToProtoInternal, optExprWithFallbackReason, scalarFunctionExprToProtoWithReturnType} | ||
|
|
||
|
|
@@ -46,6 +47,22 @@ trait CometExprShim extends Spark4xCometExprShim { | |
| } | ||
| } | ||
|
|
||
| // Function names on `DateTimeUtils` reached via `StaticInvoke` from the Spark 4.1 `TIME` family of | ||
| // `RuntimeReplaceable` expressions (`HoursOfTime`, `MinutesOfTime`, `SecondsOfTime`, | ||
| // `SecondsOfTimeWithFraction`, `TimeAddInterval`, `SubtractTimes`, `TimeDiff`, `TimeTrunc`). | ||
| // Each of these is codegen-safe (the replacement itself is a `StaticInvoke` with a proper | ||
| // `doGenCode`) but has no native lowering yet, so we route them through the JVM codegen | ||
| // dispatcher to keep the enclosing projection native. | ||
| private val timeCodegenDispatchFunctions: Set[String] = Set( | ||
| "getHoursOfTime", | ||
| "getMinutesOfTime", | ||
| "getSecondsOfTime", | ||
| "getSecondsOfTimeWithFraction", | ||
| "timeAddInterval", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This dispatches Could we add |
||
| "subtractTimes", | ||
| "timeDiff", | ||
| "timeTrunc") | ||
|
|
||
| // Spark 4.1 introduced TimeType and the make_time / to_time / try_to_time functions. | ||
| // Their planner forms differ from the shared 4.x patterns (DateTimeUtils.makeTime | ||
| // StaticInvoke and ToTimeParser Invoke / TryEval(Invoke)), so they live here rather | ||
|
|
@@ -66,6 +83,14 @@ trait CometExprShim extends Spark4xCometExprShim { | |
| scalarFunctionExprToProtoWithReturnType("make_time", s.dataType, true, childExprs: _*) | ||
| optExprWithFallbackReason(optExpr, expr, s.arguments: _*) | ||
|
|
||
| // Route the other Spark 4.1 TIME `StaticInvoke` forms through the JVM codegen dispatcher. | ||
| // `emitJvmCodegenDispatch` runs Spark's own `doGenCode` inside the Comet pipeline, so the | ||
| // projection stays native while behavior matches Spark exactly. | ||
| case s: StaticInvoke | ||
| if s.staticObject == classOf[DateTimeUtils.type] && | ||
| timeCodegenDispatchFunctions.contains(s.functionName) => | ||
| CometScalaUDF.emitJvmCodegenDispatch(s, inputs, binding) | ||
|
|
||
| case i: Invoke => | ||
| (i.targetObject, i.functionName, i.arguments) match { | ||
| case (Literal(parser: ToTimeParser, _), "parse", args) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implies that all
to_timeforms are supported, but the Spark 4.1 shim still only handles the one-argument form with no explicit format (fmt.isEmpty && args.size == 1). The existing SQL tests expect formattedto_timeandtry_to_timecalls to fall back.Could we update both this row and the
try_to_timerow on line 297 to say that only the default-format form is supported, or route the formatted forms through JVM codegen dispatch?