Skip to content

Commit 905b172

Browse files
committed
Migrated the last Collation.Default references to higher-fidelity placeholders.
1 parent 53d728b commit 905b172

24 files changed

Lines changed: 219 additions & 122 deletions

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Layout: `Storage/` (pages, types, row encoder/decoder, heap, constraints, lock m
5050
`FromSource[]`; rows during enumeration are `byte[]?[]`, one slot per source, null = NULL-filled outer-join side (LEFT/RIGHT/FULL/OUTER APPLY). Column resolution is qualifier-aware via `FindSourceColumn` / `ResolveAcrossTuple`; ambiguous unqualified name → Msg 209.
5151

5252
### `MultiPartName`
53-
Readonly struct, up to 4 inline slots (SQL Server's grammar limit). API: `Leaf`, `ImmediateQualifier` (null when unqualified — pair with `Collation.Default.Equals(name.ImmediateQualifier, "INSERTED")`, the equality folds null into `false`), `Count`, `ToString()`. 5th segment → Msg 4104.
53+
Readonly struct, up to 4 inline slots (SQL Server's grammar limit). API: `Leaf`, `ImmediateQualifier` (null when unqualified — pair with `Collation.Baseline.Equals(name.ImmediateQualifier, "INSERTED")`, the equality folds null into `false`), `Count`, `ToString()`. 5th segment → Msg 4104.
5454

5555
### Exception factories
5656
`SimulatedSqlException` constructor is private; each error case is an `internal static` factory in a topical partial (`TypeErrors`, `SchemaErrors`, `ConstraintErrors`, `ResolutionErrors`, `QueryErrors`, `SyntaxErrors`). The number lands in `Data["HelpLink.EvtID"]`. **Grep for an existing factory before adding a new one.**

SqlServerSimulator.Tests.Internal/CollationTests.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ namespace SqlServerSimulator;
55
/// <summary>
66
/// Algorithm-contract tests for the <see cref="Collation"/> implementations
77
/// that aren't routed through public SQL today. The default collation's
8-
/// behavior (<see cref="Collation.Default"/>) and the parser-driven
8+
/// behavior (<see cref="Collation.Baseline"/>) and the parser-driven
99
/// name-resolution surface (<see cref="Collation.TryGet"/> /
1010
/// <see cref="Collation.IsRecognized"/>) are exercised in the public
1111
/// <c>CollationBehaviorTests</c> / <c>CollationMetadataTests</c> /
1212
/// <c>LikeTests</c>; this file keeps the non-default-collation algorithm
1313
/// contracts and the internal-only null handling of
14-
/// <see cref="Collation.Default"/>'s <see cref="IComparer{T}"/> /
14+
/// <see cref="Collation.Baseline"/>'s <see cref="IComparer{T}"/> /
1515
/// <see cref="IEqualityComparer{T}"/> contracts. The non-default
1616
/// algorithms exist in the code but aren't called from any public SQL
1717
/// site (every string op outside the LIKE case-sensitivity flag still
18-
/// goes through <see cref="Collation.Default"/> — see
18+
/// goes through <see cref="Collation.Baseline"/> — see
1919
/// <c>docs/claude/database-options.md</c>); the tests pin the contract
2020
/// so the algorithms behave correctly once routing lands.
2121
/// </summary>
@@ -44,12 +44,12 @@ public sealed class CollationTests
4444
[TestMethod]
4545
public void Sql_NullHandling()
4646
{
47-
IsTrue(Collation.Default.Equals(null, null));
48-
IsFalse(Collation.Default.Equals(null, ""));
49-
IsFalse(Collation.Default.Equals("", null));
50-
AreEqual(0, Collation.Default.Compare(null, null));
51-
IsLessThan(0, Collation.Default.Compare(null, "x"));
52-
IsGreaterThan(0, Collation.Default.Compare("x", null));
47+
IsTrue(Collation.Baseline.Equals(null, null));
48+
IsFalse(Collation.Baseline.Equals(null, ""));
49+
IsFalse(Collation.Baseline.Equals("", null));
50+
AreEqual(0, Collation.Baseline.Compare(null, null));
51+
IsLessThan(0, Collation.Baseline.Compare(null, "x"));
52+
IsGreaterThan(0, Collation.Baseline.Compare("x", null));
5353
}
5454

5555
// ---- Latin1_General_100_CI_AS (Windows-style v100) ----
@@ -155,6 +155,6 @@ public void Bin_StrictCodepoint_DistinguishesNfdAndNfc()
155155
const string nfc = "é";
156156
const string nfd = "é";
157157
IsFalse(Latin1GeneralBin.Equals(nfc, nfd));
158-
IsTrue(Collation.Default.Equals(nfc, nfd));
158+
IsTrue(Collation.Baseline.Equals(nfc, nfd));
159159
}
160160
}

SqlServerSimulator.Tests.Internal/Parser/TokenLineNumberTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void NewlineWithinACommentToken_PushesLaterTokensDown()
7777
private static IEnumerable<Token> TokenizeMeaningful(string command)
7878
{
7979
var index = 0;
80-
while (Tokenizer.NextToken(command, ref index, Collation.Default) is Token t)
80+
while (Tokenizer.NextToken(command, ref index, Collation.Baseline) is Token t)
8181
{
8282
if (t is Whitespace or Comment)
8383
continue;

SqlServerSimulator.Tests.Internal/Storage/PromoteStringConcatTests.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,35 @@ public sealed class PromoteStringConcatTests
1313
{
1414
[TestMethod]
1515
public void Varchar_Plus_Varchar_SumsLengths() =>
16-
AreEqual(30, ((VarcharSqlType)SqlType.PromoteForArithmetic(VarcharSqlType.Get(10, Collation.Default, Coercibility.CoercibleDefault), VarcharSqlType.Get(20, Collation.Default, Coercibility.CoercibleDefault), '+')).length);
16+
AreEqual(30, ((VarcharSqlType)SqlType.PromoteForArithmetic(VarcharSqlType.Get(10, Collation.Baseline, Coercibility.CoercibleDefault), VarcharSqlType.Get(20, Collation.Baseline, Coercibility.CoercibleDefault), '+')).length);
1717

1818
[TestMethod]
1919
public void Varchar_Plus_Varchar_CapsAt8000() =>
20-
AreEqual(8000, ((VarcharSqlType)SqlType.PromoteForArithmetic(VarcharSqlType.Get(8000, Collation.Default, Coercibility.CoercibleDefault), VarcharSqlType.Get(100, Collation.Default, Coercibility.CoercibleDefault), '+')).length);
20+
AreEqual(8000, ((VarcharSqlType)SqlType.PromoteForArithmetic(VarcharSqlType.Get(8000, Collation.Baseline, Coercibility.CoercibleDefault), VarcharSqlType.Get(100, Collation.Baseline, Coercibility.CoercibleDefault), '+')).length);
2121

2222
[TestMethod]
2323
public void NVarchar_Plus_NVarchar_SumsLengths_CapsAt4000() =>
24-
AreEqual(4000, ((NVarcharSqlType)SqlType.PromoteForArithmetic(NVarcharSqlType.Get(3000, Collation.Default, Coercibility.CoercibleDefault), NVarcharSqlType.Get(2000, Collation.Default, Coercibility.CoercibleDefault), '+')).length);
24+
AreEqual(4000, ((NVarcharSqlType)SqlType.PromoteForArithmetic(NVarcharSqlType.Get(3000, Collation.Baseline, Coercibility.CoercibleDefault), NVarcharSqlType.Get(2000, Collation.Baseline, Coercibility.CoercibleDefault), '+')).length);
2525

2626
[TestMethod]
2727
public void Char_Plus_Varchar_DropsToVarcharOfCombinedLength() =>
28-
AreEqual(15, ((VarcharSqlType)SqlType.PromoteForArithmetic(SqlType.GetChar(5), VarcharSqlType.Get(10, Collation.Default, Coercibility.CoercibleDefault), '+')).length);
28+
AreEqual(15, ((VarcharSqlType)SqlType.PromoteForArithmetic(SqlType.GetChar(5), VarcharSqlType.Get(10, Collation.Baseline, Coercibility.CoercibleDefault), '+')).length);
2929

3030
[TestMethod]
3131
public void NChar_Plus_Varchar_PromotesToNVarcharOfCombinedLength() =>
32-
AreEqual(15, ((NVarcharSqlType)SqlType.PromoteForArithmetic(SqlType.GetNChar(5), VarcharSqlType.Get(10, Collation.Default, Coercibility.CoercibleDefault), '+')).length);
32+
AreEqual(15, ((NVarcharSqlType)SqlType.PromoteForArithmetic(SqlType.GetNChar(5), VarcharSqlType.Get(10, Collation.Baseline, Coercibility.CoercibleDefault), '+')).length);
3333

3434
[TestMethod]
3535
public void Varchar_Plus_NVarchar_PromotesToNVarcharOfCombinedLength() =>
36-
AreEqual(30, ((NVarcharSqlType)SqlType.PromoteForArithmetic(VarcharSqlType.Get(10, Collation.Default, Coercibility.CoercibleDefault), NVarcharSqlType.Get(20, Collation.Default, Coercibility.CoercibleDefault), '+')).length);
36+
AreEqual(30, ((NVarcharSqlType)SqlType.PromoteForArithmetic(VarcharSqlType.Get(10, Collation.Baseline, Coercibility.CoercibleDefault), NVarcharSqlType.Get(20, Collation.Baseline, Coercibility.CoercibleDefault), '+')).length);
3737

3838
[TestMethod]
3939
public void Unspecified_Plus_BoundedVarchar_DropsToUnspecified()
4040
{
4141
// Length 0 means "we don't know"; the result can't reliably claim
4242
// a sum, so it falls back to the length-unspecified form.
43-
var result = SqlType.PromoteForArithmetic(VarcharSqlType.Get(0, Collation.Default, Coercibility.CoercibleDefault), VarcharSqlType.Get(10, Collation.Default, Coercibility.CoercibleDefault), '+');
44-
AreSame(VarcharSqlType.Get(0, Collation.Default, Coercibility.CoercibleDefault), result);
43+
var result = SqlType.PromoteForArithmetic(VarcharSqlType.Get(0, Collation.Baseline, Coercibility.CoercibleDefault), VarcharSqlType.Get(10, Collation.Baseline, Coercibility.CoercibleDefault), '+');
44+
AreSame(VarcharSqlType.Get(0, Collation.Baseline, Coercibility.CoercibleDefault), result);
4545
}
4646

4747
[TestMethod]
@@ -52,8 +52,8 @@ public void Text_Plus_Varchar_DropsToVarcharUnspecified()
5252
// Implicit coercibility (it's a column-typed family), so the
5353
// Collation.Resolve hand-off yields Implicit rather than
5454
// CoercibleDefault.
55-
var result = SqlType.PromoteForArithmetic(SqlType.Text, VarcharSqlType.Get(10, Collation.Default, Coercibility.CoercibleDefault), '+');
56-
AreSame(VarcharSqlType.Get(0, Collation.Default, Coercibility.Implicit), result);
55+
var result = SqlType.PromoteForArithmetic(SqlType.Text, VarcharSqlType.Get(10, Collation.Baseline, Coercibility.CoercibleDefault), '+');
56+
AreSame(VarcharSqlType.Get(0, Collation.Baseline, Coercibility.Implicit), result);
5757
}
5858

5959
[TestMethod]
@@ -62,6 +62,6 @@ public void NText_Plus_Char_DropsToNVarcharUnspecified()
6262
// NText carries Implicit; the char(5) bridge is also Implicit (via
6363
// SqlType.GetChar's static helper), so the resolved rank is Implicit.
6464
var result = SqlType.PromoteForArithmetic(SqlType.NText, SqlType.GetChar(5), '+');
65-
AreSame(NVarcharSqlType.Get(0, Collation.Default, Coercibility.Implicit), result);
65+
AreSame(NVarcharSqlType.Get(0, Collation.Baseline, Coercibility.Implicit), result);
6666
}
6767
}

SqlServerSimulator.Tests/Bacpac/BacpacLoaderTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,7 +696,7 @@ public void Collation_RoundsTripsThrough_sys_databases_AndDatabasePropertyEx()
696696
// Whitelisted collation stored on Database.CollationName + surfaced
697697
// through sys.databases.collation_name and DATABASEPROPERTYEX.
698698
// Comparison semantics still route through the default per
699-
// Collation.Default; the metadata is honest about the declaration.
699+
// Collation.Baseline; the metadata is honest about the declaration.
700700
using var bacpac = BacpacBuilder.Create()
701701
.DatabaseOption("Collation", "Latin1_General_100_CI_AS")
702702
.Build();

SqlServerSimulator.Tests/NameComparisonRegimeTests.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ public void ServerCollationName_SeededDatabase_CreateSchemaDBO_CoexistsWithDbo()
314314

315315
// ===== Scalar-function result types carry the active DB collation =====
316316
// CHAR(N) / NCHAR(N) result types pin the active database's collation
317-
// rather than the storage-baseline Collation.Default, so a CS-DB
317+
// rather than the storage-baseline Collation.Baseline, so a CS-DB
318318
// compare between two function-returned strings goes through the
319319
// CS comparer. Probe-confirmed against real SQL Server CS database
320320
// (2026-05-22): CHAR(65) = CHAR(97) returns 'neq' (literals don't
@@ -357,4 +357,21 @@ public void CsDatabase_TwoNVarcharLiteralsCompareCaseSensitively()
357357
[TestMethod]
358358
public void CiDatabase_TwoVarcharLiterals_StillEqualUnderCi()
359359
=> AreEqual("eq", new Simulation().ExecuteScalar("SELECT IIF('A' = 'a', 'eq', 'neq')"));
360+
361+
// ===== Catalog views pin _desc columns to the catalog collation =====
362+
// BuildCatalogViews declares _desc columns at Catalog (Latin1_General_CI_AS_KS_WS)
363+
// + Implicit. Under a CS-server simulation, the literal carries CS at
364+
// CoercibleDefault rank (via the tokenizer threading). Collation.Resolve
365+
// picks the column's Implicit-rank Catalog collation (CI), so the user
366+
// can still query catalog _desc values without case-matching the
367+
// declared enum string — matching real SQL Server's behavior.
368+
369+
[TestMethod]
370+
public void CsDatabase_CatalogTypeDescMatchesLowercaseUnderCatalogCollation()
371+
{
372+
var sim = new Simulation { ServerCollationName = "SQL_Latin1_General_CP1_CS_AS" };
373+
_ = sim.ExecuteNonQuery("create table dbo.catalog_t (id int)");
374+
AreEqual(1, sim.ExecuteScalar(
375+
"select count(*) from sys.objects where name = N'catalog_t' and type_desc = N'user_table'"));
376+
}
360377
}

0 commit comments

Comments
 (0)