From 32608dd4e1bc2559a600b8bdbdd0b40bea7da277 Mon Sep 17 00:00:00 2001 From: "Dailey, Alaric" Date: Thu, 29 Oct 2026 01:54:20 -0500 Subject: [PATCH 1/2] Honor IDataRecord.GetOrdinal name lookup --- .../SpannerDataReaderTests.cs | 51 +++++++++++++++++++ .../SpannerDataReader.cs | 22 +++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/SpannerDataReaderTests.cs b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/SpannerDataReaderTests.cs index 271e82186dd5..569ae9b4723a 100644 --- a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/SpannerDataReaderTests.cs +++ b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/SpannerDataReaderTests.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Xunit; using TypeCode = Google.Cloud.Spanner.V1.TypeCode; @@ -130,6 +131,39 @@ public void GetBytes_WrongType() Assert.Throws(() => reader.GetBytes(0, 0L, null, 0, 0)); } + [Fact] + public async Task GetOrdinal_CaseInsensitiveFallback() + { + var reader = CreateSpannerDataReader( + new[] { CreateResultSet(new[] { Value.ForString("value") }) }, + CreateMetadata("id")); + + Assert.Equal(0, reader.GetOrdinal("Id")); + Assert.Equal(0, await reader.GetOrdinalAsync("ID")); + } + + [Fact] + public void GetOrdinal_ExactCaseMatchPrecedesFallback() + { + var reader = CreateSpannerDataReader( + new[] { CreateResultSet(new[] { Value.ForString("lower"), Value.ForString("upper") }) }, + CreateMetadata("id", "ID")); + + Assert.Equal(1, reader.GetOrdinal("ID")); + Assert.Equal(0, reader.GetOrdinal("Id")); + } + + [Fact] + public async Task GetOrdinal_UnknownColumnThrowsIndexOutOfRangeException() + { + var reader = CreateSpannerDataReader( + new[] { CreateResultSet(new[] { Value.ForString("value") }) }, + CreateMetadata("id")); + + Assert.Throws(() => reader.GetOrdinal("missing")); + await Assert.ThrowsAsync(() => reader.GetOrdinalAsync("missing")); + } + private static SpannerDataReader CreateTestReader(byte[] bytes) { var results = new [] @@ -175,5 +209,22 @@ private static ResultSetMetadata CreateSingleFieldMetadata(TypeCode typeCode) => } } }; + + private static ResultSetMetadata CreateMetadata(params string[] fieldNames) => + new ResultSetMetadata + { + RowType = new StructType + { + Fields = + { + fieldNames.Select(name => new StructType.Types.Field + { + Name = name, + Type = new V1.Type { Code = TypeCode.String } + }) + } + } + }; + } } diff --git a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs index c117d6f868fe..e0770fc44371 100644 --- a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs +++ b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs @@ -285,7 +285,7 @@ public override int GetOrdinal(string name) PopulateMetadata(); InitializeFieldIndexFromMetadata(); } - return _fieldIndex[name]; + return GetOrdinalFromFieldIndex(name); } /// @@ -303,7 +303,25 @@ public async Task GetOrdinalAsync(string name, CancellationToken cancellati await PopulateMetadataAsync(cancellationToken).ConfigureAwait(false); InitializeFieldIndexFromMetadata(); } - return _fieldIndex[name]; + return GetOrdinalFromFieldIndex(name); + } + + private int GetOrdinalFromFieldIndex(string name) + { + if (_fieldIndex.TryGetValue(name, out int ordinal)) + { + return ordinal; + } + + foreach (var field in _metadata.RowType.Fields) + { + if (string.Equals(field.Name, name, StringComparison.OrdinalIgnoreCase)) + { + return _fieldIndex[field.Name]; + } + } + + throw new IndexOutOfRangeException($"Column '{name}' was not found."); } /// From 5e2fb193adc88df1e2aebdfc1dd8d22a24c62cf8 Mon Sep 17 00:00:00 2001 From: "Dailey, Alaric" Date: Thu, 29 Oct 2026 02:01:23 -0500 Subject: [PATCH 2/2] fix(spanner): honor IDataRecord.GetOrdinal lookup rules --- .../Google.Cloud.Spanner.Data/SpannerDataReader.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs index e0770fc44371..199cbd55a866 100644 --- a/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs +++ b/apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerDataReader.cs @@ -313,11 +313,12 @@ private int GetOrdinalFromFieldIndex(string name) return ordinal; } - foreach (var field in _metadata.RowType.Fields) + var fields = _metadata.RowType.Fields; + for (int i = 0; i < fields.Count; i++) { - if (string.Equals(field.Name, name, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(fields[i].Name, name, StringComparison.OrdinalIgnoreCase)) { - return _fieldIndex[field.Name]; + return i; } }