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
OUTPUT INSERTED.* / DELETED.* / <source>.* star expansion — parse-time expansion across all three OUTPUT parsers (TryParseOutputClauseForMutation / TryParseOutputClause / TryParseMergeOutputClause). New TryDetectStarReference helper in Simulation.Output.cs uses SaveCheckpoint/RestoreCheckpoint to do lookahead-3 on the <Name>.* shape, leaving cursor on the * token for the caller to advance past; AppendStarExpansion synthesizes one Reference(qualifier, col) per target column (or per source-alias projected column, in MERGE), using the underlying column's leaf name as the output name (probe-confirmed against SQL Server 2025 — not the qualified INSERTED.col form). UPDATE / DELETE expand to the target table's columns under the existing allowInserted / allowDeleted gates (DELETE's INSERTED.* lands on Msg 4104 via the same path that already rejected INSERTED.col); INSERT expands INSERTED.* only; MERGE supports the full INSERTED.* / DELETED.* / <source>.* trio (DELETED columns NULL-fill on WHEN NOT MATCHED INSERT rows; INSERTED columns NULL-fill on WHEN MATCHED DELETE rows — inherited from the existing per-row resolver, no new runtime path). MERGE's $action handling refactored to flow through the same loop iteration with its alias-suffix check inline (previous structure forked the loop body before the alias check; star + $action coverage exposed it). Expansion runs before Expression.Parse, so the INSERTED.* AS alias shape inherits real SQL Server's Msg 102 rejection naturally — the cursor lands on , or end-of-OUTPUT terminator, never a bare alias-eligible Name. Unbound qualifier on .* raises Msg 4104 with the qualified form (foo.*) in the message. 11 new OutputClauseTests cover INSERT INSERTED.*, mixed-with-explicit, UPDATE both-stars, DELETE star, DELETE INSERTED.* and INSERT DELETED.* rejections, INSERT INSERTED.* INTO target, MERGE $action + INSERTED.* + DELETED.* with NULL-fill assertion across UPDATE / INSERT rows, MERGE source-alias s.*, and unbound-qualifier .* rejection. 3354 / 264 tests pass; dotnet format clean. CLAUDE.md "Not modeled" entry removed; docs/claude/dml.md OUTPUT bullet expanded with the parse-time-expansion mechanics, MERGE NULL-fill semantic, and alias-rejection inheritance note.
-`OUTPUT DELETED.*` / `INSERTED.*` star expansion. (`OUTPUT INTO <target>` ships for both `@t` and regular tables — see Table variables below.)
167
166
- MERGE source as a CTE-headed SELECT (`USING (WITH cte AS … SELECT …)`) — Selection.Parse's CTE entry doesn't reach the USING-clause grammar; wrap the CTE inside a regular SELECT instead. MERGE inside a CTE body, multi-statement MERGE WHEN-clause bodies, and `MERGE INTO <view>` (real SQL Server's updatable-view MERGE) are also deferred.
168
167
-`PRIMARY KEY` / `UNIQUE` on a computed column (`NotSupportedException`).
169
168
- Heap allocation tracking (flat page list, no IAM/PFS).
Copy file name to clipboardExpand all lines: docs/claude/dml.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
@@ -7,7 +7,7 @@
7
7
-**OUTPUT** supported only when the leading identifier resolves to a real table name; OUTPUT + alias-form multi-source → `NotSupportedException` (EF doesn't combine those).
8
8
-**Multi-column SET evaluates RHS against pre-update snapshot** — `UPDATE t SET a = 100, b = a + 1` over `(a=10, b=20)` → `(a=100, b=11)`. Scalar subquery RHS sees pre-update state.
9
9
- Identity update → Msg 8102. Computed update → Msg 271. Rowversion update → Msg 272. Per-row constraint re-validation: NOT NULL → Msg 515 ("UPDATE fails."); CHECK → Msg 547 ("UPDATE statement"); PK/UNIQUE → Msg 2627 (verbatim "Cannot insert duplicate key" wording even on UPDATE — SQL Server quirk). PK/UNIQUE validation runs against the post-update virtual state, so mass-shift on a unique key can false-positive (see Quirks).
10
-
-`OUTPUT INSERTED.<col>` (post-update) / `DELETED.<col>` (pre-update). UPDATE allows both qualifiers; DELETE rejects `INSERTED.<col>` at parse → Msg 4104. Star expansion (`INSERTED.*`/`DELETED.*`) not modeled. `OUTPUT … INTO @t [(cols)]` ships for INSERT/UPDATE/DELETE/MERGE — see [Table variables](table-variables.md).
10
+
- `OUTPUT INSERTED.<col>` (post-update) / `DELETED.<col>` (pre-update). UPDATE allows both qualifiers; DELETE rejects `INSERTED.<col>` at parse → Msg 4104. **Star expansion** (`INSERTED.*` / `DELETED.*`, plus the MERGE source-alias `<src>.*`) ships via parse-time expansion in `Simulation.Output.cs`: `TryDetectStarReference` peeks for the `<qualifier>.*` token sequence and `AppendStarExpansion` synthesizes one `Reference("qualifier", col)` per column of the target (or per column of the MERGE source alias). Expanded names take the underlying column's leaf (probe-confirmed — not the qualified form). The MERGE form keeps the per-action NULL-fill semantic for `INSERTED.* / DELETED.*` (DELETED columns are NULL on a WHEN NOT MATCHED INSERT row; INSERTED columns are NULL on a WHEN MATCHED DELETE row). Unbound qualifier on `.*` raises Msg 4104, same as `<qualifier>.<col>`. The expansion runs before `Expression.Parse`, so the alias-suffix shape (`INSERTED.* AS x`) inherits real SQL Server's Msg 102 rejection naturally — the cursor advances past `*` to either `,` or the end-of-OUTPUT terminator. `OUTPUT … INTO @t [(cols)]` ships for INSERT/UPDATE/DELETE/MERGE — see [Table variables](table-variables.md).
11
11
12
12
## `rowversion` (legacy synonym `timestamp`)
13
13
8-byte big-endian database-scoped monotonic counter; advances on every INSERT into a rowversion-bearing table and every UPDATE affecting one. Storage type name surfaces as `timestamp` in `information_schema` regardless of declaration. Explicit insert → Msg 273; explicit update → Msg 272; second column on a table → Msg 2738. Outbound CAST: `varbinary(N)`/`binary(N)` copy 8 bytes; `bigint` reads big-endian. `Promote(RowVersion, Varbinary) → Varbinary` so EF's `WHERE [rv] = @originalRv` parameter works directly. EF `[Timestamp]` SaveChanges round-trips end-to-end.
0 commit comments