Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Decoding a decimal column changes the caller's Decimal.Context and never restores it

Aperta Adatta ai principianti
#191 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
78/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
elixir
Ambito
backend, databases

Direzione di ricerca

Leggi lib/tds/types.ex, concentrandoti su decode_decimal/3, encode_decimal_type/1, encode_float_type/1, encode_decimal_descriptor/1, encode_data/3 e set_decimal_precision/1. Il rapporto dice che queste chiamate modificano Decimal.Context senza usare la precisione modificata per le operazioni aritmetiche; controlla i test esistenti per la decodifica e la codifica dei decimali, quindi verifica che il contesto del chiamante rimanga invariato dopo questi percorsi.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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/3 calls set_decimal_precision(precision) and then only Decimal.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/1 and encode_data/3 for decimaln call set_decimal_precision(38), and then only Decimal.abs/1, Decimal.to_string/2 and Decimal.new/1, none of which round to the context precision either.
  • set_decimal_precision/1 is Decimal.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.

Lingua principale
Elixir
Stelle
119
Fork
87
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

  • Include un Dockerfile o un file Docker Compose
  • Nessun modello di pull request
  • Nessuna guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di elixir-ecto/tds

Tutte le issue di elixir-ecto/tds

Issue simili

Altre issue su Elixir

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.