/// <inheritdoc /> public override int ValidateAndGetLength(decimal value, NpgsqlParameter?parameter) { var groupCount = 0; var raw = new DecimalRaw(value); if (raw.Low != 0 || raw.Mid != 0 || raw.High != 0) { uint remainder = default; var scaleChunk = raw.Scale % MaxGroupScale; if (scaleChunk > 0) { var divisor = DecimalRaw.Powers10[scaleChunk]; var multiplier = DecimalRaw.Powers10[MaxGroupScale - scaleChunk]; remainder = DecimalRaw.Divide(ref raw, divisor) * multiplier; } while (remainder == 0) { remainder = DecimalRaw.Divide(ref raw, MaxGroupSize); } groupCount++; while (raw.Low != 0 || raw.Mid != 0 || raw.High != 0) { DecimalRaw.Divide(ref raw, MaxGroupSize); groupCount++; } } return(4 * sizeof(short) + groupCount * sizeof(short)); }
public override void Write(decimal value, NpgsqlWriteBuffer buf, NpgsqlParameter parameter) { var raw = Unsafe.As <decimal, DecimalRaw>(ref value); var scaleDifference = MoneyScale - raw.Scale; if (scaleDifference > 0) { DecimalRaw.Multiply(ref raw, DecimalRaw.Powers10[scaleDifference]); } else { while (scaleDifference < 0) { var scaleChunk = Math.Min(DecimalRaw.MaxUInt32Scale, -scaleDifference); DecimalRaw.Divide(ref raw, DecimalRaw.Powers10[scaleChunk]); scaleDifference -= scaleChunk; } } var result = (long)raw.Mid << 32 | (long)raw.Low; if (raw.Negative) { result = -result; } buf.WriteInt64(result); }
/// <inheritdoc /> public override void Write(decimal value, NpgsqlWriteBuffer buf, NpgsqlParameter?parameter) { var weight = 0; var groupCount = 0; Span <short> groups = stackalloc short[MaxGroupCount]; var raw = new DecimalRaw(value); if (raw.Low != 0 || raw.Mid != 0 || raw.High != 0) { var scale = raw.Scale; weight = -scale / MaxGroupScale - 1; uint remainder; var scaleChunk = scale % MaxGroupScale; if (scaleChunk > 0) { var divisor = DecimalRaw.Powers10[scaleChunk]; var multiplier = DecimalRaw.Powers10[MaxGroupScale - scaleChunk]; remainder = DecimalRaw.Divide(ref raw, divisor) * multiplier; if (remainder != 0) { weight--; goto WriteGroups; } } while ((remainder = DecimalRaw.Divide(ref raw, MaxGroupSize)) == 0) { weight++; } WriteGroups: groups[groupCount++] = (short)remainder; while (raw.Low != 0 || raw.Mid != 0 || raw.High != 0) { groups[groupCount++] = (short)DecimalRaw.Divide(ref raw, MaxGroupSize); } } buf.WriteInt16(groupCount); buf.WriteInt16(groupCount + weight); buf.WriteInt16(raw.Negative ? SignNegative : SignPositive); buf.WriteInt16(raw.Scale); while (groupCount > 0) { buf.WriteInt16(groups[--groupCount]); } }
/// <inheritdoc /> public override decimal Read(NpgsqlReadBuffer buf, int len, FieldDescription?fieldDescription = null) { var result = new DecimalRaw(); var groups = buf.ReadInt16(); var weight = buf.ReadInt16() - groups + 1; var sign = buf.ReadUInt16(); if (sign == SignNan) { throw new InvalidCastException("Numeric NaN not supported by System.Decimal"); } if (sign == SignNegative) { DecimalRaw.Negate(ref result); } var scale = buf.ReadInt16(); if (scale > MaxDecimalScale) { throw new OverflowException("Numeric value does not fit in a System.Decimal"); } result.Scale = scale; var scaleDifference = scale + weight * MaxGroupScale; 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); }