@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/admin.js
CHANGED
|
@@ -1,3 +1,249 @@
|
|
|
1
|
+
// ../../core/dist/fork-map.js
|
|
2
|
+
var ForkMap = class _ForkMap {
|
|
3
|
+
owner = {};
|
|
4
|
+
index = { owner: this.owner, groups: [] };
|
|
5
|
+
order = { owner: this.owner, cells: [] };
|
|
6
|
+
shift = 0;
|
|
7
|
+
length = 0;
|
|
8
|
+
count = 0;
|
|
9
|
+
nextSequence = 0;
|
|
10
|
+
layout = 0;
|
|
11
|
+
cleared = 0;
|
|
12
|
+
version = 0;
|
|
13
|
+
constructor(entries) {
|
|
14
|
+
if (entries)
|
|
15
|
+
for (const [key, value] of entries)
|
|
16
|
+
this.set(key, value);
|
|
17
|
+
}
|
|
18
|
+
get size() {
|
|
19
|
+
return this.count;
|
|
20
|
+
}
|
|
21
|
+
get [Symbol.toStringTag]() {
|
|
22
|
+
return "Map";
|
|
23
|
+
}
|
|
24
|
+
fork() {
|
|
25
|
+
const copy2 = new _ForkMap();
|
|
26
|
+
copy2.index = this.index;
|
|
27
|
+
copy2.order = this.order;
|
|
28
|
+
copy2.shift = this.shift;
|
|
29
|
+
copy2.length = this.length;
|
|
30
|
+
copy2.count = this.count;
|
|
31
|
+
copy2.nextSequence = this.nextSequence;
|
|
32
|
+
this.owner = {};
|
|
33
|
+
return copy2;
|
|
34
|
+
}
|
|
35
|
+
/** Visit changed hash buckets only. Values must be replaced, rather than mutated in place. */
|
|
36
|
+
*changes(previous) {
|
|
37
|
+
if (previous?.index === this.index)
|
|
38
|
+
return;
|
|
39
|
+
for (let group = 0; group < 32; group++) {
|
|
40
|
+
const currentGroup = this.index.groups[group];
|
|
41
|
+
const oldGroup = previous?.index.groups[group];
|
|
42
|
+
if (currentGroup === oldGroup)
|
|
43
|
+
continue;
|
|
44
|
+
for (let bucket = 0; bucket < 32; bucket++) {
|
|
45
|
+
const current = currentGroup?.buckets[bucket]?.data;
|
|
46
|
+
const old = oldGroup?.buckets[bucket]?.data;
|
|
47
|
+
if (current === old)
|
|
48
|
+
continue;
|
|
49
|
+
if (current)
|
|
50
|
+
for (const [key, entry] of current) {
|
|
51
|
+
const before = old?.get(key);
|
|
52
|
+
if (!before || !Object.is(before.value, entry.value) || before.sequence !== entry.sequence)
|
|
53
|
+
yield { key, value: entry.value, deleted: false };
|
|
54
|
+
}
|
|
55
|
+
if (old) {
|
|
56
|
+
for (const key of old.keys())
|
|
57
|
+
if (!current?.has(key))
|
|
58
|
+
yield { key, deleted: true };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
get(key) {
|
|
64
|
+
return this.find(key)?.value;
|
|
65
|
+
}
|
|
66
|
+
has(key) {
|
|
67
|
+
return this.find(key) !== void 0;
|
|
68
|
+
}
|
|
69
|
+
set(key, value) {
|
|
70
|
+
if (typeof key === "number" && key === 0)
|
|
71
|
+
key = 0;
|
|
72
|
+
const hash = hashKey(key);
|
|
73
|
+
const existing = this.bucket(hash)?.get(key);
|
|
74
|
+
if (existing && Object.is(existing.value, value))
|
|
75
|
+
return this;
|
|
76
|
+
const entry = existing ? { ...existing, value } : { key, value, position: this.length++, sequence: this.nextSequence++ };
|
|
77
|
+
this.writableBucket(hash).set(key, entry);
|
|
78
|
+
this.writeOrder(entry.position, entry);
|
|
79
|
+
if (!existing)
|
|
80
|
+
this.count++;
|
|
81
|
+
this.version++;
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
delete(key) {
|
|
85
|
+
const hash = hashKey(key);
|
|
86
|
+
const entry = this.bucket(hash)?.get(key);
|
|
87
|
+
if (!entry)
|
|
88
|
+
return false;
|
|
89
|
+
this.writableBucket(hash).delete(key);
|
|
90
|
+
this.writeOrder(entry.position, void 0);
|
|
91
|
+
this.count--;
|
|
92
|
+
this.version++;
|
|
93
|
+
if (this.length > 1024 && this.length > this.count * 2)
|
|
94
|
+
this.compact();
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
clear() {
|
|
98
|
+
this.index = { owner: this.owner, groups: [] };
|
|
99
|
+
this.order = { owner: this.owner, cells: [] };
|
|
100
|
+
this.shift = this.length = this.count = this.nextSequence = 0;
|
|
101
|
+
this.layout++;
|
|
102
|
+
this.cleared++;
|
|
103
|
+
this.version++;
|
|
104
|
+
}
|
|
105
|
+
entries() {
|
|
106
|
+
return this.iterate(0);
|
|
107
|
+
}
|
|
108
|
+
keys() {
|
|
109
|
+
return this.iterate(1);
|
|
110
|
+
}
|
|
111
|
+
values() {
|
|
112
|
+
return this.iterate(2);
|
|
113
|
+
}
|
|
114
|
+
[Symbol.iterator]() {
|
|
115
|
+
return this.entries();
|
|
116
|
+
}
|
|
117
|
+
forEach(callback, thisArg) {
|
|
118
|
+
for (const [key, value] of this)
|
|
119
|
+
callback.call(thisArg, value, key, this);
|
|
120
|
+
}
|
|
121
|
+
find(key) {
|
|
122
|
+
return this.bucket(hashKey(key))?.get(key);
|
|
123
|
+
}
|
|
124
|
+
bucket(hash) {
|
|
125
|
+
return this.index.groups[hash >>> 5 & 31]?.buckets[hash & 31]?.data;
|
|
126
|
+
}
|
|
127
|
+
writableBucket(hash) {
|
|
128
|
+
if (this.index.owner !== this.owner)
|
|
129
|
+
this.index = { owner: this.owner, groups: this.index.groups.slice() };
|
|
130
|
+
const groupIndex = hash >>> 5 & 31;
|
|
131
|
+
let group = this.index.groups[groupIndex];
|
|
132
|
+
if (!group || group.owner !== this.owner) {
|
|
133
|
+
group = { owner: this.owner, buckets: group?.buckets.slice() ?? [] };
|
|
134
|
+
this.index.groups[groupIndex] = group;
|
|
135
|
+
}
|
|
136
|
+
const at = hash & 31;
|
|
137
|
+
let bucket = group.buckets[at];
|
|
138
|
+
if (!bucket || bucket.owner !== this.owner) {
|
|
139
|
+
bucket = { owner: this.owner, data: bucket ? this.copyBucket(bucket.data) : /* @__PURE__ */ new Map() };
|
|
140
|
+
group.buckets[at] = bucket;
|
|
141
|
+
}
|
|
142
|
+
return bucket.data;
|
|
143
|
+
}
|
|
144
|
+
copyBucket(bucket) {
|
|
145
|
+
return new Map(bucket);
|
|
146
|
+
}
|
|
147
|
+
leaf(position) {
|
|
148
|
+
let node = this.order;
|
|
149
|
+
for (let shift = this.shift; shift > 0; shift -= 5)
|
|
150
|
+
node = node.cells[Math.floor(position / 2 ** shift) & 31];
|
|
151
|
+
return node;
|
|
152
|
+
}
|
|
153
|
+
writeOrder(position, entry) {
|
|
154
|
+
while (position >= 2 ** (this.shift + 5)) {
|
|
155
|
+
this.order = { owner: this.owner, cells: [this.order] };
|
|
156
|
+
this.shift += 5;
|
|
157
|
+
}
|
|
158
|
+
if (this.order.owner !== this.owner)
|
|
159
|
+
this.order = { owner: this.owner, cells: this.order.cells.slice() };
|
|
160
|
+
let node = this.order;
|
|
161
|
+
for (let shift = this.shift; shift > 0; shift -= 5) {
|
|
162
|
+
const at = Math.floor(position / 2 ** shift) & 31;
|
|
163
|
+
let child = node.cells[at];
|
|
164
|
+
if (!child || child.owner !== this.owner) {
|
|
165
|
+
child = { owner: this.owner, cells: child?.cells.slice() ?? [] };
|
|
166
|
+
node.cells[at] = child;
|
|
167
|
+
}
|
|
168
|
+
node = child;
|
|
169
|
+
}
|
|
170
|
+
node.cells[position & 31] = entry;
|
|
171
|
+
}
|
|
172
|
+
compact() {
|
|
173
|
+
const entries = [];
|
|
174
|
+
for (let position = 0; position < this.length; position++) {
|
|
175
|
+
const entry = this.leaf(position).cells[position & 31];
|
|
176
|
+
if (entry)
|
|
177
|
+
entries.push(entry);
|
|
178
|
+
}
|
|
179
|
+
this.index = { owner: this.owner, groups: [] };
|
|
180
|
+
this.order = { owner: this.owner, cells: [] };
|
|
181
|
+
this.shift = this.length = this.count = 0;
|
|
182
|
+
for (const original of entries) {
|
|
183
|
+
const entry = { ...original, position: this.length++ };
|
|
184
|
+
this.writableBucket(hashKey(entry.key)).set(entry.key, entry);
|
|
185
|
+
this.writeOrder(entry.position, entry);
|
|
186
|
+
this.count++;
|
|
187
|
+
}
|
|
188
|
+
this.layout++;
|
|
189
|
+
}
|
|
190
|
+
*iterate(kind) {
|
|
191
|
+
let position = 0;
|
|
192
|
+
let layout = this.layout;
|
|
193
|
+
let cleared = this.cleared;
|
|
194
|
+
let lastSequence = -1;
|
|
195
|
+
let version = -1;
|
|
196
|
+
let leaf;
|
|
197
|
+
let page = -1;
|
|
198
|
+
for (; ; ) {
|
|
199
|
+
if (cleared !== this.cleared) {
|
|
200
|
+
position = 0;
|
|
201
|
+
lastSequence = -1;
|
|
202
|
+
cleared = this.cleared;
|
|
203
|
+
}
|
|
204
|
+
if (layout !== this.layout) {
|
|
205
|
+
position = 0;
|
|
206
|
+
while (position < this.length) {
|
|
207
|
+
const entry2 = this.leaf(position).cells[position & 31];
|
|
208
|
+
if (entry2 && entry2.sequence > lastSequence)
|
|
209
|
+
break;
|
|
210
|
+
position++;
|
|
211
|
+
}
|
|
212
|
+
layout = this.layout;
|
|
213
|
+
}
|
|
214
|
+
if (position >= this.length)
|
|
215
|
+
return;
|
|
216
|
+
const nextPage = Math.floor(position / 32);
|
|
217
|
+
if (page !== nextPage || version !== this.version) {
|
|
218
|
+
leaf = this.leaf(position);
|
|
219
|
+
page = nextPage;
|
|
220
|
+
version = this.version;
|
|
221
|
+
}
|
|
222
|
+
const entry = leaf?.cells[position++ & 31];
|
|
223
|
+
if (!entry)
|
|
224
|
+
continue;
|
|
225
|
+
lastSequence = entry.sequence;
|
|
226
|
+
yield kind === 0 ? [entry.key, entry.value] : kind === 1 ? entry.key : entry.value;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
function hashKey(key) {
|
|
231
|
+
if (typeof key === "number" && Number.isInteger(key))
|
|
232
|
+
return mix((key | 0) ^ (key / 4294967296 | 0));
|
|
233
|
+
if (typeof key === "bigint")
|
|
234
|
+
return mix(Number(BigInt.asIntN(32, key ^ key >> 32n)));
|
|
235
|
+
const text = String(key);
|
|
236
|
+
let hash = 2166136261;
|
|
237
|
+
for (let i = 0; i < text.length; i++)
|
|
238
|
+
hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
|
|
239
|
+
return hash;
|
|
240
|
+
}
|
|
241
|
+
function mix(value) {
|
|
242
|
+
value = Math.imul(value ^ value >>> 16, 73244475);
|
|
243
|
+
value = Math.imul(value ^ value >>> 16, 73244475);
|
|
244
|
+
return value ^ value >>> 16;
|
|
245
|
+
}
|
|
246
|
+
|
|
1
247
|
// ../../core/dist/mount.js
|
|
2
248
|
var prefixes = /* @__PURE__ */ new WeakMap();
|
|
3
249
|
var requestBaseUrl = (request) => new URL(request.url).origin + (prefixes.get(request) ?? "");
|
|
@@ -7091,10 +7337,81 @@ function parseArrayText(t, text, ctx) {
|
|
|
7091
7337
|
|
|
7092
7338
|
// src/storage/database-state.ts
|
|
7093
7339
|
var TableData = class _TableData {
|
|
7340
|
+
/** @internal Optional physical row journal; IDs remain stable across heap splices. */
|
|
7341
|
+
durableChanges = null;
|
|
7342
|
+
durableNextId = 0;
|
|
7343
|
+
durableEpoch;
|
|
7344
|
+
durableUnsafe = false;
|
|
7345
|
+
durableIds;
|
|
7346
|
+
enableDurabilityTracking(ids, nextId) {
|
|
7347
|
+
if (this.durableChanges && !this.durableUnsafe && !ids) return;
|
|
7348
|
+
this.materializeSlab();
|
|
7349
|
+
this.durableIds = /* @__PURE__ */ new WeakMap();
|
|
7350
|
+
this.durableChanges = new ForkMap();
|
|
7351
|
+
this.durableNextId = nextId ?? this.#rows.length;
|
|
7352
|
+
for (let i = 0; i < this.#rows.length; i++) this.durableIds.set(this.#rows[i], ids?.[i] ?? i);
|
|
7353
|
+
this.durableEpoch = {};
|
|
7354
|
+
this.durableUnsafe = false;
|
|
7355
|
+
}
|
|
7356
|
+
durableRowId(row) {
|
|
7357
|
+
const id = this.durableIds?.get(row);
|
|
7358
|
+
if (id === void 0) throw new Error("Untracked durable row");
|
|
7359
|
+
return id;
|
|
7360
|
+
}
|
|
7361
|
+
disableDurabilityTracking() {
|
|
7362
|
+
this.durableChanges = null;
|
|
7363
|
+
this.durableIds = void 0;
|
|
7364
|
+
this.durableEpoch = void 0;
|
|
7365
|
+
this.durableUnsafe = false;
|
|
7366
|
+
}
|
|
7367
|
+
recordDurableRow(row, previous) {
|
|
7368
|
+
if (!this.durableChanges) return;
|
|
7369
|
+
const id = (previous && this.durableIds?.get(previous)) ?? this.durableIds?.get(row) ?? this.durableNextId++;
|
|
7370
|
+
this.durableIds.set(row, id);
|
|
7371
|
+
this.durableChanges.set(id, { row, xmin: this.rowXmins.get(row) ?? 2 });
|
|
7372
|
+
}
|
|
7373
|
+
recordDurableDelete(row) {
|
|
7374
|
+
if (this.durableChanges) this.durableChanges.set(this.durableRowId(row), { row: null, xmin: 0 });
|
|
7375
|
+
}
|
|
7376
|
+
/** @internal Metadata twin with no visits/copies of existing rows or index entries. */
|
|
7377
|
+
emptyForDurability() {
|
|
7378
|
+
const copy2 = new _TableData(this.schema, this.name, this.columns, this.oid, this.temp);
|
|
7379
|
+
copy2.constraints = this.constraints;
|
|
7380
|
+
copy2.triggers = this.triggers;
|
|
7381
|
+
copy2.unlogged = this.unlogged;
|
|
7382
|
+
return copy2;
|
|
7383
|
+
}
|
|
7384
|
+
/** @internal Serialization/SQL scans must not count as public native-array exposure. */
|
|
7385
|
+
serializationRows() {
|
|
7386
|
+
this.materializeSlab();
|
|
7387
|
+
return this.materializedRows();
|
|
7388
|
+
}
|
|
7389
|
+
/** @internal Internal mutable array access, with ordinary public mutableRows kept intact. */
|
|
7390
|
+
writeRows() {
|
|
7391
|
+
return this.serializationRows();
|
|
7392
|
+
}
|
|
7393
|
+
/** @internal Ordinary snapshot branches must not inherit a persistence journal. */
|
|
7394
|
+
untrackedFork() {
|
|
7395
|
+
const copy2 = this.emptyForDurability();
|
|
7396
|
+
copy2.rowXmins = this.rowXmins;
|
|
7397
|
+
copy2.slabXmins = this.slabXmins;
|
|
7398
|
+
if (this.slab) copy2.slab = this.slab;
|
|
7399
|
+
else {
|
|
7400
|
+
copy2.#rows = this.#rows;
|
|
7401
|
+
copy2.#rowPatches = this.#rowPatches?.fork() ?? null;
|
|
7402
|
+
copy2.#rowsShared = this.#rowsShared = true;
|
|
7403
|
+
copy2.tuplesShared = this.tuplesShared = true;
|
|
7404
|
+
}
|
|
7405
|
+
copy2.indexStores = this.indexStores ? new Map([...this.indexStores].map(([name, store]) => [name, store.clone()])) : null;
|
|
7406
|
+
return copy2;
|
|
7407
|
+
}
|
|
7094
7408
|
name;
|
|
7095
7409
|
schema;
|
|
7096
7410
|
columns;
|
|
7097
|
-
rows;
|
|
7411
|
+
#rows = [];
|
|
7412
|
+
#rowPatches = null;
|
|
7413
|
+
#rowsShared = false;
|
|
7414
|
+
#rowsExposed = false;
|
|
7098
7415
|
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
7099
7416
|
slabXmins = null;
|
|
7100
7417
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
@@ -7110,22 +7427,54 @@ var TableData = class _TableData {
|
|
|
7110
7427
|
shareCount = 0;
|
|
7111
7428
|
/** Derived unique/btree index maps; null until built or invalidated. */
|
|
7112
7429
|
indexStores = null;
|
|
7430
|
+
/** DML replaces tuples; DDL must detach them before changing cells in place. */
|
|
7431
|
+
tuplesShared = false;
|
|
7113
7432
|
constructor(schema, name, columns, oid, temp = false) {
|
|
7114
7433
|
this.schema = schema;
|
|
7115
7434
|
this.name = name;
|
|
7116
7435
|
this.columns = columns;
|
|
7117
|
-
this
|
|
7436
|
+
Object.defineProperty(this, "rows", {
|
|
7437
|
+
enumerable: true,
|
|
7438
|
+
configurable: true,
|
|
7439
|
+
get: this.nativeRows,
|
|
7440
|
+
set: this.setNativeRows
|
|
7441
|
+
});
|
|
7118
7442
|
this.constraints = [];
|
|
7119
7443
|
this.triggers = [];
|
|
7120
7444
|
this.temp = temp;
|
|
7121
7445
|
this.oid = oid;
|
|
7122
7446
|
}
|
|
7123
7447
|
rowCount() {
|
|
7124
|
-
return this.slab ? this.slab.rowCount : this
|
|
7448
|
+
return this.slab ? this.slab.rowCount : this.#rows.length;
|
|
7125
7449
|
}
|
|
7126
7450
|
rowAt(index) {
|
|
7127
7451
|
if (this.slab) return this.slab.rowAt(index);
|
|
7128
|
-
return this
|
|
7452
|
+
return this.#rowPatches?.get(index) ?? this.#rows[index] ?? [];
|
|
7453
|
+
}
|
|
7454
|
+
/** Replace an existing tuple without copying the array of unchanged row references. */
|
|
7455
|
+
replaceRow(index, row) {
|
|
7456
|
+
if (this.durableChanges) this.recordDurableRow(row, this.rowAt(index));
|
|
7457
|
+
if (this.#rowPatches) this.#rowPatches.set(index, row);
|
|
7458
|
+
else this.#rows[index] = row;
|
|
7459
|
+
}
|
|
7460
|
+
materializedRows() {
|
|
7461
|
+
if (this.#rowsShared) this.#rows = this.#rows.slice();
|
|
7462
|
+
if (this.#rowPatches) for (const [index, row] of this.#rowPatches) this.#rows[index] = row;
|
|
7463
|
+
this.#rowPatches = null;
|
|
7464
|
+
this.#rowsShared = false;
|
|
7465
|
+
return this.#rows;
|
|
7466
|
+
}
|
|
7467
|
+
nativeRows() {
|
|
7468
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
7469
|
+
this.#rowsExposed = true;
|
|
7470
|
+
return this.materializedRows();
|
|
7471
|
+
}
|
|
7472
|
+
setNativeRows(rows) {
|
|
7473
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
7474
|
+
this.#rows = rows;
|
|
7475
|
+
this.#rowPatches = null;
|
|
7476
|
+
this.#rowsShared = false;
|
|
7477
|
+
this.#rowsExposed = true;
|
|
7129
7478
|
}
|
|
7130
7479
|
/** All rows for scans; materializes slab once into `rows` when needed. */
|
|
7131
7480
|
allRows() {
|
|
@@ -7134,13 +7483,15 @@ var TableData = class _TableData {
|
|
|
7134
7483
|
}
|
|
7135
7484
|
attachSlab(slab) {
|
|
7136
7485
|
this.slab = slab;
|
|
7137
|
-
this
|
|
7486
|
+
this.#rows = [];
|
|
7487
|
+
this.#rowPatches = null;
|
|
7488
|
+
this.#rowsShared = false;
|
|
7138
7489
|
}
|
|
7139
7490
|
materializeSlab() {
|
|
7140
7491
|
if (!this.slab) return;
|
|
7141
|
-
this
|
|
7492
|
+
this.#rows = this.slab.materialize();
|
|
7142
7493
|
if (this.slabXmins)
|
|
7143
|
-
this
|
|
7494
|
+
this.#rows.forEach((row, index) => {
|
|
7144
7495
|
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
7145
7496
|
});
|
|
7146
7497
|
this.slabXmins = null;
|
|
@@ -7164,7 +7515,7 @@ var TableData = class _TableData {
|
|
|
7164
7515
|
columnIndex(name) {
|
|
7165
7516
|
return this.columns.findIndex((c) => c.name === name);
|
|
7166
7517
|
}
|
|
7167
|
-
|
|
7518
|
+
cloneMetadata() {
|
|
7168
7519
|
const t = new _TableData(
|
|
7169
7520
|
this.schema,
|
|
7170
7521
|
this.name,
|
|
@@ -7172,21 +7523,68 @@ var TableData = class _TableData {
|
|
|
7172
7523
|
this.oid,
|
|
7173
7524
|
this.temp
|
|
7174
7525
|
);
|
|
7526
|
+
t.unlogged = this.unlogged;
|
|
7527
|
+
t.durableChanges = this.durableChanges?.fork() ?? null;
|
|
7528
|
+
t.durableIds = this.durableIds;
|
|
7529
|
+
t.durableNextId = this.durableNextId;
|
|
7530
|
+
t.durableEpoch = this.durableEpoch;
|
|
7531
|
+
t.durableUnsafe = this.durableUnsafe;
|
|
7532
|
+
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
7533
|
+
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
7534
|
+
t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
|
|
7535
|
+
return t;
|
|
7536
|
+
}
|
|
7537
|
+
clone() {
|
|
7538
|
+
const t = this.cloneMetadata();
|
|
7539
|
+
if (t.durableChanges) t.durableUnsafe = true;
|
|
7175
7540
|
if (this.slab) {
|
|
7176
|
-
t
|
|
7541
|
+
t.#rows = this.slab.materialize().map((r) => r.slice());
|
|
7177
7542
|
} else {
|
|
7178
|
-
t
|
|
7543
|
+
t.#rows = this.materializedRows().map((r) => r.slice());
|
|
7179
7544
|
}
|
|
7180
|
-
t
|
|
7181
|
-
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this
|
|
7545
|
+
t.#rows.forEach((row, index) => {
|
|
7546
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.#rows[index]);
|
|
7182
7547
|
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
7183
7548
|
});
|
|
7184
|
-
t.unlogged = this.unlogged;
|
|
7185
|
-
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
7186
|
-
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
7187
|
-
t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
|
|
7188
7549
|
return t;
|
|
7189
7550
|
}
|
|
7551
|
+
/** DML creates new tuple arrays; retain existing tuples and xmin bindings until DDL. */
|
|
7552
|
+
cloneForDml() {
|
|
7553
|
+
if (this.triggers.length > 0) return this.cloneForWrite();
|
|
7554
|
+
const t = this.cloneMetadata();
|
|
7555
|
+
t.rowXmins = this.rowXmins;
|
|
7556
|
+
if (this.slab) {
|
|
7557
|
+
t.#rows = this.slab.materialize();
|
|
7558
|
+
if (this.slabXmins) {
|
|
7559
|
+
for (let index = 0; index < t.#rows.length; index++)
|
|
7560
|
+
t.rowXmins.set(t.#rows[index], this.slabXmins[index] ?? 2);
|
|
7561
|
+
}
|
|
7562
|
+
} else {
|
|
7563
|
+
if (this.#rows.length >= 4096 && !this.#rowsExposed) {
|
|
7564
|
+
this.#rowPatches ??= new ForkMap();
|
|
7565
|
+
t.#rowPatches = this.#rowPatches.fork();
|
|
7566
|
+
t.#rows = this.#rows;
|
|
7567
|
+
t.#rowsShared = this.#rowsShared = true;
|
|
7568
|
+
} else t.#rows = this.materializedRows().slice();
|
|
7569
|
+
this.tuplesShared = true;
|
|
7570
|
+
}
|
|
7571
|
+
t.tuplesShared = true;
|
|
7572
|
+
return t;
|
|
7573
|
+
}
|
|
7574
|
+
/** A live DML fork can be unfrozen while its unchanged tuples still belong to history. */
|
|
7575
|
+
ownTuples() {
|
|
7576
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
7577
|
+
if (!this.tuplesShared) return;
|
|
7578
|
+
const xmins = /* @__PURE__ */ new WeakMap();
|
|
7579
|
+
this.rows = this.rows.map((row) => {
|
|
7580
|
+
const copy2 = row.slice();
|
|
7581
|
+
const xmin = this.rowXmins.get(row);
|
|
7582
|
+
if (xmin !== void 0) xmins.set(copy2, xmin);
|
|
7583
|
+
return copy2;
|
|
7584
|
+
});
|
|
7585
|
+
this.rowXmins = xmins;
|
|
7586
|
+
this.tuplesShared = false;
|
|
7587
|
+
}
|
|
7190
7588
|
/** Independent writable copy (row tuples copied so ALTER COLUMN is isolated). */
|
|
7191
7589
|
cloneForWrite() {
|
|
7192
7590
|
const t = this.clone();
|
|
@@ -7540,12 +7938,21 @@ var DatabaseState = class _DatabaseState {
|
|
|
7540
7938
|
}
|
|
7541
7939
|
}
|
|
7542
7940
|
ensureWritableTable(table) {
|
|
7543
|
-
if (!table.frozen)
|
|
7941
|
+
if (!table.frozen) {
|
|
7942
|
+
table.ownTuples();
|
|
7943
|
+
return table;
|
|
7944
|
+
}
|
|
7544
7945
|
const schema = this.schemas.get(table.schema);
|
|
7545
7946
|
const copy2 = table.cloneForWrite();
|
|
7546
7947
|
schema?.tables.set(table.name, copy2);
|
|
7547
7948
|
return copy2;
|
|
7548
7949
|
}
|
|
7950
|
+
ensureWritableTableForDml(table) {
|
|
7951
|
+
if (!table.frozen) return table;
|
|
7952
|
+
const copy2 = table.cloneForDml();
|
|
7953
|
+
this.schemas.get(table.schema)?.tables.set(table.name, copy2);
|
|
7954
|
+
return copy2;
|
|
7955
|
+
}
|
|
7549
7956
|
ensureWritableSequence(seq) {
|
|
7550
7957
|
if ((seq.shareCount ?? 0) === 0) return seq;
|
|
7551
7958
|
const schema = this.schemas.get(seq.schema);
|
|
@@ -10655,7 +11062,7 @@ function evalPgcryptoFunction(ctx, fn, args) {
|
|
|
10655
11062
|
// src/functions/hash-fns.ts
|
|
10656
11063
|
var utf83 = new TextEncoder();
|
|
10657
11064
|
var rot = (x, k) => (x << k | x >>> 32 - k) >>> 0;
|
|
10658
|
-
function
|
|
11065
|
+
function mix2(s) {
|
|
10659
11066
|
s[0] = s[0] - s[2] >>> 0;
|
|
10660
11067
|
s[0] = (s[0] ^ rot(s[2], 4)) >>> 0;
|
|
10661
11068
|
s[2] = s[2] + s[1] >>> 0;
|
|
@@ -10699,7 +11106,7 @@ function hashAny(k, seed) {
|
|
|
10699
11106
|
const bits = BigInt.asUintN(64, seed);
|
|
10700
11107
|
s[0] = s[0] + Number(bits >> 32n) >>> 0;
|
|
10701
11108
|
s[1] = s[1] + Number(bits & 0xffffffffn) >>> 0;
|
|
10702
|
-
|
|
11109
|
+
mix2(s);
|
|
10703
11110
|
}
|
|
10704
11111
|
let at = 0;
|
|
10705
11112
|
let len = k.length;
|
|
@@ -10707,7 +11114,7 @@ function hashAny(k, seed) {
|
|
|
10707
11114
|
s[0] = s[0] + word(k, at) >>> 0;
|
|
10708
11115
|
s[1] = s[1] + word(k, at + 4) >>> 0;
|
|
10709
11116
|
s[2] = s[2] + word(k, at + 8) >>> 0;
|
|
10710
|
-
|
|
11117
|
+
mix2(s);
|
|
10711
11118
|
}
|
|
10712
11119
|
for (let i = len - 1; i >= 0; i--) {
|
|
10713
11120
|
const byte = k[at + i];
|
|
@@ -17279,6 +17686,21 @@ var IndexStore = class _IndexStore {
|
|
|
17279
17686
|
name;
|
|
17280
17687
|
unique;
|
|
17281
17688
|
entries = /* @__PURE__ */ new Map();
|
|
17689
|
+
integerKeys = null;
|
|
17690
|
+
shared = false;
|
|
17691
|
+
ownedBuckets = /* @__PURE__ */ new WeakSet();
|
|
17692
|
+
writableBucket(key, bucket) {
|
|
17693
|
+
if (this.ownedBuckets.has(bucket)) return bucket;
|
|
17694
|
+
const copy2 = bucket.slice();
|
|
17695
|
+
this.entries.set(key, copy2);
|
|
17696
|
+
this.ownedBuckets.add(copy2);
|
|
17697
|
+
return copy2;
|
|
17698
|
+
}
|
|
17699
|
+
detach() {
|
|
17700
|
+
if (!this.shared) return;
|
|
17701
|
+
if (!(this.entries instanceof ForkMap)) this.entries = new Map(this.entries);
|
|
17702
|
+
this.shared = false;
|
|
17703
|
+
}
|
|
17282
17704
|
constructor(name, unique = false) {
|
|
17283
17705
|
this.name = name;
|
|
17284
17706
|
this.unique = unique;
|
|
@@ -17297,36 +17719,78 @@ var IndexStore = class _IndexStore {
|
|
|
17297
17719
|
}
|
|
17298
17720
|
insert(key, rowIdx) {
|
|
17299
17721
|
if (this.unique) this.checkUnique(key, rowIdx);
|
|
17722
|
+
this.detach();
|
|
17723
|
+
this.integerKeys = null;
|
|
17300
17724
|
const existing = this.entries.get(key);
|
|
17301
17725
|
if (!existing) {
|
|
17302
|
-
|
|
17726
|
+
const bucket = [rowIdx];
|
|
17727
|
+
this.ownedBuckets.add(bucket);
|
|
17728
|
+
this.entries.set(key, bucket);
|
|
17303
17729
|
return;
|
|
17304
17730
|
}
|
|
17305
17731
|
if (existing.includes(rowIdx)) return;
|
|
17306
|
-
existing.push(rowIdx);
|
|
17732
|
+
this.writableBucket(key, existing).push(rowIdx);
|
|
17307
17733
|
}
|
|
17308
17734
|
remove(key, rowIdx) {
|
|
17309
17735
|
const existing = this.entries.get(key);
|
|
17310
17736
|
if (!existing) return;
|
|
17311
17737
|
const at = existing.indexOf(rowIdx);
|
|
17312
17738
|
if (at < 0) return;
|
|
17313
|
-
|
|
17314
|
-
|
|
17739
|
+
this.detach();
|
|
17740
|
+
this.integerKeys = null;
|
|
17741
|
+
if (existing.length === 1) this.entries.delete(key);
|
|
17742
|
+
else {
|
|
17743
|
+
const remaining = this.writableBucket(key, existing);
|
|
17744
|
+
remaining.splice(at, 1);
|
|
17745
|
+
this.entries.set(key, remaining);
|
|
17746
|
+
}
|
|
17315
17747
|
}
|
|
17316
17748
|
lookup(key) {
|
|
17317
17749
|
return this.entries.get(key) ?? [];
|
|
17318
17750
|
}
|
|
17751
|
+
/** Ordered access for a single int2/int4 key (the planner validates the key type). */
|
|
17752
|
+
integerRange(lower, upper, includeLower, includeUpper) {
|
|
17753
|
+
const keys = this.integerKeys ??= [...this.entries].map(([key, rows]) => ({ value: Number(key.slice(1)), rows })).sort((a, b) => a.value - b.value);
|
|
17754
|
+
let lo = 0;
|
|
17755
|
+
let hi = keys.length;
|
|
17756
|
+
while (lo < hi) {
|
|
17757
|
+
const mid = lo + hi >>> 1;
|
|
17758
|
+
const value = keys[mid].value;
|
|
17759
|
+
if (value < lower || !includeLower && value === lower) lo = mid + 1;
|
|
17760
|
+
else hi = mid;
|
|
17761
|
+
}
|
|
17762
|
+
const result = [];
|
|
17763
|
+
for (let i = lo; i < keys.length; i++) {
|
|
17764
|
+
const key = keys[i];
|
|
17765
|
+
if (key.value > upper || !includeUpper && key.value === upper) break;
|
|
17766
|
+
result.push(...key.rows);
|
|
17767
|
+
}
|
|
17768
|
+
return result.sort((a, b) => a - b);
|
|
17769
|
+
}
|
|
17319
17770
|
clear() {
|
|
17320
|
-
this.entries
|
|
17771
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
17772
|
+
this.shared = false;
|
|
17773
|
+
this.integerKeys = null;
|
|
17321
17774
|
}
|
|
17322
17775
|
clone() {
|
|
17323
17776
|
const copy2 = new _IndexStore(this.name, this.unique);
|
|
17324
|
-
|
|
17777
|
+
if (this.entries.size >= 4096 && !(this.entries instanceof ForkMap)) this.entries = new ForkMap(this.entries);
|
|
17778
|
+
copy2.entries = this.entries instanceof ForkMap ? this.entries.fork() : this.entries;
|
|
17779
|
+
copy2.integerKeys = this.integerKeys;
|
|
17780
|
+
copy2.shared = true;
|
|
17781
|
+
this.shared = true;
|
|
17782
|
+
this.ownedBuckets = /* @__PURE__ */ new WeakSet();
|
|
17325
17783
|
return copy2;
|
|
17326
17784
|
}
|
|
17327
17785
|
};
|
|
17328
17786
|
|
|
17329
17787
|
// src/indexes/maintain.ts
|
|
17788
|
+
function prepareDmlIndexStores(env, table) {
|
|
17789
|
+
if (table.indexStores || !table.frozen || table.triggers.length > 0) return;
|
|
17790
|
+
const specs = uniqueSpecsFor(env, table);
|
|
17791
|
+
if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) return;
|
|
17792
|
+
ensureIndexStores(env, table);
|
|
17793
|
+
}
|
|
17330
17794
|
function ensureIndexStores(env, table) {
|
|
17331
17795
|
if (table.indexStores) return table.indexStores;
|
|
17332
17796
|
const stores = /* @__PURE__ */ new Map();
|
|
@@ -17377,8 +17841,19 @@ function indexRemoveRow(env, table, rowIdx, row) {
|
|
|
17377
17841
|
}
|
|
17378
17842
|
}
|
|
17379
17843
|
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
17380
|
-
|
|
17381
|
-
|
|
17844
|
+
const specs = uniqueSpecsFor(env, table);
|
|
17845
|
+
if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) {
|
|
17846
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
17847
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
17848
|
+
return;
|
|
17849
|
+
}
|
|
17850
|
+
for (const spec of specs) {
|
|
17851
|
+
const before = uniqueKeyOf(env, table, spec, oldRow);
|
|
17852
|
+
const after = uniqueKeyOf(env, table, spec, newRow);
|
|
17853
|
+
if (before === after) continue;
|
|
17854
|
+
if (before !== null) table.indexStores?.get(spec.name)?.remove(before, rowIdx);
|
|
17855
|
+
if (after !== null) indexStoreFor(env, table, spec).insert(after, rowIdx);
|
|
17856
|
+
}
|
|
17382
17857
|
}
|
|
17383
17858
|
function rebuildTableIndexes(env, table) {
|
|
17384
17859
|
table.indexStores = null;
|
|
@@ -17595,6 +18070,82 @@ function conjunctions(expr) {
|
|
|
17595
18070
|
}
|
|
17596
18071
|
return [expr];
|
|
17597
18072
|
}
|
|
18073
|
+
function tryPointRowIndices(env, table, alias, where) {
|
|
18074
|
+
const eqs = [];
|
|
18075
|
+
for (const part of conjunctions(where)) {
|
|
18076
|
+
const eq = equalityAgainstConst(part);
|
|
18077
|
+
if (!eq || !["param", "number_lit", "string_lit", "bool_lit", "null_lit"].includes(eq.valueExpr.type)) return null;
|
|
18078
|
+
if (part.type !== "binop") return null;
|
|
18079
|
+
const column = part.left.type === "colref" ? part.left : part.right;
|
|
18080
|
+
if (column.type !== "colref") return null;
|
|
18081
|
+
if (column.parts.length > 1 && column.parts[column.parts.length - 2] !== alias) return null;
|
|
18082
|
+
eqs.push(eq);
|
|
18083
|
+
}
|
|
18084
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
18085
|
+
if (spec.where || spec.keys.length !== eqs.length || spec.keys.some((key2) => key2.expr) || !eqs.every((eq, index) => eq.column === spec.columnNames[index]))
|
|
18086
|
+
continue;
|
|
18087
|
+
const values = table.columns.map(() => null);
|
|
18088
|
+
let matches3 = true;
|
|
18089
|
+
for (let index = 0; index < spec.keys.length; index++) {
|
|
18090
|
+
const key2 = spec.keys[index];
|
|
18091
|
+
const column = table.columns[key2.colIdx];
|
|
18092
|
+
const eq = eqs[index];
|
|
18093
|
+
if (!column || !eq || column.domain) {
|
|
18094
|
+
matches3 = false;
|
|
18095
|
+
break;
|
|
18096
|
+
}
|
|
18097
|
+
const value = evalExpr(env.ctx, makeEvalScope(env, null), eq.valueExpr);
|
|
18098
|
+
if (value.t !== column.type.id && !(column.type.id === "text" && value.t === "unknown" && typeof value.v === "string")) {
|
|
18099
|
+
matches3 = false;
|
|
18100
|
+
break;
|
|
18101
|
+
}
|
|
18102
|
+
values[key2.colIdx] = value.v;
|
|
18103
|
+
}
|
|
18104
|
+
if (!matches3) continue;
|
|
18105
|
+
const key = uniqueKeyOf(env, table, spec, values);
|
|
18106
|
+
return { indices: key === null ? [] : indexStoreFor(env, table, spec).lookup(key), indexName: spec.name };
|
|
18107
|
+
}
|
|
18108
|
+
return null;
|
|
18109
|
+
}
|
|
18110
|
+
function recordIndexScan(env, table, name) {
|
|
18111
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
18112
|
+
const index = schema?.indexes.get(name);
|
|
18113
|
+
if (schema && index) {
|
|
18114
|
+
const lastScan = env.ctx.state.clock().getTime();
|
|
18115
|
+
schema.indexes.set(name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
|
|
18116
|
+
}
|
|
18117
|
+
}
|
|
18118
|
+
function tryRangeRowIndices(env, table, alias, where) {
|
|
18119
|
+
const parts = conjunctions(where);
|
|
18120
|
+
if (parts.length !== 2) return null;
|
|
18121
|
+
const bounds = [];
|
|
18122
|
+
for (const part of parts) {
|
|
18123
|
+
if (part.type !== "binop" || ![">", ">=", "<", "<="].includes(part.op)) return null;
|
|
18124
|
+
const column2 = part.left.type === "colref" ? part.left : part.right;
|
|
18125
|
+
const value = part.left.type === "colref" ? part.right : part.left;
|
|
18126
|
+
if (column2.type !== "colref" || column2.parts.length > 2 || column2.parts.length === 2 && column2.parts[0] !== alias || !["param", "number_lit"].includes(value.type))
|
|
18127
|
+
return null;
|
|
18128
|
+
const op = part.left === column2 ? part.op : { ">": "<", ">=": "<=", "<": ">", "<=": ">=" }[part.op];
|
|
18129
|
+
bounds.push({ column: column2.parts.at(-1), op, value });
|
|
18130
|
+
}
|
|
18131
|
+
const lower = bounds.find((bound) => bound.op === ">" || bound.op === ">=");
|
|
18132
|
+
const upper = bounds.find((bound) => bound.op === "<" || bound.op === "<=");
|
|
18133
|
+
if (!lower || !upper || lower.column !== upper.column) return null;
|
|
18134
|
+
const column = table.columns.find((column2) => column2.name === lower.column);
|
|
18135
|
+
if (!column || column.domain || !["int2", "int4"].includes(column.type.id)) return null;
|
|
18136
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
18137
|
+
if (spec.where || spec.keys.length !== 1 || spec.keys[0].expr || spec.columnNames[0] !== lower.column) continue;
|
|
18138
|
+
const low = evalExpr(env.ctx, makeEvalScope(env, null), lower.value);
|
|
18139
|
+
const high = evalExpr(env.ctx, makeEvalScope(env, null), upper.value);
|
|
18140
|
+
if (low.t !== column.type.id || high.t !== column.type.id || typeof low.v !== "number" || typeof high.v !== "number")
|
|
18141
|
+
return null;
|
|
18142
|
+
return {
|
|
18143
|
+
indices: indexStoreFor(env, table, spec).integerRange(low.v, high.v, lower.op === ">=", upper.op === "<="),
|
|
18144
|
+
indexName: spec.name
|
|
18145
|
+
};
|
|
18146
|
+
}
|
|
18147
|
+
return null;
|
|
18148
|
+
}
|
|
17598
18149
|
function tryIndexedTableRows(env, table, alias, where) {
|
|
17599
18150
|
const parts = conjunctions(where);
|
|
17600
18151
|
const eqs = [];
|
|
@@ -17631,12 +18182,7 @@ function tryIndexedTableRows(env, table, alias, where) {
|
|
|
17631
18182
|
const key = uniqueKeyOf(env, table, spec, probeRow);
|
|
17632
18183
|
if (key === null) return [];
|
|
17633
18184
|
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
17634
|
-
|
|
17635
|
-
const index = schema?.indexes.get(spec.name);
|
|
17636
|
-
if (schema && index) {
|
|
17637
|
-
const lastScan = env.ctx.state.clock().getTime();
|
|
17638
|
-
schema.indexes.set(spec.name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
|
|
17639
|
-
}
|
|
18185
|
+
recordIndexScan(env, table, spec.name);
|
|
17640
18186
|
return hits.map((i) => table.rowAt(i));
|
|
17641
18187
|
}
|
|
17642
18188
|
function tryIndexedFromItem(env, item, where) {
|
|
@@ -23612,7 +24158,7 @@ function renameWithAliases(rel4, label, colAliases, what) {
|
|
|
23612
24158
|
}));
|
|
23613
24159
|
return { columns, rows: rel4.rows };
|
|
23614
24160
|
}
|
|
23615
|
-
function materializeItem(env, item, scope) {
|
|
24161
|
+
function materializeItem(env, item, scope, shapeOnly = false) {
|
|
23616
24162
|
switch (item.type) {
|
|
23617
24163
|
case "from_table": {
|
|
23618
24164
|
const label = item.alias ?? item.name[item.name.length - 1];
|
|
@@ -23631,7 +24177,7 @@ function materializeItem(env, item, scope) {
|
|
|
23631
24177
|
...table.columns.map((c) => ({ name: c.name, type: c.type.id, mod: c.type.mod, table: label })),
|
|
23632
24178
|
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
23633
24179
|
],
|
|
23634
|
-
rows: table.
|
|
24180
|
+
rows: shapeOnly ? [] : table.serializationRows().map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
23635
24181
|
};
|
|
23636
24182
|
return { rel: renameWithAliases(rel4, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
23637
24183
|
}
|
|
@@ -24904,14 +25450,30 @@ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
|
|
|
24904
25450
|
function executeCore(env0, core, orderBy, opts) {
|
|
24905
25451
|
const env = env0;
|
|
24906
25452
|
const ctx = env.ctx;
|
|
24907
|
-
const
|
|
25453
|
+
const item = core.from.length === 1 ? core.from[0] : null;
|
|
25454
|
+
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;
|
|
25455
|
+
const point2 = pointTable && core.where && item?.type === "from_table" ? tryPointRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
|
|
25456
|
+
const range = !point2 && pointTable && core.where && item?.type === "from_table" ? tryRangeRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
|
|
25457
|
+
const access = point2 ?? range;
|
|
25458
|
+
const source = access && item ? materializeItem(env, item, env.outer, true) : buildFrom(env, core.from, core.where);
|
|
24908
25459
|
const srcCols = source.rel.columns;
|
|
24909
25460
|
const rangeVars = source.rangeVars;
|
|
24910
25461
|
const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
|
|
24911
25462
|
let srcRows = source.rel.rows;
|
|
24912
25463
|
if (core.where) {
|
|
24913
25464
|
checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
|
|
24914
|
-
if (
|
|
25465
|
+
if (access && pointTable) {
|
|
25466
|
+
pointTable.materializeSlab();
|
|
25467
|
+
srcRows = access.indices.map((index) => {
|
|
25468
|
+
const row = pointTable.rowAt(index);
|
|
25469
|
+
return [...row, pointTable.rowXmins.get(row) ?? 2];
|
|
25470
|
+
});
|
|
25471
|
+
if (range) {
|
|
25472
|
+
const where = core.where;
|
|
25473
|
+
srcRows = srcRows.filter((row) => evalPredicate2(env, rowScope(row), where));
|
|
25474
|
+
}
|
|
25475
|
+
recordIndexScan(env, pointTable, access.indexName);
|
|
25476
|
+
} else if (core.from.length === 1) {
|
|
24915
25477
|
const indexed = tryIndexedFromItem(env, core.from[0], core.where);
|
|
24916
25478
|
if (indexed !== null) {
|
|
24917
25479
|
srcRows = indexed;
|
|
@@ -25092,11 +25654,11 @@ function executeCore(env0, core, orderBy, opts) {
|
|
|
25092
25654
|
}
|
|
25093
25655
|
}
|
|
25094
25656
|
}
|
|
25095
|
-
const
|
|
25657
|
+
const item2 = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
|
|
25096
25658
|
const spec = { colIdx: projItems.length, dir, nullsFirst };
|
|
25097
|
-
projItems.push(
|
|
25659
|
+
projItems.push(item2);
|
|
25098
25660
|
sortSpecs.push(spec);
|
|
25099
|
-
orderExprs.push({ item, spec });
|
|
25661
|
+
orderExprs.push({ item: item2, spec });
|
|
25100
25662
|
}
|
|
25101
25663
|
if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
|
|
25102
25664
|
const used = new Set(sortSpecs.map((s) => s.colIdx));
|
|
@@ -25470,7 +26032,7 @@ var TransactionManager = class {
|
|
|
25470
26032
|
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
25471
26033
|
}
|
|
25472
26034
|
restore(snap) {
|
|
25473
|
-
this.state.restoreFrom(snap.state);
|
|
26035
|
+
this.state.restoreFrom(snap.state.cloneShallow());
|
|
25474
26036
|
this.state.prng.setState(snap.prngState);
|
|
25475
26037
|
}
|
|
25476
26038
|
thawOnce() {
|
|
@@ -25570,7 +26132,10 @@ function withStatementRollback(env, fn) {
|
|
|
25570
26132
|
function requireTargetTable(env, parts, verb) {
|
|
25571
26133
|
const state = env.ctx.state;
|
|
25572
26134
|
const table = state.findTable(parts);
|
|
25573
|
-
if (table)
|
|
26135
|
+
if (table) {
|
|
26136
|
+
prepareDmlIndexStores(env, table);
|
|
26137
|
+
return state.ensureWritableTableForDml(table);
|
|
26138
|
+
}
|
|
25574
26139
|
const view = state.findView(parts);
|
|
25575
26140
|
if (view) {
|
|
25576
26141
|
throw pgError("wrong_object_type", `cannot ${verb} view "${view.name}"`, "42809");
|
|
@@ -25738,7 +26303,7 @@ function resolveArbiters(env, table, clause) {
|
|
|
25738
26303
|
return matches3.map((spec) => ({ spec }));
|
|
25739
26304
|
}
|
|
25740
26305
|
function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, where) {
|
|
25741
|
-
const rows = table.
|
|
26306
|
+
const rows = table.writeRows();
|
|
25742
26307
|
const existing = rows[existingIdx];
|
|
25743
26308
|
const cols = [
|
|
25744
26309
|
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
@@ -25750,7 +26315,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
25750
26315
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
25751
26316
|
computeGeneratedColumns(env, table, updated);
|
|
25752
26317
|
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
25753
|
-
|
|
26318
|
+
table.replaceRow(existingIdx, updated);
|
|
25754
26319
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
25755
26320
|
checkNotNull(env, table, updated);
|
|
25756
26321
|
checkChecks(env, table, updated);
|
|
@@ -25762,7 +26327,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
25762
26327
|
function executeInsert(env0, stmt) {
|
|
25763
26328
|
const env = applyWith(env0, stmt.with);
|
|
25764
26329
|
const table = requireTargetTable(env, stmt.table, "insert into");
|
|
25765
|
-
const rows = table.
|
|
26330
|
+
const rows = table.writeRows();
|
|
25766
26331
|
const label = stmt.alias ?? table.name;
|
|
25767
26332
|
const colIdxs = insertTargetColumns(env, table, stmt);
|
|
25768
26333
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
@@ -25846,6 +26411,7 @@ function executeInsert(env0, stmt) {
|
|
|
25846
26411
|
checkForeignKeys(env, table, newRow);
|
|
25847
26412
|
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
25848
26413
|
rows.push(newRow);
|
|
26414
|
+
table.recordDurableRow(newRow);
|
|
25849
26415
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
25850
26416
|
insertedCount++;
|
|
25851
26417
|
insertedRows.push(newRow);
|
|
@@ -25938,13 +26504,17 @@ function executeUpdate(env0, stmt) {
|
|
|
25938
26504
|
const label = stmt.alias ?? table.name;
|
|
25939
26505
|
fireStatementTriggers(env, table, "before", "update");
|
|
25940
26506
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
25941
|
-
const rows = table.mutableRows();
|
|
25942
26507
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
25943
26508
|
const updatedRows = [];
|
|
25944
26509
|
const replacedRows = [];
|
|
25945
26510
|
let updateCount = 0;
|
|
25946
|
-
|
|
25947
|
-
|
|
26511
|
+
const point2 = !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(
|
|
26512
|
+
(set) => set.columns.every((column) => column.subscripts === null && column.fields.length === 0) && "type" in set.value && isPureUpdateValue(set.value)
|
|
26513
|
+
) && referencingConstraints(env, table).length === 0 ? tryPointRowIndices(env, table, label, stmt.where) : null;
|
|
26514
|
+
const rows = point2 ? null : table.writeRows();
|
|
26515
|
+
for (let candidate = 0; candidate < (point2 ? point2.indices.length : rows.length); candidate++) {
|
|
26516
|
+
const ri = point2 ? point2.indices[candidate] : candidate;
|
|
26517
|
+
const oldRow = point2 ? table.rowAt(ri) : rows[ri];
|
|
25948
26518
|
let matchScope = null;
|
|
25949
26519
|
if (fromSource) {
|
|
25950
26520
|
let found = false;
|
|
@@ -25970,14 +26540,14 @@ function executeUpdate(env0, stmt) {
|
|
|
25970
26540
|
const finalRow = fired.row;
|
|
25971
26541
|
computeGeneratedColumns(env, table, finalRow);
|
|
25972
26542
|
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
25973
|
-
|
|
26543
|
+
table.replaceRow(ri, finalRow);
|
|
25974
26544
|
try {
|
|
25975
26545
|
checkNotNull(env, table, finalRow);
|
|
25976
26546
|
checkChecks(env, table, finalRow);
|
|
25977
26547
|
checkUnique(env, table, finalRow, ri);
|
|
25978
26548
|
checkForeignKeys(env, table, finalRow);
|
|
25979
26549
|
} catch (err) {
|
|
25980
|
-
|
|
26550
|
+
table.replaceRow(ri, oldRow);
|
|
25981
26551
|
throw err;
|
|
25982
26552
|
}
|
|
25983
26553
|
indexUpdateRow(env, table, ri, oldRow, finalRow);
|
|
@@ -25995,12 +26565,29 @@ function executeUpdate(env0, stmt) {
|
|
|
25995
26565
|
}
|
|
25996
26566
|
return commandResult("UPDATE", updateCount);
|
|
25997
26567
|
}
|
|
26568
|
+
function isPureUpdateValue(expr) {
|
|
26569
|
+
switch (expr.type) {
|
|
26570
|
+
case "param":
|
|
26571
|
+
case "number_lit":
|
|
26572
|
+
case "string_lit":
|
|
26573
|
+
case "bool_lit":
|
|
26574
|
+
case "null_lit":
|
|
26575
|
+
case "colref":
|
|
26576
|
+
return true;
|
|
26577
|
+
case "binop":
|
|
26578
|
+
return isPureUpdateValue(expr.left) && isPureUpdateValue(expr.right);
|
|
26579
|
+
case "unop":
|
|
26580
|
+
return isPureUpdateValue(expr.operand);
|
|
26581
|
+
default:
|
|
26582
|
+
return false;
|
|
26583
|
+
}
|
|
26584
|
+
}
|
|
25998
26585
|
function executeDelete(env0, stmt) {
|
|
25999
26586
|
const env = applyWith(env0, stmt.with);
|
|
26000
26587
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
26001
26588
|
const label = stmt.alias ?? table.name;
|
|
26002
26589
|
fireStatementTriggers(env, table, "before", "delete");
|
|
26003
|
-
const rows = table.
|
|
26590
|
+
const rows = table.writeRows();
|
|
26004
26591
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
26005
26592
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
26006
26593
|
const toDelete = [];
|
|
@@ -26030,6 +26617,7 @@ function executeDelete(env0, stmt) {
|
|
|
26030
26617
|
if (skipped.has(ri)) continue;
|
|
26031
26618
|
const row = rows[ri];
|
|
26032
26619
|
handleReferencedDelete(env, table, row, 0);
|
|
26620
|
+
table.recordDurableDelete(row);
|
|
26033
26621
|
rows.splice(ri, 1);
|
|
26034
26622
|
deletedRows.unshift(row);
|
|
26035
26623
|
}
|
|
@@ -26076,13 +26664,14 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
26076
26664
|
const idxs = referencingRowIdxs(ref, key);
|
|
26077
26665
|
if (idxs.length === 0) continue;
|
|
26078
26666
|
const action = con.onDelete ?? "no_action";
|
|
26079
|
-
const child = env.ctx.state.
|
|
26080
|
-
const childRows = child.
|
|
26667
|
+
const child = env.ctx.state.ensureWritableTableForDml(ref.table);
|
|
26668
|
+
const childRows = child.writeRows();
|
|
26081
26669
|
switch (action) {
|
|
26082
26670
|
case "cascade": {
|
|
26083
26671
|
for (let k = idxs.length - 1; k >= 0; k--) {
|
|
26084
26672
|
const childRow = childRows[idxs[k]];
|
|
26085
26673
|
handleReferencedDelete(env, child, childRow, depth + 1);
|
|
26674
|
+
child.recordDurableDelete(childRow);
|
|
26086
26675
|
childRows.splice(idxs[k], 1);
|
|
26087
26676
|
}
|
|
26088
26677
|
break;
|
|
@@ -26094,7 +26683,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
26094
26683
|
newRow[child.columnIndex(c)] = null;
|
|
26095
26684
|
}
|
|
26096
26685
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26097
|
-
|
|
26686
|
+
child.replaceRow(i, newRow);
|
|
26098
26687
|
checkNotNull(env, child, newRow);
|
|
26099
26688
|
checkChecks(env, child, newRow);
|
|
26100
26689
|
}
|
|
@@ -26108,7 +26697,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
26108
26697
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
26109
26698
|
}
|
|
26110
26699
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26111
|
-
|
|
26700
|
+
child.replaceRow(i, newRow);
|
|
26112
26701
|
checkNotNull(env, child, newRow);
|
|
26113
26702
|
checkChecks(env, child, newRow);
|
|
26114
26703
|
checkForeignKeys(env, child, newRow);
|
|
@@ -26134,8 +26723,8 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26134
26723
|
const idxs = referencingRowIdxs(ref, oldKey);
|
|
26135
26724
|
if (idxs.length === 0) continue;
|
|
26136
26725
|
const action = con.onUpdate ?? "no_action";
|
|
26137
|
-
const child = env.ctx.state.
|
|
26138
|
-
const childRows = child.
|
|
26726
|
+
const child = env.ctx.state.ensureWritableTableForDml(ref.table);
|
|
26727
|
+
const childRows = child.writeRows();
|
|
26139
26728
|
switch (action) {
|
|
26140
26729
|
case "cascade": {
|
|
26141
26730
|
for (const i of idxs) {
|
|
@@ -26146,7 +26735,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26146
26735
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
26147
26736
|
}
|
|
26148
26737
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26149
|
-
|
|
26738
|
+
child.replaceRow(i, newRow);
|
|
26150
26739
|
checkChecks(env, child, newRow);
|
|
26151
26740
|
}
|
|
26152
26741
|
break;
|
|
@@ -26156,7 +26745,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26156
26745
|
const newRow = childRows[i].slice();
|
|
26157
26746
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
26158
26747
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26159
|
-
|
|
26748
|
+
child.replaceRow(i, newRow);
|
|
26160
26749
|
checkNotNull(env, child, newRow);
|
|
26161
26750
|
}
|
|
26162
26751
|
break;
|
|
@@ -26169,7 +26758,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
26169
26758
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
26170
26759
|
}
|
|
26171
26760
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26172
|
-
|
|
26761
|
+
child.replaceRow(i, newRow);
|
|
26173
26762
|
checkForeignKeys(env, child, newRow);
|
|
26174
26763
|
}
|
|
26175
26764
|
break;
|
|
@@ -26692,6 +27281,8 @@ function openSnapshot(snapshot, options = {}) {
|
|
|
26692
27281
|
now = () => new Date(ms);
|
|
26693
27282
|
}
|
|
26694
27283
|
const state = snapshot.state.cloneShallow();
|
|
27284
|
+
for (const schema of state.schemas.values())
|
|
27285
|
+
for (const [name, table] of schema.tables) if (table.durableChanges) schema.tables.set(name, table.untrackedFork());
|
|
26695
27286
|
state.prng = prng;
|
|
26696
27287
|
state.clock = now;
|
|
26697
27288
|
return createAdoptedDatabase({
|
|
@@ -31374,6 +31965,24 @@ var Statement = class _Statement {
|
|
|
31374
31965
|
this.database = database;
|
|
31375
31966
|
this.sql = sql;
|
|
31376
31967
|
this.statements = statements;
|
|
31968
|
+
const observer = database.durabilityObserver;
|
|
31969
|
+
if (observer) {
|
|
31970
|
+
const execute = this.execute;
|
|
31971
|
+
this.execute = (params) => {
|
|
31972
|
+
observer.assertWritable();
|
|
31973
|
+
if (params.some((value) => value instanceof Uint8Array)) observer.exposed();
|
|
31974
|
+
try {
|
|
31975
|
+
const result = execute.call(this, params);
|
|
31976
|
+
if (result.columns.some(
|
|
31977
|
+
(column, index) => column.type === "bytea" && result.rows.some((row) => row[index] !== null && row[index] !== void 0)
|
|
31978
|
+
))
|
|
31979
|
+
observer.exposed();
|
|
31980
|
+
return result;
|
|
31981
|
+
} finally {
|
|
31982
|
+
observer.changed();
|
|
31983
|
+
}
|
|
31984
|
+
};
|
|
31985
|
+
}
|
|
31377
31986
|
}
|
|
31378
31987
|
database;
|
|
31379
31988
|
statements;
|
|
@@ -31406,7 +32015,7 @@ var Statement = class _Statement {
|
|
|
31406
32015
|
*/
|
|
31407
32016
|
textResult(...params) {
|
|
31408
32017
|
const res = this.execute(params);
|
|
31409
|
-
const ctx = new EngineCtx(this.database.
|
|
32018
|
+
const ctx = new EngineCtx(this.database.engineState);
|
|
31410
32019
|
return {
|
|
31411
32020
|
columns: res.columns.map((c) => c.name),
|
|
31412
32021
|
columnTypes: res.columns.map((c) => c.type === UNKNOWN ? "text" : c.type),
|
|
@@ -31443,7 +32052,7 @@ var Statement = class _Statement {
|
|
|
31443
32052
|
const refused = this.database.transactions.inTransaction ? refusedInTransactionBlock(stmt) : null;
|
|
31444
32053
|
if (refused) throw pgError("misuse", `${refused} cannot run inside a transaction block`, "25001");
|
|
31445
32054
|
const env = {
|
|
31446
|
-
ctx: new EngineCtx(this.database.
|
|
32055
|
+
ctx: new EngineCtx(this.database.engineState),
|
|
31447
32056
|
params: typed,
|
|
31448
32057
|
ctes: /* @__PURE__ */ new Map(),
|
|
31449
32058
|
outer: null
|
|
@@ -31453,12 +32062,13 @@ var Statement = class _Statement {
|
|
|
31453
32062
|
return last;
|
|
31454
32063
|
}
|
|
31455
32064
|
toRows(res) {
|
|
31456
|
-
const ctx = new EngineCtx(this.database.
|
|
32065
|
+
const ctx = new EngineCtx(this.database.engineState);
|
|
31457
32066
|
return res.rows.map((row) => {
|
|
31458
32067
|
const obj = {};
|
|
31459
32068
|
for (let i = 0; i < res.columns.length; i++) {
|
|
31460
32069
|
const c = res.columns[i];
|
|
31461
|
-
|
|
32070
|
+
const value = datumToJs(c.type, row[i] ?? null, ctx, this.database.int8Mode);
|
|
32071
|
+
obj[c.name] = value;
|
|
31462
32072
|
}
|
|
31463
32073
|
return obj;
|
|
31464
32074
|
});
|
|
@@ -31476,6 +32086,10 @@ function project(point2) {
|
|
|
31476
32086
|
var Database = class {
|
|
31477
32087
|
/** @internal Engine catalog, tables, session settings. */
|
|
31478
32088
|
state;
|
|
32089
|
+
/** @internal Engine-only access; buffered mode observes public state exposure. */
|
|
32090
|
+
engineState;
|
|
32091
|
+
/** @internal Installed only by buffered durability. */
|
|
32092
|
+
durabilityObserver;
|
|
31479
32093
|
/** Seed used to construct the PRNG. Ignored when {@link randomMode} is `"os"`. */
|
|
31480
32094
|
seed;
|
|
31481
32095
|
/** Entropy mode for `random()` / `gen_random_uuid()`. */
|
|
@@ -31505,10 +32119,10 @@ var Database = class {
|
|
|
31505
32119
|
this.int8Mode = options.int8Mode;
|
|
31506
32120
|
this.prng = options.prng;
|
|
31507
32121
|
this.now = options.now;
|
|
31508
|
-
this.
|
|
31509
|
-
this.
|
|
31510
|
-
this.
|
|
31511
|
-
this.transactions = txManagerFor(this.
|
|
32122
|
+
this.engineState = options.state;
|
|
32123
|
+
this.engineState.prng = this.prng;
|
|
32124
|
+
this.engineState.clock = () => this.now();
|
|
32125
|
+
this.transactions = txManagerFor(this.engineState);
|
|
31512
32126
|
} else {
|
|
31513
32127
|
this.seed = options.seed ?? DEFAULT_DATABASE_SEED;
|
|
31514
32128
|
this.randomMode = options.random ?? "deterministic";
|
|
@@ -31516,9 +32130,10 @@ var Database = class {
|
|
|
31516
32130
|
this.int8Mode = options.int8 ?? "bigint";
|
|
31517
32131
|
this.prng = this.randomMode === "os" ? new OsEntropy() : new Prng(this.seed);
|
|
31518
32132
|
this.now = resolveClock(options.now);
|
|
31519
|
-
this.
|
|
31520
|
-
this.transactions = txManagerFor(this.
|
|
32133
|
+
this.engineState = new DatabaseState(this.prng, () => this.now());
|
|
32134
|
+
this.transactions = txManagerFor(this.engineState);
|
|
31521
32135
|
}
|
|
32136
|
+
this.state = this.engineState;
|
|
31522
32137
|
this.timeline = new Timeline({
|
|
31523
32138
|
now: () => this.now().getTime(),
|
|
31524
32139
|
...options.maxCheckpoints !== void 0 ? { maxCheckpoints: options.maxCheckpoints } : {}
|
|
@@ -31545,14 +32160,15 @@ var Database = class {
|
|
|
31545
32160
|
* a live in-memory snapshot.
|
|
31546
32161
|
*/
|
|
31547
32162
|
registerFunction(spec) {
|
|
32163
|
+
this.durabilityObserver?.assertWritable();
|
|
31548
32164
|
this.assertOpen();
|
|
31549
32165
|
const parts = spec.name.split(".").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
31550
32166
|
if (parts.length === 0) throw pgError("syntax", "function name is required", "42601");
|
|
31551
|
-
const schemaName = (parts.length >= 2 ? parts[0] : this.
|
|
32167
|
+
const schemaName = (parts.length >= 2 ? parts[0] : this.engineState.currentSchema()).toLowerCase();
|
|
31552
32168
|
const name = parts[parts.length - 1].toLowerCase();
|
|
31553
|
-
const functions = schemaName === "pg_catalog" ? this.
|
|
31554
|
-
const argTypes = spec.args.map((a) => resolveTypeName(this.
|
|
31555
|
-
const returns = resolveTypeName(this.
|
|
32169
|
+
const functions = schemaName === "pg_catalog" ? this.engineState.systemFunctions : this.engineState.getSchema(schemaName).functions;
|
|
32170
|
+
const argTypes = spec.args.map((a) => resolveTypeName(this.engineState, parseTypeName(a)).column.id);
|
|
32171
|
+
const returns = resolveTypeName(this.engineState, parseTypeName(spec.returns)).column.id;
|
|
31556
32172
|
const fn = {
|
|
31557
32173
|
name,
|
|
31558
32174
|
schema: schemaName,
|
|
@@ -31566,7 +32182,7 @@ var Database = class {
|
|
|
31566
32182
|
body: null,
|
|
31567
32183
|
rawBody: null,
|
|
31568
32184
|
strict: spec.strict ?? true,
|
|
31569
|
-
oid: this.
|
|
32185
|
+
oid: this.engineState.nextOid(),
|
|
31570
32186
|
jsImpl: spec.fn
|
|
31571
32187
|
};
|
|
31572
32188
|
const existing = functions.get(name) ?? [];
|
|
@@ -31576,6 +32192,7 @@ var Database = class {
|
|
|
31576
32192
|
if (sameSig !== -1) existing[sameSig] = fn;
|
|
31577
32193
|
else existing.push(fn);
|
|
31578
32194
|
functions.set(name, existing);
|
|
32195
|
+
this.durabilityObserver?.exposed();
|
|
31579
32196
|
}
|
|
31580
32197
|
/** Execute a single-statement query and return all rows keyed by column name. */
|
|
31581
32198
|
query(sql, params = [], options = {}) {
|
|
@@ -31602,6 +32219,7 @@ var Database = class {
|
|
|
31602
32219
|
*/
|
|
31603
32220
|
transaction(fn) {
|
|
31604
32221
|
this.assertOpen();
|
|
32222
|
+
this.durabilityObserver?.assertWritable();
|
|
31605
32223
|
this.apiTransactionDepth++;
|
|
31606
32224
|
try {
|
|
31607
32225
|
if (!this.transactions.inTransaction) {
|
|
@@ -31628,6 +32246,7 @@ var Database = class {
|
|
|
31628
32246
|
}
|
|
31629
32247
|
} finally {
|
|
31630
32248
|
this.apiTransactionDepth--;
|
|
32249
|
+
this.durabilityObserver?.changed();
|
|
31631
32250
|
}
|
|
31632
32251
|
}
|
|
31633
32252
|
/**
|
|
@@ -31722,7 +32341,7 @@ var Database = class {
|
|
|
31722
32341
|
*/
|
|
31723
32342
|
fault(faults) {
|
|
31724
32343
|
this.assertOpen();
|
|
31725
|
-
Object.assign(this.
|
|
32344
|
+
Object.assign(this.engineState.faults, faults);
|
|
31726
32345
|
}
|
|
31727
32346
|
/** Close the database. Further SQL throws. Idempotent. */
|
|
31728
32347
|
close() {
|
|
@@ -31732,6 +32351,7 @@ var Database = class {
|
|
|
31732
32351
|
}
|
|
31733
32352
|
if (this.transactions.inTransaction) this.transactions.rollback();
|
|
31734
32353
|
this.closed = true;
|
|
32354
|
+
this.durabilityObserver?.closed?.();
|
|
31735
32355
|
}
|
|
31736
32356
|
/**
|
|
31737
32357
|
* Execute `COPY table [(cols)] FROM STDIN` with the given text/csv payload
|
|
@@ -31750,13 +32370,18 @@ var Database = class {
|
|
|
31750
32370
|
if (statements.length !== 1 || !stmt || stmt.type !== "copy" || stmt.direction !== "from") {
|
|
31751
32371
|
throw pgError("misuse", "copyFrom() requires a single COPY ... FROM STDIN statement", "XX000");
|
|
31752
32372
|
}
|
|
31753
|
-
|
|
31754
|
-
|
|
32373
|
+
this.durabilityObserver?.assertWritable();
|
|
32374
|
+
try {
|
|
32375
|
+
const env = { ctx: new EngineCtx(this.engineState), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
32376
|
+
return executeCopyFromData(env, stmt, data).rowCount;
|
|
32377
|
+
} finally {
|
|
32378
|
+
this.durabilityObserver?.changed();
|
|
32379
|
+
}
|
|
31755
32380
|
}
|
|
31756
32381
|
/** Rows affected by the most recent INSERT / UPDATE / DELETE. */
|
|
31757
32382
|
get changes() {
|
|
31758
32383
|
this.assertOpen();
|
|
31759
|
-
return this.
|
|
32384
|
+
return this.engineState.changes;
|
|
31760
32385
|
}
|
|
31761
32386
|
/** @internal */
|
|
31762
32387
|
assertOpen() {
|
|
@@ -31768,7 +32393,7 @@ var Database = class {
|
|
|
31768
32393
|
}
|
|
31769
32394
|
captureLive() {
|
|
31770
32395
|
return captureSnapshot(
|
|
31771
|
-
this.
|
|
32396
|
+
this.engineState,
|
|
31772
32397
|
this.prng,
|
|
31773
32398
|
this.now,
|
|
31774
32399
|
this.seed,
|
|
@@ -31778,7 +32403,8 @@ var Database = class {
|
|
|
31778
32403
|
);
|
|
31779
32404
|
}
|
|
31780
32405
|
install(snapshot) {
|
|
31781
|
-
this.
|
|
32406
|
+
this.durabilityObserver?.exposed();
|
|
32407
|
+
this.engineState.restoreFrom(snapshot.state.cloneShallow());
|
|
31782
32408
|
this.prng.setState(snapshot.prngState);
|
|
31783
32409
|
if (!this.systemClock) this.now = fixedClock(new Date(snapshot.nowMs));
|
|
31784
32410
|
}
|