Writing a decimal as numeric allocates a short[9] per value

Aperta Adatta ai principianti
#6,728 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 6 giorni

@tamasprincz97-dot ci sta già lavorando.

Dal 28/10/2026.

  • #6729 di @tamasprincz97-dot — aperta

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
89/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
csharp, postgresql

Direzione di ricerca

Inizia con DecimalNumericConverter<T>.Write e PgNumeric.Builder.Create, citati nell’issue, poi esegui il comando BenchmarkDotNet fornito da test/Npgsql.Benchmarks. Confronta la dimensione del buffer dello stack con il limite superiore del builder per i valori decimali; il lavoro è completato quando le scritture numeriche non allocano più un short[9] per valore e il benchmark conferma la modifica delle allocazioni.

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

Descrizione

Steps to reproduce

Write any non-null decimal parameter as numeric, or run the existing benchmark:

cd test/Npgsql.Benchmarks
dotnet run -c Release -- --filter '*TypeHandlers.Numeric.Write*' --job short
The issue

DecimalNumericConverter<T>.Write gives PgNumeric.Builder a stack buffer of MaxDecimalNumericDigits (8) shorts:

Span<short> destination = stackalloc short[PgNumeric.Builder.MaxDecimalNumericDigits];

PgNumeric.Builder.Create reserves an upper bound before converting, and allocates if the destination is smaller:

var bitsUpperBound = (bits.Length * (MaxUInt32Scale + 1) + MaxUInt16Scale - 1) / MaxUInt16Scale + 1;
if (bitsUpperBound > destination.Length)
    destination = digitsArray = new short[bitsUpperBound];

For a decimal, bits.Length is 3, so the bound is (3 * 10 + 3) / 4 + 1 = 9. That is more than 8, so every non-null value allocates a short[9] (48 B), and the stack buffer is never used. The same converter is used for byte, short, int, long, float and double mapped to numeric, and for numeric ranges and multiranges.

A decimal never needs more than 8 numeric digits. The 9th slot is the builder's generic headroom, so the buffer is one short too small for the check.

TypeHandlers.Numeric.Write on main (b35800b4), BenchmarkDotNet ShortRun, .NET 10.0.14: all 15 benchmark values allocate 48 B per op.

This is unrelated to #6509, which is a read-side bug in PgNumeric.Builder.ToDecimal.

Further technical details

Npgsql version: main (11.0.0-preview.1, b35800b4); also present in 10.0.3
PostgreSQL version: any (client side)
Operating system: any

Lingua principale
C#
Stelle
3.7k
Fork
890
Merge medio
4g 11h
PR unite (30g)
19

Preparare l'ambiente

Apri in Codespaces

Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.

  • Nessun Dockerfile né 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 npgsql/npgsql

Tutte le issue di npgsql/npgsql

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.