andygrove commented on code in PR #5161:
URL: https://github.com/apache/datafusion-comet/pull/5161#discussion_r3690464235


##########
spark/src/main/scala/org/apache/comet/rules/CometScanRule.scala:
##########
@@ -855,6 +855,8 @@ case class CometScanTypeChecker() extends DataTypeSupport 
with CometTypeShim {
       name: String,
       fallbackReasons: ListBuffer[String]): Boolean = {
     dt match {
+      case _: YearMonthIntervalType | _: DayTimeIntervalType =>

Review Comment:
   `isSchemaSupported` is called for `r.partitionSchema` as well as 
`requiredSchema` (lines 831 and 839), and Spark does allow ANSI intervals as 
partition columns. `PartitioningUtils.canPartitionOn` takes any `AtomicType`, 
and `castPartValueToDesiredType` has an explicit `case it: AnsiIntervalType` 
branch. Once the checker admits the type, `partition2Proto` tries 
`exprToProto(Literal(value, YearMonthIntervalType))`, and 
`CometLiteral.getSupportLevel` only whitelists `DayTimeIntervalType` today 
(`literals.scala:60`), because `QueryPlanSerde.supportedDataType` lists neither 
interval type. So the literal comes back as `None` and the `assert` at 
`serde/operator/package.scala:64` fires.
   
   I reproduced this on your branch with Spark 4.1:
   
   ```
   java.lang.AssertionError: assertion failed: Unsupported partition value: 38, 
type: YearMonthIntervalType(0,1)
     at 
org.apache.comet.serde.operator.package$.partition2Proto(package.scala:52)
     at 
org.apache.spark.sql.comet.CometNativeScanExec.$anonfun$serializedPartitionData$10(...)
   ```
   
   Reverting just this hunk goes back to a clean fallback with `Unsupported p 
of type YearMonthIntervalType(0,1)`. Day-time interval partition columns are 
fine, because the literal path already handles them.
   
   I think this is also what the Spark 4.1 `sql_core-1` job is hitting. 
`PartitionedWriteSuite` has `"SPARK-37231, SPARK-37240: Dynamic writes/reads of 
ANSI interval partitions"`, which writes a Parquet dir partitioned by 
`YearMonthIntervalType(YEAR)` and `YearMonthIntervalType(YEAR, MONTH)` and 
reads it back. The suite is untagged so it runs in that shard, and it is not 
excluded in `dev/diffs/4.1.2.diff`.
   
   Could you either teach `CometLiteral` and the native `IntVal` branch about 
`YearMonthIntervalType`, or keep the partition-schema gate narrow so interval 
partition columns still fall back? Either way a test for both interval types as 
partition columns would be good, since nothing covers that today.
   
   Separately, the `assert` in `partition2Proto` turning a planner gap into an 
`AssertionError` rather than a fallback looks fragile. That seems worth a 
follow-up issue of its own.



##########
spark/src/test/scala/org/apache/comet/parquet/ParquetReadSuite.scala:
##########
@@ -125,6 +127,64 @@ abstract class ParquetReadSuite extends CometTestBase {
     }
   }
 
+  test("ANSI interval types") {

Review Comment:
   This is a thorough test. I like that you assert the row group count and 
dictionary encoding rather than hoping the write options took effect.
   
   A few cases that are newly reachable through this change and might be worth 
covering, since `DataTypeSupport.isTypeSupported` recurses into complex types 
via your override:
   
   - interval leaves nested in a struct, an array and a map
   - a filter on an interval column, with and without 
`spark.sql.parquet.filterPushdown`
   - the interval min and max (`INTERVAL '178956970-7' YEAR TO MONTH` and the 
day-time equivalents)
   - both interval types as partition columns
   
   I checked all of these on your branch and everything except the year-month 
partition column produces Spark-matching results, so mostly this is about 
locking the behavior in rather than chasing a bug.
   
   One thing worth knowing: a `ym` predicate is currently dropped from the 
native data filters because the year-month literal is unsupported, so that 
column gets no row group pruning. Results stay correct but the filter is not 
accelerated. Same root cause as the partition value problem.



##########
spark/src/main/scala/org/apache/comet/rules/CometScanRule.scala:
##########
@@ -855,6 +855,8 @@ case class CometScanTypeChecker() extends DataTypeSupport 
with CometTypeShim {
       name: String,
       fallbackReasons: ListBuffer[String]): Boolean = {
     dt match {
+      case _: YearMonthIntervalType | _: DayTimeIntervalType =>
+        true

Review Comment:
   Did you look at what happens when the Parquet physical type does not match 
the requested interval type? Spark's `ParquetVectorUpdaterFactory` accepts any 
INT32 as `YearMonthIntervalType` via `IntegerUpdater` and any INT64 as 
`DayTimeIntervalType` via `LongUpdater`, and raises 
`PARQUET_COLUMN_DATA_TYPE_MISMATCH` for anything else. Comet's 
`parquet_convert_array` goes through arrow `can_cast_types` and then the `_ => 
Ok(array)` fallthrough, which gives different answers in two cases. I probed 
these on your branch:
   
   | file column | requested schema | Spark | Comet |
   | --- | --- | --- | --- |
   | `date` | `interval year to month` | succeeds (`P1522Y1M`, ...) | `Invalid 
argument error: column types must match schema types, expected 
Interval(YearMonth) but found Date32` |
   | `int` | `interval day to second` | `PARQUET_COLUMN_DATA_TYPE_MISMATCH` | 
succeeds, values reinterpreted as micros |
   | `timestamp` | `interval day to second` | error | error |
   | `long` | `interval year to month` | error | error |
   
   The `int` row is the one I would want resolved, since Comet returns rows 
where Spark raises. arrow's `(_, Duration(_)) if from_type.is_numeric()` 
happily accepts that cast. The `date` row is the mirror image, a hard native 
failure where Spark succeeds.
   
   Both need schema-on-read to trigger, so I do not think they have to be fixed 
in this PR. Could you file a tracking issue and link it here? Left unfiled I 
suspect it will not get picked up.



##########
docs/source/user-guide/latest/datatypes.md:
##########
@@ -82,15 +82,15 @@ the tables below and may be reconsidered based on demand:
 
 All three interval types are mapped to Arrow and flow through serde, native 
shuffle, and the
 codegen dispatcher, so interval columns and the interval-producing expressions 
run natively.
-Several operators still gate on the type and fall back: Parquet scans of ANSI 
interval columns,
-single-column sorts, hash aggregates (`min` / `max` / `sum` / `avg`), `GROUP 
BY`, window
-functions, and hashing a `CalendarInterval`. Remaining work is tracked by
+Comet's V1 native Parquet scan also supports both ANSI interval types. Several 
operators still

Review Comment:
   Comet has a single native Parquet scan path now, so "V1 native Parquet scan" 
may read as if there is a V2 variant with different support. Could this just 
say "Comet's native Parquet scan"?
   
   Two more things for this section. The notes should call out whatever the 
partition column outcome ends up being. And #5060 asked whether the 
`CalendarIntervalType` entry in the shared `DataTypeSupport.isTypeSupported` 
should move to `CometLocalTableScanExec` or go away, given it can never appear 
in a Parquet file. Did you decide to leave that for a follow-up? A linked issue 
would help if so.
   
   Unrelated to the docs, but worth adding to the PR description: 
`CometScanTypeChecker` also gates the native Iceberg scan 
(`CometScanRule.scala:366` and `:525`), not just Parquet V1. That is moot in 
practice since Iceberg has no interval type, but the current wording reads as 
if the change is Parquet-only and a future reader may not realize the checker 
is shared.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to