You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ee...@apache.org on 2022/07/28 22:00:40 UTC

[arrow] branch master updated: ARROW-17223: [C#] DecimalArray incorrectly appends values greater than Decimal.MaxValue / 2 and less than Decimal.MinValue / 2 (#13732)

This is an automated email from the ASF dual-hosted git repository.

eerhardt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new f645ffa2a0 ARROW-17223: [C#] DecimalArray incorrectly appends values greater than Decimal.MaxValue / 2 and less than Decimal.MinValue / 2 (#13732)
f645ffa2a0 is described below

commit f645ffa2a089805ed6a4d2d64fd50ef40d7ddbc7
Author: Aleksei Smirnov <tl...@inbox.ru>
AuthorDate: Fri Jul 29 01:00:31 2022 +0300

    ARROW-17223: [C#] DecimalArray incorrectly appends values greater than Decimal.MaxValue / 2 and less than Decimal.MinValue / 2 (#13732)
    
    Authored-by: asmirnov82 <tl...@inbox.ru>
    Signed-off-by: Eric Erhardt <er...@microsoft.com>
---
 csharp/src/Apache.Arrow/DecimalUtility.cs          | 42 +++++++++++-----------
 .../Apache.Arrow.Tests/Decimal128ArrayTests.cs     | 20 +++++++++++
 .../Apache.Arrow.Tests/Decimal256ArrayTests.cs     | 20 +++++++++++
 3 files changed, 61 insertions(+), 21 deletions(-)

diff --git a/csharp/src/Apache.Arrow/DecimalUtility.cs b/csharp/src/Apache.Arrow/DecimalUtility.cs
index b7ee6b9a87..c117c26361 100644
--- a/csharp/src/Apache.Arrow/DecimalUtility.cs
+++ b/csharp/src/Apache.Arrow/DecimalUtility.cs
@@ -83,33 +83,33 @@ namespace Apache.Arrow
             int[] decimalBits = decimal.GetBits(value);
             int decScale = (decimalBits[3] >> 16) & 0x7F;
 #if NETCOREAPP
-            Span<byte> bigIntBytes = stackalloc byte[12];
+            Span<byte> bigIntBytes = stackalloc byte[13];
 
-                for (int i = 0; i < 3; i++)
+            Span<byte> intBytes = stackalloc byte[4];
+            for (int i = 0; i < 3; i++)
+            {
+                int bit = decimalBits[i];
+                if (!BitConverter.TryWriteBytes(intBytes, bit))
+                    throw new OverflowException($"Could not extract bytes from int {bit}");
+
+                for (int j = 0; j < 4; j++)
                 {
-                    int bit = decimalBits[i];
-                    Span<byte> intBytes = stackalloc byte[4];
-                    if (!BitConverter.TryWriteBytes(intBytes, bit))
-                        throw new OverflowException($"Could not extract bytes from int {bit}");
-
-                    for (int j = 0; j < 4; j++)
-                    {
-                        bigIntBytes[4 * i + j] = intBytes[j];
-                    }
+                    bigIntBytes[4 * i + j] = intBytes[j];
                 }
-                bigInt = new BigInteger(bigIntBytes);
+            }
+            bigInt = new BigInteger(bigIntBytes);
 #else
-            byte[] bigIntBytes = new byte[12];
-                for (int i = 0; i < 3; i++)
+            byte[] bigIntBytes = new byte[13];
+            for (int i = 0; i < 3; i++)
+            {
+                int bit = decimalBits[i];
+                byte[] intBytes = BitConverter.GetBytes(bit);
+                for (int j = 0; j < intBytes.Length; j++)
                 {
-                    int bit = decimalBits[i];
-                    byte[] intBytes = BitConverter.GetBytes(bit);
-                    for (int j = 0; j < intBytes.Length; j++)
-                    {
-                        bigIntBytes[4 * i + j] = intBytes[j];
-                    }
+                    bigIntBytes[4 * i + j] = intBytes[j];
                 }
-                bigInt = new BigInteger(bigIntBytes);
+            }
+            bigInt = new BigInteger(bigIntBytes);
 #endif
 
             if (value < 0)
diff --git a/csharp/test/Apache.Arrow.Tests/Decimal128ArrayTests.cs b/csharp/test/Apache.Arrow.Tests/Decimal128ArrayTests.cs
index 68f8ee02b1..4c4e653726 100644
--- a/csharp/test/Apache.Arrow.Tests/Decimal128ArrayTests.cs
+++ b/csharp/test/Apache.Arrow.Tests/Decimal128ArrayTests.cs
@@ -97,6 +97,26 @@ namespace Apache.Arrow.Tests
                     Assert.Equal(-large, array.GetValue(1));
                 }
 
+                [Fact]
+                public void AppendMaxAndMinDecimal()
+                {
+                    // Arrange
+                    var builder = new Decimal128Array.Builder(new Decimal128Type(29, 0));
+
+                    // Act
+                    builder.Append(Decimal.MaxValue);
+                    builder.Append(Decimal.MinValue);
+                    builder.Append(Decimal.MaxValue - 10);
+                    builder.Append(Decimal.MinValue + 10);
+
+                    // Assert
+                    var array = builder.Build();
+                    Assert.Equal(Decimal.MaxValue, array.GetValue(0));
+                    Assert.Equal(Decimal.MinValue, array.GetValue(1));
+                    Assert.Equal(Decimal.MaxValue - 10, array.GetValue(2));
+                    Assert.Equal(Decimal.MinValue + 10, array.GetValue(3));
+                }
+
                 [Fact]
                 public void AppendFractionalDecimal()
                 {
diff --git a/csharp/test/Apache.Arrow.Tests/Decimal256ArrayTests.cs b/csharp/test/Apache.Arrow.Tests/Decimal256ArrayTests.cs
index 35b68823d9..e63c39d24e 100644
--- a/csharp/test/Apache.Arrow.Tests/Decimal256ArrayTests.cs
+++ b/csharp/test/Apache.Arrow.Tests/Decimal256ArrayTests.cs
@@ -97,6 +97,26 @@ namespace Apache.Arrow.Tests
                     Assert.Equal(-large, array.GetValue(1));
                 }
 
+                [Fact]
+                public void AppendMaxAndMinDecimal()
+                {
+                    // Arrange
+                    var builder = new Decimal256Array.Builder(new Decimal256Type(29, 0));
+
+                    // Act
+                    builder.Append(Decimal.MaxValue);
+                    builder.Append(Decimal.MinValue);
+                    builder.Append(Decimal.MaxValue - 10);
+                    builder.Append(Decimal.MinValue + 10);
+
+                    // Assert
+                    var array = builder.Build();
+                    Assert.Equal(Decimal.MaxValue, array.GetValue(0));
+                    Assert.Equal(Decimal.MinValue, array.GetValue(1));
+                    Assert.Equal(Decimal.MaxValue - 10, array.GetValue(2));
+                    Assert.Equal(Decimal.MinValue + 10, array.GetValue(3));
+                }
+
                 [Fact]
                 public void AppendFractionalDecimal()
                 {