Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/source/user-guide/latest/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ The type-name conversion functions (`bigint`, `binary`, `boolean`, `date`, `deci
| `localtimestamp` | ✅ | — | |
| `make_date` | ✅ | Native | |
| `make_dt_interval` | ✅ | Codegen dispatch | |
| `make_interval` | 🔜 | | Produces legacy CalendarInterval; tracked by [#5061](https://github.com/apache/datafusion-comet/issues/5061) |
| `make_interval` | | Hybrid | Routes through the JVM codegen dispatcher by default; intervals outside Arrow's nanosecond range are tracked by [#5279](https://github.com/apache/datafusion-comet/issues/5279); the native path is opt-in via allowIncompatible ([details](compatibility/expressions/datetime.md)) |
| `make_time` | 🔜 | — | Spark 4.1 TIME type; tracked by [#4288](https://github.com/apache/datafusion-comet/issues/4288) |
| `make_timestamp` | ✅ | Hybrid | |
| `make_timestamp_ltz` | ✅ | — | 2-arg TIME form falls back |
Expand Down Expand Up @@ -308,7 +308,7 @@ The type-name conversion functions (`bigint`, `binary`, `boolean`, `date`, `deci
| `to_unix_timestamp` | ✅ | Hybrid | |
| `to_utc_timestamp` | ✅ | Hybrid | Routes through the JVM codegen dispatcher by default (handles all timezone forms); the native path is opt-in via allowIncompatible ([details](compatibility/expressions/datetime.md)) |
| `trunc` | ✅ | Hybrid | |
| `try_make_interval` | 🔜 | — | Produces legacy CalendarInterval; tracked by [#5061](https://github.com/apache/datafusion-comet/issues/5061) |
| `try_make_interval` | | — | Rewrites to `MakeInterval`; same support as `make_interval` (Spark 4.0+) |
| `try_make_timestamp` | ✅ | — | |
| `try_to_date` | ✅ | — | Rewrites to `Cast`/`GetTimestamp` before Comet sees the plan; same support as `to_date` |
| `try_to_time` | 🔜 | — | Spark 4.1 TIME type; tracked by [#4288](https://github.com/apache/datafusion-comet/issues/4288) |
Expand Down
1 change: 1 addition & 0 deletions native/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions native/spark-expr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ edition = { workspace = true }
arrow = { workspace = true }
chrono = { workspace = true }
datafusion = { workspace = true }
datafusion-spark = { workspace = true }
chrono-tz = { workspace = true }
num = { workspace = true }
regex = { workspace = true }
Expand Down
7 changes: 5 additions & 2 deletions native/spark-expr/src/comet_scalar_funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use crate::{
spark_isnan, spark_lpad, spark_make_decimal, spark_month_name, spark_read_side_padding,
spark_round, spark_rpad, spark_to_time, spark_unhex, spark_unscaled_value, EvalMode,
SparkArrayPositionFunc, SparkArraySlice, SparkArraysOverlap, SparkContains, SparkDateDiff,
SparkDateFromUnixDate, SparkDateTrunc, SparkFlatten, SparkMakeDate, SparkMakeTime,
SparkNextDay, SparkSecondsToTimestamp, SparkSizeFunc,
SparkDateFromUnixDate, SparkDateTrunc, SparkFlatten, SparkMakeDate, SparkMakeInterval,
SparkMakeTime, SparkNextDay, SparkSecondsToTimestamp, SparkSizeFunc,
};
use arrow::datatypes::DataType;
use datafusion::common::{DataFusionError, Result as DataFusionResult};
Expand Down Expand Up @@ -250,6 +250,9 @@ pub fn create_comet_physical_fun_with_eval_mode(
"make_date" => Ok(Arc::new(ScalarUDF::new_from_impl(SparkMakeDate::new(
fail_on_error,
)))),
"make_interval" => Ok(Arc::new(ScalarUDF::new_from_impl(SparkMakeInterval::new(
fail_on_error,
)))),
"next_day" => Ok(Arc::new(ScalarUDF::new_from_impl(SparkNextDay::new(
fail_on_error,
)))),
Expand Down
87 changes: 87 additions & 0 deletions native/spark-expr/src/datetime_funcs/make_interval.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use crate::arithmetic_overflow_error;
use arrow::array::Array;
use arrow::datatypes::DataType;
use datafusion::common::Result;
use datafusion::logical_expr::{ColumnarValue, ScalarFunctionArgs, ScalarUDFImpl, Signature};
use datafusion_spark::function::datetime::make_interval::SparkMakeInterval as DataFusionMakeInterval;

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct SparkMakeInterval {
inner: DataFusionMakeInterval,
fail_on_error: bool,
}

impl SparkMakeInterval {
pub fn new(fail_on_error: bool) -> Self {
Self {
inner: DataFusionMakeInterval::new(),
fail_on_error,
}
}
}

impl ScalarUDFImpl for SparkMakeInterval {
fn name(&self) -> &str {
self.inner.name()
}

fn signature(&self) -> &Signature {
self.inner.signature()
}

fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
self.inner.return_type(arg_types)
}

fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
let inputs = if self.fail_on_error {
Some(args.args.clone())
} else {
None
};
let result = self.inner.invoke_with_args(args)?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a compatibility concern I'd like to flag with the underlying DataFusion kernel. Two related issues:

Nanosecond vs microsecond overflow. Spark's IntervalUtils.makeInterval stores time components as int64 microseconds via secs.toUnscaledLong, so a Decimal(18, 6) seconds value fits comfortably (max ≈ 1e18 micros, well under Long.MaxValue). DataFusion's kernel accumulates in nanoseconds, so it overflows at roughly secs > 9_223_372_036 (~292 years). Any Decimal(18, 6) seconds value beyond that boundary silently returns null under this PR (or throws under ANSI) while Spark returns a valid interval. Spark's own sql-tests/inputs/interval.sql exercises exactly this range:

select make_interval(1, 2, 3, 4, 0, 0, 123456789012.123456);

Float64 coercion loses microsecond precision. DataFusion's SparkMakeInterval signature coerces secs to Float64, but Spark's MakeInterval.inputTypes is Decimal(18, 6) and preserves microseconds exactly. For secs = 999999999.999999, the Float64 round-trip yields frac * 1e9 ≈ 999999046 instead of 999999000 — a ~46 ns drift that translates into a wrong microsecond count on the JVM side. The small values currently in the fixture (7.123456, 100.000001, -1.5) happen to be exactly representable so they don't expose this.

Given both, would it make sense to mark this expression Incompatible(Some("...")) in getSupportLevel, and add a getIncompatibleReasons() string so the auto-generated compat page warns users? Marking it Native in expressions.md with no caveat currently overstates the compatibility.


if let Some(inputs) = inputs {
let inputs_are_valid = |i| {
inputs.iter().all(|input| match input {
ColumnarValue::Array(values) => values.is_valid(i),
ColumnarValue::Scalar(value) => !value.is_null(),
})
};
let overflow = match &result {
ColumnarValue::Array(values) => values.nulls().is_some_and(|nulls| {
nulls.null_count() != 0
&& nulls
.iter()
.enumerate()
.any(|(i, is_valid)| !is_valid && inputs_are_valid(i))
}),
ColumnarValue::Scalar(value) => value.is_null() && inputs_are_valid(0),
};
if overflow {
// Spark identifies the integer or long operation that overflowed. The native
// wrapper only sees the result null mask, so it can only report interval overflow.
return Err(arithmetic_overflow_error("interval").into());
}
}

Ok(result)
}
}
2 changes: 2 additions & 0 deletions native/spark-expr/src/datetime_funcs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod day_month_name;
mod extract_date_part;
mod hours;
mod make_date;
mod make_interval;
mod make_time;
mod next_day;
mod seconds_to_timestamp;
Expand All @@ -38,6 +39,7 @@ pub use extract_date_part::SparkMinute;
pub use extract_date_part::SparkSecond;
pub use hours::SparkHoursTransform;
pub use make_date::SparkMakeDate;
pub use make_interval::SparkMakeInterval;
pub use make_time::SparkMakeTime;
pub use next_day::SparkNextDay;
pub use seconds_to_timestamp::SparkSecondsToTimestamp;
Expand Down
5 changes: 3 additions & 2 deletions native/spark-expr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ pub use comet_scalar_funcs::{
pub use csv_funcs::*;
pub use datetime_funcs::{
spark_day_name, spark_month_name, spark_to_time, SparkDateDiff, SparkDateFromUnixDate,
SparkDateTrunc, SparkHour, SparkHoursTransform, SparkMakeDate, SparkMakeTime, SparkMinute,
SparkNextDay, SparkSecond, SparkSecondsToTimestamp, SparkUnixTimestamp, TimestampTruncExpr,
SparkDateTrunc, SparkHour, SparkHoursTransform, SparkMakeDate, SparkMakeInterval,
SparkMakeTime, SparkMinute, SparkNextDay, SparkSecond, SparkSecondsToTimestamp,
SparkUnixTimestamp, TimestampTruncExpr,
};
pub use error::{decimal_overflow_error, SparkError, SparkErrorWithContext, SparkResult};
pub use hash_funcs::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ object QueryPlanSerde extends Logging with CometExprShim with CometTypeShim {
classOf[MakeTimestamp] -> CometMakeTimestamp,
classOf[MakeYMInterval] -> CometMakeYMInterval,
classOf[MakeDTInterval] -> CometMakeDTInterval,
classOf[MakeInterval] -> CometMakeInterval,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TryMakeInterval is RuntimeReplaceable and its replacement is MakeInterval(..., failOnError = false), so try_make_interval reaches this handler after ReplaceExpressions. That means this PR enables it too.

Two follow-ons. The try_make_interval row in expressions.md (line 308) still says 🔜 with the #5061 note, so it needs the same update as the make_interval row. And there is a combination neither fixture covers: failOnError = false with spark.sql.ansi.enabled = true, where try_make_interval(2147483647) must return NULL instead of throwing. Would you add a small fixture for it? It needs -- MinSparkVersion: 4.0, since try_make_interval is not registered in 3.5.

classOf[MultiplyDTInterval] -> CometMultiplyDTInterval,
classOf[TimestampAdd] -> CometTimestampAdd,
classOf[TimestampDiff] -> CometTimestampDiff,
Expand Down
37 changes: 35 additions & 2 deletions spark/src/main/scala/org/apache/comet/serde/datetime.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ package org.apache.comet.serde

import java.util.Locale

import org.apache.spark.sql.catalyst.expressions.{AddMonths, Attribute, ConvertTimezone, DateAdd, DateDiff, DateFormatClass, DateFromUnixDate, DateSub, DayOfMonth, DayOfWeek, DayOfYear, Days, Expression, FromUTCTimestamp, GetDateField, GetTimestamp, Hour, Hours, LastDay, Literal, MakeDate, MakeDTInterval, MakeTimestamp, MakeYMInterval, MicrosToTimestamp, MillisToTimestamp, Minute, Month, MonthsBetween, MultiplyDTInterval, NextDay, PreciseTimestampConversion, Quarter, Second, SecondsToTimestamp, TimestampAdd, TimestampDiff, ToUnixTimestamp, ToUTCTimestamp, TruncDate, TruncTimestamp, UnixDate, UnixMicros, UnixMillis, UnixSeconds, UnixTimestamp, WeekDay, WeekOfYear, Year}
import org.apache.spark.sql.catalyst.expressions.{AddMonths, Attribute, Cast, ConvertTimezone, DateAdd, DateDiff, DateFormatClass, DateFromUnixDate, DateSub, DayOfMonth, DayOfWeek, DayOfYear, Days, Expression, FromUTCTimestamp, GetDateField, GetTimestamp, Hour, Hours, LastDay, Literal, MakeDate, MakeDTInterval, MakeInterval, MakeTimestamp, MakeYMInterval, MicrosToTimestamp, MillisToTimestamp, Minute, Month, MonthsBetween, MultiplyDTInterval, NextDay, PreciseTimestampConversion, Quarter, Second, SecondsToTimestamp, TimestampAdd, TimestampDiff, ToUnixTimestamp, ToUTCTimestamp, TruncDate, TruncTimestamp, UnixDate, UnixMicros, UnixMillis, UnixSeconds, UnixTimestamp, WeekDay, WeekOfYear, Year}
import org.apache.spark.sql.internal.SQLConf
import org.apache.spark.sql.types.{DataType, DateType, DoubleType, FloatType, IntegerType, LongType, StringType, TimestampNTZType, TimestampType}
import org.apache.spark.sql.types.{CalendarIntervalType, DataType, DateType, DoubleType, FloatType, IntegerType, LongType, StringType, TimestampNTZType, TimestampType}
import org.apache.spark.unsafe.types.UTF8String

import org.apache.comet.CometConf
Expand Down Expand Up @@ -963,6 +963,39 @@ object CometMakeYMInterval extends CometCodegenDispatch[MakeYMInterval]

object CometMakeDTInterval extends CometCodegenDispatch[MakeDTInterval]

object CometMakeInterval extends CometExpressionSerde[MakeInterval] with CodegenDispatchFallback {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default dispatch path has a range limit of its own, and I do not think the checkmark in expressions.md covers it.

I built this branch and ran SELECT make_interval(0, 0, 0, 0, h) FROM t over a Parquet column holding 2562048, with no configs set, so the default route. Spark returns a valid interval. Comet aborts the stage.

Exception thrown while executing query in Comet:
...
+- CometNativeScan parquet spark_catalog.default.zzprobe[h#8] ...

Caused by: java.lang.ArithmeticException: long overflow
	at java.base/java.lang.Math.multiplyExact(Math.java:1004)
	at ...GeneratedClass$SpecificCometBatchKernel.process(Unknown Source)
	at org.apache.comet.udf.codegen.CometScalaUDFCodegen.evaluate(CometScalaUDFCodegen.scala:129)
	at org.apache.comet.udf.CometUdfBridge.evaluate(CometUdfBridge.java:122)

The source is CometBatchKernelCodegenOutput.scala:222-229, which writes CalendarIntervalType into an IntervalMonthDayNanoVector as Math.multiplyExact(interval.microseconds, 1000L). That caps micros at 9,223,372,036,854,775, about 292 years, while Spark's IntervalUtils.makeInterval accumulates micros with no such ceiling. It is the same #5131 root cause on the compatible path, at a 1000x higher threshold, and it surfaces as a raw uncaught ArithmeticException rather than a NULL. Note it happens with spark.sql.ansi.enabled=false, and it is not a Spark-classed error, so it does not read as an overflow to a user.

This is a constraint of Comet's CalendarIntervalType Arrow representation rather than something this PR introduced, but this PR is the first thing that lets a user construct an arbitrary CalendarInterval, so it is where the caveat becomes reachable. Could you file an issue for it, widen the expressions.md note to mention the default path's ceiling, and add the case to the dispatch fixture as query ignore(<new issue>) so it is pinned for the next reader?

private val incompatReason =
"The native implementation converts seconds to `Float64`, which can lose microsecond" +
" precision, and stores time in nanoseconds, which overflows for large time components" +
" (hours, minutes, seconds) that Spark can represent."

override def getCompatibleNotes(): Seq[String] = Seq(
"Both the default JVM codegen-dispatch path and the native path currently limit the" +
" elapsed-time component to about 292 years in either direction. This only affects" +
" extreme intervals and is tracked in" +
" [#5279](https://github.com/apache/datafusion-comet/issues/5279).")

Comment on lines +967 to +971

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason attributes the nanosecond overflow to seconds, but hours and minutes hit it too, and at much lower values. Spark's IntervalUtils.makeInterval accumulates microseconds while the DataFusion kernel accumulates nanoseconds, so every time component has a 1000x smaller range.

make_interval(0, 0, 0, 0, 2562048) is enough to show it. Spark computes 2562048 * 3_600_000_000 = 9_223_372_800_000_000 micros and returns a valid interval. The kernel computes 2562048 * 3_600_000_000_000 = 9_223_372_800_000_000_000 nanos, which exceeds i64::MAX, so checked_mul fails and it returns NULL, or throws under ANSI. The cutoffs are hours >= 2,562,048 and mins >= 153,722,868.

Could the reason say "time components (hours, minutes, seconds)" rather than just seconds? This string is what renders on the generated compat page, so it is the only warning a user gets. It would be good to widen #5131's description the same way.

override def getIncompatibleReasons(): Seq[String] = Seq(incompatReason)

override def getSupportLevel(expr: MakeInterval): SupportLevel =
Incompatible(Some(incompatReason))

override def convert(
expr: MakeInterval,
inputs: Seq[Attribute],
binding: Boolean): Option[Expr] = {
// The explicit return type skips DataFusion's registry coercion, but its kernel needs Float64.
val children = expr.children.updated(6, Cast(expr.secs, DoubleType))
val childExprs = children.map(exprToProtoInternal(_, inputs, binding))
val optExpr = scalarFunctionExprToProtoWithReturnType(
"make_interval",
CalendarIntervalType,
expr.failOnError,
childExprs: _*)
optExpr
}
}

object CometMultiplyDTInterval extends CometCodegenDispatch[MultiplyDTInterval]

object CometTimestampAdd extends CometCodegenDispatch[TimestampAdd]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.

-- Config: spark.comet.expression.MakeInterval.allowIncompatible=true

statement
CREATE TABLE test_make_interval(
years int,
months int,
weeks int,
days int,
hours int,
mins int,
secs decimal(18, 6)) USING parquet

statement
INSERT INTO test_make_interval VALUES
(1, 2, 3, 4, 5, 6, 7.123456),
(0, 1, 0, 1, 0, 0, 100.000001),
(-1, -2, -1, -1, -1, -1, -1.500000),
(NULL, 1, 2, 3, 4, 5, 6.000000),
(2, NULL, 2, 3, 4, 5, 6.000000),
(3, 1, 2, 3, 4, 5, NULL),
(-2147483648, 0, 0, 0, 0, 0, 0.000000)

query
SELECT make_interval(years, months, weeks, days, hours, mins, secs)
FROM test_make_interval
ORDER BY years

query
SELECT make_interval(1, 2), make_interval(3), make_interval()

query
SELECT make_interval(0, 1, 0, 1, 0, 0, 100.000001)

query
SELECT make_interval(2147483647)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth expanding coverage here. A few things Spark's own IntervalExpressionsSuite / interval.sql exercise that aren't covered yet:

  • Microsecond-precision seconds like Spark's docstring example make_interval(0, 1, 0, 1, 0, 0, 100.000001) asserted directly (it's currently only exercised via the column path where it can be hard to spot a per-row precision drift).
  • Nulls in components other than years in the column path (currently only the years=NULL row is tested).
  • Large-second cases from Spark's interval.sql: make_interval(1, 2, 3, 4, 0, 0, 123456789012.123456) and make_interval(0, 0, 0, 0, 0, 0, 1234567890123456789). If either is a known divergence (see the nanos-overflow comment on the Rust file), wrapping them in query ignore(<tracking issue>) would at least pin the behavior for future readers.
  • Int.MinValue for a signed-overflow smoke test on the years column.


query ignore(https://github.com/apache/datafusion-comet/issues/5131)
SELECT make_interval(1, 2, 3, 4, 0, 0, 123456789012.123456)

query
SELECT make_interval(0, 0, 0, 0, 0, 0, 999999999.999999)

query ignore(https://github.com/apache/datafusion-comet/issues/5131)
SELECT make_interval(0, 0, 0, 0, 0, 0, 999999999.000001)

query ignore(https://github.com/apache/datafusion-comet/issues/5131)
SELECT make_interval(0, 0, 0, 0, 2562048)

query
SELECT make_interval(0, 0, 0, 0, 0, 0, 1234567890123456789)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add an hours case alongside the seconds ones? It is the same #5131 nanosecond overflow but on a component the fixture does not touch, and at a value a real query is much more likely to produce than a 12-digit seconds decimal.

query ignore(https://github.com/apache/datafusion-comet/issues/5131)
SELECT make_interval(0, 0, 0, 0, 2562048)

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.

-- Native ANSI execution must preserve Spark's overflow exception.
-- Config: spark.sql.ansi.enabled=true
-- Config: spark.comet.expression.MakeInterval.allowIncompatible=true

statement
CREATE TABLE test_make_interval_ansi(years int) USING parquet

statement
INSERT INTO test_make_interval_ansi VALUES (NULL)

query
SELECT make_interval(1, 2, 3, 4, 5, 6, 7.123456)

query
SELECT make_interval(years) FROM test_make_interval_ansi

query expect_error(overflow. If necessary set)
SELECT make_interval(2147483647)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding ANSI overflow tests for components other than years — the current fixture only exercises years = Int.MaxValue. Spark's IntervalExpressionsSuite ANSI mode block covers weeks = Int.MaxValue, and per-row overflow via hours/mins/seconds interactions. Something like:

query expect_error(overflow)
SELECT make_interval(0, 0, 2147483647)

would confirm the overflow detection path fires on non-years components too.


query expect_error(overflow. If necessary set)
SELECT make_interval(0, 0, 2147483647)

query ignore(https://github.com/apache/datafusion-comet/issues/5131)
SELECT make_interval(0, 0, 0, 0, 2562048)
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-- Licensed to the Apache Software Foundation (ASF) under one
-- or more contributor license agreements. See the NOTICE file
-- distributed with this work for additional information
-- regarding copyright ownership. The ASF licenses this file
-- to you under the Apache License, Version 2.0 (the
-- "License"); you may not use this file except in compliance
-- with the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing,
-- software distributed under the License is distributed on an
-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-- KIND, either express or implied. See the License for the
-- specific language governing permissions and limitations
-- under the License.

-- With allowIncompatible unset, MakeInterval uses Spark's JVM codegen dispatcher.

statement
CREATE TABLE test_make_interval_dispatch(
years int,
months int,
weeks int,
days int,
hours int,
mins int,
secs decimal(18, 6)) USING parquet

statement
INSERT INTO test_make_interval_dispatch VALUES
(1, 2, 3, 4, 5, 6, 7.123456),
(0, 1, 0, 1, 0, 0, 100.000001),
(-1, -2, -1, -1, -1, -1, -1.500000),
(NULL, 1, 2, 3, 4, 5, 6.000000),
(2, NULL, 2, 3, 4, 5, 6.000000),
(3, 1, 2, 3, 4, 5, NULL),
(0, 0, 0, 0, 2562048, 0, 0.000000)

query
SELECT make_interval(years, months, weeks, days, hours, mins, secs)
FROM test_make_interval_dispatch
WHERE hours != 2562048
ORDER BY years

query ignore(https://github.com/apache/datafusion-comet/issues/5279)
SELECT make_interval(0, 0, 0, 0, hours)
FROM test_make_interval_dispatch
WHERE hours = 2562048
Loading
Loading