diff --git a/csharp.test/TestLogicalTypeRoundtrip.cs b/csharp.test/TestLogicalTypeRoundtrip.cs
index 2daebe0b..173da0fc 100644
--- a/csharp.test/TestLogicalTypeRoundtrip.cs
+++ b/csharp.test/TestLogicalTypeRoundtrip.cs
@@ -285,6 +285,54 @@ public static void TestNestedStructArray([Values(Repetition.Required, Repetition
fileReader.Close();
}
+ ///
+ /// This checks that LogicalColumnReader's GetEnumerator() works correctly
+ /// when the column is longer than the buffer length but not an exact multiple
+ /// (see https://github.com/G-Research/ParquetSharp/issues/242).
+ ///
+ [Test]
+ public static void TestLargeArraysEnumerator()
+ {
+ CheckEnumerator(4096, Enumerable.Range(0, 4100).ToArray());
+ CheckEnumerator(4096, Enumerable.Range(0, 4100).Select(i => new[] {$"row {i}"}).ToArray());
+ }
+
+ private static void CheckEnumerator(int bufferLength, T[] values)
+ {
+ using var buffer = new ResizableBuffer();
+
+ using (var output = new BufferOutputStream(buffer))
+ {
+ var columns = new Column[] {new Column("col0")};
+
+ using var fileWriter = new ParquetFileWriter(output, columns);
+ using var rowGroupWriter = fileWriter.AppendBufferedRowGroup();
+
+ using var col = rowGroupWriter.Column(0).LogicalWriter(bufferLength);
+ col.WriteBatch(values);
+
+ fileWriter.Close();
+ }
+
+ using (var input = new BufferReader(buffer))
+ {
+ using var fileReader = new ParquetFileReader(input);
+ using var rowGroupReader = fileReader.RowGroup(0);
+
+ using var col = rowGroupReader.Column(0).LogicalReader(bufferLength);
+
+ var enumerator = col.GetEnumerator();
+ for (var i = 0; i < values.Length; i++)
+ {
+ Assert.IsTrue(enumerator.MoveNext());
+ Assert.AreEqual(values[i], enumerator.Current);
+ }
+ Assert.IsFalse(enumerator.MoveNext());
+
+ fileReader.Close();
+ }
+ }
+
[Test]
public static void TestBigArrayRoundtrip()
{
diff --git a/csharp/LogicalColumnReader.cs b/csharp/LogicalColumnReader.cs
index 906939ea..b7d38d02 100644
--- a/csharp/LogicalColumnReader.cs
+++ b/csharp/LogicalColumnReader.cs
@@ -44,7 +44,7 @@ internal static LogicalColumnReader Create(ColumnReader colu
}
}
- public bool HasNext => Source.HasNext;
+ public abstract bool HasNext { get; }
public abstract TReturn Apply(ILogicalColumnReaderVisitor visitor);
@@ -153,6 +153,8 @@ private static (short definitionLevelDelta, int schemaSlice) StructSkip(ReadOnly
return (definitionLevel, schemaSlice);
}
+ public override bool HasNext => !_bufferedReader.IsEofDefinition;
+
public override int ReadBatch(Span destination)
{
short definitionLevel = 0;