Skip to content

Commit 25634d4

Browse files
ai: apply changes for #1006 (2 review threads)
Addresses: - #4418588494 at src/databricks/sql/parameters/native.py:660 - #4418588499 at src/databricks/sql/parameters/native.py:705 Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>
1 parent 2b3a85a commit 25634d4

3 files changed

Lines changed: 11 additions & 14 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Release History
22

33
# Unreleased
4-
- **Behaviour change:** `DecimalParameter` now binds `DECIMAL(precision, scale)`, matching SQL: `precision` is the total number of digits and `scale` the number of fractional digits (earlier docs described them the other way round). Calls written for the old convention (`scale > precision`, e.g. `scale=10, precision=2`) still bind `DECIMAL(10,2)` but emit a `FutureWarning`; swap your arguments, as this will raise `ValueError` in a future release. A declared `scale` equal to or less than `precision` is now interpreted with the SQL meaning, and a declared `scale` smaller than the value's own scale is widened (growing the precision by the same amount) so fractional digits are not lost (e.g. `DecimalParameter(Decimal("123.4567"), precision=10, scale=2)` binds `DECIMAL(12,4)`). The declared integer room (`precision - scale`) is not widened, so a value with more integer digits is still rejected by the server as out of range. Widening is capped at the 38-digit DECIMAL maximum; a value needing more digits than that still has its excess fractional digits rounded. The constructor now also raises `ValueError` for inputs it previously accepted: a `precision` outside 1..38 (e.g. `scale=0, precision=0`, which used to fall back to an inferred type), a negative `scale`, and `bool` values for `scale` or `precision`.
4+
- **Behaviour change:** `DecimalParameter` now binds `DECIMAL(precision, scale)`, matching SQL: `precision` is the total number of digits and `scale` the number of fractional digits (earlier docs described them the other way round). Calls written for the old convention (`scale > precision`, e.g. `scale=10, precision=2`) still bind `DECIMAL(10,2)` but emit a `FutureWarning`; swap your arguments, as this will raise `ValueError` in a future release. A declared `scale` equal to or less than `precision` is now interpreted with the SQL meaning, and a declared `scale` smaller than the value's own scale is widened (growing the precision by the same amount) so fractional digits are not lost (e.g. `DecimalParameter(Decimal("123.4567"), precision=10, scale=2)` binds `DECIMAL(12,4)`). The declared integer room (`precision - scale`) is not widened, so a value with more integer digits is still rejected by the server as out of range. Widening is capped at the 38-digit DECIMAL maximum; a value needing more digits than that still has its excess fractional digits rounded. The constructor now also raises `ValueError` for inputs it previously accepted: a `precision` outside 1..38 (including `precision=0`, e.g. `scale=0, precision=0` or `scale=5, precision=0`, which used to fall back to an inferred type), a negative `scale`, and `bool` values for `scale` or `precision`.
55
- Preserve the originating session when re-fetching or concurrently polling async statements on the kernel backend.
66

77
# 4.8.0 (2026-10-24)

‎src/databricks/sql/parameters/native.py‎

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,10 @@ def __init__(
657657
raise ValueError(
658658
"DecimalParameter scale must be >= 0, got {}".format(self.scale)
659659
)
660-
if self.precision < 0 or self.precision > self.MAX_PRECISION:
660+
# precision=0 is rejected here too (not swapped): earlier releases
661+
# treated it as unset and inferred the type, so swapping e.g.
662+
# scale=5, precision=0 into DECIMAL(5,0) would silently round the value.
663+
if not 1 <= self.precision <= self.MAX_PRECISION:
661664
raise ValueError(
662665
"DecimalParameter precision must be between 1 and {}, got {}".format(
663666
self.MAX_PRECISION, self.precision
@@ -700,20 +703,11 @@ def __init__(
700703
self.scale, self.precision = self.precision, self.scale
701704
# Preserve the old bound type exactly (no widening) for these callers,
702705
# so the only change they see is the warning.
706+
# No re-validation needed: the swapped scale is the raw precision
707+
# (already 1..38) and the swapped precision is the raw scale (already
708+
# > that and <= 38), so the result is always a valid DECIMAL.
703709
self._legacy_swapped = True
704710

705-
if self.scale is not None and self.precision is not None:
706-
if self.scale < 0:
707-
raise ValueError(
708-
"DecimalParameter scale must be >= 0, got {}".format(self.scale)
709-
)
710-
if not 1 <= self.precision <= self.MAX_PRECISION:
711-
raise ValueError(
712-
"DecimalParameter precision must be between 1 and {}, got {}".format(
713-
self.MAX_PRECISION, self.precision
714-
)
715-
)
716-
717711
def valid_scale_and_precision(self):
718712
def _is_int(x):
719713
# bool is a subclass of int; reject it so precision=True/scale=False

‎tests/unit/test_parameters.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ def test_decimal_bool_scale_or_precision_raises(scale, precision):
235235
(
236236
(50, 2, "scale must be between 0 and 38, got 50"),
237237
(5, -1, "precision must be between 1 and 38, got -1"),
238+
# precision=0 used to mean "unset" (type inferred); it must not be swapped
239+
# into DECIMAL(5,0), which would round the value.
240+
(5, 0, "precision must be between 1 and 38, got 0"),
238241
),
239242
)
240243
def test_decimal_out_of_range_raw_args_raise_before_legacy_swap(scale, precision, match):

0 commit comments

Comments
 (0)