Abhijeet Patil
03/24/2026, 5:45 PMdaft.DataType.decimal128(38, 20) after reading from mysql. If distributed delta merge using deltalake fails on a worker due to delta contention, I am doing retries (I am not using dynamodb as lock provider).
Is there a known issue with datatype decimal(38, 20) and how to avoid it? Please let me know if additional details are required.Robert Howell
03/24/2026, 5:56 PMRobert Howell
03/24/2026, 5:58 PMAbhijeet Patil
03/24/2026, 6:14 PMPIP_PACKAGES=(
"ray[default]==2.54.0"
"daft==0.7.4"
"deltalake==1.4.2"
"pyarrow==23.0.1"
"pymysql"
"boto3"
"sqlglot"
"sqlalchemy"
)
AWS compute instances - 26 nodes of mostly m6g.xlarge if that help.
Mysql source is InnoDB.
Size of table in S3 - 183 GBjay
03/25/2026, 3:43 PMjay
03/25/2026, 3:44 PMAbhijeet Patil
03/26/2026, 2:11 AMRobert Howell
03/26/2026, 2:21 AMRobert Howell
03/27/2026, 9:01 PMRobert Howell
03/27/2026, 9:05 PMTrigger A: Existing Delta Table Has a Different Scale (Highest Likelihood)
Your delta merge reads the existing Delta table as DECIMAL(38, S) — written previously by Spark (which frequently infers DECIMAL(38, 18) from data), by a prior Daft version, or via a different connector. The new MySQL data arrives as DECIMAL(38, 20).
Daft's supertype computation (supertype.rs:204):
Some(DataType::Decimal128(max(p1, p2), max(s1, s2)))
// DECIMAL(38, 18) + DECIMAL(38, 20) → DECIMAL(38, 20)
This forces old rows to be upscaled from S=18 to S=20. Any row with |value| > i128::MAX / 10² (≈ 1.7×10^36 internal, ≈ 1.7×10^18 actual) will overflow → NULL. Since DECIMAL(38, 18) allows values up to 10^20, roughly 98% of the range (10^18 to 10^20) is the danger zone.
Trigger B: PyArrow Scale Inference at MySQL Read Time
Python MySQL connectors (mysql-connector-python, PyMySQL) return decimal.Decimal objects with trailing zeros stripped. For example, a MySQL DECIMAL(38, 20) value 1000000000000000000.00000000000000000000 comes back as Decimal('1000000000000000000') (scale=0).
PyArrow infers the type from the actual values per partition. If a Ray partition happens to contain only integer-valued decimals (scale=0 after stripping), PyArrow creates DECIMAL(19, 0) for that partition. When Daft reconciles with other partitions (via supertype) or you call .cast(DataType.decimal128(38, 20)), the upscaling is fallible.
Overflow threshold for scale=0 → scale=20: |value| > 10^18 (which equals the precision cap of DECIMAL(38, 20) itself, meaning ALL values near the maximum are at risk).
Abhijeet Patil
03/29/2026, 1:17 PMAbhijeet Patil
03/31/2026, 5:55 PMjay
03/31/2026, 6:02 PMRobert Howell
03/31/2026, 6:03 PMAbhijeet Patil
04/01/2026, 7:30 AMjay
04/06/2026, 9:49 PMAbhijeet Patil
04/20/2026, 4:35 PM