Repository navigation
Implement GetBytes and GetChars - #377
Conversation
GetBytes threw NotImplementedException and GetChars NotSupportedException. IDataRecord.GetBytes and GetChars read part of a value into a buffer, and "If you pass a buffer that is null" return the value's length. GetBytes reads the blob through GetStream; GetChars reads the string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Coverage Report for CI Build 39428820408Warning Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes. Coverage at 92.527% (no base build to compare)Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats💛 - Coveralls |
|
Thanks for this. I compared it with Npgsql 10.0.0 on PostgreSQL 18.3, and whole reads, partial reads, reads at and past the end, the null-buffer length, NULL values and surrogate pairs all give the same results. One request before merging: could The UTF-8 bytes are already available without a string:
Two edge cases to keep the results the same as now:
Optionally, the reader could remember the last (row, column, char offset → byte offset) position, so that reading a value chunk by chunk doesn't scan from the start on every call. The vector readers are performance-sensitive: please read |
|
The chunked UTF-8 GetBytes/GetChars changes are implemented and verified. Build and CodeQL are passing, with no unresolved review requests from my side. Ready for review. |
DuckDBDataReader.GetBytesthrowsNotImplementedException, andGetCharsthrowsNotSupportedException. Both are abstract members ofDbDataReaderthat are meant to read part of a value into a caller's buffer.The contract
IDataRecord.GetBytes: "Reads a stream of bytes from the specified column offset into the buffer as an array, starting at the given buffer offset." Returns "The actual number of bytes read." Remarks:
IDataRecord.GetChars: "Reads a stream of characters from the specified column offset into the buffer as an array, starting at the given buffer offset." Remarks:
Why it matters
These are the standard ways to read large values in chunks, or to ask for a value's length without materialising it, and data layers written against
DbDataReadercall them. SqlClient, Npgsql, MySqlConnector and Microsoft.Data.Sqlite all implement them.Change
GetBytesreads through the existingGetStream(ordinal), which is anUnmanagedMemoryStreamover the blob, so nothing is copied beyond what the caller asks for. A null buffer returns the blob's length. Otherwise it copiesmin(length, remaining)bytes starting atdataOffsetand returns the count, or 0 past the end.GetCharsdoes the same overGetString(ordinal), in UTF-16 characters ('ab¢d'has length 4).dataOffset, abufferOffsetoutside the buffer, or alengththat doesn't fit afterbufferOffsetthrowsArgumentOutOfRangeException.GetByteson a non-blob column throws the sameInvalidCastExceptionthatGetStreamdoes.Tests:
GetBytesReadsABlobWholeOrInParts,GetCharsReadsAStringWholeOrInParts(with a multi-byte UTF-8 character),GetBytesAndGetCharsRejectOffsetsOutsideTheBuffer. The full suite passes.Conformance tests:
GetBytes_works,GetBytes_returns_length_when_buffer_is_null,GetBytes_reads_part_of_blob,GetChars_works,GetChars_returns_length_when_buffer_is_null,GetChars_reads_part_of_string.Found by the pengdows ADO.NET conformance suite, which runs the documented
System.Data.Commoncontract against every provider; each failure it reports cites the learn.microsoft.com sentence the provider departs from.🤖 Generated with Claude Code