Skip to content

ExtractANSIIntervalDays and the other interval field extractors have no serde, so date + <day interval column> and extract of an interval fall back #6193

Description

@andygrove

What is the problem the feature request solves?

Spark lowers extract(field FROM interval) and date_part('field', interval) to one of twelve ExtractIntervalPart subclasses. The ANSI types get ExtractANSIInterval{Years,Months,Days,Hours,Minutes,Seconds} and CalendarInterval gets ExtractInterval{Years,Months,Days,Hours,Minutes,Seconds}. None of them has a serde, so a projection that uses one falls back to Spark.

ExtractANSIIntervalDays also sits under ordinary date arithmetic. Spark rewrites date + <DAY-precision interval> to DateAdd(date, ExtractANSIIntervalDays(interval)), and the subtract form to DateAdd(date, UnaryMinus(ExtractANSIIntervalDays(interval))). That happens in Analyzer.ResolveBinaryArithmetic on 3.4 and 3.5, and in BinaryArithmeticWithDatetimeResolver on 4.0 and later. DateAdd is native, but its argument is not. A literal such as date + INTERVAL '30' DAY is unaffected in practice, because ConstantFolding reduces ExtractANSIIntervalDays(literal) to an int. An interval column is affected, and the commonest one is date subtraction itself: d1 - d2 returns INTERVAL DAY in the default interval mode, so d + (d1 - d2) falls back.

It also limits testing. CometSqlFileTestSuite excludes ConstantFolding, so inside a SQL fixture even date + INTERVAL '1' DAY falls back, and that spelling can't be pinned by a fixture until this is fixed.

Reproduced on main at dd68a531c, default Spark 4.1 profile:

CREATE TABLE t (d date, d1 date, d2 date, n int) USING parquet;
INSERT INTO t VALUES (date'2024-01-31', date'2024-03-15', date'2024-01-01', 5), (NULL, NULL, NULL, NULL);

SELECT d + (d1 - d2) FROM t;                                   -- extractansiintervaldays is not supported
SELECT d - (d1 - d2) FROM t;                                   -- extractansiintervaldays is not supported
SELECT extract(DAY FROM make_dt_interval(n, 1, 2, 3)) FROM t;  -- extractansiintervaldays is not supported
SELECT date_part('HOUR', make_dt_interval(n, 1, 2, 3)) FROM t; -- extractansiintervalhours is not supported
SELECT extract(YEAR FROM make_ym_interval(n, 1)) FROM t;       -- extractansiintervalyears is not supported
SELECT extract(DAY FROM make_interval(0, 0, 0, n)) FROM t;     -- extractintervaldays is not supported

Each comment is the fallback reason Comet reports. The first two queries also need #5864, which adds the SubtractDates serde. On main the extractor is just the first unsupported node the serde reaches.

Describe the potential solution

All twelve are UnaryExpressions whose doGenCode is a single IntervalUtils.getX(child) call, returning IntegerType, ByteType or DecimalType(8, 6). The codegen dispatcher already reads all three interval types and writes all three result types, so each one needs only a CometCodegenDispatch registration in temporalExpressions, like CometMakeDTInterval. The classes and their result types are the same on 3.4.3, 3.5.9, 4.0.4, 4.1.3 and 4.2.0, so no shim is needed.

I checked that locally on #5864's head with the 4.1 profile. With all twelve registered as new CometCodegenDispatch[...], expect_dispatch passes and the answers match Spark for d + (d1 - d2), d - (d1 - d2), d +/- INTERVAL '<n>' DAY inside the harness, and extract of every field of all three interval types, over Parquet data with negative and NULL values.

The PR for this should:

  • Register the twelve extractors.
  • Add SQL fixtures with expect_dispatch(...) for each field, derived from Parquet columns. Cover negative values, NULLs, both the extract and date_part spellings, and date +/- (d1 - d2) and date +/- INTERVAL '<n>' DAY for the DateAdd rewrite.
  • Update expressions.md. The + and - notes that feat: route date and timestamp interval arithmetic through codegen dispatch #5864 adds say a DAY-precision interval column on a date falls back because ExtractANSIIntervalDays has no serde. The extract, date_part and datepart rows carry no interval caveat at all today.

Additional context

Part of #5061, whose table of expressions not yet wired lists "extract / date_part of interval fields (ExtractANSIInterval*, ExtractInterval*)" as needing an issue. Found while reviewing #5864.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions