@quereus/quereus 4.13.1 → 4.15.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/statement.d.ts +30 -0
- package/dist/src/core/statement.d.ts.map +1 -1
- package/dist/src/core/statement.js +49 -0
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/emit/ast-stringify.d.ts.map +1 -1
- package/dist/src/emit/ast-stringify.js +0 -4
- package/dist/src/emit/ast-stringify.js.map +1 -1
- package/dist/src/func/builtins/explain.d.ts.map +1 -1
- package/dist/src/func/builtins/explain.js +89 -62
- package/dist/src/func/builtins/explain.js.map +1 -1
- package/dist/src/func/registration.d.ts +7 -0
- package/dist/src/func/registration.d.ts.map +1 -1
- package/dist/src/func/registration.js +7 -0
- package/dist/src/func/registration.js.map +1 -1
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/ast.d.ts +0 -2
- package/dist/src/parser/ast.d.ts.map +1 -1
- package/dist/src/parser/parser.d.ts +1 -0
- package/dist/src/parser/parser.d.ts.map +1 -1
- package/dist/src/parser/parser.js +29 -28
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/src/planner/mutation/capture-correlation.d.ts +57 -0
- package/dist/src/planner/mutation/capture-correlation.d.ts.map +1 -0
- package/dist/src/planner/mutation/capture-correlation.js +57 -0
- package/dist/src/planner/mutation/capture-correlation.js.map +1 -0
- package/dist/src/planner/mutation/decomposition.d.ts.map +1 -1
- package/dist/src/planner/mutation/decomposition.js +86 -23
- package/dist/src/planner/mutation/decomposition.js.map +1 -1
- package/dist/src/planner/mutation/lens-enforcement.d.ts.map +1 -1
- package/dist/src/planner/mutation/lens-enforcement.js +15 -20
- package/dist/src/planner/mutation/lens-enforcement.js.map +1 -1
- package/dist/src/planner/mutation/multi-source.d.ts +52 -11
- package/dist/src/planner/mutation/multi-source.d.ts.map +1 -1
- package/dist/src/planner/mutation/multi-source.js +273 -86
- package/dist/src/planner/mutation/multi-source.js.map +1 -1
- package/dist/src/planner/mutation/set-op.d.ts.map +1 -1
- package/dist/src/planner/mutation/set-op.js +4 -12
- package/dist/src/planner/mutation/set-op.js.map +1 -1
- package/dist/src/planner/mutation/single-source.js +1 -1
- package/dist/src/planner/mutation/single-source.js.map +1 -1
- package/dist/src/runtime/emit/alter-table.d.ts.map +1 -1
- package/dist/src/runtime/emit/alter-table.js +8 -10
- package/dist/src/runtime/emit/alter-table.js.map +1 -1
- package/dist/src/runtime/emit/dml-executor.d.ts.map +1 -1
- package/dist/src/runtime/emit/dml-executor.js +23 -0
- package/dist/src/runtime/emit/dml-executor.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts +16 -4
- package/dist/src/runtime/emit/materialized-view-helpers.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view-helpers.js +182 -25
- package/dist/src/runtime/emit/materialized-view-helpers.js.map +1 -1
- package/dist/src/runtime/emit/materialized-view.d.ts.map +1 -1
- package/dist/src/runtime/emit/materialized-view.js +1 -1
- package/dist/src/runtime/emit/materialized-view.js.map +1 -1
- package/dist/src/runtime/emit/scan.d.ts.map +1 -1
- package/dist/src/runtime/emit/scan.js +52 -9
- package/dist/src/runtime/emit/scan.js.map +1 -1
- package/dist/src/runtime/emit/set-object-tags.js +4 -4
- package/dist/src/runtime/emit/set-object-tags.js.map +1 -1
- package/dist/src/runtime/emitters.d.ts.map +1 -1
- package/dist/src/runtime/emitters.js +6 -0
- package/dist/src/runtime/emitters.js.map +1 -1
- package/dist/src/runtime/parallel-driver.d.ts +5 -0
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -1
- package/dist/src/runtime/parallel-driver.js +6 -0
- package/dist/src/runtime/parallel-driver.js.map +1 -1
- package/dist/src/runtime/scheduler.d.ts +9 -0
- package/dist/src/runtime/scheduler.d.ts.map +1 -1
- package/dist/src/runtime/scheduler.js +27 -11
- package/dist/src/runtime/scheduler.js.map +1 -1
- package/dist/src/runtime/types.d.ts +19 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/dist/src/runtime/types.js.map +1 -1
- package/dist/src/runtime/work-counters.d.ts +180 -0
- package/dist/src/runtime/work-counters.d.ts.map +1 -0
- package/dist/src/runtime/work-counters.js +210 -0
- package/dist/src/runtime/work-counters.js.map +1 -0
- package/dist/src/schema/ddl-generator.d.ts.map +1 -1
- package/dist/src/schema/ddl-generator.js +65 -24
- package/dist/src/schema/ddl-generator.js.map +1 -1
- package/dist/src/schema/lens-ack.d.ts +1 -1
- package/dist/src/schema/lens-ack.js +2 -2
- package/dist/src/schema/lens-compiler.d.ts.map +1 -1
- package/dist/src/schema/lens-compiler.js +63 -34
- package/dist/src/schema/lens-compiler.js.map +1 -1
- package/dist/src/schema/lens-prover.d.ts +4 -4
- package/dist/src/schema/lens-prover.d.ts.map +1 -1
- package/dist/src/schema/lens-prover.js +13 -5
- package/dist/src/schema/lens-prover.js.map +1 -1
- package/dist/src/schema/lens.d.ts +1 -1
- package/dist/src/schema/manager.d.ts.map +1 -1
- package/dist/src/schema/manager.js +25 -13
- package/dist/src/schema/manager.js.map +1 -1
- package/dist/src/schema/reserved-tags.js +1 -1
- package/dist/src/schema/reserved-tags.js.map +1 -1
- package/dist/src/schema/schema-differ.d.ts.map +1 -1
- package/dist/src/schema/schema-differ.js +4 -3
- package/dist/src/schema/schema-differ.js.map +1 -1
- package/dist/src/schema/table.d.ts +41 -34
- package/dist/src/schema/table.d.ts.map +1 -1
- package/dist/src/schema/table.js +24 -43
- package/dist/src/schema/table.js.map +1 -1
- package/dist/src/vtab/alter-event-shape.d.ts +35 -0
- package/dist/src/vtab/alter-event-shape.d.ts.map +1 -0
- package/dist/src/vtab/alter-event-shape.js +47 -0
- package/dist/src/vtab/alter-event-shape.js.map +1 -0
- package/dist/src/vtab/memory/layer/alter-column.d.ts +8 -1
- package/dist/src/vtab/memory/layer/alter-column.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/alter-column.js +20 -10
- package/dist/src/vtab/memory/layer/alter-column.js.map +1 -1
- package/dist/src/vtab/memory/layer/base.d.ts +9 -1
- package/dist/src/vtab/memory/layer/base.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/base.js +12 -1
- package/dist/src/vtab/memory/layer/base.js.map +1 -1
- package/dist/src/vtab/memory/layer/manager.d.ts +23 -18
- package/dist/src/vtab/memory/layer/manager.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/manager.js +44 -33
- package/dist/src/vtab/memory/layer/manager.js.map +1 -1
- package/dist/src/vtab/memory/layer/row-convert.d.ts +13 -0
- package/dist/src/vtab/memory/layer/row-convert.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/row-convert.js +24 -0
- package/dist/src/vtab/memory/layer/row-convert.js.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.d.ts +21 -7
- package/dist/src/vtab/memory/layer/transaction.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/transaction.js +30 -14
- package/dist/src/vtab/memory/layer/transaction.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +0 -8
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +2 -25
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/module.d.ts +20 -2
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/package.json +6 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-source.d.ts","sourceRoot":"","sources":["../../../../src/planner/mutation/multi-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,uBAAuB,CAAC;AAGrF,OAAO,EAAY,KAAK,kBAAkB,EAAkB,KAAK,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC7I,OAAO,KAAK,EAAgB,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGzE,OAAO,EAAE,kBAAkB,EAAuB,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAI1F,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"multi-source.d.ts","sourceRoot":"","sources":["../../../../src/planner/mutation/multi-source.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ import { buildExpression } from '../building/expression.js';
|
|
|
8
8
|
import { columnSchemaToScalarType } from '../type-utils.js';
|
|
9
9
|
import { JoinNode } from '../nodes/join-node.js';
|
|
10
10
|
import { EXISTENCE_FLAG_TYPE } from '../nodes/join-utils.js';
|
|
11
|
+
import { captureKeyEquality } from './capture-correlation.js';
|
|
11
12
|
import { FilterNode } from '../nodes/filter.js';
|
|
12
13
|
import { ProjectNode } from '../nodes/project-node.js';
|
|
13
14
|
import { raiseMutationDiagnostic } from './mutation-diagnostic.js';
|
|
@@ -104,6 +105,21 @@ import { requireValidatedNewRefIndex } from '../analysis/authored-inverse.js';
|
|
|
104
105
|
* `k<sideIndex>_<pkColumnOrdinal>` ({@link keyColumnName}) — so a composite-PK side
|
|
105
106
|
* contributes `k<side>_0, k<side>_1, …`. This flattened per-side-per-column shape is
|
|
106
107
|
* what generalizes the substrate past the retired single-column `(k0, k1)` tuple.
|
|
108
|
+
*
|
|
109
|
+
* Two invariants keep the capture sound now that a key column may be nullable
|
|
110
|
+
* (`docs/schema.md` § Primary-key nullability — NULL is an ordinary, self-equal key value):
|
|
111
|
+
*
|
|
112
|
+
* 1. **Correlation is NULL-safe per nullable key column.** Every reader correlates a
|
|
113
|
+
* captured key column through {@link captureKeyEquality}: plain `=` for a column
|
|
114
|
+
* declared NOT NULL (index-friendly), `left = right or (left is null and right is
|
|
115
|
+
* null)` for a nullable one — so a row keyed NULL stays addressable.
|
|
116
|
+
* 2. **"Had no join partner" is carried explicitly.** For each captured non-preserved
|
|
117
|
+
* (outer-join) side the capture projects a boolean **match marker**
|
|
118
|
+
* (`m<side>` — {@link matchFlagName}), an {@link ExistenceColumnSpec} flag set by the
|
|
119
|
+
* join runtime from the actual null-extension decision. The outer-join branches read
|
|
120
|
+
* the marker — never "all of the side's captured key columns are NULL", which a real
|
|
121
|
+
* partner keyed NULL would satisfy too. A NULL marker (the flag itself null-extended
|
|
122
|
+
* by an enclosing outer join) reads as false.
|
|
107
123
|
*/
|
|
108
124
|
export const MS_UPDATE_KEYS_CTE = '__vmupd_keys';
|
|
109
125
|
/**
|
|
@@ -113,6 +129,33 @@ export const MS_UPDATE_KEYS_CTE = '__vmupd_keys';
|
|
|
113
129
|
export function keyColumnName(sideIndex, j) {
|
|
114
130
|
return `k${sideIndex}_${j}`;
|
|
115
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* The capture column name of side `sideIndex`'s **match marker** — the boolean
|
|
134
|
+
* "did this non-preserved side have a join partner" flag the capture projects
|
|
135
|
+
* alongside the side's `k<side>_<j>` key columns (invariant 2 of
|
|
136
|
+
* {@link MS_UPDATE_KEYS_CTE}). Minted only for captured non-preserved sides;
|
|
137
|
+
* readers and the capture projection both derive the name here so they cannot
|
|
138
|
+
* drift. Namespace-disjoint from `k<side>_<j>` and the `srcN` value aliases.
|
|
139
|
+
*/
|
|
140
|
+
export function matchFlagName(sideIndex) {
|
|
141
|
+
return `m${sideIndex}`;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The AST predicate reading side `sideIndex`'s capture match marker as "this side had
|
|
145
|
+
* NO join partner": `k.m<side> is null or not k.m<side>`. A NULL marker — the flag
|
|
146
|
+
* itself null-extended by an enclosing outer join in an n-way body — must read as
|
|
147
|
+
* false ("no partner"), so the declared NOT NULL of {@link EXISTENCE_FLAG_TYPE} is
|
|
148
|
+
* deliberately not assumed here.
|
|
149
|
+
*/
|
|
150
|
+
function matchFlagIsFalse(sideIndex) {
|
|
151
|
+
const flag = () => ({ type: 'column', name: matchFlagName(sideIndex), table: 'k' });
|
|
152
|
+
return {
|
|
153
|
+
type: 'binary',
|
|
154
|
+
operator: 'OR',
|
|
155
|
+
left: { type: 'unary', operator: 'IS NULL', expr: flag() },
|
|
156
|
+
right: { type: 'unary', operator: 'NOT', expr: flag() },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
116
159
|
// --- entry ----------------------------------------------------------------
|
|
117
160
|
/**
|
|
118
161
|
* True when the view body is a join (and so routes to this multi-source path
|
|
@@ -1351,12 +1394,14 @@ export function decomposeUpdate(ctx, view, analysis, stmt, sourceValues, capture
|
|
|
1351
1394
|
// Joins — Updates on a non-preserved-side column): where the non-preserved side
|
|
1352
1395
|
// matched it is an ordinary base update; where the row is null-extended (no match) it
|
|
1353
1396
|
// is rewritten as an insert on that side. Both ride the up-front `__vmupd_keys`
|
|
1354
|
-
// capture, materialized pre-mutation over the join body
|
|
1355
|
-
//
|
|
1356
|
-
//
|
|
1357
|
-
//
|
|
1358
|
-
//
|
|
1359
|
-
//
|
|
1397
|
+
// capture, materialized pre-mutation over the join body, and both partition on the
|
|
1398
|
+
// capture's explicit MATCH MARKER (invariant 2 of MS_UPDATE_KEYS_CTE): the matched
|
|
1399
|
+
// op correlates only marker-true capture rows; the null-extended op fires for the
|
|
1400
|
+
// marker-false rows. The assigned value is captured ONCE (so both branches read the
|
|
1401
|
+
// identical pre-mutation value), and the matched op reads it back keyed NULL-safely
|
|
1402
|
+
// on the non-preserved PK. Needs the capture carrier; the legacy
|
|
1403
|
+
// `propagateMultiSource` path (no carrier) keeps deferring with
|
|
1404
|
+
// `unsupported-outer-join-update`.
|
|
1360
1405
|
if (out.nullExtended && out.sideIndex !== undefined && out.baseColumn) {
|
|
1361
1406
|
if (!registerCapturedExpr) {
|
|
1362
1407
|
raiseMutationDiagnostic({
|
|
@@ -1382,13 +1427,15 @@ export function decomposeUpdate(ctx, view, analysis, stmt, sourceValues, capture
|
|
|
1382
1427
|
const baseValue = substituteViewColumns(ctx, asg.value, analysis.viewColToBaseRef, view, analysis.sides);
|
|
1383
1428
|
const valAlias = registerCapturedExpr(`neval:${out.sideIndex}:${out.baseColumn.toLowerCase()}`, baseValue);
|
|
1384
1429
|
// Matched rows: a per-side UPDATE reading the captured value back, correlated by
|
|
1385
|
-
// the non-preserved side's PK (`buildCapturedKeyPredicate`
|
|
1386
|
-
// matched rows
|
|
1387
|
-
//
|
|
1388
|
-
//
|
|
1389
|
-
//
|
|
1390
|
-
//
|
|
1391
|
-
|
|
1430
|
+
// the non-preserved side's PK (`buildCapturedKeyPredicate` restricts the op to
|
|
1431
|
+
// matched rows via the capture's match marker; `matchedOnly` gates this read-back
|
|
1432
|
+
// the same way, so a null-extended capture row — key columns NULL — cannot feed a
|
|
1433
|
+
// target row whose key genuinely holds NULL). The read-back is `min`-de-duped per
|
|
1434
|
+
// non-preserved partner: when N preserved rows share one existing partner, that
|
|
1435
|
+
// partner's PK matches all N capture rows, so a bare scalar read would error
|
|
1436
|
+
// `Scalar subquery returned more than one row` — `min` collapses the
|
|
1437
|
+
// shared-partner group to one value (a no-op for a constant / np-only SET).
|
|
1438
|
+
perSide[out.sideIndex].push({ column: out.baseColumn, value: capturedValueSubquery(valAlias, out.sideIndex, requireKeyColumns(view, npSide), { dedupAggregate: 'min', correlationAlias: SELF_ALIAS, captureRelationName, matchedOnly: true }) });
|
|
1392
1439
|
// Null-extended rows: accumulate the (column, captured value) for this side's
|
|
1393
1440
|
// single materialization insert, built after the loop.
|
|
1394
1441
|
let list = nullExtendedBySide.get(out.sideIndex);
|
|
@@ -1565,9 +1612,11 @@ export function decomposeUpdate(ctx, view, analysis, stmt, sourceValues, capture
|
|
|
1565
1612
|
ops.push(buildNullExtendedInsert(ctx, view, analysis, sideIndex, cols, registerCapturedExpr, stmt, captureRelationName));
|
|
1566
1613
|
}
|
|
1567
1614
|
// Existence-flip deletes (§ Existence columns): `set hasB = false` removes the matched
|
|
1568
|
-
// non-preserved rows
|
|
1569
|
-
//
|
|
1570
|
-
//
|
|
1615
|
+
// non-preserved rows — the captured-key EXISTS carries the capture's match-marker
|
|
1616
|
+
// conjunct (`buildCapturedKeyPredicate` on a non-preserved side), so a null-extended
|
|
1617
|
+
// capture row is excluded explicitly, not by its NULL key columns failing `=`. The
|
|
1618
|
+
// preserved side is untouched, so a deleted row reads back null-extended (`hasB` now
|
|
1619
|
+
// false).
|
|
1571
1620
|
for (const sideIndex of existenceDeleteSides) {
|
|
1572
1621
|
const side = analysis.sides[sideIndex];
|
|
1573
1622
|
const where = buildCapturedKeyPredicate(view, side, sideIndex, captureRelationName);
|
|
@@ -1595,12 +1644,14 @@ export function decomposeUpdate(ctx, view, analysis, stmt, sourceValues, capture
|
|
|
1595
1644
|
/**
|
|
1596
1645
|
* Build the null-extended materialization INSERT for a non-preserved outer-join side:
|
|
1597
1646
|
* `insert into <np> (<joinKey>, <set cols…>) select k.<jk>, min(k.<val…>) from __vmupd_keys k
|
|
1598
|
-
* where <
|
|
1599
|
-
* Updates). The `group by k.<jk>` de-dups per dangling join key so a shared missing
|
|
1600
|
-
* materializes exactly once (a fan-out of N preserved rows would otherwise
|
|
1601
|
-
* partner PK); the value projections are `min` so each is single-valued
|
|
1602
|
-
* fires only for the affected rows the join null-extended
|
|
1603
|
-
*
|
|
1647
|
+
* where (k.m<np> is null or not k.m<np>) and k.<jk> is not null group by k.<jk>` (§ Outer
|
|
1648
|
+
* Joins — Updates). The `group by k.<jk>` de-dups per dangling join key so a shared missing
|
|
1649
|
+
* partner materializes exactly once (a fan-out of N preserved rows would otherwise
|
|
1650
|
+
* double-insert the partner PK); the value projections are `min` so each is single-valued
|
|
1651
|
+
* per group. It fires only for the affected rows the join null-extended — the capture's
|
|
1652
|
+
* match marker says "no partner" (invariant 2 of {@link MS_UPDATE_KEYS_CTE}; a real matched
|
|
1653
|
+
* partner keyed NULL keeps its marker true and is never re-materialized) — whose
|
|
1654
|
+
* preserved-side join key is non-null (a null key cannot seed a joinable row).
|
|
1604
1655
|
* The new row carries the EC join key (so the preserved row joins it), the assigned
|
|
1605
1656
|
* value(s) read from the same pre-mutation `__vmupd_keys` capture the matched UPDATE reads,
|
|
1606
1657
|
* and base defaults for everything else; a NOT NULL base column without a default that no
|
|
@@ -1636,10 +1687,12 @@ function buildNullExtendedInsert(_ctx, view, analysis, npSideIndex, cols, regist
|
|
|
1636
1687
|
projections.push({ type: 'column', expr: { type: 'function', name: 'min', args: [{ type: 'column', name: c.valAlias, table: 'k' }] }, alias: c.baseColumn });
|
|
1637
1688
|
}
|
|
1638
1689
|
assertNullExtendedInsertCovered(view, npSide.schema, targetColumns);
|
|
1639
|
-
// Restrict to the null-extended partition:
|
|
1640
|
-
//
|
|
1641
|
-
//
|
|
1642
|
-
|
|
1690
|
+
// Restrict to the null-extended partition: the capture's match marker says this side
|
|
1691
|
+
// had NO join partner (invariant 2 of MS_UPDATE_KEYS_CTE — never "every captured PK
|
|
1692
|
+
// column is null", which a real matched partner keyed NULL would satisfy too; a NULL
|
|
1693
|
+
// marker reads as false), and the preserved join key is non-null (a null key has no
|
|
1694
|
+
// joinable row to create).
|
|
1695
|
+
const conds = [matchFlagIsFalse(npSideIndex)];
|
|
1643
1696
|
conds.push({ type: 'unary', operator: 'IS NOT NULL', expr: { type: 'column', name: jkAlias, table: 'k' } });
|
|
1644
1697
|
const where = conds.reduce((acc, c) => combineAnd(acc, c));
|
|
1645
1698
|
const select = {
|
|
@@ -1755,7 +1808,10 @@ function preservedSideIndices(sides) {
|
|
|
1755
1808
|
* <pk1> …])` — matching ALL of the side's PK columns (composite keys included) against
|
|
1756
1809
|
* the up-front materialized key set (the both-sides-assigned UPDATE path, every
|
|
1757
1810
|
* single-side update/delete, and the multi-side DELETE fan-out; see
|
|
1758
|
-
* {@link MS_UPDATE_KEYS_CTE}).
|
|
1811
|
+
* {@link MS_UPDATE_KEYS_CTE}). Each per-column equality is NULL-safe when the key column
|
|
1812
|
+
* is declared nullable ({@link captureKeyEquality} — invariant 1), and a non-preserved
|
|
1813
|
+
* side additionally conjoins its match marker (`k.m<side>` — invariant 2) so only
|
|
1814
|
+
* MATCHED capture rows correlate. The right-hand `<pk_j>` are unqualified, so they bind to
|
|
1759
1815
|
* the base op's own target table; `k.k<side>_<j>` reads the captured column. The builder
|
|
1760
1816
|
* injects `__vmupd_keys` into the base op's planning `cteNodes` (resolving to the
|
|
1761
1817
|
* context-backed key relation), so this is read by descriptor rather than re-querying
|
|
@@ -1764,12 +1820,15 @@ function preservedSideIndices(sides) {
|
|
|
1764
1820
|
*/
|
|
1765
1821
|
function buildCapturedKeyPredicate(view, side, sideIndex, captureRelationName = MS_UPDATE_KEYS_CTE) {
|
|
1766
1822
|
const keyCols = requireKeyColumns(view, side);
|
|
1767
|
-
const conds = keyCols.map((
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1823
|
+
const conds = keyCols.map((pk, j) => captureKeyEquality({ type: 'column', name: keyColumnName(sideIndex, j), table: 'k' }, { type: 'column', name: pk.name }, pk.nullable));
|
|
1824
|
+
// A non-preserved (outer-join) side correlates only its MATCHED capture rows: the
|
|
1825
|
+
// capture's match marker (invariant 2 of MS_UPDATE_KEYS_CTE) is AND'd in, so a
|
|
1826
|
+
// null-extended capture row — whose captured key columns are NULL — cannot
|
|
1827
|
+
// NULL-safe-match a real partner row whose key genuinely holds NULL. A NULL marker
|
|
1828
|
+
// reads as false (the bare-column conjunct is not-true for NULL).
|
|
1829
|
+
if (!side.preserved) {
|
|
1830
|
+
conds.push({ type: 'column', name: matchFlagName(sideIndex), table: 'k' });
|
|
1831
|
+
}
|
|
1773
1832
|
return {
|
|
1774
1833
|
type: 'exists',
|
|
1775
1834
|
subquery: {
|
|
@@ -1847,6 +1906,76 @@ export function capturedSideIndices(baseOps, analysis) {
|
|
|
1847
1906
|
}
|
|
1848
1907
|
return [...set].sort((a, b) => a - b);
|
|
1849
1908
|
}
|
|
1909
|
+
/** True when the `TableReferenceNode` with plan-node id `tableId` sits anywhere beneath `node`. */
|
|
1910
|
+
function subtreeContainsTable(node, tableId) {
|
|
1911
|
+
if (node instanceof TableReferenceNode)
|
|
1912
|
+
return Number(node.id) === tableId;
|
|
1913
|
+
return node.getRelations().some(child => subtreeContainsTable(child, tableId));
|
|
1914
|
+
}
|
|
1915
|
+
/**
|
|
1916
|
+
* Rebuild the capture's join tree with one synthetic {@link ExistenceColumnSpec} match
|
|
1917
|
+
* flag per requested non-preserved side (invariant 2 of {@link MS_UPDATE_KEYS_CTE}).
|
|
1918
|
+
* Each flag is appended at the **nearest enclosing join that null-extends its side** —
|
|
1919
|
+
* the join whose non-preserved child subtree contains the side's table — so the flag's
|
|
1920
|
+
* value is the actual null-extension decision for that side (`runtime/emit/join.ts`
|
|
1921
|
+
* sets it from the match bit, never from a re-evaluation of the ON predicate). For an
|
|
1922
|
+
* n-way body the ancestors are rebuilt around the flagged join; a flag minted below an
|
|
1923
|
+
* enclosing outer join is itself nullable-widened by the parent's attribute rebuild
|
|
1924
|
+
* (readers treat NULL as false). Attribute identity is preserved throughout: the
|
|
1925
|
+
* children are reused verbatim and only the `JoinNode` wrappers are re-created, with
|
|
1926
|
+
* each flag carrying a freshly minted stable attribute id.
|
|
1927
|
+
*
|
|
1928
|
+
* NOTE: a flag-bearing join is pinned to the nested-loop emitter (the existence-flag
|
|
1929
|
+
* guards disable physical join selection), so an outer-join write's capture forgoes
|
|
1930
|
+
* hash/merge join. The capture materializes once per statement; if outer-join view
|
|
1931
|
+
* writes over large bodies ever show up as slow, teach the physical joins to emit
|
|
1932
|
+
* match flags rather than weakening the guards.
|
|
1933
|
+
*/
|
|
1934
|
+
function rebuildJoinWithMatchFlags(view, root, sides, npSideIndices) {
|
|
1935
|
+
const flagsBySide = new Map();
|
|
1936
|
+
// Post-order: inner joins rebuild first, so each side is claimed at the NEAREST
|
|
1937
|
+
// join that null-extends it (a nested outer join claims before its ancestors).
|
|
1938
|
+
const rebuild = (node) => {
|
|
1939
|
+
if (!(node instanceof JoinNode))
|
|
1940
|
+
return node;
|
|
1941
|
+
const newLeft = rebuild(node.left);
|
|
1942
|
+
const newRight = rebuild(node.right);
|
|
1943
|
+
const nullExtends = (child) => (node.joinType === 'left' && child === 'right')
|
|
1944
|
+
|| (node.joinType === 'right' && child === 'left')
|
|
1945
|
+
|| node.joinType === 'full';
|
|
1946
|
+
const newSpecs = [];
|
|
1947
|
+
for (const i of npSideIndices) {
|
|
1948
|
+
if (flagsBySide.has(i))
|
|
1949
|
+
continue;
|
|
1950
|
+
const tableId = Number(sides[i].table.id);
|
|
1951
|
+
const child = subtreeContainsTable(node.left, tableId) ? 'left'
|
|
1952
|
+
: subtreeContainsTable(node.right, tableId) ? 'right'
|
|
1953
|
+
: undefined;
|
|
1954
|
+
if (!child || !nullExtends(child))
|
|
1955
|
+
continue;
|
|
1956
|
+
const spec = { attrId: PlanNode.nextAttrId(), name: matchFlagName(i), side: child };
|
|
1957
|
+
flagsBySide.set(i, spec);
|
|
1958
|
+
newSpecs.push(spec);
|
|
1959
|
+
}
|
|
1960
|
+
if (newLeft === node.left && newRight === node.right && newSpecs.length === 0)
|
|
1961
|
+
return node;
|
|
1962
|
+
return new JoinNode(node.scope, newLeft, newRight, node.joinType, node.condition, node.usingColumns, [...(node.existence ?? []), ...newSpecs]);
|
|
1963
|
+
};
|
|
1964
|
+
const rebuilt = rebuild(root);
|
|
1965
|
+
// A non-preserved side is, by collectJoinSources' classification, null-extended by
|
|
1966
|
+
// SOME enclosing outer join — a missing claim means the planned tree and the AST
|
|
1967
|
+
// classification disagree.
|
|
1968
|
+
for (const i of npSideIndices) {
|
|
1969
|
+
if (!flagsBySide.has(i)) {
|
|
1970
|
+
raiseMutationDiagnostic({
|
|
1971
|
+
reason: 'unsupported-join',
|
|
1972
|
+
table: view.name,
|
|
1973
|
+
message: `internal: cannot write through view '${view.name}': non-preserved side '${sides[i].schema.name}' did not resolve to a null-extending join for its match marker`,
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
return { joinNode: rebuilt, flagsBySide };
|
|
1978
|
+
}
|
|
1850
1979
|
/**
|
|
1851
1980
|
* Build the up-front identity capture: each affected view row's base-PK identities,
|
|
1852
1981
|
* by the same identifying predicate the base ops route on (user WHERE → base ∧ body
|
|
@@ -1885,9 +2014,23 @@ export function buildMultiSourceKeyCapture(ctx, view, where, analysis, sideIndic
|
|
|
1885
2014
|
const predicate = idPredicateAst
|
|
1886
2015
|
? buildExpression({ ...ctx, scope: analysis.joinScope }, idPredicateAst)
|
|
1887
2016
|
: undefined;
|
|
2017
|
+
// Match markers (invariant 2 of MS_UPDATE_KEYS_CTE): the capture — and ONLY the
|
|
2018
|
+
// capture — reads the join through a rebuilt copy carrying one synthetic
|
|
2019
|
+
// `ExistenceColumnSpec` per captured non-preserved side, so "did this side have a
|
|
2020
|
+
// join partner" is materialized explicitly (set by the join runtime from the actual
|
|
2021
|
+
// null-extension decision) instead of being inferred from NULL key columns. The
|
|
2022
|
+
// rebuild preserves every pre-existing attribute id (`buildJoinAttributes` copies
|
|
2023
|
+
// the child attributes verbatim), so `analysis.joinScope` still resolves the
|
|
2024
|
+
// identifying predicate and PK projections against it; the RETURNING re-query keeps
|
|
2025
|
+
// reading `analysis.joinNode` unchanged and reads `k.m<side>` out of the capture.
|
|
2026
|
+
// An all-preserved (inner-join) capture rebuilds nothing — byte-identical shape.
|
|
2027
|
+
const npSideIndices = sideIndices.filter(i => !analysis.sides[i].preserved);
|
|
2028
|
+
const { joinNode: captureJoin, flagsBySide } = npSideIndices.length > 0
|
|
2029
|
+
? rebuildJoinWithMatchFlags(view, analysis.joinNode, analysis.sides, npSideIndices)
|
|
2030
|
+
: { joinNode: analysis.joinNode, flagsBySide: new Map() };
|
|
1888
2031
|
const filtered = predicate
|
|
1889
|
-
? new FilterNode(analysis.joinScope,
|
|
1890
|
-
:
|
|
2032
|
+
? new FilterNode(analysis.joinScope, captureJoin, predicate)
|
|
2033
|
+
: captureJoin;
|
|
1891
2034
|
// One capture column per requested side per PK column: `k<side>_<j>`. A composite-PK
|
|
1892
2035
|
// side projects all its PK columns; the readers' EXISTS correlate on the same set.
|
|
1893
2036
|
const keyColumns = [];
|
|
@@ -1897,13 +2040,43 @@ export function buildMultiSourceKeyCapture(ctx, view, where, analysis, sideIndic
|
|
|
1897
2040
|
const pkCols = requireKeyColumns(view, side);
|
|
1898
2041
|
pkCols.forEach((pk, j) => {
|
|
1899
2042
|
const name = keyColumnName(i, j);
|
|
1900
|
-
keyColumns.push({ name, type: columnSchemaToScalarType(columnByName(side.schema, pk)) });
|
|
2043
|
+
keyColumns.push({ name, type: columnSchemaToScalarType(columnByName(side.schema, pk.name)) });
|
|
1901
2044
|
projections.push({
|
|
1902
|
-
node: buildExpression({ ...ctx, scope: analysis.joinScope }, { type: 'column', name: pk, table: side.alias }),
|
|
2045
|
+
node: buildExpression({ ...ctx, scope: analysis.joinScope }, { type: 'column', name: pk.name, table: side.alias }),
|
|
1903
2046
|
alias: name,
|
|
1904
2047
|
});
|
|
1905
2048
|
});
|
|
1906
2049
|
}
|
|
2050
|
+
// Project each non-preserved side's match marker as a capture column (`m<side>`),
|
|
2051
|
+
// referenced directly by the flag's own attribute id — the scope knows nothing of the
|
|
2052
|
+
// synthetic flags. The attribute's type is read off the rebuilt join (nullable-widened
|
|
2053
|
+
// when an enclosing outer join can null-extend the flag itself; readers treat NULL as
|
|
2054
|
+
// false).
|
|
2055
|
+
if (npSideIndices.length > 0) {
|
|
2056
|
+
const captureAttrs = captureJoin.getAttributes();
|
|
2057
|
+
for (const i of npSideIndices) {
|
|
2058
|
+
const spec = flagsBySide.get(i);
|
|
2059
|
+
const columnIndex = captureAttrs.findIndex(a => a.id === spec.attrId);
|
|
2060
|
+
if (columnIndex < 0) {
|
|
2061
|
+
// Unreachable by construction (the flag is minted on a join inside the rebuilt
|
|
2062
|
+
// spine, and `buildJoinAttributes` propagates every child attribute to the root);
|
|
2063
|
+
// named explicitly so a future rebuild regression fails legibly instead of as an
|
|
2064
|
+
// undefined-property TypeError.
|
|
2065
|
+
raiseMutationDiagnostic({
|
|
2066
|
+
reason: 'unsupported-join',
|
|
2067
|
+
table: view.name,
|
|
2068
|
+
message: `internal: cannot write through view '${view.name}': match marker '${matchFlagName(i)}' is missing from the rebuilt capture join's attributes`,
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
const flagType = captureAttrs[columnIndex].type;
|
|
2072
|
+
const name = matchFlagName(i);
|
|
2073
|
+
keyColumns.push({ name, type: flagType });
|
|
2074
|
+
projections.push({
|
|
2075
|
+
node: new ColumnReferenceNode(analysis.joinScope, { type: 'column', name }, flagType, spec.attrId, columnIndex),
|
|
2076
|
+
alias: name,
|
|
2077
|
+
});
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
1907
2080
|
// Cross-source SET read values: project each partner base column the SET reads under
|
|
1908
2081
|
// its stable `srcN` alias (over the same join-body scope), so every per-side base op's
|
|
1909
2082
|
// correlated `select srcN from __vmupd_keys k where …` reads the captured pre-mutation
|
|
@@ -1929,15 +2102,16 @@ export function buildMultiSourceKeyCapture(ctx, view, where, analysis, sideIndic
|
|
|
1929
2102
|
* still returned (single-source NEW semantics). It keeps only the structural join
|
|
1930
2103
|
* ON-condition; the body/user WHERE is intentionally NOT re-applied.
|
|
1931
2104
|
*
|
|
1932
|
-
* The per-side identity is **preserved-keyed**: a preserved side matches by
|
|
1933
|
-
*
|
|
1934
|
-
*
|
|
1935
|
-
*
|
|
1936
|
-
*
|
|
1937
|
-
*
|
|
1938
|
-
*
|
|
1939
|
-
*
|
|
1940
|
-
*
|
|
2105
|
+
* The per-side identity is **preserved-keyed**: a preserved side matches by per-PK-column
|
|
2106
|
+
* equality (`k.k<p>_<j> = s<p>.pk<j>`, NULL-safe per nullable key column —
|
|
2107
|
+
* {@link captureKeyEquality}), while a non-preserved (outer-join null-extended) side uses
|
|
2108
|
+
* a matched-OR-no-partner disjunction `(AND_j k.k<np>_<j> ≈ s<np>.pk<j>) OR (k.m<np> is
|
|
2109
|
+
* false-or-null)` keyed off the capture's **match marker** ({@link matchFlagName}). This
|
|
2110
|
+
* re-keys the re-query off the **stable preserved-side identity** so a freshly-materialized
|
|
2111
|
+
* null-extended row (whose marker was captured false) surfaces via its preserved-side
|
|
2112
|
+
* equalities alone, rather than being silently dropped by a `NULL = <minted pk>` match.
|
|
2113
|
+
* For an all-preserved (inner) join every side is plain equality over its NOT NULL key
|
|
2114
|
+
* columns — byte-identical to the prior behavior, so inner-join RETURNING is unchanged.
|
|
1941
2115
|
*
|
|
1942
2116
|
* Reads the shared {@link MultiSourceKeyCapture} the builder materializes
|
|
1943
2117
|
* before the base ops fire (via its own freshly-minted key ref over the same
|
|
@@ -1954,36 +2128,33 @@ export function buildMultiSourceUpdateReturning(ctx, view, stmt, capture, analys
|
|
|
1954
2128
|
// join row through `joinScope`.
|
|
1955
2129
|
//
|
|
1956
2130
|
// The per-side identity predicate is AND'd over all sides:
|
|
1957
|
-
// - a **preserved** side keys by
|
|
1958
|
-
//
|
|
1959
|
-
//
|
|
1960
|
-
//
|
|
1961
|
-
//
|
|
2131
|
+
// - a **preserved** side keys by per-PK-column equality (`AND_j k.k<side>_<j> =
|
|
2132
|
+
// s<side>.pk<j>`, NULL-safe when the column is declared nullable) — its PK is
|
|
2133
|
+
// stable across the mutation and uniquely identifies the view row (the premise
|
|
2134
|
+
// that makes a non-preserved column updatable at all);
|
|
2135
|
+
// - a **non-preserved** (outer-join null-extended) side keys by a matched-OR-no-
|
|
2136
|
+
// partner disjunction `(AND_j k.k<np>_<j> ≈ s<np>.pk<j>) OR (k.m<np> is null or
|
|
2137
|
+
// not k.m<np>)`.
|
|
1962
2138
|
//
|
|
1963
|
-
// A *matched* capture row (
|
|
1964
|
-
// stable np row
|
|
1965
|
-
//
|
|
1966
|
-
//
|
|
1967
|
-
// is identified by the preserved-side equalities ALONE
|
|
1968
|
-
// partner row (and a preserved-side update touching
|
|
1969
|
-
// latent partial-set bug #2).
|
|
1970
|
-
//
|
|
2139
|
+
// A *matched* capture row (marker true) takes the matched branch and finds the
|
|
2140
|
+
// stable np row (NULL-safe per nullable key column, so a partner genuinely keyed
|
|
2141
|
+
// NULL is still found); its no-partner branch is false. A *materialized
|
|
2142
|
+
// null-extended* capture row (marker false — it had no pre-mutation partner) takes
|
|
2143
|
+
// the no-partner branch, so it is identified by the preserved-side equalities ALONE
|
|
2144
|
+
// — surfacing the freshly-minted partner row (and a preserved-side update touching
|
|
2145
|
+
// a still-null-extended row, the latent partial-set bug #2). The marker — not "the
|
|
2146
|
+
// captured np PK is all NULL", which a real partner keyed NULL would satisfy too —
|
|
2147
|
+
// is what partitions the two branches (invariant 2 of MS_UPDATE_KEYS_CTE); a NULL
|
|
2148
|
+
// marker reads as false.
|
|
1971
2149
|
const sideConds = analysis.sides.map((side, sideIndex) => {
|
|
1972
2150
|
const pkCols = requireKeyColumns(view, side);
|
|
1973
|
-
const exact = pkCols.map((pk, j) => ({
|
|
1974
|
-
type: 'binary',
|
|
1975
|
-
operator: '=',
|
|
1976
|
-
left: { type: 'column', name: keyColumnName(sideIndex, j), table: 'k' },
|
|
1977
|
-
right: { type: 'column', name: pk, table: side.alias },
|
|
1978
|
-
})).reduce((acc, c) => combineAnd(acc, c));
|
|
2151
|
+
const exact = pkCols.map((pk, j) => captureKeyEquality({ type: 'column', name: keyColumnName(sideIndex, j), table: 'k' }, { type: 'column', name: pk.name, table: side.alias }, pk.nullable)).reduce((acc, c) => combineAnd(acc, c));
|
|
1979
2152
|
if (side.preserved)
|
|
1980
2153
|
return exact;
|
|
1981
|
-
//
|
|
1982
|
-
//
|
|
1983
|
-
//
|
|
1984
|
-
|
|
1985
|
-
.reduce((acc, c) => combineAnd(acc, c));
|
|
1986
|
-
return { type: 'binary', operator: 'OR', left: exact, right: allNull };
|
|
2154
|
+
// No-partner branch: the capture's match marker says this non-preserved side had
|
|
2155
|
+
// no pre-mutation join partner, so the row is identified by the preserved sides'
|
|
2156
|
+
// equalities alone.
|
|
2157
|
+
return { type: 'binary', operator: 'OR', left: exact, right: matchFlagIsFalse(sideIndex) };
|
|
1987
2158
|
});
|
|
1988
2159
|
// Read the capture's own relation name so a fresh-named capture's RETURNING re-query
|
|
1989
2160
|
// reads back from (and injects under) the same relation its base ops do — the constant
|
|
@@ -2405,7 +2576,7 @@ function stripSideQualifier(expr, view, owning, owningSideIndex, allSides, regis
|
|
|
2405
2576
|
// Qualify the owning-PK operands with the per-side UPDATE's collision-proof alias so
|
|
2406
2577
|
// the read-back correlates to the target row even when this subquery nests inside a
|
|
2407
2578
|
// user value subquery whose FROM has a same-named column (the bug-1 site).
|
|
2408
|
-
return capturedValueSubquery(srcAlias, owningSideIndex, owningPk,
|
|
2579
|
+
return capturedValueSubquery(srcAlias, owningSideIndex, owningPk, { correlationAlias: SELF_ALIAS });
|
|
2409
2580
|
};
|
|
2410
2581
|
// QUALIFIED-only substitution: an owning-alias ref is re-qualified to the lowered
|
|
2411
2582
|
// target's `__vm_self` correlation alias; a partner-alias ref
|
|
@@ -2467,14 +2638,23 @@ function stripSideQualifier(expr, view, owning, owningSideIndex, allSides, regis
|
|
|
2467
2638
|
* `captureRelationName` is the relation the correlated read scans (`from <name> k`); it
|
|
2468
2639
|
* defaults to {@link MS_UPDATE_KEYS_CTE} so the standalone multi-source and decomposition
|
|
2469
2640
|
* callers are byte-identical, while a nested multi-source capture threads its fresh name.
|
|
2641
|
+
*
|
|
2642
|
+
* Correlation is NULL-safe per nullable owning-PK column ({@link captureKeyEquality} —
|
|
2643
|
+
* invariant 1 of {@link MS_UPDATE_KEYS_CTE}); `matchedOnly` additionally restricts the
|
|
2644
|
+
* read to matched capture rows via the owning side's match marker (invariant 2) — the
|
|
2645
|
+
* non-preserved matched read-back passes it so a null-extended capture row cannot
|
|
2646
|
+
* pollute the aggregate for a target row keyed NULL.
|
|
2470
2647
|
*/
|
|
2471
|
-
export function capturedValueSubquery(srcAlias, owningSideIndex, owningPk,
|
|
2472
|
-
const
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2648
|
+
export function capturedValueSubquery(srcAlias, owningSideIndex, owningPk, options = {}) {
|
|
2649
|
+
const { dedupAggregate, correlationAlias, captureRelationName = MS_UPDATE_KEYS_CTE, matchedOnly = false } = options;
|
|
2650
|
+
const conds = owningPk.map((pk, j) => captureKeyEquality({ type: 'column', name: keyColumnName(owningSideIndex, j), table: 'k' }, correlationAlias ? { type: 'column', name: pk.name, table: correlationAlias } : { type: 'column', name: pk.name }, pk.nullable));
|
|
2651
|
+
// `matchedOnly`: restrict the read to MATCHED capture rows via the owning side's
|
|
2652
|
+
// match marker (the non-preserved matched read-back). Without it, a null-extended
|
|
2653
|
+
// capture row — key columns all NULL — would NULL-safe-match a target row whose key
|
|
2654
|
+
// genuinely holds NULL and pollute the aggregate with the null-extended branch's value.
|
|
2655
|
+
if (matchedOnly) {
|
|
2656
|
+
conds.push({ type: 'column', name: matchFlagName(owningSideIndex), table: 'k' });
|
|
2657
|
+
}
|
|
2478
2658
|
const colRef = { type: 'column', name: srcAlias, table: 'k' };
|
|
2479
2659
|
const projection = dedupAggregate
|
|
2480
2660
|
? { type: 'function', name: dedupAggregate, args: [colRef] }
|
|
@@ -2577,10 +2757,12 @@ function asBooleanLiteral(expr) {
|
|
|
2577
2757
|
return undefined;
|
|
2578
2758
|
}
|
|
2579
2759
|
/**
|
|
2580
|
-
* The side's primary-key
|
|
2581
|
-
* identifying key the capture projects and
|
|
2582
|
-
*
|
|
2583
|
-
*
|
|
2760
|
+
* The side's primary-key columns (≥1), in declaration order, each carrying its
|
|
2761
|
+
* **declared nullability** — the per-side identifying key the capture projects and
|
|
2762
|
+
* the base ops' EXISTS correlates on, NULL-safely per nullable column
|
|
2763
|
+
* ({@link captureKeyEquality}). Composite keys are admitted (each PK column
|
|
2764
|
+
* contributes a `k<side>_<j>` capture column); a keyless table is the only reject
|
|
2765
|
+
* (`unsupported-join`).
|
|
2584
2766
|
*/
|
|
2585
2767
|
function requireKeyColumns(view, side) {
|
|
2586
2768
|
const pk = side.schema.primaryKeyDefinition;
|
|
@@ -2591,7 +2773,10 @@ function requireKeyColumns(view, side) {
|
|
|
2591
2773
|
message: `cannot write through view '${view.name}': base table '${side.schema.name}' has no primary key; multi-source identifying predicates need a key`,
|
|
2592
2774
|
});
|
|
2593
2775
|
}
|
|
2594
|
-
return pk.map(def =>
|
|
2776
|
+
return pk.map(def => {
|
|
2777
|
+
const col = side.schema.columns[def.index];
|
|
2778
|
+
return { name: col.name, nullable: !col.notNull };
|
|
2779
|
+
});
|
|
2595
2780
|
}
|
|
2596
2781
|
/**
|
|
2597
2782
|
* True when `fk` (declared on `child`) targets `parent` — the shared FK-match
|
|
@@ -2784,8 +2969,10 @@ function resolveColumnSide(col, sides) {
|
|
|
2784
2969
|
* **non-partial** UNIQUE index. A **partial** unique key (one carrying a `predicate`) does
|
|
2785
2970
|
* not bound the rows outside its predicate scope, so it does not prove global at-most-one
|
|
2786
2971
|
* and is NOT counted. NULL semantics need no special handling — a `=` join only matches
|
|
2787
|
-
* non-null equal values and a unique key bounds each non-null value to ≤1 row
|
|
2788
|
-
*
|
|
2972
|
+
* non-null equal values and a unique key bounds each non-null value to ≤1 row. That holds
|
|
2973
|
+
* even for a nullable key column (key membership does not imply NOT NULL — `docs/schema.md`
|
|
2974
|
+
* § Primary-key nullability): key equality is NULL-self-equal, so uniqueness over the pinned
|
|
2975
|
+
* non-null values is if anything stronger.
|
|
2789
2976
|
*
|
|
2790
2977
|
* This is the inverse of the FK-correlation reasoning {@link edgeCorrelated} the delete
|
|
2791
2978
|
* path uses, but **FK is not required** — the proof is purely partner-side uniqueness (the
|