feat(etl): add binary method overrides to DataTransformerBase

Add virtual methods to DataTransformerBase for GetBytes, GetChars,
GetData, and GetDataTypeName that properly handle computed columns
by throwing NotSupportedException when MapOrdinal returns -1.

Update TransformingDataReader to delegate these methods to the
transformer instead of directly to the source reader.
This commit is contained in:
Joseph Doherty
2026-01-03 10:33:13 -05:00
parent f5468d019f
commit 506ba5c61d
3 changed files with 213 additions and 5 deletions
@@ -71,4 +71,58 @@ public abstract class DataTransformerBase : IDataTransformer
/// <param name="source">The source data reader.</param>
/// <returns>The corresponding source ordinal, or -1 for computed columns.</returns>
public virtual int MapOrdinal(int transformedOrdinal, IDataReader source) => transformedOrdinal;
/// <summary>
/// Gets bytes from a field at the specified ordinal.
/// Throws NotSupportedException for computed columns (where MapOrdinal returns -1).
/// </summary>
public virtual long GetBytes(int ordinal, long fieldOffset, byte[]? buffer,
int bufferOffset, int length, IDataReader source)
{
var sourceOrdinal = MapOrdinal(ordinal, source);
if (sourceOrdinal < 0)
throw new NotSupportedException(
$"GetBytes not supported for computed column at ordinal {ordinal}.");
return source.GetBytes(sourceOrdinal, fieldOffset, buffer, bufferOffset, length);
}
/// <summary>
/// Gets characters from a field at the specified ordinal.
/// Throws NotSupportedException for computed columns (where MapOrdinal returns -1).
/// </summary>
public virtual long GetChars(int ordinal, long fieldOffset, char[]? buffer,
int bufferOffset, int length, IDataReader source)
{
var sourceOrdinal = MapOrdinal(ordinal, source);
if (sourceOrdinal < 0)
throw new NotSupportedException(
$"GetChars not supported for computed column at ordinal {ordinal}.");
return source.GetChars(sourceOrdinal, fieldOffset, buffer, bufferOffset, length);
}
/// <summary>
/// Gets nested data reader for a field at the specified ordinal.
/// Throws NotSupportedException for computed columns (where MapOrdinal returns -1).
/// </summary>
public virtual IDataReader GetData(int ordinal, IDataReader source)
{
var sourceOrdinal = MapOrdinal(ordinal, source);
if (sourceOrdinal < 0)
throw new NotSupportedException(
$"GetData not supported for computed column at ordinal {ordinal}.");
return source.GetData(sourceOrdinal);
}
/// <summary>
/// Gets the data type name for a field at the specified ordinal.
/// Throws NotSupportedException for computed columns (where MapOrdinal returns -1).
/// </summary>
public virtual string GetDataTypeName(int ordinal, IDataReader source)
{
var sourceOrdinal = MapOrdinal(ordinal, source);
if (sourceOrdinal < 0)
throw new NotSupportedException(
$"GetDataTypeName not supported for computed column at ordinal {ordinal}.");
return source.GetDataTypeName(sourceOrdinal);
}
}
@@ -50,8 +50,8 @@ internal sealed class TransformingDataReader : IDataReader
public long GetInt64(int i) => (long)GetValue(i);
public string GetString(int i) => (string)GetValue(i);
// Schema and bulk data access - delegated to source
public string GetDataTypeName(int i) => _source.GetDataTypeName(i);
// Schema and bulk data access - delegated to transformer
public string GetDataTypeName(int i) => _transformer.GetDataTypeName(i, _source);
public int GetValues(object[] values)
{
@@ -62,12 +62,12 @@ internal sealed class TransformingDataReader : IDataReader
}
public long GetBytes(int i, long fieldOffset, byte[]? buffer, int bufferoffset, int length)
=> _source.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
=> _transformer.GetBytes(i, fieldOffset, buffer, bufferoffset, length, _source);
public long GetChars(int i, long fieldoffset, char[]? buffer, int bufferoffset, int length)
=> _source.GetChars(i, fieldoffset, buffer, bufferoffset, length);
=> _transformer.GetChars(i, fieldoffset, buffer, bufferoffset, length, _source);
public IDataReader GetData(int i) => _source.GetData(i);
public IDataReader GetData(int i) => _transformer.GetData(i, _source);
public DataTable? GetSchemaTable() => _source.GetSchemaTable();
}