@quereus/quereus 3.1.2 → 3.2.1
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/database-assertions.js +3 -3
- package/dist/src/core/database-assertions.js.map +1 -1
- package/dist/src/core/database.js +3 -3
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/statement.js +3 -3
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- 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/visitor.js +1 -1
- package/dist/src/parser/visitor.js.map +1 -1
- package/dist/src/planner/analysis/attribute-provenance.d.ts +45 -0
- package/dist/src/planner/analysis/attribute-provenance.d.ts.map +1 -0
- package/dist/src/planner/analysis/attribute-provenance.js +81 -0
- package/dist/src/planner/analysis/attribute-provenance.js.map +1 -0
- package/dist/src/planner/analysis/const-evaluator.js +5 -5
- package/dist/src/planner/analysis/const-evaluator.js.map +1 -1
- package/dist/src/planner/building/select-window.d.ts.map +1 -1
- package/dist/src/planner/building/select-window.js +54 -21
- package/dist/src/planner/building/select-window.js.map +1 -1
- package/dist/src/planner/cache/correlation-detector.d.ts +7 -0
- package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -1
- package/dist/src/planner/cache/correlation-detector.js +34 -2
- package/dist/src/planner/cache/correlation-detector.js.map +1 -1
- package/dist/src/planner/nodes/async-gather-node.d.ts +169 -0
- package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/async-gather-node.js +488 -0
- package/dist/src/planner/nodes/async-gather-node.js.map +1 -0
- package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.js +8 -7
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
- package/dist/src/planner/nodes/eager-prefetch-node.d.ts +47 -0
- package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/eager-prefetch-node.js +96 -0
- package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +150 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.js +265 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.js +8 -7
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.d.ts +3 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +3 -0
- package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +36 -0
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js +26 -0
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +13 -0
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/optimizer-tuning.d.ts +107 -0
- package/dist/src/planner/optimizer-tuning.d.ts.map +1 -1
- package/dist/src/planner/optimizer-tuning.js +43 -0
- package/dist/src/planner/optimizer-tuning.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +91 -0
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js +1 -6
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts +74 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +139 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts +58 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +592 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts +43 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js +115 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts +102 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +545 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts +45 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts.map +1 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js +78 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js.map +1 -0
- package/dist/src/planner/scopes/param.d.ts.map +1 -1
- package/dist/src/planner/scopes/param.js +13 -11
- package/dist/src/planner/scopes/param.js.map +1 -1
- package/dist/src/planner/type-utils.js +1 -1
- package/dist/src/planner/type-utils.js.map +1 -1
- package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.js +17 -19
- package/dist/src/planner/validation/plan-validator.js.map +1 -1
- package/dist/src/runtime/async-semaphore.d.ts +36 -0
- package/dist/src/runtime/async-semaphore.d.ts.map +1 -0
- package/dist/src/runtime/async-semaphore.js +72 -0
- package/dist/src/runtime/async-semaphore.js.map +1 -0
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +4 -3
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/emit/async-gather.d.ts +77 -0
- package/dist/src/runtime/emit/async-gather.d.ts.map +1 -0
- package/dist/src/runtime/emit/async-gather.js +234 -0
- package/dist/src/runtime/emit/async-gather.js.map +1 -0
- package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/bloom-join.js +38 -17
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/eager-prefetch.d.ts +77 -0
- package/dist/src/runtime/emit/eager-prefetch.d.ts.map +1 -0
- package/dist/src/runtime/emit/eager-prefetch.js +223 -0
- package/dist/src/runtime/emit/eager-prefetch.js.map +1 -0
- package/dist/src/runtime/emit/fanout-lookup-join.d.ts +130 -0
- package/dist/src/runtime/emit/fanout-lookup-join.d.ts.map +1 -0
- package/dist/src/runtime/emit/fanout-lookup-join.js +521 -0
- package/dist/src/runtime/emit/fanout-lookup-join.js.map +1 -0
- package/dist/src/runtime/parallel-driver.d.ts +68 -0
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -0
- package/dist/src/runtime/parallel-driver.js +233 -0
- package/dist/src/runtime/parallel-driver.js.map +1 -0
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +9 -0
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/strict-fork.d.ts +36 -0
- package/dist/src/runtime/strict-fork.d.ts.map +1 -0
- package/dist/src/runtime/strict-fork.js +125 -0
- package/dist/src/runtime/strict-fork.js.map +1 -0
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +11 -1
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/vtab/concurrency.d.ts +29 -0
- package/dist/src/vtab/concurrency.d.ts.map +1 -0
- package/dist/src/vtab/concurrency.js +47 -0
- package/dist/src/vtab/concurrency.js.map +1 -0
- package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.js +67 -29
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +21 -0
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +21 -0
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/module.d.ts +47 -0
- package/dist/src/vtab/module.d.ts.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: Async Gather ZIP BY KEY
|
|
3
|
+
*
|
|
4
|
+
* Recognizes a `Project` over a chain of binary full-outer `JoinNode`s that
|
|
5
|
+
* all equate the **same** key column set across every participating relation,
|
|
6
|
+
* and folds the whole shape into a single N-ary
|
|
7
|
+
* `AsyncGatherNode({ kind: 'zipByKey', branchKeyAttrs, outputKeyAttrs })`.
|
|
8
|
+
*
|
|
9
|
+
* Generalizes `rule-async-gather-union-all` from the `unionAll` combinator to
|
|
10
|
+
* `zipByKey`. The recognized SQL is the natural spelling of an N-way
|
|
11
|
+
* full-outer merge on a shared key:
|
|
12
|
+
*
|
|
13
|
+
* select coalesce(a.k, b.k, c.k) as k, a.av, b.bv, c.cv
|
|
14
|
+
* from a full outer join b on a.k = b.k
|
|
15
|
+
* full outer join c on a.k = c.k
|
|
16
|
+
*
|
|
17
|
+
* which the builder produces as:
|
|
18
|
+
*
|
|
19
|
+
* Project[ coalesce(a.k,b.k,c.k) as k, a.av, b.bv, c.cv ]
|
|
20
|
+
* Join(full, on a.k = c.k)
|
|
21
|
+
* Join(full, on a.k = b.k)
|
|
22
|
+
* <a> <b>
|
|
23
|
+
* <c>
|
|
24
|
+
*
|
|
25
|
+
* The binary full-outer chain is O(N²) null-padding and infers worse FDs than
|
|
26
|
+
* the symmetric N-ary merge; the `zipByKey` gather drives the N branches
|
|
27
|
+
* concurrently and hash-merges them by key. (Binary FULL JOIN has no runtime
|
|
28
|
+
* lowering at all — this rewrite is the only execution path for it.)
|
|
29
|
+
*
|
|
30
|
+
* ## Recognized shape
|
|
31
|
+
*
|
|
32
|
+
* 1. A `ProjectNode` whose `source` is a `JoinNode(joinType='full')`.
|
|
33
|
+
* 2. The full-join chain flattens (any nesting) into ≥ `minBranches` leaf
|
|
34
|
+
* branches. Each join's `ON` condition is a pure conjunction of
|
|
35
|
+
* column-ref equalities (no residual / non-equi predicate — those block).
|
|
36
|
+
* (`USING`/`NATURAL` full joins carry no synthesized `ON` condition, so the
|
|
37
|
+
* chain walk declines them — out of scope; see *Out of scope* below.)
|
|
38
|
+
* 3. Those equalities partition the branches' key columns into K equivalence
|
|
39
|
+
* classes ("key positions"), and **every branch contributes exactly one
|
|
40
|
+
* column to every class** (the shared-key precondition). A branch missing
|
|
41
|
+
* from any class would be a cross-product, not a zip — block.
|
|
42
|
+
* 4. The projection list must express, in **any order**:
|
|
43
|
+
* - K merged keys, each a `coalesce(...)` whose argument set is exactly
|
|
44
|
+
* one key class's per-branch key attrs; and
|
|
45
|
+
* - the forwarded non-key column references it selects (a subset is fine),
|
|
46
|
+
* plus arbitrary additional pure scalar expressions over those outputs
|
|
47
|
+
* (e.g. `coalesce(a.k, b.k) * 10`). The only hard constraint: a branch *key*
|
|
48
|
+
* column may appear **only** inside a recognizing full-group `coalesce` — a
|
|
49
|
+
* bare/partial reference to it (e.g. `select a.k …`) blocks, because the
|
|
50
|
+
* per-branch key is consumed into the single merged key and is unavailable
|
|
51
|
+
* above the gather.
|
|
52
|
+
*
|
|
53
|
+
* When the projection happens to be exactly the emitter's canonical order
|
|
54
|
+
* (`[K coalesce calls][branch0 non-key][branch1 non-key]…`), the gather
|
|
55
|
+
* replaces the `Project` outright (fast path). Otherwise the gather is built
|
|
56
|
+
* in canonical layout and wrapped in a thin reordering `Project` that
|
|
57
|
+
* reproduces the user's list (rewriting each full-group `coalesce` to a
|
|
58
|
+
* reference to the gather's merged-key output).
|
|
59
|
+
*
|
|
60
|
+
* ## Gates (mirror `rule-async-gather-union-all`)
|
|
61
|
+
*
|
|
62
|
+
* - **Concurrency safety.** Every branch must declare
|
|
63
|
+
* `physical.concurrencySafe === true`.
|
|
64
|
+
* - **Uncorrelated branches.** No branch may reference attributes outside its
|
|
65
|
+
* own subtree (lateral dependency) — the parallel driver forks independent
|
|
66
|
+
* contexts. `isCorrelatedSubquery` on each branch must be false.
|
|
67
|
+
* - **Latency win.** The slowest branch's `physical.expectedLatencyMs` must
|
|
68
|
+
* meet `tuning.parallel.gatherThresholdMs`. This is 0 on memory-vtab /
|
|
69
|
+
* in-process leaves, so the rule is inert by design on local-only plans
|
|
70
|
+
* (the golden-plan no-rewrite invariant).
|
|
71
|
+
* - **Key collation agreement.** Every key column at a given key position must
|
|
72
|
+
* declare the *same* collation across all branches (binary or not). The
|
|
73
|
+
* runtime comparator derives from branch 0 only, so a disagreement would
|
|
74
|
+
* compare keys under the wrong collation. Non-binary collations are allowed:
|
|
75
|
+
* the emitter composes the merged key deterministically from the
|
|
76
|
+
* lowest-indexed present branch (`composeMergedKeyCells`), matching
|
|
77
|
+
* `coalesce`'s left-to-right pick even when collation-equal keys are
|
|
78
|
+
* byte-distinct (e.g. NOCASE merging `'A'`/`'a'`). This mirrors the
|
|
79
|
+
* *agreement* invariant `AsyncGatherNode.validateZipByKey` enforces (which
|
|
80
|
+
* throws on a true mismatch); checking it here declines gracefully instead.
|
|
81
|
+
*
|
|
82
|
+
* ## Attribute provenance (Option A — per-branch refs + minted output keys)
|
|
83
|
+
*
|
|
84
|
+
* - `branchKeyAttrs[b]` — branch b's K key attr ids, in key order (distinct
|
|
85
|
+
* per branch; each branch originates its own key id — provenance-clean).
|
|
86
|
+
* - `outputKeyAttrs` — the K ids the `Project` minted for its `coalesce`
|
|
87
|
+
* outputs (computed expressions → fresh ids, disjoint from all child ids).
|
|
88
|
+
* The gather *mints* these, so `preserveAttributeIds[0..K-1] ===
|
|
89
|
+
* outputKeyAttrs` and downstream references to the coalesced key resolve.
|
|
90
|
+
* - `preserveAttributeIds` — the `Project`'s full output attribute list,
|
|
91
|
+
* which (because we matched the canonical order) is exactly
|
|
92
|
+
* `[minted keys] ++ [each branch's non-key attrs]`.
|
|
93
|
+
*
|
|
94
|
+
* ## Idempotence
|
|
95
|
+
*
|
|
96
|
+
* After the rewrite the matched node is an `AsyncGatherNode`, not a
|
|
97
|
+
* `ProjectNode`, so a second firing's matcher rejects immediately.
|
|
98
|
+
*/
|
|
99
|
+
import { createLogger } from '../../../common/logger.js';
|
|
100
|
+
import { PlanNode, isRelationalNode } from '../../nodes/plan-node.js';
|
|
101
|
+
import { ProjectNode } from '../../nodes/project-node.js';
|
|
102
|
+
import { JoinNode } from '../../nodes/join-node.js';
|
|
103
|
+
import { BinaryOpNode } from '../../nodes/scalar.js';
|
|
104
|
+
import { ColumnReferenceNode } from '../../nodes/reference.js';
|
|
105
|
+
import { ScalarFunctionCallNode } from '../../nodes/function.js';
|
|
106
|
+
import { AsyncGatherNode } from '../../nodes/async-gather-node.js';
|
|
107
|
+
import { isCorrelatedSubquery } from '../../cache/correlation-detector.js';
|
|
108
|
+
const log = createLogger('optimizer:rule:async-gather-zip-by-key');
|
|
109
|
+
export function ruleAsyncGatherZipByKey(node, context) {
|
|
110
|
+
if (!(node instanceof ProjectNode))
|
|
111
|
+
return null;
|
|
112
|
+
if (!(node.source instanceof JoinNode) || node.source.joinType !== 'full')
|
|
113
|
+
return null;
|
|
114
|
+
const tuning = context.tuning.parallel;
|
|
115
|
+
if (tuning.minBranches < 2)
|
|
116
|
+
return null;
|
|
117
|
+
// (1) Flatten the full-outer chain into leaf branches + ON conditions.
|
|
118
|
+
const branches = [];
|
|
119
|
+
const conditions = [];
|
|
120
|
+
if (!collectFullJoinChain(node.source, branches, conditions))
|
|
121
|
+
return null;
|
|
122
|
+
if (branches.length < tuning.minBranches)
|
|
123
|
+
return null;
|
|
124
|
+
// (2) Each ON condition must be a pure AND-of-column-equalities. Collect the
|
|
125
|
+
// (attrId, attrId) pairs; a residual / non-equi conjunct blocks the rewrite.
|
|
126
|
+
const equalities = [];
|
|
127
|
+
for (const cond of conditions) {
|
|
128
|
+
if (!extractKeyEqualities(cond, equalities)) {
|
|
129
|
+
log('Aborting: join condition has a residual / non-equi predicate');
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (equalities.length === 0)
|
|
134
|
+
return null;
|
|
135
|
+
// (3) Partition the equated columns into key groups (equivalence classes),
|
|
136
|
+
// requiring every branch to contribute exactly one column to every group.
|
|
137
|
+
const branchOfAttr = buildBranchOfAttr(branches);
|
|
138
|
+
const groups = buildKeyGroups(equalities, branchOfAttr, branches.length);
|
|
139
|
+
if (!groups)
|
|
140
|
+
return null;
|
|
141
|
+
const k = groups.length;
|
|
142
|
+
// Per-branch key attr ids in key-group order — shared by the gates and the
|
|
143
|
+
// reordering path. Key-position order is layout-independent here; the
|
|
144
|
+
// canonical fast path derives its own coalesce-aligned order separately.
|
|
145
|
+
const branchKeyAttrs = branches.map((_branch, b) => groups.map(g => g.byBranch[b]));
|
|
146
|
+
// Gates (mirror rule-async-gather-union-all). These are projection-layout
|
|
147
|
+
// independent, so they run once before deciding canonical-vs-reordered.
|
|
148
|
+
for (const branch of branches) {
|
|
149
|
+
if (branch.physical.concurrencySafe !== true) {
|
|
150
|
+
log('Aborting: branch %s is not concurrencySafe', branch.id);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
if (isCorrelatedSubquery(branch)) {
|
|
154
|
+
log('Aborting: branch %s is correlated (lateral dependency)', branch.id);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
let maxLatency = 0;
|
|
159
|
+
for (const branch of branches) {
|
|
160
|
+
const l = branch.physical.expectedLatencyMs ?? 0;
|
|
161
|
+
if (l > maxLatency)
|
|
162
|
+
maxLatency = l;
|
|
163
|
+
}
|
|
164
|
+
if (maxLatency < tuning.gatherThresholdMs)
|
|
165
|
+
return null;
|
|
166
|
+
// Collation agreement per key position (the runtime comparator uses branch
|
|
167
|
+
// 0's collation only). validateZipByKey also enforces this and *throws* on a
|
|
168
|
+
// mismatch, but checking here lets the rule decline the rewrite gracefully —
|
|
169
|
+
// the chain simply stays a JoinNode (which then errors at emit as an
|
|
170
|
+
// unsupported FULL JOIN, the pre-rule baseline) rather than aborting planning.
|
|
171
|
+
//
|
|
172
|
+
// Non-binary collations are permitted as long as every branch agrees on the
|
|
173
|
+
// collation per key position. The emitter's merged key value is deterministic
|
|
174
|
+
// (lowest-indexed present branch supplies the key cells — see
|
|
175
|
+
// `composeMergedKeyCells`), matching `coalesce`'s left-to-right pick even when
|
|
176
|
+
// collation-equal keys are byte-distinct (e.g. NOCASE merging 'A'/'a'). The
|
|
177
|
+
// branch-0-derived comparator is correct because the collations agree.
|
|
178
|
+
if (!keyCollationsAgree(branches, branchKeyAttrs, k)) {
|
|
179
|
+
log('Aborting: key columns disagree on collation across branches');
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
// Each branch must be key-unique on its equated key columns. The zipByKey
|
|
183
|
+
// emitter assumes one row per key per branch (a duplicate silently
|
|
184
|
+
// overwrites); a true FULL JOIN on a non-unique key would multiply rows, so
|
|
185
|
+
// folding a non-unique branch would change results. Require the zip key to
|
|
186
|
+
// cover a declared unique key of every branch.
|
|
187
|
+
if (!branchesKeyUnique(branches, branchKeyAttrs)) {
|
|
188
|
+
log('Aborting: a branch is not provably unique on the equated key columns');
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const concurrencyCap = Math.max(1, Math.min(tuning.concurrency, branches.length));
|
|
192
|
+
// (4a) Fast path: the projection is exactly the canonical zipByKey layout, so
|
|
193
|
+
// the gather replaces the Project outright (no reordering wrapper).
|
|
194
|
+
const canonical = matchCanonicalProjections(node, branches, groups, branchOfAttr);
|
|
195
|
+
if (canonical) {
|
|
196
|
+
log('Folding canonical full-outer zip chain of %d branches (K=%d) into AsyncGather(zipByKey) (cap=%d, maxLatency=%d ms)', branches.length, k, concurrencyCap, maxLatency);
|
|
197
|
+
return new AsyncGatherNode(node.scope, branches, { kind: 'zipByKey', branchKeyAttrs: canonical.branchKeyAttrs, outputKeyAttrs: canonical.outputKeyAttrs }, concurrencyCap, node.getAttributes());
|
|
198
|
+
}
|
|
199
|
+
// (4b) General path: arbitrary projection order / derived scalars over the
|
|
200
|
+
// merged-key and non-key outputs. Build the gather in its canonical layout
|
|
201
|
+
// and wrap it in a thin reordering Project reproducing the user's list.
|
|
202
|
+
const wrapped = buildReorderingGather(node, branches, groups, branchKeyAttrs, concurrencyCap);
|
|
203
|
+
if (!wrapped) {
|
|
204
|
+
log('Aborting: a projection references a branch key outside a full-group coalesce');
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
log('Folding reordered full-outer zip chain of %d branches (K=%d) into AsyncGather(zipByKey)+Project (cap=%d, maxLatency=%d ms)', branches.length, k, concurrencyCap, maxLatency);
|
|
208
|
+
return wrapped;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Build the canonical `zipByKey` gather and wrap it in a reordering `Project`
|
|
212
|
+
* that reproduces the user's projection list against the gather's canonical
|
|
213
|
+
* output. Each `coalesce(<exactly one full key group>)` sub-expression is
|
|
214
|
+
* rewritten to a bare reference to that group's merged-key output; non-key
|
|
215
|
+
* column refs and arbitrary pure scalar expressions over those outputs are
|
|
216
|
+
* carried through unchanged. Returns null if any branch key column is
|
|
217
|
+
* referenced outside a recognized full-group coalesce — such a reference is
|
|
218
|
+
* unavailable above the gather, which consumes each per-branch key into the
|
|
219
|
+
* single merged key.
|
|
220
|
+
*/
|
|
221
|
+
function buildReorderingGather(proj, branches, groups, branchKeyAttrs, concurrencyCap) {
|
|
222
|
+
// Mint the K merged-key output ids (key-group order) and build the gather in
|
|
223
|
+
// its natural [merged keys][branch non-key] layout. preserveAttributeIds is
|
|
224
|
+
// omitted so the node mints/forwards the canonical ids itself; the wrapper
|
|
225
|
+
// Project below restores the user's original output attribute ids.
|
|
226
|
+
const outputKeyAttrs = groups.map(() => PlanNode.nextAttrId());
|
|
227
|
+
const gather = new AsyncGatherNode(proj.scope, branches, { kind: 'zipByKey', branchKeyAttrs, outputKeyAttrs }, concurrencyCap);
|
|
228
|
+
const gatherAttrs = gather.getAttributes();
|
|
229
|
+
const keyAttrIds = new Set();
|
|
230
|
+
for (const g of groups)
|
|
231
|
+
for (const id of g.idSet)
|
|
232
|
+
keyAttrIds.add(id);
|
|
233
|
+
const outAttrs = proj.getAttributes();
|
|
234
|
+
const newProjections = [];
|
|
235
|
+
for (let i = 0; i < proj.projections.length; i++) {
|
|
236
|
+
const rewritten = rewriteMergedKeyRefs(proj.projections[i].node, groups, outputKeyAttrs, gatherAttrs, keyAttrIds);
|
|
237
|
+
if (!rewritten)
|
|
238
|
+
return null;
|
|
239
|
+
newProjections.push({
|
|
240
|
+
node: rewritten,
|
|
241
|
+
alias: proj.projections[i].alias,
|
|
242
|
+
attributeId: outAttrs[i].id,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return new ProjectNode(proj.scope, gather, newProjections, undefined, outAttrs, proj.preserveInputColumns);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Rewrite a projection scalar expression for evaluation above the gather:
|
|
249
|
+
* - `coalesce(<exactly one full key group's branch keys>)` → a bare reference
|
|
250
|
+
* to that group's merged-key output (`outputKeyAttrs[gi]`);
|
|
251
|
+
* - bare non-key column refs are forwarded unchanged (the gather forwards
|
|
252
|
+
* their ids); arbitrary pure scalar structure is rebuilt around the above;
|
|
253
|
+
* - any other reference to a branch *key* column blocks (returns null) — the
|
|
254
|
+
* per-branch key is consumed into the merged key and is unavailable above.
|
|
255
|
+
* Returns the rewritten expression, or null to decline the whole rewrite.
|
|
256
|
+
*/
|
|
257
|
+
function rewriteMergedKeyRefs(expr, groups, outputKeyAttrs, gatherAttrs, keyAttrIds) {
|
|
258
|
+
// coalesce over exactly one full key group → merged-key reference.
|
|
259
|
+
if (expr instanceof ScalarFunctionCallNode && expr.expression.name.toLowerCase() === 'coalesce') {
|
|
260
|
+
const gi = matchFullGroupCoalesce(expr, groups);
|
|
261
|
+
if (gi >= 0) {
|
|
262
|
+
const attr = gatherAttrs[gi];
|
|
263
|
+
return new ColumnReferenceNode(expr.scope, { type: 'column', name: attr.name }, attr.type, outputKeyAttrs[gi], gi);
|
|
264
|
+
}
|
|
265
|
+
// Not a full-group coalesce — fall through to generic child recursion.
|
|
266
|
+
}
|
|
267
|
+
if (expr instanceof ColumnReferenceNode) {
|
|
268
|
+
// A stray reference to a branch key column cannot survive the merge.
|
|
269
|
+
if (keyAttrIds.has(expr.attributeId))
|
|
270
|
+
return null;
|
|
271
|
+
return expr;
|
|
272
|
+
}
|
|
273
|
+
const children = expr.getChildren();
|
|
274
|
+
if (children.length === 0)
|
|
275
|
+
return expr;
|
|
276
|
+
const newChildren = [];
|
|
277
|
+
let changed = false;
|
|
278
|
+
for (const child of children) {
|
|
279
|
+
if (isRelationalNode(child)) {
|
|
280
|
+
// A relational child (e.g. a scalar subquery). Keep it only when it does
|
|
281
|
+
// not reference a consumed branch key column (conservative — such a
|
|
282
|
+
// reference would not resolve above the gather).
|
|
283
|
+
if (subtreeReferencesKey(child, keyAttrIds))
|
|
284
|
+
return null;
|
|
285
|
+
newChildren.push(child);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
const rewritten = rewriteMergedKeyRefs(child, groups, outputKeyAttrs, gatherAttrs, keyAttrIds);
|
|
289
|
+
if (!rewritten)
|
|
290
|
+
return null;
|
|
291
|
+
if (rewritten !== child)
|
|
292
|
+
changed = true;
|
|
293
|
+
newChildren.push(rewritten);
|
|
294
|
+
}
|
|
295
|
+
return changed ? expr.withChildren(newChildren) : expr;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* If `call`'s operands are exactly one key group's branch key columns (as bare
|
|
299
|
+
* column references), return that group's index; otherwise -1.
|
|
300
|
+
*/
|
|
301
|
+
function matchFullGroupCoalesce(call, groups) {
|
|
302
|
+
const argIds = [];
|
|
303
|
+
for (const operand of call.operands) {
|
|
304
|
+
if (!(operand instanceof ColumnReferenceNode))
|
|
305
|
+
return -1;
|
|
306
|
+
argIds.push(operand.attributeId);
|
|
307
|
+
}
|
|
308
|
+
return groups.findIndex(g => g.idSet.size === argIds.length && argIds.every(id => g.idSet.has(id)));
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Walk a plan subtree (relational + scalar children) for any column reference
|
|
312
|
+
* to a key attr id the merge consumes.
|
|
313
|
+
*/
|
|
314
|
+
function subtreeReferencesKey(node, keyAttrIds) {
|
|
315
|
+
if (node instanceof ColumnReferenceNode && keyAttrIds.has(node.attributeId))
|
|
316
|
+
return true;
|
|
317
|
+
for (const child of node.getChildren()) {
|
|
318
|
+
if (subtreeReferencesKey(child, keyAttrIds))
|
|
319
|
+
return true;
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Flatten a left-deep (or arbitrarily nested) chain of full-outer `JoinNode`s
|
|
325
|
+
* into leaf branches and ON conditions. Branch order mirrors the join's
|
|
326
|
+
* attribute concatenation (left subtree before right), so it lines up with the
|
|
327
|
+
* canonical projection layout. Returns false if a full join is missing its ON
|
|
328
|
+
* condition (cross-shaped full join — not recognizable).
|
|
329
|
+
*/
|
|
330
|
+
function collectFullJoinChain(node, branches, conditions) {
|
|
331
|
+
if (node instanceof JoinNode && node.joinType === 'full') {
|
|
332
|
+
if (!node.condition)
|
|
333
|
+
return false;
|
|
334
|
+
conditions.push(node.condition);
|
|
335
|
+
return collectFullJoinChain(node.left, branches, conditions)
|
|
336
|
+
&& collectFullJoinChain(node.right, branches, conditions);
|
|
337
|
+
}
|
|
338
|
+
branches.push(node);
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Walk a join condition collecting `=`-of-two-column-refs pairs as
|
|
343
|
+
* (attrId, attrId). Returns false if any conjunct is not an `AND` or a
|
|
344
|
+
* column=column equality (i.e. a residual predicate the zip can't absorb).
|
|
345
|
+
*/
|
|
346
|
+
function extractKeyEqualities(cond, out) {
|
|
347
|
+
const stack = [cond];
|
|
348
|
+
while (stack.length) {
|
|
349
|
+
const n = stack.pop();
|
|
350
|
+
if (!(n instanceof BinaryOpNode))
|
|
351
|
+
return false;
|
|
352
|
+
const op = n.expression.operator;
|
|
353
|
+
if (op === 'AND') {
|
|
354
|
+
stack.push(n.left, n.right);
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
if (op !== '=')
|
|
358
|
+
return false;
|
|
359
|
+
if (!(n.left instanceof ColumnReferenceNode) || !(n.right instanceof ColumnReferenceNode))
|
|
360
|
+
return false;
|
|
361
|
+
out.push([n.left.attributeId, n.right.attributeId]);
|
|
362
|
+
}
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
/** Map each branch attribute id to its branch index (for key-group membership). */
|
|
366
|
+
function buildBranchOfAttr(branches) {
|
|
367
|
+
const map = new Map();
|
|
368
|
+
branches.forEach((branch, b) => {
|
|
369
|
+
for (const attr of branch.getAttributes())
|
|
370
|
+
map.set(attr.id, b);
|
|
371
|
+
});
|
|
372
|
+
return map;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Union-find the equality pairs into key groups, then validate that each group
|
|
376
|
+
* holds exactly one attr from every branch. Returns null (block) on any
|
|
377
|
+
* cross-branch shape that isn't a clean shared key.
|
|
378
|
+
*/
|
|
379
|
+
function buildKeyGroups(equalities, branchOfAttr, branchCount) {
|
|
380
|
+
const parent = new Map();
|
|
381
|
+
const find = (x) => {
|
|
382
|
+
let root = x;
|
|
383
|
+
while (parent.get(root) !== root)
|
|
384
|
+
root = parent.get(root);
|
|
385
|
+
let cur = x;
|
|
386
|
+
while (parent.get(cur) !== root) {
|
|
387
|
+
const next = parent.get(cur);
|
|
388
|
+
parent.set(cur, root);
|
|
389
|
+
cur = next;
|
|
390
|
+
}
|
|
391
|
+
return root;
|
|
392
|
+
};
|
|
393
|
+
const ensure = (x) => { if (!parent.has(x))
|
|
394
|
+
parent.set(x, x); };
|
|
395
|
+
for (const [a, b] of equalities) {
|
|
396
|
+
// Every equated column must belong to one of the flattened branches.
|
|
397
|
+
if (!branchOfAttr.has(a) || !branchOfAttr.has(b))
|
|
398
|
+
return null;
|
|
399
|
+
ensure(a);
|
|
400
|
+
ensure(b);
|
|
401
|
+
parent.set(find(a), find(b));
|
|
402
|
+
}
|
|
403
|
+
const byRoot = new Map();
|
|
404
|
+
for (const id of parent.keys()) {
|
|
405
|
+
const root = find(id);
|
|
406
|
+
let members = byRoot.get(root);
|
|
407
|
+
if (!members) {
|
|
408
|
+
members = [];
|
|
409
|
+
byRoot.set(root, members);
|
|
410
|
+
}
|
|
411
|
+
members.push(id);
|
|
412
|
+
}
|
|
413
|
+
const groups = [];
|
|
414
|
+
for (const members of byRoot.values()) {
|
|
415
|
+
const byBranch = new Array(branchCount).fill(-1);
|
|
416
|
+
for (const id of members) {
|
|
417
|
+
const b = branchOfAttr.get(id);
|
|
418
|
+
if (byBranch[b] !== -1)
|
|
419
|
+
return null; // two key columns from one branch in one group
|
|
420
|
+
byBranch[b] = id;
|
|
421
|
+
}
|
|
422
|
+
if (byBranch.some(v => v === -1))
|
|
423
|
+
return null; // a branch is missing from this key group
|
|
424
|
+
groups.push({ byBranch, idSet: new Set(members) });
|
|
425
|
+
}
|
|
426
|
+
return groups;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Fast-path detector: is the projection list *exactly* the canonical zipByKey
|
|
430
|
+
* layout
|
|
431
|
+
* [ K coalesce(group) calls ] ++ [ branch0 non-key refs, branch1 non-key refs, … ]
|
|
432
|
+
* so the gather can replace the `Project` outright with no reordering wrapper?
|
|
433
|
+
* If so, derive `branchKeyAttrs` (ordered to match the coalesce order) and
|
|
434
|
+
* `outputKeyAttrs` (the coalesce output attr ids). Returns null on any mismatch —
|
|
435
|
+
* the caller then tries the general reordering path (`buildReorderingGather`).
|
|
436
|
+
*/
|
|
437
|
+
function matchCanonicalProjections(proj, branches, groups, branchOfAttr) {
|
|
438
|
+
const k = groups.length;
|
|
439
|
+
const projections = proj.projections;
|
|
440
|
+
const outAttrs = proj.getAttributes();
|
|
441
|
+
// Expected non-key tail: each branch's non-key attrs, in branch + column order.
|
|
442
|
+
const keyAttrIds = new Set();
|
|
443
|
+
for (const g of groups)
|
|
444
|
+
for (const id of g.idSet)
|
|
445
|
+
keyAttrIds.add(id);
|
|
446
|
+
const nonKeyTail = [];
|
|
447
|
+
for (const branch of branches) {
|
|
448
|
+
for (const attr of branch.getAttributes()) {
|
|
449
|
+
if (!keyAttrIds.has(attr.id))
|
|
450
|
+
nonKeyTail.push(attr.id);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (projections.length !== k + nonKeyTail.length)
|
|
454
|
+
return null;
|
|
455
|
+
// First K projections: each a coalesce over exactly one (still-unused) group.
|
|
456
|
+
const orderedGroups = [];
|
|
457
|
+
const outputKeyAttrs = [];
|
|
458
|
+
const usedGroup = new Set();
|
|
459
|
+
for (let p = 0; p < k; p++) {
|
|
460
|
+
const expr = projections[p].node;
|
|
461
|
+
if (!(expr instanceof ScalarFunctionCallNode))
|
|
462
|
+
return null;
|
|
463
|
+
if (expr.expression.name.toLowerCase() !== 'coalesce')
|
|
464
|
+
return null;
|
|
465
|
+
const argIds = [];
|
|
466
|
+
for (const operand of expr.operands) {
|
|
467
|
+
if (!(operand instanceof ColumnReferenceNode))
|
|
468
|
+
return null;
|
|
469
|
+
argIds.push(operand.attributeId);
|
|
470
|
+
}
|
|
471
|
+
const group = groups.find(g => !usedGroup.has(g)
|
|
472
|
+
&& g.idSet.size === argIds.length
|
|
473
|
+
&& argIds.every(id => g.idSet.has(id)));
|
|
474
|
+
if (!group)
|
|
475
|
+
return null;
|
|
476
|
+
usedGroup.add(group);
|
|
477
|
+
orderedGroups.push(group);
|
|
478
|
+
outputKeyAttrs.push(outAttrs[p].id);
|
|
479
|
+
}
|
|
480
|
+
// Remaining projections: bare column refs matching the non-key tail exactly.
|
|
481
|
+
for (let i = 0; i < nonKeyTail.length; i++) {
|
|
482
|
+
const expr = projections[k + i].node;
|
|
483
|
+
if (!(expr instanceof ColumnReferenceNode))
|
|
484
|
+
return null;
|
|
485
|
+
if (expr.attributeId !== nonKeyTail[i])
|
|
486
|
+
return null;
|
|
487
|
+
// A non-key projection must forward its source id (ProjectNode does this
|
|
488
|
+
// for bare column refs); confirm it actually belongs to a branch.
|
|
489
|
+
if (!branchOfAttr.has(expr.attributeId))
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
const branchKeyAttrs = branches.map((_branch, b) => orderedGroups.map(g => g.byBranch[b]));
|
|
493
|
+
return { branchKeyAttrs, outputKeyAttrs };
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Confirm every branch is provably unique on its equated key columns: some
|
|
497
|
+
* declared unique key of the branch must be covered by (a subset of) the zip's
|
|
498
|
+
* key-column indices. Branches without statistics-free uniqueness (no covering
|
|
499
|
+
* key) block the rewrite — the zip's one-row-per-key merge would otherwise
|
|
500
|
+
* differ from a true full join's per-key product.
|
|
501
|
+
*/
|
|
502
|
+
function branchesKeyUnique(branches, branchKeyAttrs) {
|
|
503
|
+
for (let b = 0; b < branches.length; b++) {
|
|
504
|
+
const attrs = branches[b].getAttributes();
|
|
505
|
+
const keyIndices = new Set();
|
|
506
|
+
for (const id of branchKeyAttrs[b]) {
|
|
507
|
+
const ix = attrs.findIndex((a) => a.id === id);
|
|
508
|
+
if (ix < 0)
|
|
509
|
+
return false;
|
|
510
|
+
keyIndices.add(ix);
|
|
511
|
+
}
|
|
512
|
+
const declaredKeys = branches[b].getType().keys;
|
|
513
|
+
const covered = declaredKeys.some(key => key.every(ref => keyIndices.has(ref.index)));
|
|
514
|
+
if (!covered)
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Confirm every branch's key column at every key position declares the **same**
|
|
521
|
+
* collation as branch 0's (absent collation = binary). The runtime comparator
|
|
522
|
+
* derives solely from branch 0's collations, so a disagreement would silently
|
|
523
|
+
* compare (and merge) keys under the wrong collation. Agreement is sufficient:
|
|
524
|
+
* the emitter's merged key value is deterministic (lowest-indexed present branch
|
|
525
|
+
* wins — see `composeMergedKeyCells`), so any agreed collation, binary or not,
|
|
526
|
+
* yields a well-defined merged key that matches `coalesce`.
|
|
527
|
+
*/
|
|
528
|
+
function keyCollationsAgree(branches, branchKeyAttrs, k) {
|
|
529
|
+
const norm = (c) => (c && c.length > 0 ? c.toUpperCase() : 'BINARY');
|
|
530
|
+
const collationOf = (branch, attrId) => {
|
|
531
|
+
const attrs = branch.getAttributes();
|
|
532
|
+
const cols = branch.getType().columns;
|
|
533
|
+
const ix = attrs.findIndex((a) => a.id === attrId);
|
|
534
|
+
return ix >= 0 ? norm(cols[ix].type.collationName) : 'BINARY';
|
|
535
|
+
};
|
|
536
|
+
for (let pos = 0; pos < k; pos++) {
|
|
537
|
+
const base = collationOf(branches[0], branchKeyAttrs[0][pos]);
|
|
538
|
+
for (let b = 1; b < branches.length; b++) {
|
|
539
|
+
if (collationOf(branches[b], branchKeyAttrs[b][pos]) !== base)
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
545
|
+
//# sourceMappingURL=rule-async-gather-zip-by-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-async-gather-zip-by-key.js","sourceRoot":"","sources":["../../../../../src/planner/rules/parallel/rule-async-gather-zip-by-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule: Eager Prefetch Probe
|
|
3
|
+
*
|
|
4
|
+
* Wraps the probe (`left`) input of a physical hash join in an
|
|
5
|
+
* `EagerPrefetchNode` when the build (`right`) side advertises high first-row
|
|
6
|
+
* latency, so the buffered pump can pipeline its probe-side reads with the
|
|
7
|
+
* parent emit's per-row work.
|
|
8
|
+
*
|
|
9
|
+
* Target shape: `BloomJoinNode` (physical, `PlanNodeType.HashJoin`). Per the
|
|
10
|
+
* node contract, **`left` is the probe (streamed) side** and `right` is the
|
|
11
|
+
* build (materialized) side — opposite of the textbook convention. The wrap
|
|
12
|
+
* target is therefore `left`.
|
|
13
|
+
*
|
|
14
|
+
* Cost gate: anchored on `node.right.physical.expectedLatencyMs`, the same
|
|
15
|
+
* field consumed by `rule-fanout-lookup-join` and `rule-async-gather-union-all`.
|
|
16
|
+
* That field is 0 on every in-process / memory-vtab leaf and non-zero only
|
|
17
|
+
* when a remote vtab plugin declares `expectedLatencyMs` at a leaf. As a
|
|
18
|
+
* consequence the rule is **inert by design on memory-vtab plans**, preserving
|
|
19
|
+
* the local-only golden-plan invariant the parallel rules already lock. We gate
|
|
20
|
+
* on the build side specifically: if `left` were the slow one the consumer
|
|
21
|
+
* above the join takes the latency hit regardless, so prefetching it doesn't
|
|
22
|
+
* change first-row time meaningfully.
|
|
23
|
+
*
|
|
24
|
+
* Skip predicates (the probe is already pump-driven or pre-materialized):
|
|
25
|
+
* - `left` is an `EagerPrefetchNode` — already wrapped (idempotence).
|
|
26
|
+
* - `left` is a `Cache` — pre-materialized; a prefetch over a cache buys
|
|
27
|
+
* nothing and confuses plan output.
|
|
28
|
+
* - `left` is an `AsyncGather` — already drives its branches concurrently;
|
|
29
|
+
* inserting a prefetch buffer just adds latency-of-first-row.
|
|
30
|
+
*
|
|
31
|
+
* Concurrency gate: as of the eager-start change, the prefetch pump begins on
|
|
32
|
+
* `run()` (scheduler arg-assembly), so the probe (`left`) subtree iterates
|
|
33
|
+
* **concurrently** with the build's for-await over `right`. If either side sits
|
|
34
|
+
* over a non-reentrant (`'serial'`) cursor, concurrent iteration corrupts state.
|
|
35
|
+
* We therefore only wrap when **both** `node.left` and `node.right` advertise
|
|
36
|
+
* `physical.concurrencySafe === true` (mirroring `rule-async-gather-union-all`'s
|
|
37
|
+
* strict `=== true` check — wrap only when *proven* safe; `undefined` blocks).
|
|
38
|
+
*
|
|
39
|
+
* Idempotence: after the rewrite `left` is an `EagerPrefetchNode`, so a second
|
|
40
|
+
* firing hits the first skip predicate and no-ops.
|
|
41
|
+
*/
|
|
42
|
+
import type { OptContext } from '../../framework/context.js';
|
|
43
|
+
import type { PlanNode } from '../../nodes/plan-node.js';
|
|
44
|
+
export declare function ruleEagerPrefetchProbe(node: PlanNode, context: OptContext): PlanNode | null;
|
|
45
|
+
//# sourceMappingURL=rule-eager-prefetch-probe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-eager-prefetch-probe.d.ts","sourceRoot":"","sources":["../../../../../src/planner/rules/parallel/rule-eager-prefetch-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAOzD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CAkC3F"}
|