@@ -26,9 +26,11 @@ internal sealed class Database
2626 /// default <c>dbo</c> schema; <c>CREATE SCHEMA <name></c> adds more.
2727 /// Schema-qualified table references (<c>SELECT * FROM audit.t</c>) route
2828 /// through here; unqualified references fall back to
29- /// <see cref="DefaultSchemaName"/>.
29+ /// <see cref="DefaultSchemaName"/>. Comparer is <see cref="Collation"/>
30+ /// at the database's construction time; doesn't rebuild if a later
31+ /// <c>ALTER DATABASE COLLATE</c> shifts <see cref="Collation"/>.
3032 /// </summary>
31- public readonly ConcurrentDictionary < string , Schema > Schemas = new ( Collation . Default ) ;
33+ public readonly ConcurrentDictionary < string , Schema > Schemas ;
3234
3335 /// <summary>
3436 /// Schema-id of the default <c>dbo</c> schema. Matches real SQL Server's
@@ -44,8 +46,19 @@ internal sealed class Database
4446 public const int SysSchemaId = 4 ;
4547
4648 public Database ( string name )
49+ : this ( name , Collation . Default )
50+ {
51+ }
52+
53+ public Database ( string name , Collation collation )
4754 {
4855 this . Name = name ;
56+ this . Collation = collation ;
57+ this . CollationName = collation . Name ;
58+ this . Schemas = new ( collation ) ;
59+ this . DdlTriggers = new ( collation ) ;
60+ this . Principals = new ( collation ) ;
61+ this . FullTextCatalogs = new ( collation ) ;
4962 this . Schemas [ DefaultSchemaName ] = new Schema ( this , DefaultSchemaName , DboSchemaId ) ;
5063 this . Schemas [ "INFORMATION_SCHEMA" ] = new Schema ( this , "INFORMATION_SCHEMA" , InformationSchemaId ) ;
5164 this . Schemas [ "sys" ] = new Schema ( this , "sys" , SysSchemaId ) ;
@@ -87,18 +100,32 @@ public Database(string name)
87100 public CompatibilityLevel CompatibilityLevel = CompatibilityLevel . Sql170 ;
88101
89102 /// <summary>
90- /// Database-scope <c>COLLATE</c> declaration. The simulator routes every
91- /// comparison / sort / LIKE through <see cref="Collation.Default"/>
92- /// regardless of what this names — it's a metadata field for BACPAC
93- /// round-trip and catalog-view fidelity (<c>sys.databases.collation_name</c>,
94- /// <c>DATABASEPROPERTYEX(name, 'Collation')</c>,
95- /// <c>INFORMATION_SCHEMA.COLUMNS.COLLATION_NAME</c>). Whitelist of accepted
96- /// names lives in <see cref="Collation.IsRecognized"/>; <c>ALTER DATABASE
97- /// name COLLATE name</c> raises <see cref="NotSupportedException"/> on an
98- /// unrecognized name. Defaults to the simulator's modeled collation
99- /// (<see cref="Collation.Default"/>.Name).
103+ /// Database identifier-resolution collation. Drives every catalog dict
104+ /// comparer in this database (<see cref="Schemas"/>,
105+ /// <see cref="Schema.HeapTables"/>, <see cref="Schema.Functions"/>, …)
106+ /// and every <c>BatchContext</c> / <c>Schema</c> identifier-equality
107+ /// site. Set once at construction; <c>ALTER DATABASE COLLATE</c>
108+ /// updates this so subsequent identifier compares route through the
109+ /// new collation, but the construction-time dict comparers don't
110+ /// rebuild (matches real SQL Server's behavior: existing objects keep
111+ /// their identifier registration, new ones bind under the new
112+ /// collation). Defaults to <see cref="Collation.Default"/>.
113+ /// </summary>
114+ public Collation Collation ;
115+
116+ /// <summary>
117+ /// Database-scope <c>COLLATE</c> declaration as a string. Surfaces in
118+ /// <c>sys.databases.collation_name</c>,
119+ /// <c>DATABASEPROPERTYEX(name, 'Collation')</c>, and
120+ /// <c>INFORMATION_SCHEMA.COLUMNS.COLLATION_NAME</c>. Kept in sync with
121+ /// <see cref="Collation"/>.Name on every <c>ALTER DATABASE COLLATE</c>;
122+ /// also seeds the per-column default collation for new columns that
123+ /// don't carry an explicit <c>COLLATE</c> clause. Whitelist of accepted
124+ /// names lives in <see cref="Collation.IsRecognized"/>; an unrecognized
125+ /// name raises <see cref="NotSupportedException"/> from
126+ /// <c>ALTER DATABASE COLLATE</c>.
100127 /// </summary>
101- public string CollationName = Collation . Default . Name ;
128+ public string CollationName ;
102129
103130 /// <summary>
104131 /// Explicit override of the per-database <c>VERBOSE_TRUNCATION_WARNINGS</c>
@@ -229,7 +256,7 @@ public Database(string name)
229256 /// and <c>sys.sql_modules</c>. <strong>Not fired</strong> — see
230257 /// <see cref="DdlTrigger"/> for the no-enforcement rationale.
231258 /// </summary>
232- public readonly ConcurrentDictionary < string , DdlTrigger > DdlTriggers = new ( Collation . Default ) ;
259+ public readonly ConcurrentDictionary < string , DdlTrigger > DdlTriggers ;
233260
234261 /// <summary>
235262 /// Per-database principals (users + roles). Pre-seeded with the fixed
@@ -240,7 +267,7 @@ public Database(string name)
240267 /// model; this dict exists for catalog-view round-trip and for
241268 /// resolving <c>GRANT … TO <name></c> at parse time.
242269 /// </summary>
243- public readonly ConcurrentDictionary < string , DatabasePrincipal > Principals = new ( Collation . Default ) ;
270+ public readonly ConcurrentDictionary < string , DatabasePrincipal > Principals ;
244271
245272 /// <summary>
246273 /// Per-database permission grants/denies. Populated by
@@ -277,7 +304,7 @@ public Database(string name)
277304 /// visibility — query-time CONTAINS / FREETEXT predicates raise
278305 /// <see cref="NotSupportedException"/> rather than evaluate.
279306 /// </summary>
280- public readonly ConcurrentDictionary < string , FullTextCatalog > FullTextCatalogs = new ( Collation . Default ) ;
307+ public readonly ConcurrentDictionary < string , FullTextCatalog > FullTextCatalogs ;
281308
282309 private int nextFullTextCatalogId ;
283310
@@ -326,12 +353,12 @@ public bool Equals(ExtendedPropertyKey other) =>
326353 this . Class == other . Class
327354 && this . MajorId == other . MajorId
328355 && this . MinorId == other . MinorId
329- && Collation . Default . Equals ( this . Name , other . Name ) ;
356+ && BuiltInToken . Equals ( this . Name , other . Name ) ;
330357
331358 public override bool Equals ( object ? obj ) => obj is ExtendedPropertyKey other && this . Equals ( other ) ;
332359
333360 public override int GetHashCode ( ) =>
334- HashCode . Combine ( this . Class , this . MajorId , this . MinorId , Collation . Default . GetHashCode ( this . Name ) ) ;
361+ HashCode . Combine ( this . Class , this . MajorId , this . MinorId , BuiltInToken . GetHashCode ( this . Name ) ) ;
335362
336363 public static bool operator == ( ExtendedPropertyKey left , ExtendedPropertyKey right ) => left . Equals ( right ) ;
337364 public static bool operator != ( ExtendedPropertyKey left , ExtendedPropertyKey right ) => ! left . Equals ( right ) ;
0 commit comments