Skip to content

Strange logic in System.Data.ProviderBase.DbMetaDataFactory.FindMetaDataCollectionRow() #39620

@yyjdelete

Description

@yyjdelete

Description

internal DataRow FindMetaDataCollectionRow(string collectionName)
{
bool versionFailure;
bool haveExactMatch;
bool haveMultipleInexactMatches;
string candidateCollectionName;
DataTable metaDataCollectionsTable = _metaDataCollectionsDataSet.Tables[DbMetaDataCollectionNames.MetaDataCollections];
if (metaDataCollectionsTable == null)
{
throw ADP.InvalidXml();
}
DataColumn collectionNameColumn = metaDataCollectionsTable.Columns[DbMetaDataColumnNames.CollectionName];
if ((null == collectionNameColumn) || (typeof(string) != collectionNameColumn.DataType))
{
throw ADP.InvalidXmlMissingColumn(DbMetaDataCollectionNames.MetaDataCollections, DbMetaDataColumnNames.CollectionName);
}
DataRow requestedCollectionRow = null;
string exactCollectionName = null;
// find the requested collection
versionFailure = false;
haveExactMatch = false;
haveMultipleInexactMatches = false;
foreach (DataRow row in metaDataCollectionsTable.Rows)
{
candidateCollectionName = row[collectionNameColumn, DataRowVersion.Current] as string;
if (string.IsNullOrEmpty(candidateCollectionName))
{
throw ADP.InvalidXmlInvalidValue(DbMetaDataCollectionNames.MetaDataCollections, DbMetaDataColumnNames.CollectionName);
}
if (ADP.CompareInsensitiveInvariant(candidateCollectionName, collectionName))
{
if (SupportedByCurrentVersion(row) == false)
{
versionFailure = true;
}
else
{
if (collectionName == candidateCollectionName)
{
if (haveExactMatch == true)
{
throw ADP.CollectionNameIsNotUnique(collectionName);
}
requestedCollectionRow = row;
exactCollectionName = candidateCollectionName;
haveExactMatch = true;
}
else
{
// have an inexact match - ok only if it is the only one
if (exactCollectionName != null)
{
// can't fail here becasue we may still find an exact match
haveMultipleInexactMatches = true;
}
requestedCollectionRow = row;
exactCollectionName = candidateCollectionName;
}
}
}
}
if (requestedCollectionRow == null)
{
if (versionFailure == false)
{
throw ADP.UndefinedCollection(collectionName);
}
else
{
throw ADP.UnsupportedVersion(collectionName);
}
}
if ((haveExactMatch == false) && (haveMultipleInexactMatches == true))
{
throw ADP.AmbigousCollectionName(collectionName);
}
return requestedCollectionRow;
}

Seems the code here want to do an case-sensitive match first, and fallback to an case-insensitive match, and throw if get more than one matches(in case-sensitive or case-insensitive).
But if it first hit an case-sensitive match, and then some case-insensitive match, var requestedCollectionRow will be overwrite by the last case-insensitive match, but won't throw AmbigousCollectionName since haveExactMatch is true, and finally return the case-insensitive result instead of the extra match one.


Is it the expected logic? Maybe it should be else if (!haveExactMatch) here instead?

Regression?

No. And didn't hit any problem with this, just found this when do some research for the behavior of DbConnection.GetScmema().

Other information

Note: There is also some copy of this file in OleDb and MD.SqlClient, which have the same problem.
https://github.com/dotnet/runtime/search?q=FindMetaDataCollectionRow&unscoped_q=FindMetaDataCollectionRow
https://github.com/dotnet/sqlclient/search?q=FindMetaDataCollectionRow&unscoped_q=FindMetaDataCollectionRow

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions