Skip to content

fix(spanner): honor IDataRecord.GetOrdinal lookup rules - #16044

Open
alaricd wants to merge 2 commits into
googleapis:mainfrom
alaricd:codex/spanner-getordinal
Open

alaricd wants to merge 2 commits into
googleapis:mainfrom
alaricd:codex/spanner-getordinal

Conversation

@alaricd

@alaricd alaricd commented Oct 29, 2026

Copy link
Copy Markdown

Summary

Implement the documented IDataRecord.GetOrdinal lookup behavior in SpannerDataReader: exact-case match first, then case-insensitive fallback, and IndexOutOfRangeException when no field matches. Add sync and async regression coverage, including exact-match precedence.

Resolves #16041.

Microsoft contract

Microsoft documents the case-sensitive then case-insensitive lookup sequence and IndexOutOfRangeException for missing names: https://learn.microsoft.com/dotnet/api/system.data.idatarecord.getordinal

Compatibility

This allows case variants that currently fail to resolve and leaves exact matches unchanged. The only observable change is that callers relying on an exception for a valid case-insensitive match will now receive its ordinal; exact-case precedence preserves deterministic behavior for names that differ only by case.

Validation

dotnet test apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data.Tests/Google.Cloud.Spanner.Data.Tests.csproj -f net8.0 -p:NoWarn=CS8981%3BxUnit2004%3BxUnit2013 — 2,835 passed, 0 failed.

Discovery

Found using pengdows.AdoNetApiTest.conformance.

@alaricd
alaricd requested a review from a team as a code owner October 29, 2026 06:56
@google-cla

google-cla Bot commented Oct 29, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces case-insensitive fallback logic for retrieving column ordinals in SpannerDataReader, along with comprehensive unit tests. The review feedback recommends optimizing the fallback search to prevent potential KeyNotFoundException errors and redundant dictionary lookups, while also adding a null check for the column name.

@alaricd
alaricd force-pushed the codex/spanner-getordinal branch from 7d361f2 to 5e2fb19 Compare October 29, 2026 07:25
@alaricd alaricd changed the title Honor IDataRecord.GetOrdinal lookup rules fix(spanner): honor IDataRecord.GetOrdinal lookup rules Oct 29, 2026
@product-auto-label product-auto-label Bot added the api: spanner Issues related to the Spanner API. label Oct 29, 2026
@amanda-tarafa amanda-tarafa self-assigned this Oct 29, 2026
@amanda-tarafa
amanda-tarafa marked this pull request as draft October 29, 2026 16:29
@amanda-tarafa
amanda-tarafa self-requested a review October 29, 2026 16:29
@alaricd
alaricd marked this pull request as ready for review October 29, 2026 18:40
@alaricd

alaricd commented Oct 29, 2026

Copy link
Copy Markdown
Author

@amanda-tarafa Thanks. I agree compatibility matters, and I don’t expect every conformance finding to justify a behavior change. You’re right that a lot of ADO.NET is underspecified, so I’d like to separate my PRs along that line.

#16041 / #16044 (GetOrdinal) is documented at the interface level, not on SqlClient. The remarks on IDataRecord.GetOrdinal describe the lookup:

A case-sensitive match first.
A case-insensitive fallback.
IndexOutOfRangeException if neither matches.

This works purely against result-set metadata the reader already has, so it doesn’t depend on any Spanner capability.

Other mature providers have accepted fixes like this, including Microsoft’s own. I’ve sent the same kind of contract fixes, each citing the learn.microsoft.com sentence involved, to a number of providers:

Microsoft merged 7 across Microsoft.Data.Sqlite and Microsoft.Data.SqlClient. That includes a GetOrdinal fix that changed the exception type callers catch (dotnet/efcore#39353), which is a more breaking change than this PR.
DuckDB.NET merged 14, including the same GetOrdinal fallback (#375).
Ydb.Sdk merged the identical fallback (#763).
Oracle accepted the MySql.Data equivalents into its internal queue (Bug
#121583).

None has been declined on the grounds that the documented behavior isn’t the contract.

On compatibility risk for #16044:

Every exact-case lookup that succeeds today behaves the same after this change.
The only observable difference is that a wrong-cased name now resolves instead of throwing.
So the affected callers would be code that relies on getting an exception for a column that exists. That’s a narrower case than the ones the Microsoft.Data.Sqlite and SqlClient teams weighed and accepted.

I wrote the conformance suite specifically because the contract is clear, and so many providers do NOT implement it correctly. DuckDB.NET and npgsql are the 2 ado.net providers that are the closest, other than my own pengdows.flatfile.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: spanner Issues related to the Spanner API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SpannerDataReader.GetOrdinal should fall back to a case-insensitive match

2 participants