diff --git a/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs b/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs index 1b83735925556..a7e4c13525236 100644 --- a/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs +++ b/csharp/src/Apache.Arrow/Ipc/ArrowStreamWriter.cs @@ -165,8 +165,13 @@ public void Visit(ListArray array) _buffers.Add(CreateBitmapBuffer(array.NullBitmapBuffer, array.Offset, array.Length)); _buffers.Add(CreateBuffer(GetZeroBasedValueOffsets(array.ValueOffsetsBuffer, array.Offset, array.Length))); - int valuesOffset = array.ValueOffsets[0]; - int valuesLength = array.ValueOffsets[array.Length] - valuesOffset; + int valuesOffset = 0; + int valuesLength = 0; + if (array.Length > 0) + { + valuesOffset = array.ValueOffsets[0]; + valuesLength = array.ValueOffsets[array.Length] - valuesOffset; + } var values = array.Values; if (valuesOffset > 0 || valuesLength < values.Length) @@ -206,8 +211,13 @@ public void Visit(BinaryArray array) _buffers.Add(CreateBitmapBuffer(array.NullBitmapBuffer, array.Offset, array.Length)); _buffers.Add(CreateBuffer(GetZeroBasedValueOffsets(array.ValueOffsetsBuffer, array.Offset, array.Length))); - int valuesOffset = array.ValueOffsets[0]; - int valuesLength = array.ValueOffsets[array.Length] - valuesOffset; + int valuesOffset = 0; + int valuesLength = 0; + if (array.Length > 0) + { + valuesOffset = array.ValueOffsets[0]; + valuesLength = array.ValueOffsets[array.Length] - valuesOffset; + } _buffers.Add(CreateSlicedBuffer(array.ValueBuffer, valuesOffset, valuesLength)); } diff --git a/csharp/test/Apache.Arrow.Tests/ArrowFileWriterTests.cs b/csharp/test/Apache.Arrow.Tests/ArrowFileWriterTests.cs index baea4d61e5b66..297cb5e181cd3 100644 --- a/csharp/test/Apache.Arrow.Tests/ArrowFileWriterTests.cs +++ b/csharp/test/Apache.Arrow.Tests/ArrowFileWriterTests.cs @@ -193,5 +193,57 @@ public async Task WritesEmptyFileAsync() Assert.Null(readBatch); SchemaComparer.Compare(originalBatch.Schema, reader.Schema); } + + [Fact] + public async Task WriteBinaryArrayWithEmptyOffsets() + { + // Empty binary arrays generated by the C# builder have a single offset, + // but some implementations may produce an empty offsets buffer. + + var array = new BinaryArray( + new BinaryType(), + length: 0, + valueOffsetsBuffer: ArrowBuffer.Empty, + dataBuffer: ArrowBuffer.Empty, + nullBitmapBuffer: ArrowBuffer.Empty, + nullCount: 0); + + var recordBatch = new RecordBatch.Builder().Append("x", true, array).Build(); + + var stream = new MemoryStream(); + var writer = new ArrowFileWriter(stream, recordBatch.Schema, leaveOpen: true); + + await writer.WriteRecordBatchAsync(recordBatch); + await writer.WriteEndAsync(); + + stream.Position = 0; + + await ValidateRecordBatchFile(stream, recordBatch, strictCompare: false); + } + + [Fact] + public async Task WriteListArrayWithEmptyOffsets() + { + var values = new Int32Array.Builder().Build(); + var array = new ListArray( + new ListType(new Int32Type()), + length: 0, + valueOffsetsBuffer: ArrowBuffer.Empty, + values: values, + nullBitmapBuffer: ArrowBuffer.Empty, + nullCount: 0); + + var recordBatch = new RecordBatch.Builder().Append("x", true, array).Build(); + + var stream = new MemoryStream(); + var writer = new ArrowFileWriter(stream, recordBatch.Schema, leaveOpen: true); + + await writer.WriteRecordBatchAsync(recordBatch); + await writer.WriteEndAsync(); + + stream.Position = 0; + + await ValidateRecordBatchFile(stream, recordBatch, strictCompare: false); + } } }