@@ -109,48 +109,57 @@ public async Task<DbObjectsResult> GetDbObjectsAsync(string dataSourceName)
109109 }
110110 case "postgresql" or "postgres" :
111111 {
112+ var pgTables = new List < ( string Schema , string Name , bool IsView ) > ( ) ;
112113 await using ( var cmd = conn . CreateCommand ( ) )
113114 {
114- cmd . CommandText = "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog','information_schema') ORDER BY table_name" ;
115+ cmd . CommandText = "SELECT table_schema, table_name, table_type FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog','information_schema') ORDER BY table_schema, table_name" ;
115116 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
116117 while ( await reader . ReadAsync ( ) )
117- {
118- var name = reader . GetValue ( 0 ) ? . ToString ( ) ?? "" ;
119- var type = reader . GetValue ( 1 ) ? . ToString ( ) ?? "" ;
120- if ( type == "VIEW" ) result . Views . Add ( new DbObjectItem { Name = name } ) ;
121- else result . Tables . Add ( new DbObjectItem { Name = name } ) ;
122- }
118+ pgTables . Add ( (
119+ reader . GetValue ( 0 ) ? . ToString ( ) ?? "" ,
120+ reader . GetValue ( 1 ) ? . ToString ( ) ?? "" ,
121+ string . Equals ( reader . GetValue ( 2 ) ? . ToString ( ) , "VIEW" , StringComparison . OrdinalIgnoreCase ) ) ) ;
123122 }
123+ AddWithSchemaQualify ( pgTables . Where ( t => ! t . IsView ) . Select ( t => ( t . Schema , t . Name ) ) , result . Tables ) ;
124+ AddWithSchemaQualify ( pgTables . Where ( t => t . IsView ) . Select ( t => ( t . Schema , t . Name ) ) , result . Views ) ;
125+
126+ var pgProcs = new List < ( string Schema , string Name ) > ( ) ;
124127 await using ( var cmd = conn . CreateCommand ( ) )
125128 {
126- cmd . CommandText = "SELECT routine_name FROM information_schema.routines WHERE routine_type = 'PROCEDURE' AND routine_schema NOT IN ('pg_catalog','information_schema') ORDER BY routine_name" ;
129+ cmd . CommandText = "SELECT routine_schema, routine_name FROM information_schema.routines WHERE routine_type = 'PROCEDURE' AND routine_schema NOT IN ('pg_catalog','information_schema') ORDER BY routine_schema, routine_name" ;
127130 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
128131 while ( await reader . ReadAsync ( ) )
129- result . Procedures . Add ( new DbObjectItem { Name = reader . GetValue ( 0 ) ? . ToString ( ) ?? "" } ) ;
132+ pgProcs . Add ( ( reader . GetValue ( 0 ) ? . ToString ( ) ?? "" , reader . GetValue ( 1 ) ? . ToString ( ) ?? "" ) ) ;
130133 }
134+ AddWithSchemaQualify ( pgProcs , result . Procedures ) ;
131135 break ;
132136 }
133137 case "sqlserver" or "mssql" :
134138 {
139+ // INFORMATION_SCHEMA.TABLES 含所有 schema,同名表跨 schema 时用 schema.名 限定
140+ var msTables = new List < ( string Schema , string Name , bool IsView ) > ( ) ;
135141 await using ( var cmd = conn . CreateCommand ( ) )
136142 {
137- cmd . CommandText = "SELECT TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES ORDER BY TABLE_NAME" ;
143+ cmd . CommandText = "SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA NOT IN ('sys','INFORMATION_SCHEMA') ORDER BY TABLE_SCHEMA, TABLE_NAME" ;
138144 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
139145 while ( await reader . ReadAsync ( ) )
140- {
141- var name = reader . GetValue ( 0 ) ? . ToString ( ) ?? "" ;
142- var type = reader . GetValue ( 1 ) ? . ToString ( ) ?? "" ;
143- if ( type == "VIEW" ) result . Views . Add ( new DbObjectItem { Name = name } ) ;
144- else result . Tables . Add ( new DbObjectItem { Name = name } ) ;
145- }
146+ msTables . Add ( (
147+ reader . GetValue ( 0 ) ? . ToString ( ) ?? "" ,
148+ reader . GetValue ( 1 ) ? . ToString ( ) ?? "" ,
149+ string . Equals ( reader . GetValue ( 2 ) ? . ToString ( ) , "VIEW" , StringComparison . OrdinalIgnoreCase ) ) ) ;
146150 }
151+ AddWithSchemaQualify ( msTables . Where ( t => ! t . IsView ) . Select ( t => ( t . Schema , t . Name ) ) , result . Tables ) ;
152+ AddWithSchemaQualify ( msTables . Where ( t => t . IsView ) . Select ( t => ( t . Schema , t . Name ) ) , result . Views ) ;
153+
154+ var msProcs = new List < ( string Schema , string Name ) > ( ) ;
147155 await using ( var cmd = conn . CreateCommand ( ) )
148156 {
149- cmd . CommandText = "SELECT name FROM sys.procedures ORDER BY name" ;
157+ cmd . CommandText = "SELECT s. name, p.name FROM sys.procedures p JOIN sys.schemas s ON p.schema_id = s.schema_id WHERE s.name NOT IN ('sys') ORDER BY s.name, p. name" ;
150158 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
151159 while ( await reader . ReadAsync ( ) )
152- result . Procedures . Add ( new DbObjectItem { Name = reader . GetValue ( 0 ) ? . ToString ( ) ?? "" } ) ;
160+ msProcs . Add ( ( reader . GetValue ( 0 ) ? . ToString ( ) ?? "" , reader . GetValue ( 1 ) ? . ToString ( ) ?? "" ) ) ;
153161 }
162+ AddWithSchemaQualify ( msProcs , result . Procedures ) ;
154163 break ;
155164 }
156165 case "oracle" :
@@ -246,12 +255,13 @@ public async Task<List<DbColumnItem>> GetColumnsAsync(string dataSourceName, str
246255 }
247256 case "postgresql" or "postgres" :
248257 {
258+ var ( pgSchema , pgTable ) = SplitSchemaName ( tableName , "public" ) ;
249259 await using var cmd = conn . CreateCommand ( ) ;
250260 cmd . CommandText = $ """
251261 SELECT c.column_name, c.data_type, c.is_nullable, c.column_default,
252262 pg_catalog.col_description(format('%I.%I', c.table_schema, c.table_name)::regclass, c.ordinal_position) AS comment
253263 FROM information_schema.columns c
254- WHERE c.table_schema NOT IN ('pg_catalog', 'information_schema') AND c.table_name = '{ safeName } '
264+ WHERE c.table_schema = ' { pgSchema } ' AND c.table_name = '{ pgTable } '
255265 ORDER BY c.ordinal_position
256266 """ ;
257267 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
@@ -270,6 +280,8 @@ ORDER BY c.ordinal_position
270280 }
271281 case "sqlserver" or "mssql" :
272282 {
283+ // 按 schema+表名 精确过滤,避免同名表跨 schema 时字段混合重复
284+ var ( msSchema , msTable ) = SplitSchemaName ( tableName , "dbo" ) ;
273285 await using var cmd = conn . CreateCommand ( ) ;
274286 cmd . CommandText = $ """
275287 SELECT c.COLUMN_NAME, c.DATA_TYPE, c.IS_NULLABLE, c.COLUMN_DEFAULT,
@@ -279,7 +291,7 @@ LEFT JOIN sys.extended_properties ep
279291 ON ep.major_id = OBJECT_ID(c.TABLE_SCHEMA + '.' + c.TABLE_NAME)
280292 AND ep.minor_id = c.ORDINAL_POSITION
281293 AND ep.class = 1 AND ep.name = 'MS_Description'
282- WHERE c.TABLE_NAME = '{ safeName } '
294+ WHERE c.TABLE_SCHEMA = ' { msSchema } ' AND c. TABLE_NAME = '{ msTable } '
283295 ORDER BY c.ORDINAL_POSITION
284296 """ ;
285297 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
@@ -362,11 +374,12 @@ ORDER BY ORDINAL_POSITION
362374 }
363375 case "postgresql" or "postgres" :
364376 {
377+ var ( pgSchema , pgProc ) = SplitSchemaName ( procName , "public" ) ;
365378 await using var cmd = conn . CreateCommand ( ) ;
366379 cmd . CommandText = $ """
367380 SELECT parameter_name, data_type, parameter_mode
368381 FROM information_schema.parameters
369- WHERE specific_name = '{ safeName } '
382+ WHERE routine_schema = ' { pgSchema } ' AND specific_name = '{ pgProc } '
370383 ORDER BY ordinal_position
371384 """ ;
372385 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
@@ -383,15 +396,18 @@ ORDER BY ordinal_position
383396 }
384397 case "sqlserver" or "mssql" :
385398 {
399+ // 按 schema+存储过程名 精确过滤,避免跨 schema 同名过程参数混合
400+ var ( msSchema , msProc ) = SplitSchemaName ( procName , "dbo" ) ;
386401 await using var cmd = conn . CreateCommand ( ) ;
387402 cmd . CommandText = $ """
388403 SELECT p.name, t.name AS data_type,
389404 CASE WHEN p.has_default_value = 1 THEN CAST(p.default_value AS NVARCHAR(200)) ELSE NULL END AS default_value,
390405 CASE WHEN p.is_output = 1 THEN 'OUT' ELSE 'IN' END AS mode
391406 FROM sys.procedures sp
407+ JOIN sys.schemas s ON sp.schema_id = s.schema_id
392408 JOIN sys.parameters p ON sp.object_id = p.object_id
393409 JOIN sys.types t ON p.user_type_id = t.user_type_id
394- WHERE sp.name = '{ safeName } ' AND p.parameter_id > 0
410+ WHERE s.name = ' { msSchema } ' AND sp.name = '{ msProc } ' AND p.parameter_id > 0
395411 ORDER BY p.parameter_id
396412 """ ;
397413 await using var reader = await cmd . ExecuteReaderAsync ( ) ;
@@ -538,6 +554,29 @@ private static string RenderTemplate(string sql, Dictionary<string, string?>? va
538554 return vars != null && vars . TryGetValue ( varName , out var v ) && v != null ? v : "" ;
539555 } ) ;
540556 }
557+
558+ /// <summary>
559+ /// 写入对象列表:同名对象跨 schema 时用 schema.名 限定,保证列表唯一不重复。
560+ /// </summary>
561+ private static void AddWithSchemaQualify ( IEnumerable < ( string Schema , string Name ) > items , List < DbObjectItem > target )
562+ {
563+ foreach ( var group in items . GroupBy ( i => i . Name , StringComparer . OrdinalIgnoreCase ) )
564+ {
565+ foreach ( var item in group )
566+ target . Add ( new DbObjectItem
567+ {
568+ Name = group . Count ( ) > 1 ? $ "{ item . Schema } .{ item . Name } " : item . Name
569+ } ) ;
570+ }
571+ }
572+
573+ /// <summary>拆分 schema.表名(无 schema 时返回默认 schema)</summary>
574+ private static ( string Schema , string Name ) SplitSchemaName ( string objectName , string defaultSchema )
575+ {
576+ var idx = objectName . LastIndexOf ( '.' ) ;
577+ if ( idx <= 0 ) return ( defaultSchema , objectName . Replace ( "'" , "''" ) ) ;
578+ return ( objectName [ .. idx ] . Replace ( "'" , "''" ) , objectName [ ( idx + 1 ) .. ] . Replace ( "'" , "''" ) ) ;
579+ }
541580}
542581
543582/// <summary>数据库对象列表(表/视图/存储过程)</summary>
0 commit comments