Skip to content

Commit 8704753

Browse files
authored
Merge pull request #52 from sabbadino-ca/add-fk-info
Add foreign key table information
2 parents a7f973e + bc8ec76 commit 8704753

File tree

2 files changed

+71
-4
lines changed

2 files changed

+71
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ AzureSQLPromptFlowSamples/src/sql-promptflow-demo/deployment/model.yaml
1919
AzureSQLPromptFlowSamples/src/sql-promptflow-demo/promptflow_v2/flow.dag.yaml
2020
AzureSQLPromptFlowSamples/src/sql-promptflow-demo/promptflow_v2/.promptflow/
2121
AzureSQLPromptFlowSamples/src/sql-promptflow-demo/promptflow_v2/__pycache__/
22+
.vs/

MssqlMcp/dotnet/MssqlMcp/Tools/DescribeTable.cs

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,31 @@ public partial class Tools
1919
public async Task<DbOperationResult> DescribeTable(
2020
[Description("Name of table")] string name)
2121
{
22+
string? schema = null;
23+
if (name.Contains('.'))
24+
{
25+
// If the table name contains a schema, split it into schema and table name
26+
var parts = name.Split('.');
27+
if (parts.Length > 1)
28+
{
29+
name = parts[1]; // Use only the table name part
30+
schema = parts[0]; // Use the first part as schema
31+
}
32+
}
2233
// Query for table metadata
2334
const string TableInfoQuery = @"SELECT t.object_id AS id, t.name, s.name AS [schema], p.value AS description, t.type, u.name AS owner
2435
FROM sys.tables t
2536
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
2637
LEFT JOIN sys.extended_properties p ON p.major_id = t.object_id AND p.minor_id = 0 AND p.name = 'MS_Description'
2738
LEFT JOIN sys.sysusers u ON t.principal_id = u.uid
28-
WHERE t.name = @TableName";
39+
WHERE t.name = @TableName and (s.name = @TableSchema or @TableSchema IS NULL) ";
2940

3041
// Query for columns
3142
const string ColumnsQuery = @"SELECT c.name, ty.name AS type, c.max_length AS length, c.precision, c.is_nullable AS nullable, p.value AS description
3243
FROM sys.columns c
3344
INNER JOIN sys.types ty ON c.user_type_id = ty.user_type_id
3445
LEFT JOIN sys.extended_properties p ON p.major_id = c.object_id AND p.minor_id = c.column_id AND p.name = 'MS_Description'
35-
WHERE c.object_id = (SELECT object_id FROM sys.tables WHERE name = @TableName)";
46+
WHERE c.object_id = (SELECT object_id FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.name = @TableName and (s.name = @TableSchema or @TableSchema IS NULL ) )";
3647

3748
// Query for indexes
3849
const string IndexesQuery = @"SELECT i.name, i.type_desc AS type, p.value AS description,
@@ -41,16 +52,43 @@ FROM sys.columns c
4152
WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id ORDER BY ic.key_ordinal FOR XML PATH('')), 1, 1, '') AS keys
4253
FROM sys.indexes i
4354
LEFT JOIN sys.extended_properties p ON p.major_id = i.object_id AND p.minor_id = i.index_id AND p.name = 'MS_Description'
44-
WHERE i.object_id = (SELECT object_id FROM sys.tables WHERE name = @TableName) AND i.is_primary_key = 0 AND i.is_unique_constraint = 0";
55+
WHERE i.object_id = ( SELECT object_id FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.name = @TableName and (s.name = @TableSchema or @TableSchema IS NULL ) ) AND i.is_primary_key = 0 AND i.is_unique_constraint = 0";
4556

4657
// Query for constraints
4758
const string ConstraintsQuery = @"SELECT kc.name, kc.type_desc AS type,
4859
STUFF((SELECT ',' + c.name FROM sys.index_columns ic
4960
INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
5061
WHERE ic.object_id = kc.parent_object_id AND ic.index_id = kc.unique_index_id ORDER BY ic.key_ordinal FOR XML PATH('')), 1, 1, '') AS keys
5162
FROM sys.key_constraints kc
52-
WHERE kc.parent_object_id = (SELECT object_id FROM sys.tables WHERE name = @TableName)";
63+
WHERE kc.parent_object_id = (SELECT object_id FROM sys.tables t INNER JOIN sys.schemas s ON t.schema_id = s.schema_id WHERE t.name = @TableName and (s.name = @TableSchema or @TableSchema IS NULL ) )";
64+
5365

66+
const string ForeignKeyInformation = @"SELECT
67+
fk.name AS name,
68+
SCHEMA_NAME(tp.schema_id) AS [schema],
69+
tp.name AS table_name,
70+
STRING_AGG(cp.name, ', ') WITHIN GROUP (ORDER BY fkc.constraint_column_id) AS column_names,
71+
SCHEMA_NAME(tr.schema_id) AS referenced_schema,
72+
tr.name AS referenced_table,
73+
STRING_AGG(cr.name, ', ') WITHIN GROUP (ORDER BY fkc.constraint_column_id) AS referenced_column_names
74+
FROM
75+
sys.foreign_keys AS fk
76+
JOIN
77+
sys.foreign_key_columns AS fkc ON fk.object_id = fkc.constraint_object_id
78+
JOIN
79+
sys.tables AS tp ON fkc.parent_object_id = tp.object_id
80+
JOIN
81+
sys.columns AS cp ON fkc.parent_object_id = cp.object_id AND fkc.parent_column_id = cp.column_id
82+
JOIN
83+
sys.tables AS tr ON fkc.referenced_object_id = tr.object_id
84+
JOIN
85+
sys.columns AS cr ON fkc.referenced_object_id = cr.object_id AND fkc.referenced_column_id = cr.column_id
86+
WHERE
87+
( SCHEMA_NAME(tp.schema_id) = @TableSchema OR @TableSchema IS NULL )
88+
AND tp.name = @TableName
89+
GROUP BY
90+
fk.name, tp.schema_id, tp.name, tr.schema_id, tr.name;
91+
";
5492
var conn = await _connectionFactory.GetOpenConnectionAsync();
5593
try
5694
{
@@ -61,6 +99,7 @@ FROM sys.key_constraints kc
6199
using (var cmd = new SqlCommand(TableInfoQuery, conn))
62100
{
63101
var _ = cmd.Parameters.AddWithValue("@TableName", name);
102+
_ = cmd.Parameters.AddWithValue("@TableSchema", schema == null ? DBNull.Value : schema);
64103
using var reader = await cmd.ExecuteReaderAsync();
65104
if (await reader.ReadAsync())
66105
{
@@ -83,6 +122,7 @@ FROM sys.key_constraints kc
83122
using (var cmd = new SqlCommand(ColumnsQuery, conn))
84123
{
85124
var _ = cmd.Parameters.AddWithValue("@TableName", name);
125+
_ = cmd.Parameters.AddWithValue("@TableSchema", schema == null ? DBNull.Value : schema);
86126
using var reader = await cmd.ExecuteReaderAsync();
87127
var columns = new List<object>();
88128
while (await reader.ReadAsync())
@@ -103,6 +143,7 @@ FROM sys.key_constraints kc
103143
using (var cmd = new SqlCommand(IndexesQuery, conn))
104144
{
105145
var _ = cmd.Parameters.AddWithValue("@TableName", name);
146+
_ = cmd.Parameters.AddWithValue("@TableSchema", schema == null ? DBNull.Value : schema);
106147
using var reader = await cmd.ExecuteReaderAsync();
107148
var indexes = new List<object>();
108149
while (await reader.ReadAsync())
@@ -121,6 +162,7 @@ FROM sys.key_constraints kc
121162
using (var cmd = new SqlCommand(ConstraintsQuery, conn))
122163
{
123164
var _ = cmd.Parameters.AddWithValue("@TableName", name);
165+
_ = cmd.Parameters.AddWithValue("@TableSchema", schema == null ? DBNull.Value : schema);
124166
using var reader = await cmd.ExecuteReaderAsync();
125167
var constraints = new List<object>();
126168
while (await reader.ReadAsync())
@@ -134,6 +176,30 @@ FROM sys.key_constraints kc
134176
}
135177
result["constraints"] = constraints;
136178
}
179+
180+
// Foreign Keys
181+
using (var cmd = new SqlCommand(ForeignKeyInformation, conn))
182+
{
183+
var _ = cmd.Parameters.AddWithValue("@TableName", name);
184+
_ = cmd.Parameters.AddWithValue("@TableSchema", schema == null ? DBNull.Value : schema);
185+
using var reader = await cmd.ExecuteReaderAsync();
186+
var foreignKeys = new List<object>();
187+
while (await reader.ReadAsync())
188+
{
189+
foreignKeys.Add(new
190+
{
191+
name = reader["name"],
192+
schema = reader["schema"],
193+
table_name = reader["table_name"],
194+
column_name = reader["column_names"],
195+
referenced_schema = reader["referenced_schema"],
196+
referenced_table = reader["referenced_table"],
197+
referenced_column = reader["referenced_column_names"],
198+
});
199+
}
200+
result["foreignKeys"] = foreignKeys;
201+
}
202+
137203
return new DbOperationResult(success: true, data: result);
138204
}
139205
}

0 commit comments

Comments
 (0)