[ 
https://issues.apache.org/jira/browse/SPARK-58820?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Uroš Bojanić updated SPARK-58820:
---------------------------------
    Description: 
*Q1. What are you trying to do? Articulate your objectives using absolutely no 
jargon.*

Add a new Spark SQL data type *DECFLOAT* that stores decimal numbers with a 
flexible decimal point (floating point decimal numbers). Each value keeps up to 
a fixed number of significant decimal digits and its own exponent, so one 
column can hold both very large integers and very small fractions without 
picking a single fixed scale for the whole column.

The type follows the IEEE 754 decimal floating-point formats:
||*SQL type*||*IEEE format*||*Significant digits*||*Storage width*||
|DECFLOAT(16)|decimal64|16|8 bytes|
|DECFLOAT(34)|decimal128|34|16 bytes|

Bare DECFLOAT means DECFLOAT(34).

Unlike DECIMAL(p,s), there is no column-wide scale. Unlike FLOAT / DOUBLE, 
arithmetic is done in base 10, so values such as 0.1 are exact.

Because each value carries at most 16 or 34 significant digits, a result 
needing more digits is rounded to the format's precision. Rounding is decimal 
(base 10), unlike binary rounding in FLOAT/DOUBLE. The v1 fixed default is IEEE 
roundTiesToEven / HALF_EVEN (banker's rounding), which differs from Spark's 
existing DECIMAL arithmetic (rounds HALF_UP). This can be configurable in 
future iterations.

The type also supports IEEE special values: signed zero, +/-Infinity, and quiet 
NaN.

*Q2. What problem is this proposal NOT designed to solve?*
 * *Arbitrary-precision / unbounded decimals.* Extending Spark's fixed-point 
DECIMAL beyond 38 digits, or adding a PostgreSQL-style unbounded NUMERIC, is 
out of scope. Those needs are different from IEEE decimal floating point.
 * *Wider-than-IEEE formats in v1.* Formats such as a 70-digit / 256-bit 
decimal float (sometimes discussed as DECFLOAT(70) / decimal256) are out of 
scope for the first delivery. The type and storage designs should not preclude 
them later.
 * *Replacing* DECIMAL *or* DOUBLE{*}.{*} Existing fixed-point and binary-float 
types remain unchanged. DECFLOAT is additive.
 * *Non-IEEE decimal-float dialects as the native type.* Engines such as 
Snowflake, Oracle, and Teradata expose a decimal float that is not a strict 
IEEE width (e.g. 38 digits, no NaN/Inf). Spark's native type targets IEEE 754 
decimal64 and decimal128. Mapping those dialects into Spark is a connector / 
cast concern, not a second native type.
 * *ORC / CSV / JSON as first-class DECFLOAT storage in v1.* Persistence focus
for v1 is Parquet (and table formats that sit on Parquet). Other formats may
round-trip via string or binary until separately specified.

*Q3. How is it done today, and what are the limits of current practice?*

Spark SQL today offers two numeric families for real numbers:
 # DECIMAL(p,s) *(fixed-point).* Precision and scale are fixed for the column. 
Spark caps precision at 38. Mixed magnitudes force a tradeoff: many fractional 
digits leave few integer digits (and the reverse). Chains of arithmetic expand 
precision quickly and often require manual casts.
 # FLOAT */* DOUBLE *(binary floating-point).* Wide range, but many common 
decimal fractions are not exact. About 15-16 significant decimal digits for 
DOUBLE, with binary rounding error.

Workarounds in use today:
||*Workaround*||*Limitation*||
|Map high-precision source decimals to DECIMAL(38,s)|Overflow / out-of-range 
errors for large integers; silent rounding of long fractions|
|Cast to DOUBLE|Binary rounding; unsuitable when exact decimal fractions matter|
|Store as STRING|Loses numeric semantics; arithmetic and aggregation must be 
rebuilt|
|Emulate with (unscaled DECIMAL, scale INT) structs|Not a first-class type; 
poor pushdown, stats, and ecosystem support|

Spark also cannot recognize IEEE decimal floating-point values in Parquet (or 
other built-in file sources) as a distinct logical type today, so even when 
another system wrote such values, Spark cannot load them as decimals with 
per-value exponents.

*Q4. What is new in your approach and why do you think it will be successful?*

The approach is deliberately conventional and layered, following prior Spark 
type introductions (TIMESTAMP_NTZ, ANSI intervals, TIME):
 # *Standard semantics first.* Align the SQL type with IEEE 754-2019 decimal64 
/ decimal128 and with existing SQL DECFLOAT practice (DB2,  Firebird, MongoDB). 
Prefer IEEE default exception handling (produce Inf/NaN), rather than inventing 
a Spark-only numeric model. Same goes for rounding, roundTiesToEven is chosen 
because it's the IEEE default and libbid/DB2 behaviour.
 # *Concrete physical representation.* Use the IEEE binary integer decimal 
(BID) interchange encoding in memory and on disk, with a well-known math 
library (Intel Decimal Floating-Point Math Library / libbid) for arithmetic 
kernels. This avoids a logical-only typedef over DECIMAL / STRING that would 
diverge across implementations.
 # *Open storage path.* Propose a 
[Parquet|https://docs.google.com/document/d/104397AVUqg_JSlzGBdpa3D98X6Dd-RONIgABn3omBcw/edit?tab=t.0]
 logical type for decimal floating point (width-extensible FIXED_LEN_BYTE_ARRAY 
annotation; initially decimal64 and decimal128) so Spark, other engines, and 
table formats can interoperate without Arrow-footer private conventions.
 # *Additive rollout.* Gate the type behind a config during incubation (pattern 
used for TIME), then enable by default once coverage matches peer numeric types.

We expect this to succeed because:
 * The user-visible type matches what migrators already know from DB2 / 
Firebird / MongoDB Decimal128, and closes a clear gap versus warehouses that 
already ship a decimal-float type.
 * The encoding and math library are industry-proven rather than bespoke.
 * Spark already has a playbook for introducing a new atomic type end-to-end 
(parser → Catalyst → execution → datasources → Connect / PySpark / JDBC).

*Q5. Who cares? If you are successful, what difference will it make?*
 * *Users migrating from PostgreSQL, Oracle, DB2, BigQuery, and similar 
systems* who today hit Spark's DECIMAL(38,*) ceiling or lose precision via 
DOUBLE / STRING workarounds. Unconstrained or high-precision source numerics 
map cleanly to a first-class numeric type.
 * *Financial, actuarial, and crypto / fintech workloads* that need exact 
decimal fractions and mixed magnitudes in one column (rates, notionals, 
micro-quantities and large balances together).
 * *Existing Spark users* who need to read or write Parquet datasets produced 
by systems that already use IEEE decimal128 / DECFLOAT.
 * *The wider storage ecosystem* (Parquet, and eventually Iceberg / Delta 
consumers) gains a portable decimal-float logical type rather than 
engine-private encodings.

Success means: declare DECFLOAT columns, run SQL arithmetic and aggregations 
without leaving the numeric domain, and round-trip values through Parquet with 
IEEE semantics preserved (including cohort / quantum where the format retains 
it).

*Q6. What are the risks?*
||*Risk*||*Mitigation*||
|Parquet / table-format standardization lagging Spark SQL|Ship Spark SQL type 
with a documented on-disk encoding; upstream Parquet logical type in parallel; 
avoid relying on undocumented footer keys|
|Surprising type coercion (DECFLOAT outranking DOUBLE / interacting with 
DECIMAL)|Document precedence explicitly; add golden SQL tests; match IEEE / SQL 
expectations rather than silent demotion to binary float|
|Special-value semantics (NaN, Inf) surprising users coming from engines 
without them (e.g. some warehouse DECFLOAT dialects)|Document clearly; default 
IEEE non-stop handling; ANSI mode provides fail-fast behavior consistent with 
other numeric types.|
|External API choice for Inf/NaN (Java BigDecimal cannot represent them)|Pick 
an explicit external type story early (see Appendix B) and test Connect / 
PySpark / JDBC thoroughly|
|Scope creep into arbitrary precision or DECFLOAT(70)|Keep v1 strictly at 
precisions 16 and 34; record wider formats as follow-ons|
|Implementation overhead and ensuring full behavioural consistency in a custom 
JVM implementation versus existing libraries|Implement DECFLOAT via JNI calls 
to the existing libbid library (which offers fast, exact math for decimal 
floating-point numbers)|

*Q7. How long will it take?*

Rough estimate: *on the order of 9-12 months* for feature-complete parity with 
peer numeric types, based on TIME (SPARK-51162), TIMESTAMP_NTZ (SPARK-35662), 
and ANSI intervals (SPARK-27790), plus extra time for the math library 
integration and Parquet logical type.

Suggested work split (can become JIRA sub-tasks):
 # *Base type: ~1 month* DecFloatType, parser / DDL, literals (DECFLOAT '...', 
optional DF suffix), casts to/from string and numeric types, etc.
 # *Arithmetic and comparison kernels: ~2 months* + - * /, unary minus, 
comparisons, ordering (totalOrder for sort), hashing / grouping equality 
(canonicalization for =-equal values), codegen / interpreted execution.
 # *Functions and aggregates: ~2 months* Core scalars (abs, sign, floor, ceil, 
round, sqrt, isnan, …), DECFLOAT-specific helpers (quantize, same_quantum, 
total_order), sum / avg / min / max / count, window variants.
 # *Persistence: ~3 months* Parquet read/write with logical annotation, 
partition values, stats / predicate pushdown, caching / shuffle; coordinate 
with Parquet format RFC.
 # *Clients: ~1.5 months* Spark Connect proto, JDBC / Thrift / Hive result 
mapping, catalog / information_schema.
 # *PySpark / Arrow: ~1.5 months* DataFrame API, pandas / Arrow interchange, 
Python UDFs.
 # *Docs, golden tests, benchmarks: ~1 month (overlaps)*

[OPEN] Confirm estimate after sketching the Parquet dependency and whether 
Arrow needs a parallel extension type for transport.

*Q8. What are the mid-term and final "exams" to check for success?*

*Mid-term (~4-5 months):*
 * DecFloatType(16|34) usable in SQL: literals, DDL, casts, arithmetic, 
comparisons, basic aggregates.
 * Correct IEEE behavior for a representative set of finite values, signed 
zeros, Inf, and NaN (under both ANSI and non-ANSI modes), and rounding 
(especially at the precision boundary, e.g. results exceeding 16/34 digits, 
ties).
 * Round-trip through at least one built-in file source (Parquet) with a stable 
encoding, even if the upstream Parquet annotation is still landing.
 * No behavioral change to existing DECIMAL / DOUBLE workloads when the new 
type is unused.

*Final exam (~9-12 months):*
 * Feature parity with other numeric types for the agreed v1 function set (see 
Appendix C sketch).
 * Interoperable Parquet read/write against an independent implementation (e.g. 
parquet-java ↔ parquet-rs) once the logical type is specified.
 * Connect, JDBC, and PySpark can create, query, and collect DECFLOAT columns.
 * Documented ANSI / IEEE compliance notes and migration guidance from DECIMAL 
/ DOUBLE / string workarounds.

  was:
*Q1. What are you trying to do? Articulate your objectives using absolutely no 
jargon.*

Add a new Spark SQL data type *DECFLOAT* that stores decimal numbers with a 
flexible decimal point (floating point decimal numbers). Each value keeps up to 
a fixed number of significant decimal digits and its own exponent, so one 
column can hold both very large integers and very small fractions without 
picking a single fixed scale for the whole column.

The type follows the IEEE 754 decimal floating-point formats:
||*SQL type*||*IEEE format*||*Significant digits*||*Storage width*||
|DECFLOAT(16)|decimal64|16|8 bytes|
|DECFLOAT(34)|decimal128|34|16 bytes|

Bare DECFLOAT means DECFLOAT(34).

Unlike DECIMAL(p,s), there is no column-wide scale. Unlike FLOAT / DOUBLE, 
arithmetic is done in base 10, so values such as 0.1 are exact.

Because each value carries at most 16 or 34 significant digits, a result 
needing more digits is rounded to the format's precision. Rounding is decimal 
(base 10), unlike binary rounding in FLOAT/DOUBLE. The default is IEEE 
roundTiesToEven / HALF_EVEN (banker's rounding), which differs from Spark's 
existing DECIMAL arithmetic (rounds HALF_UP).

The type also supports IEEE special values: signed zero, +/-Infinity, and quiet 
NaN.

*Q2. What problem is this proposal NOT designed to solve?*
 * *Arbitrary-precision / unbounded decimals.* Extending Spark's fixed-point 
DECIMAL beyond 38 digits, or adding a PostgreSQL-style unbounded NUMERIC, is 
out of scope. Those needs are different from IEEE decimal floating point.
 * *Wider-than-IEEE formats in v1.* Formats such as a 70-digit / 256-bit 
decimal float (sometimes discussed as DECFLOAT(70) / decimal256) are out of 
scope for the first delivery. The type and storage designs should not preclude 
them later.
 * *Replacing* DECIMAL *or* DOUBLE{*}.{*} Existing fixed-point and binary-float 
types remain unchanged. DECFLOAT is additive.
 * *Non-IEEE decimal-float dialects as the native type.* Engines such as 
Snowflake, Oracle, and Teradata expose a decimal float that is not a strict 
IEEE width (e.g. 38 digits, no NaN/Inf). Spark's native type targets IEEE 754 
decimal64 and decimal128. Mapping those dialects into Spark is a connector / 
cast concern, not a second native type.
 * *ORC / CSV / JSON as first-class DECFLOAT storage in v1.* Persistence focus
for v1 is Parquet (and table formats that sit on Parquet). Other formats may
round-trip via string or binary until separately specified.

*Q3. How is it done today, and what are the limits of current practice?*

Spark SQL today offers two numeric families for real numbers:
 # DECIMAL(p,s) *(fixed-point).* Precision and scale are fixed for the column. 
Spark caps precision at 38. Mixed magnitudes force a tradeoff: many fractional 
digits leave few integer digits (and the reverse). Chains of arithmetic expand 
precision quickly and often require manual casts.
 # FLOAT */* DOUBLE *(binary floating-point).* Wide range, but many common 
decimal fractions are not exact. About 15-16 significant decimal digits for 
DOUBLE, with binary rounding error.

Workarounds in use today:
||*Workaround*||*Limitation*||
|Map high-precision source decimals to DECIMAL(38,s)|Overflow / out-of-range 
errors for large integers; silent rounding of long fractions|
|Cast to DOUBLE|Binary rounding; unsuitable when exact decimal fractions matter|
|Store as STRING|Loses numeric semantics; arithmetic and aggregation must be 
rebuilt|
|Emulate with (unscaled DECIMAL, scale INT) structs|Not a first-class type; 
poor pushdown, stats, and ecosystem support|

Spark also cannot recognize IEEE decimal floating-point values in Parquet (or 
other built-in file sources) as a distinct logical type today, so even when 
another system wrote such values, Spark cannot load them as decimals with 
per-value exponents.

*Q4. What is new in your approach and why do you think it will be successful?*

The approach is deliberately conventional and layered, following prior Spark 
type introductions (TIMESTAMP_NTZ, ANSI intervals, TIME):
 # *Standard semantics first.* Align the SQL type with IEEE 754-2019 decimal64 
/ decimal128 and with existing SQL DECFLOAT practice (DB2,  Firebird, MongoDB). 
Prefer IEEE default exception handling (produce Inf/NaN), rather than inventing 
a Spark-only numeric model. Same goes for rounding, roundTiesToEven is chosen 
because it's the IEEE default and libbid/DB2 behaviour.
 # *Concrete physical representation.* Use the IEEE binary integer decimal 
(BID) interchange encoding in memory and on disk, with a well-known math 
library (Intel Decimal Floating-Point Math Library / libbid) for arithmetic 
kernels. This avoids a logical-only typedef over DECIMAL / STRING that would 
diverge across implementations.
 # *Open storage path.* Propose a 
[Parquet|https://docs.google.com/document/d/104397AVUqg_JSlzGBdpa3D98X6Dd-RONIgABn3omBcw/edit?tab=t.0]
 logical type for decimal floating point (width-extensible FIXED_LEN_BYTE_ARRAY 
annotation; initially decimal64 and decimal128) so Spark, other engines, and 
table formats can interoperate without Arrow-footer private conventions.
 # *Additive rollout.* Gate the type behind a config during incubation (pattern 
used for TIME), then enable by default once coverage matches peer numeric types.

We expect this to succeed because:
 * The user-visible type matches what migrators already know from DB2 / 
Firebird / MongoDB Decimal128, and closes a clear gap versus warehouses that 
already ship a decimal-float type.
 * The encoding and math library are industry-proven rather than bespoke.
 * Spark already has a playbook for introducing a new atomic type end-to-end 
(parser → Catalyst → execution → datasources → Connect / PySpark / JDBC).

*Q5. Who cares? If you are successful, what difference will it make?*
 * *Users migrating from PostgreSQL, Oracle, DB2, BigQuery, and similar 
systems* who today hit Spark's DECIMAL(38,*) ceiling or lose precision via 
DOUBLE / STRING workarounds. Unconstrained or high-precision source numerics 
map cleanly to a first-class numeric type.
 * *Financial, actuarial, and crypto / fintech workloads* that need exact 
decimal fractions and mixed magnitudes in one column (rates, notionals, 
micro-quantities and large balances together).
 * *Existing Spark users* who need to read or write Parquet datasets produced 
by systems that already use IEEE decimal128 / DECFLOAT.
 * *The wider storage ecosystem* (Parquet, and eventually Iceberg / Delta 
consumers) gains a portable decimal-float logical type rather than 
engine-private encodings.

Success means: declare DECFLOAT columns, run SQL arithmetic and aggregations 
without leaving the numeric domain, and round-trip values through Parquet with 
IEEE semantics preserved (including cohort / quantum where the format retains 
it).

*Q6. What are the risks?*
||*Risk*||*Mitigation*||
|Parquet / table-format standardization lagging Spark SQL|Ship Spark SQL type 
with a documented on-disk encoding; upstream Parquet logical type in parallel; 
avoid relying on undocumented footer keys|
|Surprising type coercion (DECFLOAT outranking DOUBLE / interacting with 
DECIMAL)|Document precedence explicitly; add golden SQL tests; match IEEE / SQL 
expectations rather than silent demotion to binary float|
|Special-value semantics (NaN, Inf) surprising users coming from engines 
without them (e.g. some warehouse DECFLOAT dialects)|Document clearly; default 
IEEE non-stop handling; ANSI mode provides fail-fast behavior consistent with 
other numeric types.|
|External API choice for Inf/NaN (Java BigDecimal cannot represent them)|Pick 
an explicit external type story early (see Appendix B) and test Connect / 
PySpark / JDBC thoroughly|
|Scope creep into arbitrary precision or DECFLOAT(70)|Keep v1 strictly at 
precisions 16 and 34; record wider formats as follow-ons|
|Implementation overhead and ensuring full behavioural consistency in a custom 
JVM implementation versus existing libraries|Implement DECFLOAT via JNI calls 
to the existing libbid library (which offers fast, exact math for decimal 
floating-point numbers)|

*Q7. How long will it take?*

Rough estimate: *on the order of 9-12 months* for feature-complete parity with 
peer numeric types, based on TIME (SPARK-51162), TIMESTAMP_NTZ (SPARK-35662), 
and ANSI intervals (SPARK-27790), plus extra time for the math library 
integration and Parquet logical type.

Suggested work split (can become JIRA sub-tasks):
 # *Base type: ~1 month* DecFloatType, parser / DDL, literals (DECFLOAT '...', 
optional DF suffix), casts to/from string and numeric types, session rounding 
mode.
 # *Arithmetic and comparison kernels: ~2 months* + - * /, unary minus, 
comparisons, ordering (totalOrder for sort), hashing / grouping equality 
(canonicalization for =-equal values), codegen / interpreted execution.
 # *Functions and aggregates: ~2 months* Core scalars (abs, sign, floor, ceil, 
round, sqrt, isnan, …), DECFLOAT-specific helpers (quantize, same_quantum, 
total_order), sum / avg / min / max / count, window variants.
 # *Persistence: ~3 months* Parquet read/write with logical annotation, 
partition values, stats / predicate pushdown, caching / shuffle; coordinate 
with Parquet format RFC.
 # *Clients: ~1.5 months* Spark Connect proto, JDBC / Thrift / Hive result 
mapping, catalog / information_schema.
 # *PySpark / Arrow: ~1.5 months* DataFrame API, pandas / Arrow interchange, 
Python UDFs.
 # *Docs, golden tests, benchmarks: ~1 month (overlaps)*

[OPEN] Confirm estimate after sketching the Parquet dependency and whether 
Arrow needs a parallel extension type for transport.

*Q8. What are the mid-term and final "exams" to check for success?*

*Mid-term (~4-5 months):*
 * DecFloatType(16|34) usable in SQL: literals, DDL, casts, arithmetic, 
comparisons, basic aggregates.
 * Correct IEEE behavior for a representative set of finite values, signed 
zeros, Inf, and NaN (under both ANSI and non-ANSI modes), and rounding 
(especially at the precision boundary, e.g. results exceeding 16/34 digits, 
ties).
 * Round-trip through at least one built-in file source (Parquet) with a stable 
encoding, even if the upstream Parquet annotation is still landing.
 * No behavioral change to existing DECIMAL / DOUBLE workloads when the new 
type is unused.

*Final exam (~9-12 months):*
 * Feature parity with other numeric types for the agreed v1 function set (see 
Appendix C sketch).
 * Interoperable Parquet read/write against an independent implementation (e.g. 
parquet-java ↔ parquet-rs) once the logical type is specified.
 * Connect, JDBC, and PySpark can create, query, and collect DECFLOAT columns.
 * Documented ANSI / IEEE compliance notes and migration guidance from DECIMAL 
/ DOUBLE / string workarounds.


> SPIP: Add the DECFLOAT data type
> --------------------------------
>
>                 Key: SPARK-58820
>                 URL: https://issues.apache.org/jira/browse/SPARK-58820
>             Project: Spark
>          Issue Type: Umbrella
>          Components: SQL
>    Affects Versions: 5.0.0
>            Reporter: Uroš Bojanić
>            Assignee: Uroš Bojanić
>            Priority: Major
>              Labels: SPIP
>
> *Q1. What are you trying to do? Articulate your objectives using absolutely 
> no jargon.*
> Add a new Spark SQL data type *DECFLOAT* that stores decimal numbers with a 
> flexible decimal point (floating point decimal numbers). Each value keeps up 
> to a fixed number of significant decimal digits and its own exponent, so one 
> column can hold both very large integers and very small fractions without 
> picking a single fixed scale for the whole column.
> The type follows the IEEE 754 decimal floating-point formats:
> ||*SQL type*||*IEEE format*||*Significant digits*||*Storage width*||
> |DECFLOAT(16)|decimal64|16|8 bytes|
> |DECFLOAT(34)|decimal128|34|16 bytes|
> Bare DECFLOAT means DECFLOAT(34).
> Unlike DECIMAL(p,s), there is no column-wide scale. Unlike FLOAT / DOUBLE, 
> arithmetic is done in base 10, so values such as 0.1 are exact.
> Because each value carries at most 16 or 34 significant digits, a result 
> needing more digits is rounded to the format's precision. Rounding is decimal 
> (base 10), unlike binary rounding in FLOAT/DOUBLE. The v1 fixed default is 
> IEEE roundTiesToEven / HALF_EVEN (banker's rounding), which differs from 
> Spark's existing DECIMAL arithmetic (rounds HALF_UP). This can be 
> configurable in future iterations.
> The type also supports IEEE special values: signed zero, +/-Infinity, and 
> quiet NaN.
> *Q2. What problem is this proposal NOT designed to solve?*
>  * *Arbitrary-precision / unbounded decimals.* Extending Spark's fixed-point 
> DECIMAL beyond 38 digits, or adding a PostgreSQL-style unbounded NUMERIC, is 
> out of scope. Those needs are different from IEEE decimal floating point.
>  * *Wider-than-IEEE formats in v1.* Formats such as a 70-digit / 256-bit 
> decimal float (sometimes discussed as DECFLOAT(70) / decimal256) are out of 
> scope for the first delivery. The type and storage designs should not 
> preclude them later.
>  * *Replacing* DECIMAL *or* DOUBLE{*}.{*} Existing fixed-point and 
> binary-float types remain unchanged. DECFLOAT is additive.
>  * *Non-IEEE decimal-float dialects as the native type.* Engines such as 
> Snowflake, Oracle, and Teradata expose a decimal float that is not a strict 
> IEEE width (e.g. 38 digits, no NaN/Inf). Spark's native type targets IEEE 754 
> decimal64 and decimal128. Mapping those dialects into Spark is a connector / 
> cast concern, not a second native type.
>  * *ORC / CSV / JSON as first-class DECFLOAT storage in v1.* Persistence focus
> for v1 is Parquet (and table formats that sit on Parquet). Other formats may
> round-trip via string or binary until separately specified.
> *Q3. How is it done today, and what are the limits of current practice?*
> Spark SQL today offers two numeric families for real numbers:
>  # DECIMAL(p,s) *(fixed-point).* Precision and scale are fixed for the 
> column. Spark caps precision at 38. Mixed magnitudes force a tradeoff: many 
> fractional digits leave few integer digits (and the reverse). Chains of 
> arithmetic expand precision quickly and often require manual casts.
>  # FLOAT */* DOUBLE *(binary floating-point).* Wide range, but many common 
> decimal fractions are not exact. About 15-16 significant decimal digits for 
> DOUBLE, with binary rounding error.
> Workarounds in use today:
> ||*Workaround*||*Limitation*||
> |Map high-precision source decimals to DECIMAL(38,s)|Overflow / out-of-range 
> errors for large integers; silent rounding of long fractions|
> |Cast to DOUBLE|Binary rounding; unsuitable when exact decimal fractions 
> matter|
> |Store as STRING|Loses numeric semantics; arithmetic and aggregation must be 
> rebuilt|
> |Emulate with (unscaled DECIMAL, scale INT) structs|Not a first-class type; 
> poor pushdown, stats, and ecosystem support|
> Spark also cannot recognize IEEE decimal floating-point values in Parquet (or 
> other built-in file sources) as a distinct logical type today, so even when 
> another system wrote such values, Spark cannot load them as decimals with 
> per-value exponents.
> *Q4. What is new in your approach and why do you think it will be successful?*
> The approach is deliberately conventional and layered, following prior Spark 
> type introductions (TIMESTAMP_NTZ, ANSI intervals, TIME):
>  # *Standard semantics first.* Align the SQL type with IEEE 754-2019 
> decimal64 / decimal128 and with existing SQL DECFLOAT practice (DB2,  
> Firebird, MongoDB). Prefer IEEE default exception handling (produce Inf/NaN), 
> rather than inventing a Spark-only numeric model. Same goes for rounding, 
> roundTiesToEven is chosen because it's the IEEE default and libbid/DB2 
> behaviour.
>  # *Concrete physical representation.* Use the IEEE binary integer decimal 
> (BID) interchange encoding in memory and on disk, with a well-known math 
> library (Intel Decimal Floating-Point Math Library / libbid) for arithmetic 
> kernels. This avoids a logical-only typedef over DECIMAL / STRING that would 
> diverge across implementations.
>  # *Open storage path.* Propose a 
> [Parquet|https://docs.google.com/document/d/104397AVUqg_JSlzGBdpa3D98X6Dd-RONIgABn3omBcw/edit?tab=t.0]
>  logical type for decimal floating point (width-extensible 
> FIXED_LEN_BYTE_ARRAY annotation; initially decimal64 and decimal128) so 
> Spark, other engines, and table formats can interoperate without Arrow-footer 
> private conventions.
>  # *Additive rollout.* Gate the type behind a config during incubation 
> (pattern used for TIME), then enable by default once coverage matches peer 
> numeric types.
> We expect this to succeed because:
>  * The user-visible type matches what migrators already know from DB2 / 
> Firebird / MongoDB Decimal128, and closes a clear gap versus warehouses that 
> already ship a decimal-float type.
>  * The encoding and math library are industry-proven rather than bespoke.
>  * Spark already has a playbook for introducing a new atomic type end-to-end 
> (parser → Catalyst → execution → datasources → Connect / PySpark / JDBC).
> *Q5. Who cares? If you are successful, what difference will it make?*
>  * *Users migrating from PostgreSQL, Oracle, DB2, BigQuery, and similar 
> systems* who today hit Spark's DECIMAL(38,*) ceiling or lose precision via 
> DOUBLE / STRING workarounds. Unconstrained or high-precision source numerics 
> map cleanly to a first-class numeric type.
>  * *Financial, actuarial, and crypto / fintech workloads* that need exact 
> decimal fractions and mixed magnitudes in one column (rates, notionals, 
> micro-quantities and large balances together).
>  * *Existing Spark users* who need to read or write Parquet datasets produced 
> by systems that already use IEEE decimal128 / DECFLOAT.
>  * *The wider storage ecosystem* (Parquet, and eventually Iceberg / Delta 
> consumers) gains a portable decimal-float logical type rather than 
> engine-private encodings.
> Success means: declare DECFLOAT columns, run SQL arithmetic and aggregations 
> without leaving the numeric domain, and round-trip values through Parquet 
> with IEEE semantics preserved (including cohort / quantum where the format 
> retains it).
> *Q6. What are the risks?*
> ||*Risk*||*Mitigation*||
> |Parquet / table-format standardization lagging Spark SQL|Ship Spark SQL type 
> with a documented on-disk encoding; upstream Parquet logical type in 
> parallel; avoid relying on undocumented footer keys|
> |Surprising type coercion (DECFLOAT outranking DOUBLE / interacting with 
> DECIMAL)|Document precedence explicitly; add golden SQL tests; match IEEE / 
> SQL expectations rather than silent demotion to binary float|
> |Special-value semantics (NaN, Inf) surprising users coming from engines 
> without them (e.g. some warehouse DECFLOAT dialects)|Document clearly; 
> default IEEE non-stop handling; ANSI mode provides fail-fast behavior 
> consistent with other numeric types.|
> |External API choice for Inf/NaN (Java BigDecimal cannot represent them)|Pick 
> an explicit external type story early (see Appendix B) and test Connect / 
> PySpark / JDBC thoroughly|
> |Scope creep into arbitrary precision or DECFLOAT(70)|Keep v1 strictly at 
> precisions 16 and 34; record wider formats as follow-ons|
> |Implementation overhead and ensuring full behavioural consistency in a 
> custom JVM implementation versus existing libraries|Implement DECFLOAT via 
> JNI calls to the existing libbid library (which offers fast, exact math for 
> decimal floating-point numbers)|
> *Q7. How long will it take?*
> Rough estimate: *on the order of 9-12 months* for feature-complete parity 
> with peer numeric types, based on TIME (SPARK-51162), TIMESTAMP_NTZ 
> (SPARK-35662), and ANSI intervals (SPARK-27790), plus extra time for the math 
> library integration and Parquet logical type.
> Suggested work split (can become JIRA sub-tasks):
>  # *Base type: ~1 month* DecFloatType, parser / DDL, literals (DECFLOAT 
> '...', optional DF suffix), casts to/from string and numeric types, etc.
>  # *Arithmetic and comparison kernels: ~2 months* + - * /, unary minus, 
> comparisons, ordering (totalOrder for sort), hashing / grouping equality 
> (canonicalization for =-equal values), codegen / interpreted execution.
>  # *Functions and aggregates: ~2 months* Core scalars (abs, sign, floor, 
> ceil, round, sqrt, isnan, …), DECFLOAT-specific helpers (quantize, 
> same_quantum, total_order), sum / avg / min / max / count, window variants.
>  # *Persistence: ~3 months* Parquet read/write with logical annotation, 
> partition values, stats / predicate pushdown, caching / shuffle; coordinate 
> with Parquet format RFC.
>  # *Clients: ~1.5 months* Spark Connect proto, JDBC / Thrift / Hive result 
> mapping, catalog / information_schema.
>  # *PySpark / Arrow: ~1.5 months* DataFrame API, pandas / Arrow interchange, 
> Python UDFs.
>  # *Docs, golden tests, benchmarks: ~1 month (overlaps)*
> [OPEN] Confirm estimate after sketching the Parquet dependency and whether 
> Arrow needs a parallel extension type for transport.
> *Q8. What are the mid-term and final "exams" to check for success?*
> *Mid-term (~4-5 months):*
>  * DecFloatType(16|34) usable in SQL: literals, DDL, casts, arithmetic, 
> comparisons, basic aggregates.
>  * Correct IEEE behavior for a representative set of finite values, signed 
> zeros, Inf, and NaN (under both ANSI and non-ANSI modes), and rounding 
> (especially at the precision boundary, e.g. results exceeding 16/34 digits, 
> ties).
>  * Round-trip through at least one built-in file source (Parquet) with a 
> stable encoding, even if the upstream Parquet annotation is still landing.
>  * No behavioral change to existing DECIMAL / DOUBLE workloads when the new 
> type is unused.
> *Final exam (~9-12 months):*
>  * Feature parity with other numeric types for the agreed v1 function set 
> (see Appendix C sketch).
>  * Interoperable Parquet read/write against an independent implementation 
> (e.g. parquet-java ↔ parquet-rs) once the logical type is specified.
>  * Connect, JDBC, and PySpark can create, query, and collect DECFLOAT columns.
>  * Documented ANSI / IEEE compliance notes and migration guidance from 
> DECIMAL / DOUBLE / string workarounds.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

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

Reply via email to