/// <inheritdoc /> public override void Write(decimal value, NpgsqlWriteBuffer buf, NpgsqlParameter?parameter) { var raw = new DecimalRaw(value); var scaleDifference = MoneyScale - raw.Scale; if (scaleDifference > 0) { DecimalRaw.Multiply(ref raw, DecimalRaw.Powers10[scaleDifference]); } else { value = Math.Round(value, MoneyScale, MidpointRounding.AwayFromZero); raw = new DecimalRaw(value); } var result = (long)raw.Mid << 32 | raw.Low; if (raw.Negative) { result = -result; } buf.WriteInt64(result); }
/// <inheritdoc /> public override async ValueTask <decimal> Read(NpgsqlReadBuffer buf, int len, bool async, FieldDescription?fieldDescription = null) { await buf.Ensure(4 *sizeof(short), async); var result = new DecimalRaw(); var groups = buf.ReadInt16(); var weight = buf.ReadInt16() - groups + 1; var sign = buf.ReadUInt16(); if ((sign & SignSpecialMask) == SignSpecialMask) { throw sign switch { SignNan => new InvalidCastException("Numeric NaN not supported by System.Decimal"), SignPinf => new InvalidCastException("Numeric Infinity not supported by System.Decimal"), SignNinf => new InvalidCastException("Numeric -Infinity not supported by System.Decimal"), _ => new InvalidCastException($"Numeric special value {sign} not supported by System.Decimal") }; } if (sign == SignNegative) { DecimalRaw.Negate(ref result); } var scale = buf.ReadInt16(); if (scale < 0 is var exponential && exponential) { scale = (short)(-scale); } else { result.Scale = scale; } if (scale > MaxDecimalScale) { throw new OverflowException("Numeric value does not fit in a System.Decimal"); } var scaleDifference = exponential ? weight * MaxGroupScale : weight * MaxGroupScale + scale; if (groups > MaxGroupCount) { throw new OverflowException("Numeric value does not fit in a System.Decimal"); } await buf.Ensure(groups *sizeof(ushort), async); if (groups == MaxGroupCount) { while (groups-- > 1) { DecimalRaw.Multiply(ref result, MaxGroupSize); DecimalRaw.Add(ref result, buf.ReadUInt16()); } var group = buf.ReadUInt16(); var groupSize = DecimalRaw.Powers10[-scaleDifference]; if (group % groupSize != 0) { throw new OverflowException("Numeric value does not fit in a System.Decimal"); } DecimalRaw.Multiply(ref result, MaxGroupSize / groupSize); DecimalRaw.Add(ref result, group / groupSize); } else { while (groups-- > 0) { DecimalRaw.Multiply(ref result, MaxGroupSize); DecimalRaw.Add(ref result, buf.ReadUInt16()); } if (scaleDifference < 0) { DecimalRaw.Divide(ref result, DecimalRaw.Powers10[-scaleDifference]); } else { while (scaleDifference > 0) { var scaleChunk = Math.Min(DecimalRaw.MaxUInt32Scale, scaleDifference); DecimalRaw.Multiply(ref result, DecimalRaw.Powers10[scaleChunk]); scaleDifference -= scaleChunk; } } } return(result.Value); }