@@ -125,24 +125,35 @@ private protected Collation()
125125 /// Comparison routes through .NET's <c>ja-JP</c> <see cref="CompareInfo"/>
126126 /// with the simulator's standard CI/AS options (case-insensitive,
127127 /// accent-sensitive, kana-type-insensitive, width-insensitive).
128- /// Probe-confirmed presence in real-database column-collation profiles;
129- /// per-name sort-order parity with real SQL Server is not yet probed.
128+ /// Equality + kana-type / width folding match SQL Server end-to-end;
129+ /// the secondary sort tiebreaker inside the hiragana / full-width
130+ /// katakana / half-width katakana equivalence classes diverges
131+ /// (probe-confirmed against SQL Server 2025: ~half the positions
132+ /// reorder on nvarchar; varchar essentially unusable since CP1252
133+ /// can't represent Japanese where real SQL Server uses CP932). See
134+ /// <c>docs/claude/collations.md</c> "Locale-comparer sort-parity gap".
130135 /// </summary>
131136 internal static readonly CultureCollation JapaneseXJIS140CiAs = new ( "Japanese_XJIS_140_CI_AS" , "ja-JP" , caseSensitive : false ) ;
132137
133138 /// <summary>
134139 /// "Chinese_PRC_CI_AS" — Simplified Chinese (pinyin sort) via .NET's
135- /// <c>zh-CN</c> <see cref="CompareInfo"/>. Per-name sort-order parity
136- /// with real SQL Server is not yet probed.
140+ /// <c>zh-CN</c> <see cref="CompareInfo"/>. Internal pinyin ordering
141+ /// mostly aligns with SQL Server 2025; the .NET vs SQL Server
142+ /// convention for Latin-vs-CJK block position is reversed (.NET puts
143+ /// CJK before Latin, SQL Server puts Latin before CJK), so any
144+ /// mixed-script ORDER BY will shift every position. See
145+ /// <c>docs/claude/collations.md</c> "Locale-comparer sort-parity gap".
137146 /// </summary>
138147 internal static readonly CultureCollation ChinesePrcCiAs = new ( "Chinese_PRC_CI_AS" , "zh-CN" , caseSensitive : false ) ;
139148
140149 /// <summary>
141150 /// "Turkish_CI_AS" — Turkish collation via .NET's <c>tr-TR</c>
142151 /// <see cref="CompareInfo"/>. Notably handles the i / İ / ı / I
143152 /// folding that catches non-Turkish-aware code (the "Turkish-i
144- /// problem"). Per-name sort-order parity with real SQL Server is not
145- /// yet probed.
153+ /// problem"). Equality / case-folding match SQL Server end-to-end on
154+ /// nvarchar; tiebreaker within case-equivalence classes (e.g. `çay`
155+ /// vs `Çay`) differs (~2 / 19 position drift on probed inputs). See
156+ /// <c>docs/claude/collations.md</c> "Locale-comparer sort-parity gap".
146157 /// </summary>
147158 internal static readonly CultureCollation TurkishCiAs = new ( "Turkish_CI_AS" , "tr-TR" , caseSensitive : false ) ;
148159
@@ -180,6 +191,104 @@ internal sealed class UNICODE_CODEPOINT : BinaryCollation
180191 public override string Name => "UNICODE_CODEPOINT" ;
181192 }
182193
194+ /// <summary>"Korean_100_CI_AS" — Korean (Hangul) v100 sort via .NET's
195+ /// <c>ko-KR</c> <see cref="CompareInfo"/>. Same sort-tiebreaker
196+ /// divergence caveat as the other locale collations
197+ /// (see <c>docs/claude/collations.md</c>).</summary>
198+ internal static readonly CultureCollation Korean100CiAs = new ( "Korean_100_CI_AS" , "ko-KR" , caseSensitive : false ) ;
199+
200+ /// <summary>"Korean_Wansung_CI_AS" — legacy Korean Wansung code-page
201+ /// binding. Behavior body identical to <see cref="Korean100CiAs"/> at
202+ /// the simulator's value layer; the Wansung-vs-v100 distinction is a
203+ /// non-Unicode codepage detail that the simulator's UTF-16 storage
204+ /// doesn't materialize.</summary>
205+ internal static readonly CultureCollation KoreanWansungCiAs = new ( "Korean_Wansung_CI_AS" , "ko-KR" , caseSensitive : false ) ;
206+
207+ /// <summary>"Greek_CI_AS" — Greek collation via .NET's <c>el-GR</c>
208+ /// <see cref="CompareInfo"/>. Tonos / dialytika fold under accent-
209+ /// sensitive rules; final-sigma (ς) vs medial-sigma (σ) treated as
210+ /// case-insensitive peers (matches real SQL Server).</summary>
211+ internal static readonly CultureCollation GreekCiAs = new ( "Greek_CI_AS" , "el-GR" , caseSensitive : false ) ;
212+
213+ /// <summary>"Greek_100_CI_AS" — v100 Greek collation. Same culture as
214+ /// <see cref="GreekCiAs"/>; the v100 update touches Unicode-table
215+ /// ordering for supplementary characters not relevant to most Greek
216+ /// text.</summary>
217+ internal static readonly CultureCollation Greek100CiAs = new ( "Greek_100_CI_AS" , "el-GR" , caseSensitive : false ) ;
218+
219+ /// <summary>"Cyrillic_General_CI_AS" — pan-Cyrillic collation routed
220+ /// through .NET's <c>ru-RU</c> <see cref="CompareInfo"/>. Covers
221+ /// Russian, Ukrainian, Bulgarian, Serbian, etc. at the same fidelity
222+ /// bar as the other locale collations — equality / case folding align;
223+ /// secondary sort tiebreakers may differ.</summary>
224+ internal static readonly CultureCollation CyrillicGeneralCiAs = new ( "Cyrillic_General_CI_AS" , "ru-RU" , caseSensitive : false ) ;
225+
226+ /// <summary>"Cyrillic_General_100_CI_AS" — v100 Cyrillic. Same culture
227+ /// as <see cref="CyrillicGeneralCiAs"/>.</summary>
228+ internal static readonly CultureCollation CyrillicGeneral100CiAs = new ( "Cyrillic_General_100_CI_AS" , "ru-RU" , caseSensitive : false ) ;
229+
230+ /// <summary>"German_PhoneBook_CI_AS" — German with phonebook sort
231+ /// (ä → ae, ö → oe, ü → ue, ß → ss equivalence at sort time). The
232+ /// simulator routes through .NET's <c>de-DE</c> default ordering
233+ /// (umlaut-as-letter, not phonebook). Recognized for BACPAC quiet-
234+ /// loading; sort order for the umlauted letters diverges from real
235+ /// SQL Server. Apps that rely on phonebook ordering hit the broader
236+ /// locale-comparer sort-parity gap documented in collations.md.</summary>
237+ internal static readonly CultureCollation GermanPhoneBookCiAs = new ( "German_PhoneBook_CI_AS" , "de-DE" , caseSensitive : false ) ;
238+
239+ /// <summary>"German_PhoneBook_100_CI_AS" — v100 German phonebook.
240+ /// Same routing as <see cref="GermanPhoneBookCiAs"/>; same phonebook
241+ /// divergence applies.</summary>
242+ internal static readonly CultureCollation GermanPhoneBook100CiAs = new ( "German_PhoneBook_100_CI_AS" , "de-DE" , caseSensitive : false ) ;
243+
244+ /// <summary>"French_CI_AS" — French via .NET's <c>fr-FR</c>
245+ /// <see cref="CompareInfo"/>. Note: real SQL Server's French
246+ /// collation sorts accents from the END of the string (a French-
247+ /// specific rule); .NET's <c>fr-FR</c> default doesn't, so accented
248+ /// strings near each other sort differently. Same fidelity bar as
249+ /// the other locale collations.</summary>
250+ internal static readonly CultureCollation FrenchCiAs = new ( "French_CI_AS" , "fr-FR" , caseSensitive : false ) ;
251+
252+ /// <summary>"French_100_CI_AS" — v100 French.</summary>
253+ internal static readonly CultureCollation French100CiAs = new ( "French_100_CI_AS" , "fr-FR" , caseSensitive : false ) ;
254+
255+ /// <summary>"Modern_Spanish_CI_AS" — Spanish (modern, no ch/ll as
256+ /// separate letters) via .NET's <c>es-ES</c> <see cref="CompareInfo"/>.
257+ /// .NET's default Spanish sort already follows the modern convention,
258+ /// so equality / sort alignment is closer here than for the other
259+ /// European locales.</summary>
260+ internal static readonly CultureCollation ModernSpanishCiAs = new ( "Modern_Spanish_CI_AS" , "es-ES" , caseSensitive : false ) ;
261+
262+ /// <summary>"Modern_Spanish_100_CI_AS" — v100 modern Spanish.</summary>
263+ internal static readonly CultureCollation ModernSpanish100CiAs = new ( "Modern_Spanish_100_CI_AS" , "es-ES" , caseSensitive : false ) ;
264+
265+ /// <summary>"Latin1_General_100_CI_AS_SC_UTF8" — Latin1 v100 CI_AS
266+ /// with supplementary-character support and UTF-8 varchar storage.
267+ /// UTF-8 is a storage encoding only; sort / compare semantics are
268+ /// identical to <see cref="Latin1General100CiAs"/>. .NET's
269+ /// <see cref="CompareInfo"/> handles surrogate pairs natively, so the
270+ /// SC marker doesn't require special handling either.</summary>
271+ internal static readonly CultureCollation Latin1General100CiAsScUtf8 = new (
272+ "Latin1_General_100_CI_AS_SC_UTF8" , CultureInfo . InvariantCulture . Name , caseSensitive : false ) ;
273+
274+ /// <summary>"Latin1_General_100_CS_AS_SC_UTF8" — case-sensitive UTF-8
275+ /// variant. Sort / compare matches <see cref="Latin1GeneralCsAs"/>;
276+ /// UTF-8 / SC distinctions are storage-layer only.</summary>
277+ internal static readonly CultureCollation Latin1General100CsAsScUtf8 = new (
278+ "Latin1_General_100_CS_AS_SC_UTF8" , CultureInfo . InvariantCulture . Name , caseSensitive : true ) ;
279+
280+ /// <summary>"Latin1_General_100_BIN2_UTF8" — binary UTF-8 variant.
281+ /// Pure codepoint comparison via <see cref="BinaryCollation"/>;
282+ /// metadata-only instance for catalog recognition.</summary>
283+ internal static readonly Latin1_General_100_BIN2_UTF8 Latin1General100Bin2Utf8 = new ( ) ;
284+
285+ /// <summary>Metadata-only binary collation under the
286+ /// <c>Latin1_General_100_BIN2_UTF8</c> name.</summary>
287+ internal sealed class Latin1_General_100_BIN2_UTF8 : BinaryCollation
288+ {
289+ public override string Name => "Latin1_General_100_BIN2_UTF8" ;
290+ }
291+
183292 /// <summary>
184293 /// Closed accept-list of collation names the simulator recognizes.
185294 /// ALTER DATABASE COLLATE / CREATE TABLE column COLLATE accept these
@@ -211,6 +320,21 @@ internal sealed class UNICODE_CODEPOINT : BinaryCollation
211320 [ JapaneseXJIS140CiAs . Name ] = "Japanese-XJIS-140, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
212321 [ ChinesePrcCiAs . Name ] = "Chinese-PRC, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
213322 [ TurkishCiAs . Name ] = "Turkish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
323+ [ Korean100CiAs . Name ] = "Korean-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
324+ [ KoreanWansungCiAs . Name ] = "Korean-Wansung, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
325+ [ GreekCiAs . Name ] = "Greek, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
326+ [ Greek100CiAs . Name ] = "Greek-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
327+ [ CyrillicGeneralCiAs . Name ] = "Cyrillic-General, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
328+ [ CyrillicGeneral100CiAs . Name ] = "Cyrillic-General-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
329+ [ GermanPhoneBookCiAs . Name ] = "German-PhoneBook, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
330+ [ GermanPhoneBook100CiAs . Name ] = "German-PhoneBook-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
331+ [ FrenchCiAs . Name ] = "French, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
332+ [ French100CiAs . Name ] = "French-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
333+ [ ModernSpanishCiAs . Name ] = "Modern-Spanish, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
334+ [ ModernSpanish100CiAs . Name ] = "Modern-Spanish-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive" ,
335+ [ Latin1General100CiAsScUtf8 . Name ] = "Latin1-General-100, case-insensitive, accent-sensitive, kanatype-insensitive, width-insensitive, supplementary characters, UTF8" ,
336+ [ Latin1General100CsAsScUtf8 . Name ] = "Latin1-General-100, case-sensitive, accent-sensitive, kanatype-insensitive, width-insensitive, supplementary characters, UTF8" ,
337+ [ Latin1General100Bin2Utf8 . Name ] = "Latin1-General-100, binary code point comparison sort, UTF8" ,
214338 } . ToFrozenDictionary ( StringComparer . OrdinalIgnoreCase ) ;
215339
216340 /// <summary>
@@ -234,6 +358,21 @@ internal sealed class UNICODE_CODEPOINT : BinaryCollation
234358 [ JapaneseXJIS140CiAs . Name ] = JapaneseXJIS140CiAs ,
235359 [ ChinesePrcCiAs . Name ] = ChinesePrcCiAs ,
236360 [ TurkishCiAs . Name ] = TurkishCiAs ,
361+ [ Korean100CiAs . Name ] = Korean100CiAs ,
362+ [ KoreanWansungCiAs . Name ] = KoreanWansungCiAs ,
363+ [ GreekCiAs . Name ] = GreekCiAs ,
364+ [ Greek100CiAs . Name ] = Greek100CiAs ,
365+ [ CyrillicGeneralCiAs . Name ] = CyrillicGeneralCiAs ,
366+ [ CyrillicGeneral100CiAs . Name ] = CyrillicGeneral100CiAs ,
367+ [ GermanPhoneBookCiAs . Name ] = GermanPhoneBookCiAs ,
368+ [ GermanPhoneBook100CiAs . Name ] = GermanPhoneBook100CiAs ,
369+ [ FrenchCiAs . Name ] = FrenchCiAs ,
370+ [ French100CiAs . Name ] = French100CiAs ,
371+ [ ModernSpanishCiAs . Name ] = ModernSpanishCiAs ,
372+ [ ModernSpanish100CiAs . Name ] = ModernSpanish100CiAs ,
373+ [ Latin1General100CiAsScUtf8 . Name ] = Latin1General100CiAsScUtf8 ,
374+ [ Latin1General100CsAsScUtf8 . Name ] = Latin1General100CsAsScUtf8 ,
375+ [ Latin1General100Bin2Utf8 . Name ] = Latin1General100Bin2Utf8 ,
237376 } . ToFrozenDictionary ( StringComparer . OrdinalIgnoreCase ) ;
238377
239378 /// <summary>
0 commit comments