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
SET TEXTSIZE truncates LOB data at the client boundary: the session byte cap clips the six MAX/legacy-LOB types in result columns and output parameters through a TextSizeCursor decorator on the shared client-cursor seam keyed by declared schema type with the cap stamped per statement at production, so a proc body's SET governs its own result sets across the exit revert, wide chars floor the odd byte, xml/bounded/UDT types are exempt, and server-side computation, assignment, and stored data stay full. The direct proc-RPC binding now honors Size=-1 as a MAX declaration like the batch path always did.
Copy file name to clipboardExpand all lines: docs/claude/backlog.md
+6-23Lines changed: 6 additions & 23 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -34,24 +34,11 @@ Remaining phases, roughly in value order:
34
34
**SSMS is the final boss** — an ongoing campaign, not a single leg: each surface is its own multi-round harvest, and clearing one unlocks the next.
35
35
Cleared legs are recorded in the per-feature deep-dives (catalog surface in [`catalog-views.md`](catalog-views.md), wire behavior in [`tds-endpoint.md`](tds-endpoint.md)); the discovery harnesses are the gitignored `.vs/ssms-host` TDS host and the headless SMO property-bag drain.
36
36
**Remaining frontier**: Table Designer, Activity Monitor, standard reports, and IntelliSense's background metadata harvest.
37
-
(The sp_cursor* API-server-cursor RPC family — SSMS query-editor grid navigation / multi-row edit — shipped; see [`tds-endpoint.md`](tds-endpoint.md).)
38
37
Candidate follow-on legs within tool scope: Visual Studio's SQL Server Object Explorer (DacFx-driven, a different query dialect from SMO) and LINQPad.
39
38
-**SMO API sweep campaign** — `.vs/smo-sweep` (gitignored local harness) walks SMO's full reachable read surface against the self-hosted simulator and, identically, against the live reference, draining every `Property.Value` and `Script()`-ing every `IScriptable`; modes `sweep` / `sweep --live` / `diff` → sorted JSON reports + `reports/triage.md`; workflow = sweep both sides → triage → fix bundles → graduated `Tests.Smo` tests → re-sweep.
40
39
Open items from the latest triage: (a) `DBCC SHOW_STATISTICS … WITH STATS_STREAM` (SMO `Statistic.Stream`) stays `NotSupportedException` — it wants the raw serialized statistics-histogram blob, which the simulator has no faithful source for; (b) the unmodeled runtime/OS surfaces SMO reaches as absent objects (backup history `msdb.dbo.backupset`, `sys.dm_tran_persistent_version_store_stats`, file-space/IO DMVs, `sys.dm_os_process_memory`, `master.dbo.sysprocesses`, `FILEPROPERTY`, registry/OS xps) — surfaced as `PropertyCannotBeRetrievedException` / defaults, the legitimate-gap category.
41
-
-**Wire forms deferred by the codec**: the RPC-parameter and bulk/TVP-column decoders now share one implementation (`TdsWireValue` + `TdsColumnDecoder`; see [`tds-endpoint.md`](tds-endpoint.md#client-value-decode-tdswirevalue--tdscolumndecoder)), which closed the split's residuals.
42
-
**`text`/`ntext`/`image` ship fully** (2026-07-19) — result columns, `image` (0x22) input parameters, and **`SqlBulkCopy` into a legacy-LOB column** (2026-07-19: the BCP LONGLEN COLMETADATA + in-band text-pointer ROW value now decode); see [`tds-endpoint.md`](tds-endpoint.md#legacy-text--ntext--image-wire-forms).
43
-
**`sql_variant` and UDT (`geography`/`geometry`/`hierarchyid`) ship as RPC *input* parameters AND as *columns inside a TVP*** (2026-07-19 — the shared decoder made the TVP columns near-free; see [`tds-endpoint.md`](tds-endpoint.md#tvp-parameters-sqldbtypestructured)).
44
-
**TVP parameters (0xF3, `SqlDbType.Structured`) ship** — `DataTable` / `IEnumerable<SqlDataRecord>` / `DbDataReader` sources over proc-RPC + sp_executesql, error parity for arity / type / NOT NULL / CHECK / PK / UNIQUE / unknown-type.
45
-
Residuals: **`SET TEXTSIZE`** doesn't truncate returned LOB data (parse-and-discard).
46
-
(Output-direction UDT / `sql_variant` params shipped 2026-07-19 — probed RETURNVALUE wire forms in [`tds-endpoint.md`](tds-endpoint.md#clr-udt--sql_variant-parameters).)
47
-
(The LOB-backed TVP column → stored-proc READONLY parameter dangling-pointer bug was fixed 2026-07-19: the proc-parameter copy re-homes off-row values into the parameter's heap; see [`table-valued-parameters.md`](table-valued-parameters.md).)
48
-
-**Smaller fidelity items**: TDS 8.0 / `Encrypt=Strict` (ALPN via `SslApplicationProtocol`); user-supplied `X509Certificate2` — an add-on-demand public-surface expansion.
49
-
(Off-loopback binding shipped 2026-07-19 as `ListenNetworkAsync`, gated on a registered login; per-interface bind-address selection remains add-on-demand.)
50
-
(**Terminal crash boundary** shipped 2026-07-19 — an exception outside the typed catch list now emits a best-effort Msg 0 / severity 20 ERROR at a token boundary instead of a silent transport reset, `AtTokenBoundary`-gated for mid-token safety, on both the non-MARS and MARS session loops; see [`tds-endpoint.md`](tds-endpoint.md#terminal-crash-boundary).
Residual: cancel reaction is bounded by the in-flight statement's materialization, not interruptible inside a single statement's row loop.
53
-
**MARS** shipped 2026-07-18 — SMP demux/mux, strictly-additive prelogin negotiation, serialized cooperative multiplexing over one shared connection, per-session attention; see [`tds-endpoint.md`](tds-endpoint.md#mars-multiple-active-result-sets).
54
-
Residual: Msg 8628/8651 never raised, per-session response fully materialized under the execution gate.)
40
+
-**Smaller fidelity items**: TDS 8.0 / `Encrypt=Strict` (ALPN via `SslApplicationProtocol`); user-supplied `X509Certificate2` and per-interface bind-address selection — add-on-demand public-surface expansions.
41
+
Open residuals of shipped wire features (details in [`tds-endpoint.md`](tds-endpoint.md)): cancel/attention reaction is bounded by the in-flight statement's materialization, not interruptible inside a single statement's row loop; MARS never raises Msg 8628/8651 and fully materializes each session's response under the execution gate.
55
42
-**Chunked `OFFSET/FETCH` paging: per-page constant factor, complexity class matches real** (probed 2026-07-18, plans + timings): real SQL Server also redoes the work on every page — `Top(OFFSET…)` over an ordered index scan reading offset+fetch rows when an index supplies the order, or a full scan + `Sort(TOP offset+fetch)` re-sorted per page when not; no cross-query sorted-result caching exists on either side, so "sort once, serve many pages" is rejected (it would invent behavior real doesn't have).
56
43
The residual is constant-factor only: the simulator materializes (and for non-index order, sorts) all n rows per page regardless of offset where real's indexed plan touches only offset+fetch (measured at 150k rows / fetch 100 / offset 140k: sim ~41 ms vs real ~13 ms indexed, ~116 ms vs ~22 ms unindexed — real's sort is also 16-way parallel).
57
44
Possible lever if paged drains ever matter: recognize index-supplied order in the `OFFSET/FETCH` path (real's plan shape) to skip the sort and bound the scan.
@@ -81,11 +68,10 @@ Low priority / niche — simulatable (as placeholder constants or a small model)
81
68
A named-filegroup registry now ships (`Database.Filegroups`, seeded PRIMARY=1, extended by the bacpac loader's `SqlFilegroup` dispatch; surfaced by `sys.filegroups`/`sys.data_spaces` and FILEGROUP-scoped extended properties) — the scalar helpers above could read it, though a `file_id` 1 placeholder is still needed for the file-level ones.
82
69
-**Certificates** — CERTENCODED / CERTPRIVATEKEY (needs a small certificate-name → bytes model, or NULL placeholders).
83
70
-**Full-text properties** — FULLTEXTCATALOGPROPERTY (the `CREATE FULLTEXT CATALOG` / `INDEX` DDL already ships; this reads its metadata).
84
-
-**`sql_variant` mixed-inner-family ordering** — the last open piece of the `sql_variant` migration (all property scalars and catalog sql_variant columns now project true `sql_variant` with probed inner base types — 2026-07-19; see [`scalars.md`](scalars.md#sql_variant-expression-semantics), [`catalog-views.md`](catalog-views.md#the-sql_variant-type)).
85
-
`ORDER BY` / `GROUP BY` over a variant column with *mixed inner base-type families* (int + nvarchar in one column) isn't modeled — real orders by a datatype-family rank, the inner `CompareTo` rejects the cross-type pair (surfaces as `InvalidOperationException` from the sort).
86
-
Same-inner-family ordering, mixed-inner `DISTINCT`, and the single-scalar / comparison / `CAST` flows the built-ins realistically feed all work.
87
-
(Minor related quirk: a decimal-declared sequence/column's inner reports BaseType `numeric` rather than real's `decimal` — the single-decimal-family divergence.)
88
-
One catalog surface stays on `nvarchar` deliberately: `msdb.dbo.syspolicy_configuration.current_value` is a *view-body* projection (not a resource column) mixing `int` rows with a `binary` GUID row; every consumer reads a single named row and CASTs it, so the `nvarchar` surfacing is CAST-compatible and a variant migration there would only touch the view SQL text for no observable gain.
71
+
-**`sql_variant` mixed-inner-family ordering** — `ORDER BY` / `GROUP BY` over a variant column with *mixed inner base-type families* (int + nvarchar in one column) isn't modeled: real orders by a datatype-family rank, while the inner `CompareTo` rejects the cross-type pair (surfaces as `InvalidOperationException` from the sort).
72
+
Same-inner-family ordering, mixed-inner `DISTINCT`, and the single-scalar / comparison / `CAST` flows all work — see [`scalars.md`](scalars.md#sql_variant-expression-semantics), [`catalog-views.md`](catalog-views.md#the-sql_variant-type).
73
+
Related open quirk: a decimal-declared sequence/column's inner reports BaseType `numeric` rather than real's `decimal` — the single-decimal-family divergence.
74
+
Deliberate exclusion, don't re-pitch: `msdb.dbo.syspolicy_configuration.current_value` stays `nvarchar` — it's a *view-body* projection (not a resource column) mixing `int` rows with a `binary` GUID row, every consumer reads a single named row and CASTs it, so a variant migration there would only touch the view SQL text for no observable gain.
89
75
-**FILESTREAM** — GET_FILESTREAM_TRANSACTION_CONTEXT (needs a FILESTREAM storage binding; NULL is a faithful "no FILESTREAM context" placeholder).
90
76
91
77
## Fidelity gaps in shipped behavior
@@ -141,9 +127,6 @@ Worth a look before re-affirming or changing.
141
127
-**CHECKSUM_AGG** uses an order-independent XOR fold.
-**`@@TEXTSIZE`** — session state (`SimulatedDbConnection.TextSize`), default -1 (unlimited — the value a fresh SqlClient login establishes, probe-confirmed).
402
+
`SET TEXTSIZE` carries semantic effect: the byte cap clips MAX-typed / legacy-LOB values at the client boundary (result columns via the `TextSizeCursor` decorator installed by `SimulatedQueryResult.CreateClientCursor`, output parameters at write-back), never server-side computation, variable assignment, or stored data; `varchar(max)`/`text` truncate at 1 byte per char, `nvarchar(max)`/`ntext` at 2 with an odd byte floored, `varbinary(max)`/`image` at raw bytes, while `xml`, bounded var types, and UDTs are exempt.
403
+
Value mapping: `-1` preserved verbatim, `0` and every other negative collapse to 4096; a past-int-range literal raises **Msg 1080**; issued inside a proc body it reverts at proc exit while the body's result sets keep their production-time cap (`ClientTextSize` stamped per statement).
404
+
All probe-confirmed against SQL Server 2025 (2026-07-19).
402
405
-**`@@OPTIONS`** — 5432 (composite of ANSI/ARITHABORT/QUOTED_IDENTIFIER/CONCAT_NULL_YIELDS_NULL flags matching the simulator's defaults).
403
406
-**`@@VERSION`** — a multi-line banner mirroring the real SQL Server 2025 `@@VERSION` shape (`Microsoft SQL Server 2025 (RTM-CU7) (KB5096981) - 17.0.4065.4 (X64)` / build-date line / copyright / edition line), with the simulator's own identity (`Developer Edition (64-bit) on SQL Server Simulator`) standing in for real's host-OS line.
404
407
-**`@@MICROSOFTVERSION`** — int `285216737` (`0x11000FE1`), the `(major << 24) | (minor << 16) | build` packing of version `17.0.4065.4` (`(17 << 24) | 4065`), self-consistent with `SERVERPROPERTY('ProductVersion')` = `"17.0.4065.4"` and the real reference instance's value.
Copy file name to clipboardExpand all lines: docs/claude/tds-endpoint.md
+3-4Lines changed: 3 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -355,10 +355,9 @@ A value larger than one packet is written as one contiguous data block — the t
355
355
Both direct-proc RPC and `sp_executesql` bind identically.
356
356
Output-direction legacy-LOB parameters aren't a real SQL Server feature and don't arrive.
357
357
358
-
**Residuals.**
359
-
`SET TEXTSIZE` — real truncates returned `text`/`ntext`/`image` data to the byte limit; the simulator parse-and-discards TEXTSIZE (`Simulation.Set.cs`), so it always returns the full value.
360
-
**`SqlBulkCopy` into a `text`/`ntext`/`image` column** now decodes (see [Bulk load](#bulk-load-sqlbulkcopy) step 3).
**`SET TEXTSIZE` truncates at wire egress** (shipped 2026-07-19): the session byte cap clips `text`/`ntext`/`image` and the MAX-typed trio in result columns and output parameters — the truncation rides the shared client-boundary cursor (`SimulatedQueryResult.CreateClientCursor` → `TextSizeCursor`), so the TDS row writer inherits it; see [`scalars.md`](scalars.md) for the full semantics.
359
+
**`SqlBulkCopy` into a `text`/`ntext`/`image` column** decodes (see [Bulk load](#bulk-load-sqlbulkcopy) step 3).
Copy file name to clipboardExpand all lines: src/SqlServerSimulator/Network/CLAUDE.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -44,8 +44,8 @@ These notes are the local implementation contracts.
44
44
ROW value (`WriteLegacyLob`) = text-pointer-length byte + 16-byte placeholder pointer (`"dummy textptr\0\0\0"`) + 8-byte timestamp (`"dummyTS\0"`) + 4-byte data length + data (CP1252 text / UTF-16LE ntext / verbatim image); NULL is a single `0x00`.
45
45
`image`**input** parameters decode (`TdsRpc.DecodeImage`): 4-byte max size + 4-byte data length (`0xFFFFFFFF` = NULL) + raw bytes, contiguous (not PLP) even multi-packet, bound as `DbType.Binary`.
46
46
**`SqlBulkCopy` into a `text`/`ntext`/`image` column decodes** (`TdsColumnDecoder`'s legacy-LOB arm): COLMETADATA LONGLEN TYPE_INFO (4-byte max size + 5-byte collation for the string pair + a two-byte zero-part TableName field SqlClient sends in a client value stream) then the in-band text-pointer ROW value (1-byte ptr length `0`=NULL, else 16-byte ptr + 8-byte timestamp — both `0xFF` from SqlClient — 4-byte data length, data).
`SET TEXTSIZE`truncates legacy-LOB and MAX-typed result columns + output parameters at the client boundary (the shared `SimulatedQueryResult.CreateClientCursor` → `TextSizeCursor` seam, so the TDS row writer inherits it; docs/claude/scalars.md).
0 commit comments