Skip to content

Commit

Permalink
Fixed incorrect saving of UInt128 if >Int128.Max #142
Browse files Browse the repository at this point in the history
  • Loading branch information
DarkWanderer committed Jul 4, 2022
1 parent c94153e commit 283d0d0
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 7 deletions.
6 changes: 5 additions & 1 deletion ClickHouse.Client.Tests/TestUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ public static IEnumerable<DataTypeSample> GetDataTypeSamples()
if (SupportedFeatures.HasFlag(Feature.WideTypes))
{
yield return new DataTypeSample("Int128", typeof(BigInteger), "toInt128(concat('-1', repeat('0', 30)))", -BigInteger.Pow(new BigInteger(10), 30));
yield return new DataTypeSample("UInt128", typeof(BigInteger), "toInt128(concat('1', repeat('0', 30)))", BigInteger.Pow(new BigInteger(10), 30));
yield return new DataTypeSample("Int128", typeof(BigInteger), "toInt128('170141183460469231731687303715884105727')", BigInteger.Parse("170141183460469231731687303715884105727"));
yield return new DataTypeSample("Int128", typeof(BigInteger), "toInt128('-170141183460469231731687303715884105728')", BigInteger.Parse("-170141183460469231731687303715884105728"));

yield return new DataTypeSample("UInt128", typeof(BigInteger), "toInt128(concat('1', repeat('0', 30)))", BigInteger.Pow(new BigInteger(10), 30));
yield return new DataTypeSample("UInt128", typeof(BigInteger), "toUInt128('340282366920938463463374607431768211455')", BigInteger.Parse("340282366920938463463374607431768211455"));

yield return new DataTypeSample("Int256", typeof(BigInteger), "toInt256(concat('-1', repeat('0', 50)))", -BigInteger.Pow(new BigInteger(10), 50));
yield return new DataTypeSample("UInt256", typeof(BigInteger), "toInt256(concat('1', repeat('0', 50)))", BigInteger.Pow(new BigInteger(10), 50));
Expand Down
25 changes: 21 additions & 4 deletions ClickHouse.Client/Types/AbstractBigIntegerType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@ internal abstract class AbstractBigIntegerType : IntegerType

public override Type FrameworkType => typeof(BigInteger);

public override object Read(ExtendedBinaryReader reader) => new BigInteger(reader.ReadBytes(Size));
public override object Read(ExtendedBinaryReader reader)
{
if (Signed)
return new BigInteger(reader.ReadBytes(Size));

var data = new byte[Size + 1];
for (int i = 0; i < Size; i++)
data[i] = reader.ReadByte();
data[Size] = 0;
return new BigInteger(data);
}

public abstract override string ToString();

Expand All @@ -30,13 +40,20 @@ public override void Write(ExtendedBinaryWriter writer, object value)
_ => new BigInteger(Convert.ToInt64(value, CultureInfo.InvariantCulture))
};

if (bigInt < 0 && !Signed)
throw new ArgumentException("Cannot convert negative BigInteger to UInt");

byte[] bigIntBytes = bigInt.ToByteArray();
byte[] decimalBytes = new byte[Size];

if (bigIntBytes.Length > Size)
throw new OverflowException();
var lengthToCopy = bigIntBytes.Length;
if (!Signed && bigIntBytes[bigIntBytes.Length - 1] == 0)
lengthToCopy = bigIntBytes.Length - 1;

if (lengthToCopy > Size)
throw new OverflowException($"Got {lengthToCopy} bytes, {Size} expected");

bigIntBytes.CopyTo(decimalBytes, 0);
Array.Copy(bigIntBytes, decimalBytes, lengthToCopy);

// If a negative BigInteger is not long enough to fill the whole buffer,
// the remainder needs to be filled with 0xFF
Expand Down
1 change: 1 addition & 0 deletions ClickHouse.Client/Types/IntegerType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
{
internal abstract class IntegerType : ClickHouseType
{
public virtual bool Signed => true;
}
}
7 changes: 6 additions & 1 deletion ClickHouse.Client/Types/UInt128Type.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
namespace ClickHouse.Client.Types
using System.Numerics;
using ClickHouse.Client.Formats;

namespace ClickHouse.Client.Types
{
internal class UInt128Type : AbstractBigIntegerType
{
public override int Size => 16;

public override string ToString() => "UInt128";

public override bool Signed => false;
}
}
7 changes: 6 additions & 1 deletion ClickHouse.Client/Types/UInt256Type.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
namespace ClickHouse.Client.Types
using System.Numerics;
using ClickHouse.Client.Formats;

namespace ClickHouse.Client.Types
{
internal class UInt256Type : AbstractBigIntegerType
{
public override int Size => 32;

public override string ToString() => "UInt256";

public override bool Signed => false;
}
}

0 comments on commit 283d0d0

Please sign in to comment.