Decoding a decimal column changes the caller's Decimal.Context and never restores it
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 78/100
調査の方向性
lib/tds/types.exを読み、decode_decimal/3、encode_decimal_type/1、encode_float_type/1、encode_decimal_descriptor/1、encode_data/3、set_decimal_precision/1に注目してください。報告によると、これらの呼び出しはDecimal.Contextを変更しますが、変更後の精度を算術演算に使用しません。小数のデコードとエンコードに関する既存のテストを確認し、それらの経路の後も呼び出し元のコンテキストが変わらないことを検証してください。
索引モデルが issue の本文から書いたものです。
説明
Summary
Tds.Types.decode_decimal/3 calls Decimal.Context.set/1 with the column's precision for every decimal value it decodes, and the decimal/float encode paths set precision 38 for every decimal parameter they encode. Nothing restores the previous context. Decoding runs in the client process, so after any query that returns a decimal column, the caller's Decimal.Context precision is that column's precision instead of the default, for the rest of the process's life.
tds 2.3.8 (latest), decimal 3.2.0, Elixir 1.20.3, Ecto 3.14 / ecto_sql 3.14 with Ecto.Adapters.Tds, SQL Server 2019.
Reproduction
Decimal.Context.set(%Decimal.Context{})
Decimal.Context.get().precision
#=> 34 (decimal 3.2.0 default; 28 on older versions)
# any table with a numeric(15, 9) column
{:ok, _} = MyRepo.query("select top 1 MUCOFA from MITAUN", [])
Decimal.Context.get().precision
#=> 15
# after decoding a numeric(5, x) column the precision is 5, and then
Decimal.round(Decimal.new("1000.000000000"), 2)
#=> ** (Decimal.Error) invalid_operation: result has more digits than the precision
Where
lib/tds/types.ex:
decode_decimal/3callsset_decimal_precision(precision)and then onlyDecimal.new/3, which does not read the context, so the call has no effect on the decoded value and only leaks.encode_decimal_type/1,encode_float_type/1,encode_decimal_descriptor/1andencode_data/3fordecimalncallset_decimal_precision(38), and then onlyDecimal.abs/1,Decimal.to_string/2andDecimal.new/1, none of which round to the context precision either.set_decimal_precision/1isDecimal.Context.get() |> Map.put(:precision, p) |> Decimal.Context.set().
Impact
Every Decimal.mult/2, add/2 or div/2 the application does after a query is rounded to the last decoded column's precision instead of its own. This was silent for a long time because Decimal.round/3 ignored the context precision until decimal 3.2.0 (2026-10-10), which made round/3 follow the spec and raise, so an application that rounds a decoded value to two places now fails on a value as plain as 1000.000000000. We found it when a production import stopped completely after upgrading decimal.
Suggested fix
Drop set_decimal_precision/1 altogether: none of the five call sites does arithmetic that depends on the context precision. Should a wider precision ever be needed, Decimal.Context.with/2 restores the previous context afterwards:
Decimal.Context.with(%{Decimal.Context.get() | precision: 38}, fn -> ... end)
Happy to send a PR if that direction is acceptable.
- 主要言語
- Elixir
- スター
- 119
- フォーク
- 87
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートなし
- コントリビューションガイドなし
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
elixir-ecto/tds のほかの issue
-
難易度 5/5 1週間以上 初心者へのやさしさ 8/100
elixir-ecto/tds#189 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 38/100
elixir-ecto/tds#170 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 30/100
elixir-ecto/tds#169 · コメント 2 件 ·
-
bug
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
elixir-ecto/tds#168 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
elixir-ecto/tds#155 ·
elixir-ecto/tds の issue をすべて見る
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
taskforcesh/bullmq#5038 ·
メンテナーはふだん 1 日以内に返信
-
pip: same package pinned twice with different casing in pyproject.toml, only the first pin is updated対応中かも @v-abhishekbhaskar が 1 日前に担当しました。 オープンL: python L: ruby:bundler T: bug 🐞
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
dependabot/dependabot-core#16756 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
feat: signup pageオープンd: medium
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
-
難易度 2/5 1時間未満 初心者へのやさしさ 85/100