@crvouga/mockingbird-service-postgres 3.11.0 → 3.12.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/CHANGELOG.md +13 -0
- package/README.md +89 -1
- package/dist/admin.js +708 -82
- package/dist/admin.js.map +4 -4
- package/dist/api/buffered.d.ts +7 -0
- package/dist/api/durable.d.ts +12 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1985 -287
- package/dist/index.js.map +4 -4
- package/dist/indexes/index.d.ts +7 -0
- package/dist/indexes/maintain.d.ts +2 -0
- package/dist/planner/access.d.ts +15 -0
- package/dist/serialization/wire.d.ts +4 -0
- package/dist/server.js +772 -113
- package/dist/server.js.map +4 -4
- package/dist/shared/core/durability-browser.d.ts +52 -0
- package/dist/shared/core/durability-buffered.d.ts +65 -0
- package/dist/shared/core/durability.d.ts +78 -0
- package/dist/shared/core/fork-map.d.ts +51 -0
- package/dist/shared/core/index.d.ts +4 -0
- package/dist/shared/core/mount.d.ts +17 -0
- package/dist/shared/core/timeline.d.ts +80 -0
- package/dist/storage/database-state.d.ts +23 -0
- package/dist/unstable.js +647 -58
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +773 -114
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/index.js +772 -113
- package/dist/wire/index.js.map +4 -4
- package/package.json +1 -1
package/dist/wire/cli.js
CHANGED
|
@@ -1,5 +1,251 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// ../../core/dist/fork-map.js
|
|
4
|
+
var ForkMap = class _ForkMap {
|
|
5
|
+
owner = {};
|
|
6
|
+
index = { owner: this.owner, groups: [] };
|
|
7
|
+
order = { owner: this.owner, cells: [] };
|
|
8
|
+
shift = 0;
|
|
9
|
+
length = 0;
|
|
10
|
+
count = 0;
|
|
11
|
+
nextSequence = 0;
|
|
12
|
+
layout = 0;
|
|
13
|
+
cleared = 0;
|
|
14
|
+
version = 0;
|
|
15
|
+
constructor(entries) {
|
|
16
|
+
if (entries)
|
|
17
|
+
for (const [key, value] of entries)
|
|
18
|
+
this.set(key, value);
|
|
19
|
+
}
|
|
20
|
+
get size() {
|
|
21
|
+
return this.count;
|
|
22
|
+
}
|
|
23
|
+
get [Symbol.toStringTag]() {
|
|
24
|
+
return "Map";
|
|
25
|
+
}
|
|
26
|
+
fork() {
|
|
27
|
+
const copy = new _ForkMap();
|
|
28
|
+
copy.index = this.index;
|
|
29
|
+
copy.order = this.order;
|
|
30
|
+
copy.shift = this.shift;
|
|
31
|
+
copy.length = this.length;
|
|
32
|
+
copy.count = this.count;
|
|
33
|
+
copy.nextSequence = this.nextSequence;
|
|
34
|
+
this.owner = {};
|
|
35
|
+
return copy;
|
|
36
|
+
}
|
|
37
|
+
/** Visit changed hash buckets only. Values must be replaced, rather than mutated in place. */
|
|
38
|
+
*changes(previous) {
|
|
39
|
+
if (previous?.index === this.index)
|
|
40
|
+
return;
|
|
41
|
+
for (let group = 0; group < 32; group++) {
|
|
42
|
+
const currentGroup = this.index.groups[group];
|
|
43
|
+
const oldGroup = previous?.index.groups[group];
|
|
44
|
+
if (currentGroup === oldGroup)
|
|
45
|
+
continue;
|
|
46
|
+
for (let bucket = 0; bucket < 32; bucket++) {
|
|
47
|
+
const current = currentGroup?.buckets[bucket]?.data;
|
|
48
|
+
const old = oldGroup?.buckets[bucket]?.data;
|
|
49
|
+
if (current === old)
|
|
50
|
+
continue;
|
|
51
|
+
if (current)
|
|
52
|
+
for (const [key, entry] of current) {
|
|
53
|
+
const before = old?.get(key);
|
|
54
|
+
if (!before || !Object.is(before.value, entry.value) || before.sequence !== entry.sequence)
|
|
55
|
+
yield { key, value: entry.value, deleted: false };
|
|
56
|
+
}
|
|
57
|
+
if (old) {
|
|
58
|
+
for (const key of old.keys())
|
|
59
|
+
if (!current?.has(key))
|
|
60
|
+
yield { key, deleted: true };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
get(key) {
|
|
66
|
+
return this.find(key)?.value;
|
|
67
|
+
}
|
|
68
|
+
has(key) {
|
|
69
|
+
return this.find(key) !== void 0;
|
|
70
|
+
}
|
|
71
|
+
set(key, value) {
|
|
72
|
+
if (typeof key === "number" && key === 0)
|
|
73
|
+
key = 0;
|
|
74
|
+
const hash2 = hashKey(key);
|
|
75
|
+
const existing = this.bucket(hash2)?.get(key);
|
|
76
|
+
if (existing && Object.is(existing.value, value))
|
|
77
|
+
return this;
|
|
78
|
+
const entry = existing ? { ...existing, value } : { key, value, position: this.length++, sequence: this.nextSequence++ };
|
|
79
|
+
this.writableBucket(hash2).set(key, entry);
|
|
80
|
+
this.writeOrder(entry.position, entry);
|
|
81
|
+
if (!existing)
|
|
82
|
+
this.count++;
|
|
83
|
+
this.version++;
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
delete(key) {
|
|
87
|
+
const hash2 = hashKey(key);
|
|
88
|
+
const entry = this.bucket(hash2)?.get(key);
|
|
89
|
+
if (!entry)
|
|
90
|
+
return false;
|
|
91
|
+
this.writableBucket(hash2).delete(key);
|
|
92
|
+
this.writeOrder(entry.position, void 0);
|
|
93
|
+
this.count--;
|
|
94
|
+
this.version++;
|
|
95
|
+
if (this.length > 1024 && this.length > this.count * 2)
|
|
96
|
+
this.compact();
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
clear() {
|
|
100
|
+
this.index = { owner: this.owner, groups: [] };
|
|
101
|
+
this.order = { owner: this.owner, cells: [] };
|
|
102
|
+
this.shift = this.length = this.count = this.nextSequence = 0;
|
|
103
|
+
this.layout++;
|
|
104
|
+
this.cleared++;
|
|
105
|
+
this.version++;
|
|
106
|
+
}
|
|
107
|
+
entries() {
|
|
108
|
+
return this.iterate(0);
|
|
109
|
+
}
|
|
110
|
+
keys() {
|
|
111
|
+
return this.iterate(1);
|
|
112
|
+
}
|
|
113
|
+
values() {
|
|
114
|
+
return this.iterate(2);
|
|
115
|
+
}
|
|
116
|
+
[Symbol.iterator]() {
|
|
117
|
+
return this.entries();
|
|
118
|
+
}
|
|
119
|
+
forEach(callback, thisArg) {
|
|
120
|
+
for (const [key, value] of this)
|
|
121
|
+
callback.call(thisArg, value, key, this);
|
|
122
|
+
}
|
|
123
|
+
find(key) {
|
|
124
|
+
return this.bucket(hashKey(key))?.get(key);
|
|
125
|
+
}
|
|
126
|
+
bucket(hash2) {
|
|
127
|
+
return this.index.groups[hash2 >>> 5 & 31]?.buckets[hash2 & 31]?.data;
|
|
128
|
+
}
|
|
129
|
+
writableBucket(hash2) {
|
|
130
|
+
if (this.index.owner !== this.owner)
|
|
131
|
+
this.index = { owner: this.owner, groups: this.index.groups.slice() };
|
|
132
|
+
const groupIndex = hash2 >>> 5 & 31;
|
|
133
|
+
let group = this.index.groups[groupIndex];
|
|
134
|
+
if (!group || group.owner !== this.owner) {
|
|
135
|
+
group = { owner: this.owner, buckets: group?.buckets.slice() ?? [] };
|
|
136
|
+
this.index.groups[groupIndex] = group;
|
|
137
|
+
}
|
|
138
|
+
const at = hash2 & 31;
|
|
139
|
+
let bucket = group.buckets[at];
|
|
140
|
+
if (!bucket || bucket.owner !== this.owner) {
|
|
141
|
+
bucket = { owner: this.owner, data: bucket ? this.copyBucket(bucket.data) : /* @__PURE__ */ new Map() };
|
|
142
|
+
group.buckets[at] = bucket;
|
|
143
|
+
}
|
|
144
|
+
return bucket.data;
|
|
145
|
+
}
|
|
146
|
+
copyBucket(bucket) {
|
|
147
|
+
return new Map(bucket);
|
|
148
|
+
}
|
|
149
|
+
leaf(position) {
|
|
150
|
+
let node = this.order;
|
|
151
|
+
for (let shift = this.shift; shift > 0; shift -= 5)
|
|
152
|
+
node = node.cells[Math.floor(position / 2 ** shift) & 31];
|
|
153
|
+
return node;
|
|
154
|
+
}
|
|
155
|
+
writeOrder(position, entry) {
|
|
156
|
+
while (position >= 2 ** (this.shift + 5)) {
|
|
157
|
+
this.order = { owner: this.owner, cells: [this.order] };
|
|
158
|
+
this.shift += 5;
|
|
159
|
+
}
|
|
160
|
+
if (this.order.owner !== this.owner)
|
|
161
|
+
this.order = { owner: this.owner, cells: this.order.cells.slice() };
|
|
162
|
+
let node = this.order;
|
|
163
|
+
for (let shift = this.shift; shift > 0; shift -= 5) {
|
|
164
|
+
const at = Math.floor(position / 2 ** shift) & 31;
|
|
165
|
+
let child = node.cells[at];
|
|
166
|
+
if (!child || child.owner !== this.owner) {
|
|
167
|
+
child = { owner: this.owner, cells: child?.cells.slice() ?? [] };
|
|
168
|
+
node.cells[at] = child;
|
|
169
|
+
}
|
|
170
|
+
node = child;
|
|
171
|
+
}
|
|
172
|
+
node.cells[position & 31] = entry;
|
|
173
|
+
}
|
|
174
|
+
compact() {
|
|
175
|
+
const entries = [];
|
|
176
|
+
for (let position = 0; position < this.length; position++) {
|
|
177
|
+
const entry = this.leaf(position).cells[position & 31];
|
|
178
|
+
if (entry)
|
|
179
|
+
entries.push(entry);
|
|
180
|
+
}
|
|
181
|
+
this.index = { owner: this.owner, groups: [] };
|
|
182
|
+
this.order = { owner: this.owner, cells: [] };
|
|
183
|
+
this.shift = this.length = this.count = 0;
|
|
184
|
+
for (const original of entries) {
|
|
185
|
+
const entry = { ...original, position: this.length++ };
|
|
186
|
+
this.writableBucket(hashKey(entry.key)).set(entry.key, entry);
|
|
187
|
+
this.writeOrder(entry.position, entry);
|
|
188
|
+
this.count++;
|
|
189
|
+
}
|
|
190
|
+
this.layout++;
|
|
191
|
+
}
|
|
192
|
+
*iterate(kind) {
|
|
193
|
+
let position = 0;
|
|
194
|
+
let layout = this.layout;
|
|
195
|
+
let cleared = this.cleared;
|
|
196
|
+
let lastSequence = -1;
|
|
197
|
+
let version = -1;
|
|
198
|
+
let leaf;
|
|
199
|
+
let page = -1;
|
|
200
|
+
for (; ; ) {
|
|
201
|
+
if (cleared !== this.cleared) {
|
|
202
|
+
position = 0;
|
|
203
|
+
lastSequence = -1;
|
|
204
|
+
cleared = this.cleared;
|
|
205
|
+
}
|
|
206
|
+
if (layout !== this.layout) {
|
|
207
|
+
position = 0;
|
|
208
|
+
while (position < this.length) {
|
|
209
|
+
const entry2 = this.leaf(position).cells[position & 31];
|
|
210
|
+
if (entry2 && entry2.sequence > lastSequence)
|
|
211
|
+
break;
|
|
212
|
+
position++;
|
|
213
|
+
}
|
|
214
|
+
layout = this.layout;
|
|
215
|
+
}
|
|
216
|
+
if (position >= this.length)
|
|
217
|
+
return;
|
|
218
|
+
const nextPage = Math.floor(position / 32);
|
|
219
|
+
if (page !== nextPage || version !== this.version) {
|
|
220
|
+
leaf = this.leaf(position);
|
|
221
|
+
page = nextPage;
|
|
222
|
+
version = this.version;
|
|
223
|
+
}
|
|
224
|
+
const entry = leaf?.cells[position++ & 31];
|
|
225
|
+
if (!entry)
|
|
226
|
+
continue;
|
|
227
|
+
lastSequence = entry.sequence;
|
|
228
|
+
yield kind === 0 ? [entry.key, entry.value] : kind === 1 ? entry.key : entry.value;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
function hashKey(key) {
|
|
233
|
+
if (typeof key === "number" && Number.isInteger(key))
|
|
234
|
+
return mix((key | 0) ^ (key / 4294967296 | 0));
|
|
235
|
+
if (typeof key === "bigint")
|
|
236
|
+
return mix(Number(BigInt.asIntN(32, key ^ key >> 32n)));
|
|
237
|
+
const text = String(key);
|
|
238
|
+
let hash2 = 2166136261;
|
|
239
|
+
for (let i = 0; i < text.length; i++)
|
|
240
|
+
hash2 = Math.imul(hash2 ^ text.charCodeAt(i), 16777619);
|
|
241
|
+
return hash2;
|
|
242
|
+
}
|
|
243
|
+
function mix(value) {
|
|
244
|
+
value = Math.imul(value ^ value >>> 16, 73244475);
|
|
245
|
+
value = Math.imul(value ^ value >>> 16, 73244475);
|
|
246
|
+
return value ^ value >>> 16;
|
|
247
|
+
}
|
|
248
|
+
|
|
3
249
|
// ../../core/dist/timeline.js
|
|
4
250
|
var BRANCH_PATTERN = /^[A-Za-z0-9_.-]{1,64}$/;
|
|
5
251
|
var Timeline = class {
|
|
@@ -3798,7 +4044,7 @@ async function preflightFleet(config, options2) {
|
|
|
3798
4044
|
break;
|
|
3799
4045
|
}
|
|
3800
4046
|
}
|
|
3801
|
-
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.
|
|
4047
|
+
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.12.1" });
|
|
3802
4048
|
} catch (error) {
|
|
3803
4049
|
throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3804
4050
|
}
|
|
@@ -10358,10 +10604,81 @@ function parseArrayText(t, text, ctx) {
|
|
|
10358
10604
|
|
|
10359
10605
|
// src/storage/database-state.ts
|
|
10360
10606
|
var TableData = class _TableData {
|
|
10607
|
+
/** @internal Optional physical row journal; IDs remain stable across heap splices. */
|
|
10608
|
+
durableChanges = null;
|
|
10609
|
+
durableNextId = 0;
|
|
10610
|
+
durableEpoch;
|
|
10611
|
+
durableUnsafe = false;
|
|
10612
|
+
durableIds;
|
|
10613
|
+
enableDurabilityTracking(ids, nextId) {
|
|
10614
|
+
if (this.durableChanges && !this.durableUnsafe && !ids) return;
|
|
10615
|
+
this.materializeSlab();
|
|
10616
|
+
this.durableIds = /* @__PURE__ */ new WeakMap();
|
|
10617
|
+
this.durableChanges = new ForkMap();
|
|
10618
|
+
this.durableNextId = nextId ?? this.#rows.length;
|
|
10619
|
+
for (let i = 0; i < this.#rows.length; i++) this.durableIds.set(this.#rows[i], ids?.[i] ?? i);
|
|
10620
|
+
this.durableEpoch = {};
|
|
10621
|
+
this.durableUnsafe = false;
|
|
10622
|
+
}
|
|
10623
|
+
durableRowId(row) {
|
|
10624
|
+
const id = this.durableIds?.get(row);
|
|
10625
|
+
if (id === void 0) throw new Error("Untracked durable row");
|
|
10626
|
+
return id;
|
|
10627
|
+
}
|
|
10628
|
+
disableDurabilityTracking() {
|
|
10629
|
+
this.durableChanges = null;
|
|
10630
|
+
this.durableIds = void 0;
|
|
10631
|
+
this.durableEpoch = void 0;
|
|
10632
|
+
this.durableUnsafe = false;
|
|
10633
|
+
}
|
|
10634
|
+
recordDurableRow(row, previous) {
|
|
10635
|
+
if (!this.durableChanges) return;
|
|
10636
|
+
const id = (previous && this.durableIds?.get(previous)) ?? this.durableIds?.get(row) ?? this.durableNextId++;
|
|
10637
|
+
this.durableIds.set(row, id);
|
|
10638
|
+
this.durableChanges.set(id, { row, xmin: this.rowXmins.get(row) ?? 2 });
|
|
10639
|
+
}
|
|
10640
|
+
recordDurableDelete(row) {
|
|
10641
|
+
if (this.durableChanges) this.durableChanges.set(this.durableRowId(row), { row: null, xmin: 0 });
|
|
10642
|
+
}
|
|
10643
|
+
/** @internal Metadata twin with no visits/copies of existing rows or index entries. */
|
|
10644
|
+
emptyForDurability() {
|
|
10645
|
+
const copy = new _TableData(this.schema, this.name, this.columns, this.oid, this.temp);
|
|
10646
|
+
copy.constraints = this.constraints;
|
|
10647
|
+
copy.triggers = this.triggers;
|
|
10648
|
+
copy.unlogged = this.unlogged;
|
|
10649
|
+
return copy;
|
|
10650
|
+
}
|
|
10651
|
+
/** @internal Serialization/SQL scans must not count as public native-array exposure. */
|
|
10652
|
+
serializationRows() {
|
|
10653
|
+
this.materializeSlab();
|
|
10654
|
+
return this.materializedRows();
|
|
10655
|
+
}
|
|
10656
|
+
/** @internal Internal mutable array access, with ordinary public mutableRows kept intact. */
|
|
10657
|
+
writeRows() {
|
|
10658
|
+
return this.serializationRows();
|
|
10659
|
+
}
|
|
10660
|
+
/** @internal Ordinary snapshot branches must not inherit a persistence journal. */
|
|
10661
|
+
untrackedFork() {
|
|
10662
|
+
const copy = this.emptyForDurability();
|
|
10663
|
+
copy.rowXmins = this.rowXmins;
|
|
10664
|
+
copy.slabXmins = this.slabXmins;
|
|
10665
|
+
if (this.slab) copy.slab = this.slab;
|
|
10666
|
+
else {
|
|
10667
|
+
copy.#rows = this.#rows;
|
|
10668
|
+
copy.#rowPatches = this.#rowPatches?.fork() ?? null;
|
|
10669
|
+
copy.#rowsShared = this.#rowsShared = true;
|
|
10670
|
+
copy.tuplesShared = this.tuplesShared = true;
|
|
10671
|
+
}
|
|
10672
|
+
copy.indexStores = this.indexStores ? new Map([...this.indexStores].map(([name2, store]) => [name2, store.clone()])) : null;
|
|
10673
|
+
return copy;
|
|
10674
|
+
}
|
|
10361
10675
|
name;
|
|
10362
10676
|
schema;
|
|
10363
10677
|
columns;
|
|
10364
|
-
rows;
|
|
10678
|
+
#rows = [];
|
|
10679
|
+
#rowPatches = null;
|
|
10680
|
+
#rowsShared = false;
|
|
10681
|
+
#rowsExposed = false;
|
|
10365
10682
|
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
10366
10683
|
slabXmins = null;
|
|
10367
10684
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
@@ -10377,22 +10694,54 @@ var TableData = class _TableData {
|
|
|
10377
10694
|
shareCount = 0;
|
|
10378
10695
|
/** Derived unique/btree index maps; null until built or invalidated. */
|
|
10379
10696
|
indexStores = null;
|
|
10697
|
+
/** DML replaces tuples; DDL must detach them before changing cells in place. */
|
|
10698
|
+
tuplesShared = false;
|
|
10380
10699
|
constructor(schema, name2, columns, oid, temp = false) {
|
|
10381
10700
|
this.schema = schema;
|
|
10382
10701
|
this.name = name2;
|
|
10383
10702
|
this.columns = columns;
|
|
10384
|
-
this
|
|
10703
|
+
Object.defineProperty(this, "rows", {
|
|
10704
|
+
enumerable: true,
|
|
10705
|
+
configurable: true,
|
|
10706
|
+
get: this.nativeRows,
|
|
10707
|
+
set: this.setNativeRows
|
|
10708
|
+
});
|
|
10385
10709
|
this.constraints = [];
|
|
10386
10710
|
this.triggers = [];
|
|
10387
10711
|
this.temp = temp;
|
|
10388
10712
|
this.oid = oid;
|
|
10389
10713
|
}
|
|
10390
10714
|
rowCount() {
|
|
10391
|
-
return this.slab ? this.slab.rowCount : this
|
|
10715
|
+
return this.slab ? this.slab.rowCount : this.#rows.length;
|
|
10392
10716
|
}
|
|
10393
10717
|
rowAt(index) {
|
|
10394
10718
|
if (this.slab) return this.slab.rowAt(index);
|
|
10395
|
-
return this
|
|
10719
|
+
return this.#rowPatches?.get(index) ?? this.#rows[index] ?? [];
|
|
10720
|
+
}
|
|
10721
|
+
/** Replace an existing tuple without copying the array of unchanged row references. */
|
|
10722
|
+
replaceRow(index, row) {
|
|
10723
|
+
if (this.durableChanges) this.recordDurableRow(row, this.rowAt(index));
|
|
10724
|
+
if (this.#rowPatches) this.#rowPatches.set(index, row);
|
|
10725
|
+
else this.#rows[index] = row;
|
|
10726
|
+
}
|
|
10727
|
+
materializedRows() {
|
|
10728
|
+
if (this.#rowsShared) this.#rows = this.#rows.slice();
|
|
10729
|
+
if (this.#rowPatches) for (const [index, row] of this.#rowPatches) this.#rows[index] = row;
|
|
10730
|
+
this.#rowPatches = null;
|
|
10731
|
+
this.#rowsShared = false;
|
|
10732
|
+
return this.#rows;
|
|
10733
|
+
}
|
|
10734
|
+
nativeRows() {
|
|
10735
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
10736
|
+
this.#rowsExposed = true;
|
|
10737
|
+
return this.materializedRows();
|
|
10738
|
+
}
|
|
10739
|
+
setNativeRows(rows) {
|
|
10740
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
10741
|
+
this.#rows = rows;
|
|
10742
|
+
this.#rowPatches = null;
|
|
10743
|
+
this.#rowsShared = false;
|
|
10744
|
+
this.#rowsExposed = true;
|
|
10396
10745
|
}
|
|
10397
10746
|
/** All rows for scans; materializes slab once into `rows` when needed. */
|
|
10398
10747
|
allRows() {
|
|
@@ -10401,13 +10750,15 @@ var TableData = class _TableData {
|
|
|
10401
10750
|
}
|
|
10402
10751
|
attachSlab(slab) {
|
|
10403
10752
|
this.slab = slab;
|
|
10404
|
-
this
|
|
10753
|
+
this.#rows = [];
|
|
10754
|
+
this.#rowPatches = null;
|
|
10755
|
+
this.#rowsShared = false;
|
|
10405
10756
|
}
|
|
10406
10757
|
materializeSlab() {
|
|
10407
10758
|
if (!this.slab) return;
|
|
10408
|
-
this
|
|
10759
|
+
this.#rows = this.slab.materialize();
|
|
10409
10760
|
if (this.slabXmins)
|
|
10410
|
-
this
|
|
10761
|
+
this.#rows.forEach((row, index) => {
|
|
10411
10762
|
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
10412
10763
|
});
|
|
10413
10764
|
this.slabXmins = null;
|
|
@@ -10431,7 +10782,7 @@ var TableData = class _TableData {
|
|
|
10431
10782
|
columnIndex(name2) {
|
|
10432
10783
|
return this.columns.findIndex((c) => c.name === name2);
|
|
10433
10784
|
}
|
|
10434
|
-
|
|
10785
|
+
cloneMetadata() {
|
|
10435
10786
|
const t = new _TableData(
|
|
10436
10787
|
this.schema,
|
|
10437
10788
|
this.name,
|
|
@@ -10439,21 +10790,68 @@ var TableData = class _TableData {
|
|
|
10439
10790
|
this.oid,
|
|
10440
10791
|
this.temp
|
|
10441
10792
|
);
|
|
10793
|
+
t.unlogged = this.unlogged;
|
|
10794
|
+
t.durableChanges = this.durableChanges?.fork() ?? null;
|
|
10795
|
+
t.durableIds = this.durableIds;
|
|
10796
|
+
t.durableNextId = this.durableNextId;
|
|
10797
|
+
t.durableEpoch = this.durableEpoch;
|
|
10798
|
+
t.durableUnsafe = this.durableUnsafe;
|
|
10799
|
+
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
10800
|
+
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
10801
|
+
t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
|
|
10802
|
+
return t;
|
|
10803
|
+
}
|
|
10804
|
+
clone() {
|
|
10805
|
+
const t = this.cloneMetadata();
|
|
10806
|
+
if (t.durableChanges) t.durableUnsafe = true;
|
|
10442
10807
|
if (this.slab) {
|
|
10443
|
-
t
|
|
10808
|
+
t.#rows = this.slab.materialize().map((r) => r.slice());
|
|
10444
10809
|
} else {
|
|
10445
|
-
t
|
|
10810
|
+
t.#rows = this.materializedRows().map((r) => r.slice());
|
|
10446
10811
|
}
|
|
10447
|
-
t
|
|
10448
|
-
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this
|
|
10812
|
+
t.#rows.forEach((row, index) => {
|
|
10813
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.#rows[index]);
|
|
10449
10814
|
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
10450
10815
|
});
|
|
10451
|
-
t.unlogged = this.unlogged;
|
|
10452
|
-
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
10453
|
-
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
10454
|
-
t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
|
|
10455
10816
|
return t;
|
|
10456
10817
|
}
|
|
10818
|
+
/** DML creates new tuple arrays; retain existing tuples and xmin bindings until DDL. */
|
|
10819
|
+
cloneForDml() {
|
|
10820
|
+
if (this.triggers.length > 0) return this.cloneForWrite();
|
|
10821
|
+
const t = this.cloneMetadata();
|
|
10822
|
+
t.rowXmins = this.rowXmins;
|
|
10823
|
+
if (this.slab) {
|
|
10824
|
+
t.#rows = this.slab.materialize();
|
|
10825
|
+
if (this.slabXmins) {
|
|
10826
|
+
for (let index = 0; index < t.#rows.length; index++)
|
|
10827
|
+
t.rowXmins.set(t.#rows[index], this.slabXmins[index] ?? 2);
|
|
10828
|
+
}
|
|
10829
|
+
} else {
|
|
10830
|
+
if (this.#rows.length >= 4096 && !this.#rowsExposed) {
|
|
10831
|
+
this.#rowPatches ??= new ForkMap();
|
|
10832
|
+
t.#rowPatches = this.#rowPatches.fork();
|
|
10833
|
+
t.#rows = this.#rows;
|
|
10834
|
+
t.#rowsShared = this.#rowsShared = true;
|
|
10835
|
+
} else t.#rows = this.materializedRows().slice();
|
|
10836
|
+
this.tuplesShared = true;
|
|
10837
|
+
}
|
|
10838
|
+
t.tuplesShared = true;
|
|
10839
|
+
return t;
|
|
10840
|
+
}
|
|
10841
|
+
/** A live DML fork can be unfrozen while its unchanged tuples still belong to history. */
|
|
10842
|
+
ownTuples() {
|
|
10843
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
10844
|
+
if (!this.tuplesShared) return;
|
|
10845
|
+
const xmins = /* @__PURE__ */ new WeakMap();
|
|
10846
|
+
this.rows = this.rows.map((row) => {
|
|
10847
|
+
const copy = row.slice();
|
|
10848
|
+
const xmin = this.rowXmins.get(row);
|
|
10849
|
+
if (xmin !== void 0) xmins.set(copy, xmin);
|
|
10850
|
+
return copy;
|
|
10851
|
+
});
|
|
10852
|
+
this.rowXmins = xmins;
|
|
10853
|
+
this.tuplesShared = false;
|
|
10854
|
+
}
|
|
10457
10855
|
/** Independent writable copy (row tuples copied so ALTER COLUMN is isolated). */
|
|
10458
10856
|
cloneForWrite() {
|
|
10459
10857
|
const t = this.clone();
|
|
@@ -10807,12 +11205,21 @@ var DatabaseState = class _DatabaseState {
|
|
|
10807
11205
|
}
|
|
10808
11206
|
}
|
|
10809
11207
|
ensureWritableTable(table) {
|
|
10810
|
-
if (!table.frozen)
|
|
11208
|
+
if (!table.frozen) {
|
|
11209
|
+
table.ownTuples();
|
|
11210
|
+
return table;
|
|
11211
|
+
}
|
|
10811
11212
|
const schema = this.schemas.get(table.schema);
|
|
10812
11213
|
const copy = table.cloneForWrite();
|
|
10813
11214
|
schema?.tables.set(table.name, copy);
|
|
10814
11215
|
return copy;
|
|
10815
11216
|
}
|
|
11217
|
+
ensureWritableTableForDml(table) {
|
|
11218
|
+
if (!table.frozen) return table;
|
|
11219
|
+
const copy = table.cloneForDml();
|
|
11220
|
+
this.schemas.get(table.schema)?.tables.set(table.name, copy);
|
|
11221
|
+
return copy;
|
|
11222
|
+
}
|
|
10816
11223
|
ensureWritableSequence(seq) {
|
|
10817
11224
|
if ((seq.shareCount ?? 0) === 0) return seq;
|
|
10818
11225
|
const schema = this.schemas.get(seq.schema);
|
|
@@ -13928,7 +14335,7 @@ function evalPgcryptoFunction(ctx, fn, args2) {
|
|
|
13928
14335
|
// src/functions/hash-fns.ts
|
|
13929
14336
|
var utf83 = new TextEncoder();
|
|
13930
14337
|
var rot = (x, k) => (x << k | x >>> 32 - k) >>> 0;
|
|
13931
|
-
function
|
|
14338
|
+
function mix2(s) {
|
|
13932
14339
|
s[0] = s[0] - s[2] >>> 0;
|
|
13933
14340
|
s[0] = (s[0] ^ rot(s[2], 4)) >>> 0;
|
|
13934
14341
|
s[2] = s[2] + s[1] >>> 0;
|
|
@@ -13972,7 +14379,7 @@ function hashAny(k, seed) {
|
|
|
13972
14379
|
const bits = BigInt.asUintN(64, seed);
|
|
13973
14380
|
s[0] = s[0] + Number(bits >> 32n) >>> 0;
|
|
13974
14381
|
s[1] = s[1] + Number(bits & 0xffffffffn) >>> 0;
|
|
13975
|
-
|
|
14382
|
+
mix2(s);
|
|
13976
14383
|
}
|
|
13977
14384
|
let at = 0;
|
|
13978
14385
|
let len = k.length;
|
|
@@ -13980,7 +14387,7 @@ function hashAny(k, seed) {
|
|
|
13980
14387
|
s[0] = s[0] + word(k, at) >>> 0;
|
|
13981
14388
|
s[1] = s[1] + word(k, at + 4) >>> 0;
|
|
13982
14389
|
s[2] = s[2] + word(k, at + 8) >>> 0;
|
|
13983
|
-
|
|
14390
|
+
mix2(s);
|
|
13984
14391
|
}
|
|
13985
14392
|
for (let i = len - 1; i >= 0; i--) {
|
|
13986
14393
|
const byte = k[at + i];
|
|
@@ -20552,6 +20959,21 @@ var IndexStore = class _IndexStore {
|
|
|
20552
20959
|
name;
|
|
20553
20960
|
unique;
|
|
20554
20961
|
entries = /* @__PURE__ */ new Map();
|
|
20962
|
+
integerKeys = null;
|
|
20963
|
+
shared = false;
|
|
20964
|
+
ownedBuckets = /* @__PURE__ */ new WeakSet();
|
|
20965
|
+
writableBucket(key, bucket) {
|
|
20966
|
+
if (this.ownedBuckets.has(bucket)) return bucket;
|
|
20967
|
+
const copy = bucket.slice();
|
|
20968
|
+
this.entries.set(key, copy);
|
|
20969
|
+
this.ownedBuckets.add(copy);
|
|
20970
|
+
return copy;
|
|
20971
|
+
}
|
|
20972
|
+
detach() {
|
|
20973
|
+
if (!this.shared) return;
|
|
20974
|
+
if (!(this.entries instanceof ForkMap)) this.entries = new Map(this.entries);
|
|
20975
|
+
this.shared = false;
|
|
20976
|
+
}
|
|
20555
20977
|
constructor(name2, unique = false) {
|
|
20556
20978
|
this.name = name2;
|
|
20557
20979
|
this.unique = unique;
|
|
@@ -20570,36 +20992,78 @@ var IndexStore = class _IndexStore {
|
|
|
20570
20992
|
}
|
|
20571
20993
|
insert(key, rowIdx) {
|
|
20572
20994
|
if (this.unique) this.checkUnique(key, rowIdx);
|
|
20995
|
+
this.detach();
|
|
20996
|
+
this.integerKeys = null;
|
|
20573
20997
|
const existing = this.entries.get(key);
|
|
20574
20998
|
if (!existing) {
|
|
20575
|
-
|
|
20999
|
+
const bucket = [rowIdx];
|
|
21000
|
+
this.ownedBuckets.add(bucket);
|
|
21001
|
+
this.entries.set(key, bucket);
|
|
20576
21002
|
return;
|
|
20577
21003
|
}
|
|
20578
21004
|
if (existing.includes(rowIdx)) return;
|
|
20579
|
-
existing.push(rowIdx);
|
|
21005
|
+
this.writableBucket(key, existing).push(rowIdx);
|
|
20580
21006
|
}
|
|
20581
21007
|
remove(key, rowIdx) {
|
|
20582
21008
|
const existing = this.entries.get(key);
|
|
20583
21009
|
if (!existing) return;
|
|
20584
21010
|
const at = existing.indexOf(rowIdx);
|
|
20585
21011
|
if (at < 0) return;
|
|
20586
|
-
|
|
20587
|
-
|
|
21012
|
+
this.detach();
|
|
21013
|
+
this.integerKeys = null;
|
|
21014
|
+
if (existing.length === 1) this.entries.delete(key);
|
|
21015
|
+
else {
|
|
21016
|
+
const remaining = this.writableBucket(key, existing);
|
|
21017
|
+
remaining.splice(at, 1);
|
|
21018
|
+
this.entries.set(key, remaining);
|
|
21019
|
+
}
|
|
20588
21020
|
}
|
|
20589
21021
|
lookup(key) {
|
|
20590
21022
|
return this.entries.get(key) ?? [];
|
|
20591
21023
|
}
|
|
21024
|
+
/** Ordered access for a single int2/int4 key (the planner validates the key type). */
|
|
21025
|
+
integerRange(lower, upper, includeLower, includeUpper) {
|
|
21026
|
+
const keys = this.integerKeys ??= [...this.entries].map(([key, rows]) => ({ value: Number(key.slice(1)), rows })).sort((a, b) => a.value - b.value);
|
|
21027
|
+
let lo = 0;
|
|
21028
|
+
let hi = keys.length;
|
|
21029
|
+
while (lo < hi) {
|
|
21030
|
+
const mid = lo + hi >>> 1;
|
|
21031
|
+
const value = keys[mid].value;
|
|
21032
|
+
if (value < lower || !includeLower && value === lower) lo = mid + 1;
|
|
21033
|
+
else hi = mid;
|
|
21034
|
+
}
|
|
21035
|
+
const result = [];
|
|
21036
|
+
for (let i = lo; i < keys.length; i++) {
|
|
21037
|
+
const key = keys[i];
|
|
21038
|
+
if (key.value > upper || !includeUpper && key.value === upper) break;
|
|
21039
|
+
result.push(...key.rows);
|
|
21040
|
+
}
|
|
21041
|
+
return result.sort((a, b) => a - b);
|
|
21042
|
+
}
|
|
20592
21043
|
clear() {
|
|
20593
|
-
this.entries
|
|
21044
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
21045
|
+
this.shared = false;
|
|
21046
|
+
this.integerKeys = null;
|
|
20594
21047
|
}
|
|
20595
21048
|
clone() {
|
|
20596
21049
|
const copy = new _IndexStore(this.name, this.unique);
|
|
20597
|
-
|
|
21050
|
+
if (this.entries.size >= 4096 && !(this.entries instanceof ForkMap)) this.entries = new ForkMap(this.entries);
|
|
21051
|
+
copy.entries = this.entries instanceof ForkMap ? this.entries.fork() : this.entries;
|
|
21052
|
+
copy.integerKeys = this.integerKeys;
|
|
21053
|
+
copy.shared = true;
|
|
21054
|
+
this.shared = true;
|
|
21055
|
+
this.ownedBuckets = /* @__PURE__ */ new WeakSet();
|
|
20598
21056
|
return copy;
|
|
20599
21057
|
}
|
|
20600
21058
|
};
|
|
20601
21059
|
|
|
20602
21060
|
// src/indexes/maintain.ts
|
|
21061
|
+
function prepareDmlIndexStores(env, table) {
|
|
21062
|
+
if (table.indexStores || !table.frozen || table.triggers.length > 0) return;
|
|
21063
|
+
const specs = uniqueSpecsFor(env, table);
|
|
21064
|
+
if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) return;
|
|
21065
|
+
ensureIndexStores(env, table);
|
|
21066
|
+
}
|
|
20603
21067
|
function ensureIndexStores(env, table) {
|
|
20604
21068
|
if (table.indexStores) return table.indexStores;
|
|
20605
21069
|
const stores = /* @__PURE__ */ new Map();
|
|
@@ -20650,8 +21114,19 @@ function indexRemoveRow(env, table, rowIdx, row) {
|
|
|
20650
21114
|
}
|
|
20651
21115
|
}
|
|
20652
21116
|
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
20653
|
-
|
|
20654
|
-
|
|
21117
|
+
const specs = uniqueSpecsFor(env, table);
|
|
21118
|
+
if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) {
|
|
21119
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
21120
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
21121
|
+
return;
|
|
21122
|
+
}
|
|
21123
|
+
for (const spec of specs) {
|
|
21124
|
+
const before = uniqueKeyOf(env, table, spec, oldRow);
|
|
21125
|
+
const after = uniqueKeyOf(env, table, spec, newRow);
|
|
21126
|
+
if (before === after) continue;
|
|
21127
|
+
if (before !== null) table.indexStores?.get(spec.name)?.remove(before, rowIdx);
|
|
21128
|
+
if (after !== null) indexStoreFor(env, table, spec).insert(after, rowIdx);
|
|
21129
|
+
}
|
|
20655
21130
|
}
|
|
20656
21131
|
function rebuildTableIndexes(env, table) {
|
|
20657
21132
|
table.indexStores = null;
|
|
@@ -20868,6 +21343,82 @@ function conjunctions(expr) {
|
|
|
20868
21343
|
}
|
|
20869
21344
|
return [expr];
|
|
20870
21345
|
}
|
|
21346
|
+
function tryPointRowIndices(env, table, alias, where) {
|
|
21347
|
+
const eqs = [];
|
|
21348
|
+
for (const part of conjunctions(where)) {
|
|
21349
|
+
const eq = equalityAgainstConst(part);
|
|
21350
|
+
if (!eq || !["param", "number_lit", "string_lit", "bool_lit", "null_lit"].includes(eq.valueExpr.type)) return null;
|
|
21351
|
+
if (part.type !== "binop") return null;
|
|
21352
|
+
const column = part.left.type === "colref" ? part.left : part.right;
|
|
21353
|
+
if (column.type !== "colref") return null;
|
|
21354
|
+
if (column.parts.length > 1 && column.parts[column.parts.length - 2] !== alias) return null;
|
|
21355
|
+
eqs.push(eq);
|
|
21356
|
+
}
|
|
21357
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
21358
|
+
if (spec.where || spec.keys.length !== eqs.length || spec.keys.some((key2) => key2.expr) || !eqs.every((eq, index) => eq.column === spec.columnNames[index]))
|
|
21359
|
+
continue;
|
|
21360
|
+
const values = table.columns.map(() => null);
|
|
21361
|
+
let matches2 = true;
|
|
21362
|
+
for (let index = 0; index < spec.keys.length; index++) {
|
|
21363
|
+
const key2 = spec.keys[index];
|
|
21364
|
+
const column = table.columns[key2.colIdx];
|
|
21365
|
+
const eq = eqs[index];
|
|
21366
|
+
if (!column || !eq || column.domain) {
|
|
21367
|
+
matches2 = false;
|
|
21368
|
+
break;
|
|
21369
|
+
}
|
|
21370
|
+
const value = evalExpr(env.ctx, makeEvalScope(env, null), eq.valueExpr);
|
|
21371
|
+
if (value.t !== column.type.id && !(column.type.id === "text" && value.t === "unknown" && typeof value.v === "string")) {
|
|
21372
|
+
matches2 = false;
|
|
21373
|
+
break;
|
|
21374
|
+
}
|
|
21375
|
+
values[key2.colIdx] = value.v;
|
|
21376
|
+
}
|
|
21377
|
+
if (!matches2) continue;
|
|
21378
|
+
const key = uniqueKeyOf(env, table, spec, values);
|
|
21379
|
+
return { indices: key === null ? [] : indexStoreFor(env, table, spec).lookup(key), indexName: spec.name };
|
|
21380
|
+
}
|
|
21381
|
+
return null;
|
|
21382
|
+
}
|
|
21383
|
+
function recordIndexScan(env, table, name2) {
|
|
21384
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
21385
|
+
const index = schema?.indexes.get(name2);
|
|
21386
|
+
if (schema && index) {
|
|
21387
|
+
const lastScan = env.ctx.state.clock().getTime();
|
|
21388
|
+
schema.indexes.set(name2, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
|
|
21389
|
+
}
|
|
21390
|
+
}
|
|
21391
|
+
function tryRangeRowIndices(env, table, alias, where) {
|
|
21392
|
+
const parts = conjunctions(where);
|
|
21393
|
+
if (parts.length !== 2) return null;
|
|
21394
|
+
const bounds = [];
|
|
21395
|
+
for (const part of parts) {
|
|
21396
|
+
if (part.type !== "binop" || ![">", ">=", "<", "<="].includes(part.op)) return null;
|
|
21397
|
+
const column2 = part.left.type === "colref" ? part.left : part.right;
|
|
21398
|
+
const value = part.left.type === "colref" ? part.right : part.left;
|
|
21399
|
+
if (column2.type !== "colref" || column2.parts.length > 2 || column2.parts.length === 2 && column2.parts[0] !== alias || !["param", "number_lit"].includes(value.type))
|
|
21400
|
+
return null;
|
|
21401
|
+
const op = part.left === column2 ? part.op : { ">": "<", ">=": "<=", "<": ">", "<=": ">=" }[part.op];
|
|
21402
|
+
bounds.push({ column: column2.parts.at(-1), op, value });
|
|
21403
|
+
}
|
|
21404
|
+
const lower = bounds.find((bound) => bound.op === ">" || bound.op === ">=");
|
|
21405
|
+
const upper = bounds.find((bound) => bound.op === "<" || bound.op === "<=");
|
|
21406
|
+
if (!lower || !upper || lower.column !== upper.column) return null;
|
|
21407
|
+
const column = table.columns.find((column2) => column2.name === lower.column);
|
|
21408
|
+
if (!column || column.domain || !["int2", "int4"].includes(column.type.id)) return null;
|
|
21409
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
21410
|
+
if (spec.where || spec.keys.length !== 1 || spec.keys[0].expr || spec.columnNames[0] !== lower.column) continue;
|
|
21411
|
+
const low = evalExpr(env.ctx, makeEvalScope(env, null), lower.value);
|
|
21412
|
+
const high = evalExpr(env.ctx, makeEvalScope(env, null), upper.value);
|
|
21413
|
+
if (low.t !== column.type.id || high.t !== column.type.id || typeof low.v !== "number" || typeof high.v !== "number")
|
|
21414
|
+
return null;
|
|
21415
|
+
return {
|
|
21416
|
+
indices: indexStoreFor(env, table, spec).integerRange(low.v, high.v, lower.op === ">=", upper.op === "<="),
|
|
21417
|
+
indexName: spec.name
|
|
21418
|
+
};
|
|
21419
|
+
}
|
|
21420
|
+
return null;
|
|
21421
|
+
}
|
|
20871
21422
|
function tryIndexedTableRows(env, table, alias, where) {
|
|
20872
21423
|
const parts = conjunctions(where);
|
|
20873
21424
|
const eqs = [];
|
|
@@ -20904,12 +21455,7 @@ function tryIndexedTableRows(env, table, alias, where) {
|
|
|
20904
21455
|
const key = uniqueKeyOf(env, table, spec, probeRow);
|
|
20905
21456
|
if (key === null) return [];
|
|
20906
21457
|
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
20907
|
-
|
|
20908
|
-
const index = schema?.indexes.get(spec.name);
|
|
20909
|
-
if (schema && index) {
|
|
20910
|
-
const lastScan = env.ctx.state.clock().getTime();
|
|
20911
|
-
schema.indexes.set(spec.name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
|
|
20912
|
-
}
|
|
21458
|
+
recordIndexScan(env, table, spec.name);
|
|
20913
21459
|
return hits.map((i) => table.rowAt(i));
|
|
20914
21460
|
}
|
|
20915
21461
|
function tryIndexedFromItem(env, item, where) {
|
|
@@ -26885,7 +27431,7 @@ function renameWithAliases(rel4, label, colAliases, what) {
|
|
|
26885
27431
|
}));
|
|
26886
27432
|
return { columns, rows: rel4.rows };
|
|
26887
27433
|
}
|
|
26888
|
-
function materializeItem(env, item, scope) {
|
|
27434
|
+
function materializeItem(env, item, scope, shapeOnly = false) {
|
|
26889
27435
|
switch (item.type) {
|
|
26890
27436
|
case "from_table": {
|
|
26891
27437
|
const label = item.alias ?? item.name[item.name.length - 1];
|
|
@@ -26904,7 +27450,7 @@ function materializeItem(env, item, scope) {
|
|
|
26904
27450
|
...table.columns.map((c) => ({ name: c.name, type: c.type.id, mod: c.type.mod, table: label })),
|
|
26905
27451
|
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
26906
27452
|
],
|
|
26907
|
-
rows: table.
|
|
27453
|
+
rows: shapeOnly ? [] : table.serializationRows().map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
26908
27454
|
};
|
|
26909
27455
|
return { rel: renameWithAliases(rel4, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
26910
27456
|
}
|
|
@@ -28177,14 +28723,30 @@ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
|
|
|
28177
28723
|
function executeCore(env0, core, orderBy, opts) {
|
|
28178
28724
|
const env = env0;
|
|
28179
28725
|
const ctx = env.ctx;
|
|
28180
|
-
const
|
|
28726
|
+
const item = core.from.length === 1 ? core.from[0] : null;
|
|
28727
|
+
const pointTable = item?.type === "from_table" && !item.colAliases?.length && !(item.name.length === 1 && env.ctes.has(item.name[0])) ? env.ctx.state.findTable(item.name) : null;
|
|
28728
|
+
const point = pointTable && core.where && item?.type === "from_table" ? tryPointRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
|
|
28729
|
+
const range = !point && pointTable && core.where && item?.type === "from_table" ? tryRangeRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
|
|
28730
|
+
const access = point ?? range;
|
|
28731
|
+
const source = access && item ? materializeItem(env, item, env.outer, true) : buildFrom(env, core.from, core.where);
|
|
28181
28732
|
const srcCols = source.rel.columns;
|
|
28182
28733
|
const rangeVars = source.rangeVars;
|
|
28183
28734
|
const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
|
|
28184
28735
|
let srcRows = source.rel.rows;
|
|
28185
28736
|
if (core.where) {
|
|
28186
28737
|
checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
|
|
28187
|
-
if (
|
|
28738
|
+
if (access && pointTable) {
|
|
28739
|
+
pointTable.materializeSlab();
|
|
28740
|
+
srcRows = access.indices.map((index) => {
|
|
28741
|
+
const row = pointTable.rowAt(index);
|
|
28742
|
+
return [...row, pointTable.rowXmins.get(row) ?? 2];
|
|
28743
|
+
});
|
|
28744
|
+
if (range) {
|
|
28745
|
+
const where = core.where;
|
|
28746
|
+
srcRows = srcRows.filter((row) => evalPredicate2(env, rowScope(row), where));
|
|
28747
|
+
}
|
|
28748
|
+
recordIndexScan(env, pointTable, access.indexName);
|
|
28749
|
+
} else if (core.from.length === 1) {
|
|
28188
28750
|
const indexed = tryIndexedFromItem(env, core.from[0], core.where);
|
|
28189
28751
|
if (indexed !== null) {
|
|
28190
28752
|
srcRows = indexed;
|
|
@@ -28365,11 +28927,11 @@ function executeCore(env0, core, orderBy, opts) {
|
|
|
28365
28927
|
}
|
|
28366
28928
|
}
|
|
28367
28929
|
}
|
|
28368
|
-
const
|
|
28930
|
+
const item2 = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
|
|
28369
28931
|
const spec = { colIdx: projItems.length, dir, nullsFirst };
|
|
28370
|
-
projItems.push(
|
|
28932
|
+
projItems.push(item2);
|
|
28371
28933
|
sortSpecs.push(spec);
|
|
28372
|
-
orderExprs.push({ item, spec });
|
|
28934
|
+
orderExprs.push({ item: item2, spec });
|
|
28373
28935
|
}
|
|
28374
28936
|
if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
|
|
28375
28937
|
const used = new Set(sortSpecs.map((s) => s.colIdx));
|
|
@@ -28743,7 +29305,7 @@ var TransactionManager = class {
|
|
|
28743
29305
|
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
28744
29306
|
}
|
|
28745
29307
|
restore(snap) {
|
|
28746
|
-
this.state.restoreFrom(snap.state);
|
|
29308
|
+
this.state.restoreFrom(snap.state.cloneShallow());
|
|
28747
29309
|
this.state.prng.setState(snap.prngState);
|
|
28748
29310
|
}
|
|
28749
29311
|
thawOnce() {
|
|
@@ -28843,7 +29405,10 @@ function withStatementRollback(env, fn) {
|
|
|
28843
29405
|
function requireTargetTable(env, parts, verb) {
|
|
28844
29406
|
const state = env.ctx.state;
|
|
28845
29407
|
const table = state.findTable(parts);
|
|
28846
|
-
if (table)
|
|
29408
|
+
if (table) {
|
|
29409
|
+
prepareDmlIndexStores(env, table);
|
|
29410
|
+
return state.ensureWritableTableForDml(table);
|
|
29411
|
+
}
|
|
28847
29412
|
const view = state.findView(parts);
|
|
28848
29413
|
if (view) {
|
|
28849
29414
|
throw pgError("wrong_object_type", `cannot ${verb} view "${view.name}"`, "42809");
|
|
@@ -29011,7 +29576,7 @@ function resolveArbiters(env, table, clause) {
|
|
|
29011
29576
|
return matches2.map((spec) => ({ spec }));
|
|
29012
29577
|
}
|
|
29013
29578
|
function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, where) {
|
|
29014
|
-
const rows = table.
|
|
29579
|
+
const rows = table.writeRows();
|
|
29015
29580
|
const existing = rows[existingIdx];
|
|
29016
29581
|
const cols = [
|
|
29017
29582
|
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
@@ -29023,7 +29588,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
29023
29588
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
29024
29589
|
computeGeneratedColumns(env, table, updated);
|
|
29025
29590
|
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
29026
|
-
|
|
29591
|
+
table.replaceRow(existingIdx, updated);
|
|
29027
29592
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
29028
29593
|
checkNotNull(env, table, updated);
|
|
29029
29594
|
checkChecks(env, table, updated);
|
|
@@ -29035,7 +29600,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
29035
29600
|
function executeInsert(env0, stmt) {
|
|
29036
29601
|
const env = applyWith(env0, stmt.with);
|
|
29037
29602
|
const table = requireTargetTable(env, stmt.table, "insert into");
|
|
29038
|
-
const rows = table.
|
|
29603
|
+
const rows = table.writeRows();
|
|
29039
29604
|
const label = stmt.alias ?? table.name;
|
|
29040
29605
|
const colIdxs = insertTargetColumns(env, table, stmt);
|
|
29041
29606
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
@@ -29119,6 +29684,7 @@ function executeInsert(env0, stmt) {
|
|
|
29119
29684
|
checkForeignKeys(env, table, newRow);
|
|
29120
29685
|
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
29121
29686
|
rows.push(newRow);
|
|
29687
|
+
table.recordDurableRow(newRow);
|
|
29122
29688
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
29123
29689
|
insertedCount++;
|
|
29124
29690
|
insertedRows.push(newRow);
|
|
@@ -29211,13 +29777,17 @@ function executeUpdate(env0, stmt) {
|
|
|
29211
29777
|
const label = stmt.alias ?? table.name;
|
|
29212
29778
|
fireStatementTriggers(env, table, "before", "update");
|
|
29213
29779
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
29214
|
-
const rows = table.mutableRows();
|
|
29215
29780
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
29216
29781
|
const updatedRows = [];
|
|
29217
29782
|
const replacedRows = [];
|
|
29218
29783
|
let updateCount = 0;
|
|
29219
|
-
|
|
29220
|
-
|
|
29784
|
+
const point = !fromSource && stmt.where && table.triggers.length === 0 && !table.columns.some((column) => column.generated || column.domain) && !table.constraints.some((constraint) => constraint.kind === "check") && stmt.sets.every(
|
|
29785
|
+
(set) => set.columns.every((column) => column.subscripts === null && column.fields.length === 0) && "type" in set.value && isPureUpdateValue(set.value)
|
|
29786
|
+
) && referencingConstraints(env, table).length === 0 ? tryPointRowIndices(env, table, label, stmt.where) : null;
|
|
29787
|
+
const rows = point ? null : table.writeRows();
|
|
29788
|
+
for (let candidate = 0; candidate < (point ? point.indices.length : rows.length); candidate++) {
|
|
29789
|
+
const ri = point ? point.indices[candidate] : candidate;
|
|
29790
|
+
const oldRow = point ? table.rowAt(ri) : rows[ri];
|
|
29221
29791
|
let matchScope = null;
|
|
29222
29792
|
if (fromSource) {
|
|
29223
29793
|
let found = false;
|
|
@@ -29243,14 +29813,14 @@ function executeUpdate(env0, stmt) {
|
|
|
29243
29813
|
const finalRow = fired.row;
|
|
29244
29814
|
computeGeneratedColumns(env, table, finalRow);
|
|
29245
29815
|
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
29246
|
-
|
|
29816
|
+
table.replaceRow(ri, finalRow);
|
|
29247
29817
|
try {
|
|
29248
29818
|
checkNotNull(env, table, finalRow);
|
|
29249
29819
|
checkChecks(env, table, finalRow);
|
|
29250
29820
|
checkUnique(env, table, finalRow, ri);
|
|
29251
29821
|
checkForeignKeys(env, table, finalRow);
|
|
29252
29822
|
} catch (err) {
|
|
29253
|
-
|
|
29823
|
+
table.replaceRow(ri, oldRow);
|
|
29254
29824
|
throw err;
|
|
29255
29825
|
}
|
|
29256
29826
|
indexUpdateRow(env, table, ri, oldRow, finalRow);
|
|
@@ -29268,12 +29838,29 @@ function executeUpdate(env0, stmt) {
|
|
|
29268
29838
|
}
|
|
29269
29839
|
return commandResult("UPDATE", updateCount);
|
|
29270
29840
|
}
|
|
29841
|
+
function isPureUpdateValue(expr) {
|
|
29842
|
+
switch (expr.type) {
|
|
29843
|
+
case "param":
|
|
29844
|
+
case "number_lit":
|
|
29845
|
+
case "string_lit":
|
|
29846
|
+
case "bool_lit":
|
|
29847
|
+
case "null_lit":
|
|
29848
|
+
case "colref":
|
|
29849
|
+
return true;
|
|
29850
|
+
case "binop":
|
|
29851
|
+
return isPureUpdateValue(expr.left) && isPureUpdateValue(expr.right);
|
|
29852
|
+
case "unop":
|
|
29853
|
+
return isPureUpdateValue(expr.operand);
|
|
29854
|
+
default:
|
|
29855
|
+
return false;
|
|
29856
|
+
}
|
|
29857
|
+
}
|
|
29271
29858
|
function executeDelete(env0, stmt) {
|
|
29272
29859
|
const env = applyWith(env0, stmt.with);
|
|
29273
29860
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
29274
29861
|
const label = stmt.alias ?? table.name;
|
|
29275
29862
|
fireStatementTriggers(env, table, "before", "delete");
|
|
29276
|
-
const rows = table.
|
|
29863
|
+
const rows = table.writeRows();
|
|
29277
29864
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
29278
29865
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
29279
29866
|
const toDelete = [];
|
|
@@ -29303,6 +29890,7 @@ function executeDelete(env0, stmt) {
|
|
|
29303
29890
|
if (skipped.has(ri)) continue;
|
|
29304
29891
|
const row = rows[ri];
|
|
29305
29892
|
handleReferencedDelete(env, table, row, 0);
|
|
29893
|
+
table.recordDurableDelete(row);
|
|
29306
29894
|
rows.splice(ri, 1);
|
|
29307
29895
|
deletedRows.unshift(row);
|
|
29308
29896
|
}
|
|
@@ -29349,13 +29937,14 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
29349
29937
|
const idxs = referencingRowIdxs(ref, key);
|
|
29350
29938
|
if (idxs.length === 0) continue;
|
|
29351
29939
|
const action = con.onDelete ?? "no_action";
|
|
29352
|
-
const child = env.ctx.state.
|
|
29353
|
-
const childRows = child.
|
|
29940
|
+
const child = env.ctx.state.ensureWritableTableForDml(ref.table);
|
|
29941
|
+
const childRows = child.writeRows();
|
|
29354
29942
|
switch (action) {
|
|
29355
29943
|
case "cascade": {
|
|
29356
29944
|
for (let k = idxs.length - 1; k >= 0; k--) {
|
|
29357
29945
|
const childRow = childRows[idxs[k]];
|
|
29358
29946
|
handleReferencedDelete(env, child, childRow, depth + 1);
|
|
29947
|
+
child.recordDurableDelete(childRow);
|
|
29359
29948
|
childRows.splice(idxs[k], 1);
|
|
29360
29949
|
}
|
|
29361
29950
|
break;
|
|
@@ -29367,7 +29956,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
29367
29956
|
newRow[child.columnIndex(c)] = null;
|
|
29368
29957
|
}
|
|
29369
29958
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
29370
|
-
|
|
29959
|
+
child.replaceRow(i, newRow);
|
|
29371
29960
|
checkNotNull(env, child, newRow);
|
|
29372
29961
|
checkChecks(env, child, newRow);
|
|
29373
29962
|
}
|
|
@@ -29381,7 +29970,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
29381
29970
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
29382
29971
|
}
|
|
29383
29972
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
29384
|
-
|
|
29973
|
+
child.replaceRow(i, newRow);
|
|
29385
29974
|
checkNotNull(env, child, newRow);
|
|
29386
29975
|
checkChecks(env, child, newRow);
|
|
29387
29976
|
checkForeignKeys(env, child, newRow);
|
|
@@ -29407,8 +29996,8 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
29407
29996
|
const idxs = referencingRowIdxs(ref, oldKey);
|
|
29408
29997
|
if (idxs.length === 0) continue;
|
|
29409
29998
|
const action = con.onUpdate ?? "no_action";
|
|
29410
|
-
const child = env.ctx.state.
|
|
29411
|
-
const childRows = child.
|
|
29999
|
+
const child = env.ctx.state.ensureWritableTableForDml(ref.table);
|
|
30000
|
+
const childRows = child.writeRows();
|
|
29412
30001
|
switch (action) {
|
|
29413
30002
|
case "cascade": {
|
|
29414
30003
|
for (const i of idxs) {
|
|
@@ -29419,7 +30008,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
29419
30008
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
29420
30009
|
}
|
|
29421
30010
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
29422
|
-
|
|
30011
|
+
child.replaceRow(i, newRow);
|
|
29423
30012
|
checkChecks(env, child, newRow);
|
|
29424
30013
|
}
|
|
29425
30014
|
break;
|
|
@@ -29429,7 +30018,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
29429
30018
|
const newRow = childRows[i].slice();
|
|
29430
30019
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
29431
30020
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
29432
|
-
|
|
30021
|
+
child.replaceRow(i, newRow);
|
|
29433
30022
|
checkNotNull(env, child, newRow);
|
|
29434
30023
|
}
|
|
29435
30024
|
break;
|
|
@@ -29442,7 +30031,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
29442
30031
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
29443
30032
|
}
|
|
29444
30033
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
29445
|
-
|
|
30034
|
+
child.replaceRow(i, newRow);
|
|
29446
30035
|
checkForeignKeys(env, child, newRow);
|
|
29447
30036
|
}
|
|
29448
30037
|
break;
|
|
@@ -29965,6 +30554,8 @@ function openSnapshot(snapshot, options2 = {}) {
|
|
|
29965
30554
|
now = () => new Date(ms);
|
|
29966
30555
|
}
|
|
29967
30556
|
const state = snapshot.state.cloneShallow();
|
|
30557
|
+
for (const schema of state.schemas.values())
|
|
30558
|
+
for (const [name2, table] of schema.tables) if (table.durableChanges) schema.tables.set(name2, table.untrackedFork());
|
|
29968
30559
|
state.prng = prng;
|
|
29969
30560
|
state.clock = now;
|
|
29970
30561
|
return createAdoptedDatabase({
|
|
@@ -34650,6 +35241,24 @@ var Statement = class _Statement {
|
|
|
34650
35241
|
this.database = database;
|
|
34651
35242
|
this.sql = sql;
|
|
34652
35243
|
this.statements = statements;
|
|
35244
|
+
const observer = database.durabilityObserver;
|
|
35245
|
+
if (observer) {
|
|
35246
|
+
const execute = this.execute;
|
|
35247
|
+
this.execute = (params) => {
|
|
35248
|
+
observer.assertWritable();
|
|
35249
|
+
if (params.some((value) => value instanceof Uint8Array)) observer.exposed();
|
|
35250
|
+
try {
|
|
35251
|
+
const result = execute.call(this, params);
|
|
35252
|
+
if (result.columns.some(
|
|
35253
|
+
(column, index) => column.type === "bytea" && result.rows.some((row) => row[index] !== null && row[index] !== void 0)
|
|
35254
|
+
))
|
|
35255
|
+
observer.exposed();
|
|
35256
|
+
return result;
|
|
35257
|
+
} finally {
|
|
35258
|
+
observer.changed();
|
|
35259
|
+
}
|
|
35260
|
+
};
|
|
35261
|
+
}
|
|
34653
35262
|
}
|
|
34654
35263
|
database;
|
|
34655
35264
|
statements;
|
|
@@ -34682,7 +35291,7 @@ var Statement = class _Statement {
|
|
|
34682
35291
|
*/
|
|
34683
35292
|
textResult(...params) {
|
|
34684
35293
|
const res = this.execute(params);
|
|
34685
|
-
const ctx = new EngineCtx(this.database.
|
|
35294
|
+
const ctx = new EngineCtx(this.database.engineState);
|
|
34686
35295
|
return {
|
|
34687
35296
|
columns: res.columns.map((c) => c.name),
|
|
34688
35297
|
columnTypes: res.columns.map((c) => c.type === UNKNOWN ? "text" : c.type),
|
|
@@ -34719,7 +35328,7 @@ var Statement = class _Statement {
|
|
|
34719
35328
|
const refused = this.database.transactions.inTransaction ? refusedInTransactionBlock(stmt) : null;
|
|
34720
35329
|
if (refused) throw pgError("misuse", `${refused} cannot run inside a transaction block`, "25001");
|
|
34721
35330
|
const env = {
|
|
34722
|
-
ctx: new EngineCtx(this.database.
|
|
35331
|
+
ctx: new EngineCtx(this.database.engineState),
|
|
34723
35332
|
params: typed,
|
|
34724
35333
|
ctes: /* @__PURE__ */ new Map(),
|
|
34725
35334
|
outer: null
|
|
@@ -34729,12 +35338,13 @@ var Statement = class _Statement {
|
|
|
34729
35338
|
return last;
|
|
34730
35339
|
}
|
|
34731
35340
|
toRows(res) {
|
|
34732
|
-
const ctx = new EngineCtx(this.database.
|
|
35341
|
+
const ctx = new EngineCtx(this.database.engineState);
|
|
34733
35342
|
return res.rows.map((row) => {
|
|
34734
35343
|
const obj = {};
|
|
34735
35344
|
for (let i = 0; i < res.columns.length; i++) {
|
|
34736
35345
|
const c = res.columns[i];
|
|
34737
|
-
|
|
35346
|
+
const value = datumToJs(c.type, row[i] ?? null, ctx, this.database.int8Mode);
|
|
35347
|
+
obj[c.name] = value;
|
|
34738
35348
|
}
|
|
34739
35349
|
return obj;
|
|
34740
35350
|
});
|
|
@@ -34752,6 +35362,10 @@ function project(point) {
|
|
|
34752
35362
|
var Database = class {
|
|
34753
35363
|
/** @internal Engine catalog, tables, session settings. */
|
|
34754
35364
|
state;
|
|
35365
|
+
/** @internal Engine-only access; buffered mode observes public state exposure. */
|
|
35366
|
+
engineState;
|
|
35367
|
+
/** @internal Installed only by buffered durability. */
|
|
35368
|
+
durabilityObserver;
|
|
34755
35369
|
/** Seed used to construct the PRNG. Ignored when {@link randomMode} is `"os"`. */
|
|
34756
35370
|
seed;
|
|
34757
35371
|
/** Entropy mode for `random()` / `gen_random_uuid()`. */
|
|
@@ -34781,10 +35395,10 @@ var Database = class {
|
|
|
34781
35395
|
this.int8Mode = options2.int8Mode;
|
|
34782
35396
|
this.prng = options2.prng;
|
|
34783
35397
|
this.now = options2.now;
|
|
34784
|
-
this.
|
|
34785
|
-
this.
|
|
34786
|
-
this.
|
|
34787
|
-
this.transactions = txManagerFor(this.
|
|
35398
|
+
this.engineState = options2.state;
|
|
35399
|
+
this.engineState.prng = this.prng;
|
|
35400
|
+
this.engineState.clock = () => this.now();
|
|
35401
|
+
this.transactions = txManagerFor(this.engineState);
|
|
34788
35402
|
} else {
|
|
34789
35403
|
this.seed = options2.seed ?? DEFAULT_DATABASE_SEED;
|
|
34790
35404
|
this.randomMode = options2.random ?? "deterministic";
|
|
@@ -34792,9 +35406,10 @@ var Database = class {
|
|
|
34792
35406
|
this.int8Mode = options2.int8 ?? "bigint";
|
|
34793
35407
|
this.prng = this.randomMode === "os" ? new OsEntropy() : new Prng(this.seed);
|
|
34794
35408
|
this.now = resolveClock(options2.now);
|
|
34795
|
-
this.
|
|
34796
|
-
this.transactions = txManagerFor(this.
|
|
35409
|
+
this.engineState = new DatabaseState(this.prng, () => this.now());
|
|
35410
|
+
this.transactions = txManagerFor(this.engineState);
|
|
34797
35411
|
}
|
|
35412
|
+
this.state = this.engineState;
|
|
34798
35413
|
this.timeline = new Timeline({
|
|
34799
35414
|
now: () => this.now().getTime(),
|
|
34800
35415
|
...options2.maxCheckpoints !== void 0 ? { maxCheckpoints: options2.maxCheckpoints } : {}
|
|
@@ -34821,14 +35436,15 @@ var Database = class {
|
|
|
34821
35436
|
* a live in-memory snapshot.
|
|
34822
35437
|
*/
|
|
34823
35438
|
registerFunction(spec) {
|
|
35439
|
+
this.durabilityObserver?.assertWritable();
|
|
34824
35440
|
this.assertOpen();
|
|
34825
35441
|
const parts = spec.name.split(".").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
34826
35442
|
if (parts.length === 0) throw pgError("syntax", "function name is required", "42601");
|
|
34827
|
-
const schemaName = (parts.length >= 2 ? parts[0] : this.
|
|
35443
|
+
const schemaName = (parts.length >= 2 ? parts[0] : this.engineState.currentSchema()).toLowerCase();
|
|
34828
35444
|
const name2 = parts[parts.length - 1].toLowerCase();
|
|
34829
|
-
const functions = schemaName === "pg_catalog" ? this.
|
|
34830
|
-
const argTypes = spec.args.map((a) => resolveTypeName(this.
|
|
34831
|
-
const returns = resolveTypeName(this.
|
|
35445
|
+
const functions = schemaName === "pg_catalog" ? this.engineState.systemFunctions : this.engineState.getSchema(schemaName).functions;
|
|
35446
|
+
const argTypes = spec.args.map((a) => resolveTypeName(this.engineState, parseTypeName(a)).column.id);
|
|
35447
|
+
const returns = resolveTypeName(this.engineState, parseTypeName(spec.returns)).column.id;
|
|
34832
35448
|
const fn = {
|
|
34833
35449
|
name: name2,
|
|
34834
35450
|
schema: schemaName,
|
|
@@ -34842,7 +35458,7 @@ var Database = class {
|
|
|
34842
35458
|
body: null,
|
|
34843
35459
|
rawBody: null,
|
|
34844
35460
|
strict: spec.strict ?? true,
|
|
34845
|
-
oid: this.
|
|
35461
|
+
oid: this.engineState.nextOid(),
|
|
34846
35462
|
jsImpl: spec.fn
|
|
34847
35463
|
};
|
|
34848
35464
|
const existing = functions.get(name2) ?? [];
|
|
@@ -34852,6 +35468,7 @@ var Database = class {
|
|
|
34852
35468
|
if (sameSig !== -1) existing[sameSig] = fn;
|
|
34853
35469
|
else existing.push(fn);
|
|
34854
35470
|
functions.set(name2, existing);
|
|
35471
|
+
this.durabilityObserver?.exposed();
|
|
34855
35472
|
}
|
|
34856
35473
|
/** Execute a single-statement query and return all rows keyed by column name. */
|
|
34857
35474
|
query(sql, params = [], options2 = {}) {
|
|
@@ -34878,6 +35495,7 @@ var Database = class {
|
|
|
34878
35495
|
*/
|
|
34879
35496
|
transaction(fn) {
|
|
34880
35497
|
this.assertOpen();
|
|
35498
|
+
this.durabilityObserver?.assertWritable();
|
|
34881
35499
|
this.apiTransactionDepth++;
|
|
34882
35500
|
try {
|
|
34883
35501
|
if (!this.transactions.inTransaction) {
|
|
@@ -34904,6 +35522,7 @@ var Database = class {
|
|
|
34904
35522
|
}
|
|
34905
35523
|
} finally {
|
|
34906
35524
|
this.apiTransactionDepth--;
|
|
35525
|
+
this.durabilityObserver?.changed();
|
|
34907
35526
|
}
|
|
34908
35527
|
}
|
|
34909
35528
|
/**
|
|
@@ -34998,7 +35617,7 @@ var Database = class {
|
|
|
34998
35617
|
*/
|
|
34999
35618
|
fault(faults) {
|
|
35000
35619
|
this.assertOpen();
|
|
35001
|
-
Object.assign(this.
|
|
35620
|
+
Object.assign(this.engineState.faults, faults);
|
|
35002
35621
|
}
|
|
35003
35622
|
/** Close the database. Further SQL throws. Idempotent. */
|
|
35004
35623
|
close() {
|
|
@@ -35008,6 +35627,7 @@ var Database = class {
|
|
|
35008
35627
|
}
|
|
35009
35628
|
if (this.transactions.inTransaction) this.transactions.rollback();
|
|
35010
35629
|
this.closed = true;
|
|
35630
|
+
this.durabilityObserver?.closed?.();
|
|
35011
35631
|
}
|
|
35012
35632
|
/**
|
|
35013
35633
|
* Execute `COPY table [(cols)] FROM STDIN` with the given text/csv payload
|
|
@@ -35026,13 +35646,18 @@ var Database = class {
|
|
|
35026
35646
|
if (statements.length !== 1 || !stmt || stmt.type !== "copy" || stmt.direction !== "from") {
|
|
35027
35647
|
throw pgError("misuse", "copyFrom() requires a single COPY ... FROM STDIN statement", "XX000");
|
|
35028
35648
|
}
|
|
35029
|
-
|
|
35030
|
-
|
|
35649
|
+
this.durabilityObserver?.assertWritable();
|
|
35650
|
+
try {
|
|
35651
|
+
const env = { ctx: new EngineCtx(this.engineState), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
35652
|
+
return executeCopyFromData(env, stmt, data).rowCount;
|
|
35653
|
+
} finally {
|
|
35654
|
+
this.durabilityObserver?.changed();
|
|
35655
|
+
}
|
|
35031
35656
|
}
|
|
35032
35657
|
/** Rows affected by the most recent INSERT / UPDATE / DELETE. */
|
|
35033
35658
|
get changes() {
|
|
35034
35659
|
this.assertOpen();
|
|
35035
|
-
return this.
|
|
35660
|
+
return this.engineState.changes;
|
|
35036
35661
|
}
|
|
35037
35662
|
/** @internal */
|
|
35038
35663
|
assertOpen() {
|
|
@@ -35044,7 +35669,7 @@ var Database = class {
|
|
|
35044
35669
|
}
|
|
35045
35670
|
captureLive() {
|
|
35046
35671
|
return captureSnapshot(
|
|
35047
|
-
this.
|
|
35672
|
+
this.engineState,
|
|
35048
35673
|
this.prng,
|
|
35049
35674
|
this.now,
|
|
35050
35675
|
this.seed,
|
|
@@ -35054,7 +35679,8 @@ var Database = class {
|
|
|
35054
35679
|
);
|
|
35055
35680
|
}
|
|
35056
35681
|
install(snapshot) {
|
|
35057
|
-
this.
|
|
35682
|
+
this.durabilityObserver?.exposed();
|
|
35683
|
+
this.engineState.restoreFrom(snapshot.state.cloneShallow());
|
|
35058
35684
|
this.prng.setState(snapshot.prngState);
|
|
35059
35685
|
if (!this.systemClock) this.now = fixedClock(new Date(snapshot.nowMs));
|
|
35060
35686
|
}
|
|
@@ -36250,6 +36876,13 @@ var Writer = class {
|
|
|
36250
36876
|
this.view.setBigInt64(this.len, value, true);
|
|
36251
36877
|
this.len += 8;
|
|
36252
36878
|
}
|
|
36879
|
+
/** Finite integer Number, encoded identically to i64(BigInt(value)) without allocation. */
|
|
36880
|
+
i64Number(value) {
|
|
36881
|
+
this.ensure(8);
|
|
36882
|
+
this.view.setUint32(this.len, value >>> 0, true);
|
|
36883
|
+
this.view.setUint32(this.len + 4, Math.floor(value / 4294967296) >>> 0, true);
|
|
36884
|
+
this.len += 8;
|
|
36885
|
+
}
|
|
36253
36886
|
f64(value) {
|
|
36254
36887
|
this.ensure(8);
|
|
36255
36888
|
this.view.setFloat64(this.len, value, true);
|
|
@@ -36260,6 +36893,13 @@ var Writer = class {
|
|
|
36260
36893
|
this.buf.set(value, this.len);
|
|
36261
36894
|
this.len += value.length;
|
|
36262
36895
|
}
|
|
36896
|
+
/** Reserve one contiguous region. Fill it before any subsequent Writer call can grow the buffer. */
|
|
36897
|
+
block(byteLength) {
|
|
36898
|
+
this.ensure(byteLength);
|
|
36899
|
+
const block = new DataView(this.buf.buffer, this.len, byteLength);
|
|
36900
|
+
this.len += byteLength;
|
|
36901
|
+
return block;
|
|
36902
|
+
}
|
|
36263
36903
|
/** Length-prefixed UTF-8. */
|
|
36264
36904
|
text(value) {
|
|
36265
36905
|
const encoded = utf8Encode(value);
|
|
@@ -36272,7 +36912,7 @@ var Writer = class {
|
|
|
36272
36912
|
}
|
|
36273
36913
|
finish() {
|
|
36274
36914
|
if (this.len === this.buf.length) return this.buf;
|
|
36275
|
-
return this.buf.
|
|
36915
|
+
return this.buf.slice(0, this.len);
|
|
36276
36916
|
}
|
|
36277
36917
|
fail() {
|
|
36278
36918
|
throw new PostgresError("snapshot_format", "invalid or truncated postgres-mem snapshot", "XX000");
|
|
@@ -36489,15 +37129,18 @@ function writeInternTable(w, strings) {
|
|
|
36489
37129
|
writeVarintU32(w, strings.length);
|
|
36490
37130
|
if (strings.length === 0) return;
|
|
36491
37131
|
const offsets = [];
|
|
37132
|
+
const encoded = [];
|
|
36492
37133
|
let total = 0;
|
|
36493
37134
|
for (const s of strings) {
|
|
36494
37135
|
offsets.push(total);
|
|
36495
|
-
|
|
37136
|
+
const bytes = utf8Encode(s);
|
|
37137
|
+
encoded.push(bytes);
|
|
37138
|
+
total += bytes.length;
|
|
36496
37139
|
}
|
|
36497
37140
|
writeVarintU32(w, total);
|
|
36498
37141
|
const base = w.position + offsets.length * 4;
|
|
36499
37142
|
for (const off of offsets) w.u32(base + off);
|
|
36500
|
-
for (const
|
|
37143
|
+
for (const bytes of encoded) w.raw(bytes);
|
|
36501
37144
|
}
|
|
36502
37145
|
function readInternTable(r) {
|
|
36503
37146
|
const count = readVarintU32(r);
|
|
@@ -36522,7 +37165,10 @@ var VERSION = 3;
|
|
|
36522
37165
|
function encodeDatabaseState(state, runtime) {
|
|
36523
37166
|
const pool = new InternPool();
|
|
36524
37167
|
const schemas = [...state.schemas.values()].sort((a, b) => compareNames(a.name, b.name));
|
|
37168
|
+
const internValues = /* @__PURE__ */ new Map();
|
|
36525
37169
|
for (const schema of schemas) {
|
|
37170
|
+
const values = [];
|
|
37171
|
+
internValues.set(schema, values);
|
|
36526
37172
|
pool.count(schema.name);
|
|
36527
37173
|
for (const table of sortedValues(schema.tables)) {
|
|
36528
37174
|
pool.count(table.name);
|
|
@@ -36533,8 +37179,13 @@ function encodeDatabaseState(state, runtime) {
|
|
|
36533
37179
|
pool.count(column.domain ?? "");
|
|
36534
37180
|
if (column.identity) pool.count(column.identity.sequence);
|
|
36535
37181
|
}
|
|
36536
|
-
for (const row of table.
|
|
36537
|
-
for (const d of row)
|
|
37182
|
+
for (const row of table.serializationRows()) {
|
|
37183
|
+
for (const d of row) {
|
|
37184
|
+
if (typeof d === "string") {
|
|
37185
|
+
pool.count(d);
|
|
37186
|
+
values.push(d);
|
|
37187
|
+
} else if (d !== null && typeof d === "object" && !(d instanceof Uint8Array)) values.push(d);
|
|
37188
|
+
}
|
|
36538
37189
|
}
|
|
36539
37190
|
}
|
|
36540
37191
|
for (const view of sortedValues(schema.views)) {
|
|
@@ -36542,7 +37193,12 @@ function encodeDatabaseState(state, runtime) {
|
|
|
36542
37193
|
pool.count(view.schema);
|
|
36543
37194
|
if (view.matRows) {
|
|
36544
37195
|
for (const row of view.matRows) {
|
|
36545
|
-
for (const d of row)
|
|
37196
|
+
for (const d of row) {
|
|
37197
|
+
if (typeof d === "string") {
|
|
37198
|
+
pool.count(d);
|
|
37199
|
+
values.push(d);
|
|
37200
|
+
} else if (d !== null && typeof d === "object" && !(d instanceof Uint8Array)) values.push(d);
|
|
37201
|
+
}
|
|
36546
37202
|
}
|
|
36547
37203
|
}
|
|
36548
37204
|
}
|
|
@@ -36575,7 +37231,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
36575
37231
|
}
|
|
36576
37232
|
}
|
|
36577
37233
|
pool.finalize();
|
|
36578
|
-
forceAllEncodeIntern(pool, state, schemas);
|
|
37234
|
+
forceAllEncodeIntern(pool, state, schemas, internValues);
|
|
36579
37235
|
const internId = (s) => pool.id(s);
|
|
36580
37236
|
const forceId = (s) => {
|
|
36581
37237
|
const id = pool.id(s);
|
|
@@ -36604,7 +37260,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
36604
37260
|
writeBjv(
|
|
36605
37261
|
w,
|
|
36606
37262
|
{
|
|
36607
|
-
xmins: table.
|
|
37263
|
+
xmins: table.serializationRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
36608
37264
|
name: table.name,
|
|
36609
37265
|
schema: table.schema,
|
|
36610
37266
|
columns: table.columns,
|
|
@@ -36617,7 +37273,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
36617
37273
|
},
|
|
36618
37274
|
forceId
|
|
36619
37275
|
);
|
|
36620
|
-
const rows = table.
|
|
37276
|
+
const rows = table.serializationRows();
|
|
36621
37277
|
writeVarintU32(w, rows.length);
|
|
36622
37278
|
for (let c = 0; c < table.columns.length; c++) writePackedColumn(w, rows, c, internId, forceId);
|
|
36623
37279
|
}
|
|
@@ -36943,44 +37599,57 @@ function writePackedColumn(w, rows, col, internId, forceId) {
|
|
|
36943
37599
|
}
|
|
36944
37600
|
if (pack === PACK_FLOAT) {
|
|
36945
37601
|
w.align4();
|
|
37602
|
+
const block = w.block((n - nulls) * 8);
|
|
37603
|
+
let offset = 0;
|
|
36946
37604
|
for (let i = 0; i < n; i++) {
|
|
36947
37605
|
if (bits[i >> 3] & 1 << (i & 7)) continue;
|
|
36948
|
-
|
|
37606
|
+
block.setFloat64(offset, rows[i][col], true);
|
|
37607
|
+
offset += 8;
|
|
36949
37608
|
}
|
|
36950
37609
|
return;
|
|
36951
37610
|
}
|
|
36952
37611
|
if (pack === PACK_INT) {
|
|
36953
37612
|
w.align4();
|
|
37613
|
+
const block = w.block((n - nulls) * 8);
|
|
37614
|
+
let offset = 0;
|
|
36954
37615
|
for (let i = 0; i < n; i++) {
|
|
36955
37616
|
if (bits[i >> 3] & 1 << (i & 7)) continue;
|
|
36956
37617
|
const v = rows[i][col];
|
|
36957
|
-
|
|
37618
|
+
if (typeof v === "bigint") block.setBigInt64(offset, v, true);
|
|
37619
|
+
else {
|
|
37620
|
+
block.setUint32(offset, v >>> 0, true);
|
|
37621
|
+
block.setUint32(offset + 4, Math.floor(v / 4294967296) >>> 0, true);
|
|
37622
|
+
}
|
|
37623
|
+
offset += 8;
|
|
36958
37624
|
}
|
|
36959
37625
|
return;
|
|
36960
37626
|
}
|
|
36961
37627
|
if (pack === PACK_TEXT_INTERN) {
|
|
36962
37628
|
w.align4();
|
|
37629
|
+
const block = w.block((n - nulls) * 4);
|
|
37630
|
+
let offset = 0;
|
|
36963
37631
|
for (let i = 0; i < n; i++) {
|
|
36964
37632
|
if (bits[i >> 3] & 1 << (i & 7)) continue;
|
|
36965
|
-
|
|
37633
|
+
block.setUint32(offset, internId(rows[i][col]), true);
|
|
37634
|
+
offset += 4;
|
|
36966
37635
|
}
|
|
36967
37636
|
return;
|
|
36968
37637
|
}
|
|
36969
37638
|
if (pack === PACK_TEXT_INLINE) {
|
|
36970
37639
|
const offsets = [];
|
|
37640
|
+
const encoded = [];
|
|
36971
37641
|
let blobLen = 0;
|
|
36972
37642
|
for (let i = 0; i < n; i++) {
|
|
36973
37643
|
if (bits[i >> 3] & 1 << (i & 7)) continue;
|
|
36974
37644
|
offsets.push(blobLen);
|
|
36975
|
-
|
|
37645
|
+
const bytes = utf8Encode(rows[i][col]);
|
|
37646
|
+
encoded.push(bytes);
|
|
37647
|
+
blobLen += bytes.length;
|
|
36976
37648
|
}
|
|
36977
37649
|
writeVarintU32(w, offsets.length);
|
|
36978
37650
|
for (const off of offsets) writeVarintU32(w, off);
|
|
36979
37651
|
writeVarintU32(w, blobLen);
|
|
36980
|
-
for (
|
|
36981
|
-
if (bits[i >> 3] & 1 << (i & 7)) continue;
|
|
36982
|
-
w.textBytes(rows[i][col]);
|
|
36983
|
-
}
|
|
37652
|
+
for (const bytes of encoded) w.raw(bytes);
|
|
36984
37653
|
return;
|
|
36985
37654
|
}
|
|
36986
37655
|
if (pack === PACK_BLOB) {
|
|
@@ -37180,7 +37849,7 @@ function compareNames(a, b) {
|
|
|
37180
37849
|
function sortedValues(map) {
|
|
37181
37850
|
return [...map.values()].sort((a, b) => compareNames(a.name, b.name));
|
|
37182
37851
|
}
|
|
37183
|
-
function forceAllEncodeIntern(pool, state, schemas) {
|
|
37852
|
+
function forceAllEncodeIntern(pool, state, schemas, internValues) {
|
|
37184
37853
|
forceSchemaIntern(pool, state, schemas);
|
|
37185
37854
|
for (const [k, v] of state.settings) {
|
|
37186
37855
|
pool.forceId(k);
|
|
@@ -37192,18 +37861,7 @@ function forceAllEncodeIntern(pool, state, schemas) {
|
|
|
37192
37861
|
}
|
|
37193
37862
|
for (const schema of schemas) {
|
|
37194
37863
|
pool.forceId(schema.name);
|
|
37195
|
-
for (const
|
|
37196
|
-
for (const row of table.allRows()) {
|
|
37197
|
-
for (const d of row) forceDatumIntern(pool, d);
|
|
37198
|
-
}
|
|
37199
|
-
}
|
|
37200
|
-
for (const view of sortedValues(schema.views)) {
|
|
37201
|
-
if (view.matRows) {
|
|
37202
|
-
for (const row of view.matRows) {
|
|
37203
|
-
for (const d of row) forceDatumIntern(pool, d);
|
|
37204
|
-
}
|
|
37205
|
-
}
|
|
37206
|
-
}
|
|
37864
|
+
for (const value of internValues.get(schema) ?? []) forceDatumIntern(pool, value);
|
|
37207
37865
|
}
|
|
37208
37866
|
}
|
|
37209
37867
|
function forceDatumIntern(pool, value) {
|
|
@@ -37248,7 +37906,8 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
37248
37906
|
pool.forceId(table.name);
|
|
37249
37907
|
pool.forceId(table.schema);
|
|
37250
37908
|
forceBjvStrings(pool, {
|
|
37251
|
-
|
|
37909
|
+
// Only strings are interned here. Traversing every numeric xmin cannot add an id.
|
|
37910
|
+
xmins: [],
|
|
37252
37911
|
name: table.name,
|
|
37253
37912
|
schema: table.schema,
|
|
37254
37913
|
columns: table.columns,
|