in csharp/src/Drivers/Apache/Hive2/DecimalUtility.cs [127:191]
private static void ProcessDecimal(ReadOnlySpan<byte> value, int precision, int scale, ParserState state, out byte sign, out ReadOnlySpan<byte> integerSpan, out ReadOnlySpan<byte> fractionalSpan, out int neededScale)
{
int int_length = 0;
int frac_length = 0;
int exponent = 0;
if (state.IntegerStart != -1 && state.IntegerEnd != -1) int_length = state.IntegerEnd - state.IntegerStart + 1;
if (state.FractionalStart != -1 && state.FractionalEnd != -1) frac_length = state.FractionalEnd - state.FractionalStart + 1;
if (state.ExponentIndex != -1 && state.ExponentStart != -1 && state.ExponentEnd != -1 && state.ExponentEnd >= state.ExponentStart)
{
int expStart = state.ExpSignIndex != -1 ? state.ExpSignIndex : state.ExponentStart;
int expLength = state.ExponentEnd - expStart + 1;
ReadOnlySpan<byte> exponentSpan = value.Slice(expStart, expLength);
if (!Utf8Parser.TryParse(exponentSpan, out exponent, out int _))
{
throw new FormatException($"unable to parse exponent value '{Encoding.UTF8.GetString(exponentSpan)}'");
}
}
integerSpan = int_length > 0 ? value.Slice(state.IntegerStart, state.IntegerEnd - state.IntegerStart + 1) : [];
fractionalSpan = frac_length > 0 ? value.Slice(state.FractionalStart, state.FractionalEnd - state.FractionalStart + 1) : [];
Span<byte> tempSignificant;
if (exponent != 0)
{
tempSignificant = new byte[int_length + frac_length];
if (int_length > 0) value.Slice(state.IntegerStart, state.IntegerEnd - state.IntegerStart + 1).CopyTo(tempSignificant.Slice(0));
if (frac_length > 0) value.Slice(state.FractionalStart, state.FractionalEnd - state.FractionalStart + 1).CopyTo(tempSignificant.Slice(int_length));
// Trim trailing zeros from combined string
while (tempSignificant[tempSignificant.Length - 1] == AsciiZero)
{
tempSignificant = tempSignificant.Slice(0, tempSignificant.Length - 1);
}
// Recalculate integer and fractional length
if (exponent > 0)
{
int_length = Math.Min(int_length + exponent, tempSignificant.Length);
frac_length = Math.Max(Math.Min(frac_length - exponent, tempSignificant.Length - int_length), 0);
}
else
{
int_length = Math.Max(int_length + exponent, 0);
frac_length = Math.Max(Math.Min(frac_length - exponent, tempSignificant.Length - int_length), 0);
}
// Reset the integer and fractional span
fractionalSpan = tempSignificant.Slice(int_length, frac_length);
integerSpan = tempSignificant.Slice(0, int_length);
// Trim leading zeros fron new integer span
while (integerSpan.Length > 0 && integerSpan[0] == AsciiZero)
{
integerSpan = integerSpan.Slice(1);
int_length -= 1;
}
}
int neededPrecision = int_length + frac_length;
neededScale = frac_length;
if (neededPrecision > precision)
{
throw new OverflowException($"Decimal precision cannot be greater than that in the Arrow vector: {Encoding.UTF8.GetString(value)} has precision > {precision}");
}
if (neededScale > scale)
{
throw new OverflowException($"Decimal scale cannot be greater than that in the Arrow vector: {Encoding.UTF8.GetString(value)} has scale > {scale}");
}
sign = state.SignIndex != -1 ? value[state.SignIndex] : AsciiPlus;
}