[SPARK-56876][SQL] Add TimestampNTZNanosType and TimestampLTZNanosType#55952
[SPARK-56876][SQL] Add TimestampNTZNanosType and TimestampLTZNanosType#55952MaxGekk wants to merge 11 commits into
Conversation
Convert NumberFormatException from overflowing precision strings
into UNSUPPORTED_TIMESTAMP_{LTZ,NTZ}_PRECISION with the original
digit string preserved.
Co-authored-by: Isaac
The regex in nameToType already handles every valid precision for timestamp_ltz(n) / timestamp_ntz(n) and emits a precision-specific error for invalid ones, so the parallel enumeration was dead lookup. Co-authored-by: Isaac
Anchor both types to their parameterless counterparts (TimestampType and TimestampNTZType) and state plainly that no time zone is stored, replacing the ambiguous "time zone affects interpretation only" phrase that could read as if the type carried a zone tag. Co-authored-by: Isaac
Drive both timestamp_ltz and timestamp_ntz through a single loop and add coverage for malformed precision forms (negative, empty, non- numeric, uppercase) that fall through to INVALID_JSON_DATA_TYPE. Co-authored-by: Isaac
Co-authored-by: Isaac
Co-authored-by: Isaac
| * @since 4.2.0 | ||
| */ | ||
| @Unstable | ||
| case class TimestampLTZNanosType(precision: Int) extends DatetimeType { |
There was a problem hiding this comment.
The current timestamp type doesn't include "LTZ" in the name. Why not go with TimestampNanosType here?
There was a problem hiding this comment.
First of all, because the SPIP https://docs.google.com/document/d/1DeW15QueI4PdRyPm6C6jsTZFmIjbXX2j4h-Ja5W_fsg/edit?usp=sharing defines this class with such name. Probably you might ask why I named it in this way in the SPIP. So, there are a few reasons:
-
Pairs with TimestampNTZNanosType. Spark already has two SQL timestamp families: with local time zone (TimestampType / TIMESTAMP_LTZ) and without (TimestampNTZType / TIMESTAMP_NTZ). The nanosecond-capable types are the same split. Alone TimestampNanosType reads as “the” nano timestamp type and does not signal which semantics apply.
-
Matches SQL and typeName. The class backs timestamp_ltz(p). TimestampLTZNanosType lines up with TimestampNTZNanosType and with the SPIP/SQL names; TimestampNanosType would mirror neither timestamp_ntz nor the explicit TIMESTAMP_LTZ(n) surface.
-
Consistency with how Spark names the NTZ side. TimestampType omits “LTZ” for history (timestamp defaulted to session-local semantics), but TimestampNTZType is explicit because the second variant exists. For new APIs where both variants are first-class, being explicit on both sides avoids the ambiguity that already bites people (TimestampType vs “timestamp with TZ” in docs).
-
Safer for pattern matches and downstream code. Much of the codebase branches TimestampType vs TimestampNTZType. TimestampLTZNanosType + TimestampNTZNanosType extend that model predictably; TimestampNanosType would be assumed LTZ-by-analogy-to-TimestampType, which is easy to get wrong in reviews and refactors.
| cause = null) | ||
| } | ||
|
|
||
| def unsupportedTimestampNtzPrecisionError(precision: String): Throwable = { |
There was a problem hiding this comment.
Why is precision a string here?
There was a problem hiding this comment.
To pass any garbage from an user while parsing the type in json. The regex captures p as text. For values like "9" * 20, p.toInt throws NumberFormatException. I catch that and raise UNSUPPORTED_TIMESTAMP_*_PRECISION with the original digit string in the error (see DataTypeSuite — I do not want a bare NumberFormatException or a misleading message).
|
@dongjoon-hyun @cloud-fan @felixcheung @peter-toth @mridulm @sunchao This is an initial PR corresponded to the SPIP SPARK-56822 "Timestamps with nanosecond precision". It contains minimum changes to unblock parallel work on new types. Please, review it. |
| }, | ||
| "UNSUPPORTED_TIMESTAMP_LTZ_PRECISION" : { | ||
| "message" : [ | ||
| "The seconds precision <precision> of TIMESTAMP_LTZ is out of the supported range [7, 9]." |
There was a problem hiding this comment.
Would it make sense to mention parameterless TIMESTAMP_LTZ as viable option for precision < 7?
…ISION
Replace UNSUPPORTED_TIMESTAMP_{LTZ,NTZ}_PRECISION (sqlState 0A001 was
"feature not supported") with a single INVALID_TIMESTAMP_PRECISION
parameterized on <type>, sqlState 22023 ("invalid parameter value").
Message now points users at parameterless TIMESTAMP_LTZ / TIMESTAMP_NTZ
for precision <= 6, addressing peter-toth's review comment.
Co-authored-by: Isaac
|
Merging to master. Thank you, @stevomitric @peter-toth for review. |
What changes were proposed in this pull request?
In the PR, I propose to extend the Spark SQL type system, and add new classes to Scala/Java APIs:
They are public API entry points only, and have no SQL/DDL/datasource integration in this PR.
The classes align with the SQL standard’s direction for optional feature F555, “Enhanced seconds precision”: datetime types can carry fractional seconds with precision p in the SECOND field beyond the traditional six decimal places (microseconds). Here p is restricted to 7, 8, and 9, i.e. the nanosecond-capable band (up to nine fractional digits, nanoseconds in the second field).
The logical layout documented on the classes matches this precision story: epoch microseconds plus nanoseconds within that microsecond, with a default estimated width of 10 bytes for planning (8 + 2).
Parameterless timestamp_ntz / timestamp_ltz are unchanged and remain the existing microsecond-oriented types.
Why are the changes needed?
New timestamp types are useful for Spark SQL users because they allow:
Does this PR introduce any user-facing change?
Public API adds two new types in org.apache.spark.sql.types; they cannot yet be used in DataFrames, schemas read from datasources, or SQL DDL.
How was this patch tested?
By extending DataTypeSuite (round-trip and precision bounds for the new types, including invalid precisions).
Plus SparkThrowableSuite / error-json validation if error-conditions.json is updated.
Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Opus 4.7