diff --git a/core/wren/src/wren/connector/athena.py b/core/wren/src/wren/connector/athena.py index 73953b4f0..07e9f9d03 100644 --- a/core/wren/src/wren/connector/athena.py +++ b/core/wren/src/wren/connector/athena.py @@ -91,7 +91,13 @@ def _trino_data_type_to_arrow(node) -> pa.DataType: return _TRINO_DATA_TYPE_TO_ARROW[kind] if kind == T.DECIMAL: - precision, scale = 38, 9 + # Trino/Athena DECIMAL semantics: DECIMAL(p) means scale 0 (an integer + # of p digits), NOT an unspecified scale. Bare DECIMAL defaults to + # (38, 0). Only DECIMAL(p, s) carries a non-zero scale. Defaulting the + # scale to a non-zero value here both mistyped DECIMAL(p) columns and, + # for small precisions (e.g. DECIMAL(5)), produced scale > precision, + # which PyArrow rejects with an ArrowInvalid. + precision, scale = 38, 0 params = node.expressions if len(params) >= 1: with contextlib.suppress(AttributeError, ValueError, TypeError): diff --git a/core/wren/tests/unit/test_athena_connector.py b/core/wren/tests/unit/test_athena_connector.py index 9b87aeae9..d67c0f2a0 100644 --- a/core/wren/tests/unit/test_athena_connector.py +++ b/core/wren/tests/unit/test_athena_connector.py @@ -78,6 +78,22 @@ def test_parse_athena_type_decimal(): assert _parse_athena_type("decimal(12,4)") == pa.decimal128(12, 4) +def test_parse_athena_type_decimal_precision_only_is_scale_zero(): + # Trino/Athena: DECIMAL(p) means scale 0, not an unspecified/default scale. + assert _parse_athena_type("decimal(10)") == pa.decimal128(10, 0) + + +def test_parse_athena_type_decimal_bare_defaults(): + # Bare DECIMAL is DECIMAL(38, 0) per the SQL standard / Trino. + assert _parse_athena_type("decimal") == pa.decimal128(38, 0) + + +def test_parse_athena_type_decimal_small_precision_only(): + # Regression: DECIMAL(5) must not yield scale > precision. A non-zero + # default scale (e.g. 9) produced decimal128(5, 9), which PyArrow rejects. + assert _parse_athena_type("decimal(5)") == pa.decimal128(5, 0) + + def test_parse_athena_type_array(): assert _parse_athena_type("array(varchar)") == pa.list_(pa.string())