in src/TriggerBinding/SqlTriggerUtils.cs [30:85]
public static IReadOnlyList<(string name, string type)> GetPrimaryKeyColumnsAsync(SqlConnection connection, int userTableId, ILogger logger, string userTableName, CancellationToken cancellationToken)
{
const int NameIndex = 0, TypeIndex = 1, LengthIndex = 2, PrecisionIndex = 3, ScaleIndex = 4;
string getPrimaryKeyColumnsQuery = $@"
SELECT
c.name,
t.name,
c.max_length,
c.precision,
c.scale
FROM sys.indexes AS i
INNER JOIN sys.index_columns AS ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
INNER JOIN sys.columns AS c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
INNER JOIN sys.types AS t ON c.user_type_id = t.user_type_id
WHERE i.is_primary_key = 1 AND i.object_id = {userTableId};
";
using (var getPrimaryKeyColumnsCommand = new SqlCommand(getPrimaryKeyColumnsQuery, connection))
using (SqlDataReader reader = getPrimaryKeyColumnsCommand.ExecuteReaderWithLogging(logger))
{
string[] variableLengthTypes = new[] { "varchar", "nvarchar", "nchar", "char", "binary", "varbinary" };
string[] variablePrecisionTypes = new[] { "numeric", "decimal" };
var primaryKeyColumns = new List<(string name, string type)>();
while (reader.Read())
{
cancellationToken.ThrowIfCancellationRequested();
string name = reader.GetString(NameIndex);
string type = reader.GetString(TypeIndex);
if (variableLengthTypes.Contains(type, StringComparer.OrdinalIgnoreCase))
{
// Special "max" case. I'm actually not sure it's valid to have varchar(max) as a primary key because
// it exceeds the byte limit of an index field (900 bytes), but just in case
short length = reader.GetInt16(LengthIndex);
type += length == -1 ? "(max)" : $"({length})";
}
else if (variablePrecisionTypes.Contains(type))
{
byte precision = reader.GetByte(PrecisionIndex);
byte scale = reader.GetByte(ScaleIndex);
type += $"({precision},{scale})";
}
primaryKeyColumns.Add((name, type));
}
if (primaryKeyColumns.Count == 0)
{
throw new InvalidOperationException($"Could not find primary key created in table: '{userTableName}'.");
}
logger.LogDebug($"GetPrimaryKeyColumns ColumnNames(types) = {string.Join(", ", primaryKeyColumns.Select(col => $"'{col.name}({col.type})'"))}.");
return primaryKeyColumns;
}
}