You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/claude/backlog.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,7 +22,7 @@ This file is the home for net-new non-function feature proposals too. CLAUDE.md'
22
22
23
23
The endpoint ships with SQLBatch + RPC + Transaction Manager support and credential enforcement via the `CREATE LOGIN` registry (see [`tds-endpoint.md`](tds-endpoint.md)); EF Core runs over the wire through vanilla `UseSqlServer`. Remaining phases, roughly in value order:
24
24
25
-
-**Tool shakedown** — point sqlcmd/SSMS/DBeaver at the endpoint and harvest their exotic catalog queries / SET shapes into this backlog. SSMS is the boss fight. Likely to want `sys.server_principals` / `sys.sql_logins` projected over the login registry.
25
+
-**Tool shakedown** — point sqlcmd/SSMS/DBeaver at the endpoint and harvest their exotic catalog queries / SET shapes into this backlog. SSMS is the boss fight. Likely to want `sys.server_principals` / `sys.sql_logins` projected over the login registry.**go-sqlcmd leg done (2026-07-14)**, first non-SqlClient client (go-mssqldb): connect/auth/batches/GO files/`:setvar`/`:r`/transactions/output modes all clean; headline find was the INFO-token/result-set DONE desync (fixed — see [`tds-endpoint.md`](tds-endpoint.md) batch-loop section); engine-level harvest landed under Fidelity gaps. SSMS + DBeaver legs remain (GUI, need a host-exposed port).
26
26
-**TVP parameters over the wire** (TYPE_INFO 0xF3) — the in-process TVP surface ships; the RPC reader rejects the wire form. Needed for `SqlDbType.Structured` and EF bulk patterns.
27
27
-**Wire forms deferred by the codec**: `text`/`ntext`/`image` (textptr ROW form + table-name-bearing COLMETADATA), `hierarchyid`/`geography`/`geometry` (UDT 0xF0), `sql_variant` (no simulator type at all).
28
28
-**Smaller fidelity items**: Msg 4060 (not 911) for login to a missing database; mid-stream attention (cancel during a large result requires a concurrent reader); `SqlBulkCopy` (BulkLoadBCP); MARS; TDS 8.0 / `Encrypt=Strict` (ALPN via `SslApplicationProtocol`); user-supplied `X509Certificate2`; off-loopback binding — the last two are add-on-demand public-surface expansions.
@@ -53,6 +53,8 @@ Low priority / niche — simulatable (as placeholder constants or a small model)
53
53
54
54
Real bugs / limitations against shipped behavior — fixes are concrete work, not design decisions.
55
55
56
+
-**`SimulatedSqlException` ERROR tokens carry `Server=''` / `Line 0`** — real SQL Server fills the server name and a 1-based line number on every error; the simulator's query errors surface blank/0 both in-process and over the wire (sqlcmd renders `Server , Line 0`). Inconsistently, `NotSupportedException`-derived wire errors *do* carry `Server=SIMULATED, Line 1`. Engine-level: the fix is stamping `SimulatedError.Server` (from `SERVERPROPERTY('ServerName')` = `SIMULATED`) at construction and threading real line numbers from the tokenizer — the latter is the large part. Harvested from the go-sqlcmd shakedown (2026-07-14).
57
+
-**String literals typed at container width, not value width** — `SELECT 'included'` advertises `varchar(8000)` (and `@@VERSION``nvarchar(4000)`) in projection schema; real types literals at exact length (`varchar(8)`). Correct data, but clients that size display columns from COLMETADATA (sqlcmd) render absurdly wide output, and `GetSchemaTable`-driven consumers see wrong sizes. Fix lives in literal `SqlType` inference (`Literal` → length-parameterized type), with CONCAT/CASE/set-op width-combination ripple effects — probe real's width algebra before starting. Harvested from the go-sqlcmd shakedown (2026-07-14).
56
58
-**Trailing-space MIN/MAX representative** — for a group of values differing only in trailing spaces (sort-equal under SQL Server), MIN/MAX returns a different byte-variant than the live server's scan-order representative. Surfaced by the AdventureWorks crosscheck on synthetic XML data (`vJobCandidateEducation._max_Edu_Loc_CountryRegion`). Needs trailing-space-insensitive compare + SQL Server's unspecified MAX-tie scan-order. See [`collations.md`](collations.md) "byte-exact sort" trailing-space note. **Deferred** — synthetic data, and the representative is unspecified scan-order on the live side.
57
59
- **Leaked-connection session cleanup** — a `SimulatedDbConnection` that's never `Dispose`d never reclaims its session state: an open transaction holds its locks and pins the MVCC version store, `##temp` tables linger, session-owned app locks stay held, and the SPID accumulates. Real SqlClient's GC-finalization eventually closes a leaked connection and the server resets the session, so this is a genuine fidelity divergence. **Scope correction (2026-07-11): the fix is bigger than "weaken the registry."** Investigation found *three* global strong-reference cycles that pin exactly the connections that hold session state, so GC can't collect them and a finalizer never fires: (1) `LockResource.Hold.Owner` is a strong `SimulatedDbConnection` (reachable Database → table → lock → hold) — pins any lock- or session-app-lock-holding connection; (2) `HeapTable.OwnerConnection` is strong and `Simulation.GlobalTempTables` holds the table — pins any `##temp` owner; (3) `Database.ActiveSnapshotTxs` holds the transaction, which strongly refs its connection — pins any open-snapshot session. Weakening `Simulation.Connections` alone accomplishes nothing because the resource *is* the pin. A correct fix must break all three cycles — cleanest via a one-way `SessionToken` indirection (resources reference a lightweight token identity; the connection references the token, not vice versa) plus a finalizer that enqueues a **deferred teardown** drained on a normal worker thread (next `CreateDbConnection` / version-store GC) so transaction rollback stays off the finalizer thread. This is a broad, mechanical owner-indirection refactor landing on the most regression-sensitive subsystem (lock manager × GC timing × threading). Payoff is bounded (EF disposes scrupulously; only buggy consumer code leaks), so it's **deliberately deferred** as high-risk / low-frequency. Eventual home: [`locking.md`](locking.md).
58
60
-**Workload-harness divergence reporting quirks** (`.vs/workload/Program.cs`, local-only) — the parity report's example line rebuilds parameters from the op seed and can mismatch the actual divergent instance, and divergent instances aren't re-run single-threaded to classify transient-vs-stable. Both made the 2026-07-10 shared-plan-state hunt slower than it needed to be (the fixed bug class itself — instance-bound aggregate/window results, baked TOP/OFFSET counts, frozen RAND, unstamped replay clock — is documented in [`plan-cache.md`](plan-cache.md)'s shared-plan contract section).
Copy file name to clipboardExpand all lines: docs/claude/tds-endpoint.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,7 +27,7 @@ Everything lives in `Network/` (internal) except the public `SimulatedNetworkLis
27
27
28
28
-**SQLBatch** (type 1): ALL_HEADERS skipped via its leading length DWORD; UCS-2 text executed on the session connection. Per result set: COLMETADATA + ROW stream + DONE (`DONE_COUNT` + `DONE_MORE` when more outcomes follow); per non-query statement: DONE with `DONE_COUNT` only when `RecordsAffected >= 0`. Zero outcomes → single final DONE. All tokens are `0xFD DONE` (DONEPROC/DONEINPROC are proc-scoped and RPC isn't shipped).
29
29
-**Errors**: `SimulatedSqlException.Errors` map field-for-field onto ERROR tokens (number/state/class/message/server/procedure/line) + DONE with `DONE_ERROR`; the session survives and keeps serving. `NotSupportedException` becomes a synthetic ERROR number 50000 class 16 prefixed `SqlServerSimulator:`.
30
-
-**PRINT / low-severity RAISERROR**: the session subscribes to `SimulatedDbConnection.InfoMessage` and drains the queue as INFO tokens between statements and at batch end.
30
+
-**PRINT / low-severity RAISERROR**: the session subscribes to `SimulatedDbConnection.InfoMessage` and drains the queue as INFO tokens between statements and at batch end.**Each INFO flush in a SQLBatch response gets its own DONE**, mirroring real per-statement DONEs: info preceding an outcome is followed by `DONE_MORE` count 0 before the outcome's tokens, and trailing info (batch ends in PRINT) forces the last outcome's DONE to `DONE_MORE` with a closing `DONE_FINAL` count 0 after the INFO — an INFO token must never follow the final DONE. Without both, SqlClient's token reader stalls until command timeout on any batch mixing PRINT with a result set, and go-mssqldb silently drops the message (go-sqlcmd shakedown, 2026-07-14; the pre-fix oracle only covered PRINT-without-result-set). RPC responses are unaffected — every DONEINPROC already carries `DONE_MORE`.
31
31
-**`USE`**: database change detected by before/after comparison and emitted as ENVCHANGE type 1 (after the DONEs, before flush — SqlClient processes it anywhere pre-EOM).
32
32
-**Reset-connection status bit** (pooled-connection recycle): backing connection disposed and recreated on the same database, acked with the empty ENVCHANGE type 18 before the batch's tokens.
33
33
-**Attention** (type 6): acked with DONE `DONE_ATTN`. Execution is synchronous per message, so attention is only observed between messages — a cancel never interrupts a running statement server-side, it just gets acked when the stream drains. In-process execution is fast enough that this matches observable SqlClient behavior.
0 commit comments