@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/unstable.js
CHANGED
|
@@ -8566,6 +8566,252 @@ function validateStorageSetting(name, value) {
|
|
|
8566
8566
|
}
|
|
8567
8567
|
}
|
|
8568
8568
|
|
|
8569
|
+
// ../../core/dist/fork-map.js
|
|
8570
|
+
var ForkMap = class _ForkMap {
|
|
8571
|
+
owner = {};
|
|
8572
|
+
index = { owner: this.owner, groups: [] };
|
|
8573
|
+
order = { owner: this.owner, cells: [] };
|
|
8574
|
+
shift = 0;
|
|
8575
|
+
length = 0;
|
|
8576
|
+
count = 0;
|
|
8577
|
+
nextSequence = 0;
|
|
8578
|
+
layout = 0;
|
|
8579
|
+
cleared = 0;
|
|
8580
|
+
version = 0;
|
|
8581
|
+
constructor(entries) {
|
|
8582
|
+
if (entries)
|
|
8583
|
+
for (const [key, value] of entries)
|
|
8584
|
+
this.set(key, value);
|
|
8585
|
+
}
|
|
8586
|
+
get size() {
|
|
8587
|
+
return this.count;
|
|
8588
|
+
}
|
|
8589
|
+
get [Symbol.toStringTag]() {
|
|
8590
|
+
return "Map";
|
|
8591
|
+
}
|
|
8592
|
+
fork() {
|
|
8593
|
+
const copy = new _ForkMap();
|
|
8594
|
+
copy.index = this.index;
|
|
8595
|
+
copy.order = this.order;
|
|
8596
|
+
copy.shift = this.shift;
|
|
8597
|
+
copy.length = this.length;
|
|
8598
|
+
copy.count = this.count;
|
|
8599
|
+
copy.nextSequence = this.nextSequence;
|
|
8600
|
+
this.owner = {};
|
|
8601
|
+
return copy;
|
|
8602
|
+
}
|
|
8603
|
+
/** Visit changed hash buckets only. Values must be replaced, rather than mutated in place. */
|
|
8604
|
+
*changes(previous) {
|
|
8605
|
+
if (previous?.index === this.index)
|
|
8606
|
+
return;
|
|
8607
|
+
for (let group = 0; group < 32; group++) {
|
|
8608
|
+
const currentGroup = this.index.groups[group];
|
|
8609
|
+
const oldGroup = previous?.index.groups[group];
|
|
8610
|
+
if (currentGroup === oldGroup)
|
|
8611
|
+
continue;
|
|
8612
|
+
for (let bucket = 0; bucket < 32; bucket++) {
|
|
8613
|
+
const current = currentGroup?.buckets[bucket]?.data;
|
|
8614
|
+
const old = oldGroup?.buckets[bucket]?.data;
|
|
8615
|
+
if (current === old)
|
|
8616
|
+
continue;
|
|
8617
|
+
if (current)
|
|
8618
|
+
for (const [key, entry] of current) {
|
|
8619
|
+
const before = old?.get(key);
|
|
8620
|
+
if (!before || !Object.is(before.value, entry.value) || before.sequence !== entry.sequence)
|
|
8621
|
+
yield { key, value: entry.value, deleted: false };
|
|
8622
|
+
}
|
|
8623
|
+
if (old) {
|
|
8624
|
+
for (const key of old.keys())
|
|
8625
|
+
if (!current?.has(key))
|
|
8626
|
+
yield { key, deleted: true };
|
|
8627
|
+
}
|
|
8628
|
+
}
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8631
|
+
get(key) {
|
|
8632
|
+
return this.find(key)?.value;
|
|
8633
|
+
}
|
|
8634
|
+
has(key) {
|
|
8635
|
+
return this.find(key) !== void 0;
|
|
8636
|
+
}
|
|
8637
|
+
set(key, value) {
|
|
8638
|
+
if (typeof key === "number" && key === 0)
|
|
8639
|
+
key = 0;
|
|
8640
|
+
const hash = hashKey(key);
|
|
8641
|
+
const existing = this.bucket(hash)?.get(key);
|
|
8642
|
+
if (existing && Object.is(existing.value, value))
|
|
8643
|
+
return this;
|
|
8644
|
+
const entry = existing ? { ...existing, value } : { key, value, position: this.length++, sequence: this.nextSequence++ };
|
|
8645
|
+
this.writableBucket(hash).set(key, entry);
|
|
8646
|
+
this.writeOrder(entry.position, entry);
|
|
8647
|
+
if (!existing)
|
|
8648
|
+
this.count++;
|
|
8649
|
+
this.version++;
|
|
8650
|
+
return this;
|
|
8651
|
+
}
|
|
8652
|
+
delete(key) {
|
|
8653
|
+
const hash = hashKey(key);
|
|
8654
|
+
const entry = this.bucket(hash)?.get(key);
|
|
8655
|
+
if (!entry)
|
|
8656
|
+
return false;
|
|
8657
|
+
this.writableBucket(hash).delete(key);
|
|
8658
|
+
this.writeOrder(entry.position, void 0);
|
|
8659
|
+
this.count--;
|
|
8660
|
+
this.version++;
|
|
8661
|
+
if (this.length > 1024 && this.length > this.count * 2)
|
|
8662
|
+
this.compact();
|
|
8663
|
+
return true;
|
|
8664
|
+
}
|
|
8665
|
+
clear() {
|
|
8666
|
+
this.index = { owner: this.owner, groups: [] };
|
|
8667
|
+
this.order = { owner: this.owner, cells: [] };
|
|
8668
|
+
this.shift = this.length = this.count = this.nextSequence = 0;
|
|
8669
|
+
this.layout++;
|
|
8670
|
+
this.cleared++;
|
|
8671
|
+
this.version++;
|
|
8672
|
+
}
|
|
8673
|
+
entries() {
|
|
8674
|
+
return this.iterate(0);
|
|
8675
|
+
}
|
|
8676
|
+
keys() {
|
|
8677
|
+
return this.iterate(1);
|
|
8678
|
+
}
|
|
8679
|
+
values() {
|
|
8680
|
+
return this.iterate(2);
|
|
8681
|
+
}
|
|
8682
|
+
[Symbol.iterator]() {
|
|
8683
|
+
return this.entries();
|
|
8684
|
+
}
|
|
8685
|
+
forEach(callback, thisArg) {
|
|
8686
|
+
for (const [key, value] of this)
|
|
8687
|
+
callback.call(thisArg, value, key, this);
|
|
8688
|
+
}
|
|
8689
|
+
find(key) {
|
|
8690
|
+
return this.bucket(hashKey(key))?.get(key);
|
|
8691
|
+
}
|
|
8692
|
+
bucket(hash) {
|
|
8693
|
+
return this.index.groups[hash >>> 5 & 31]?.buckets[hash & 31]?.data;
|
|
8694
|
+
}
|
|
8695
|
+
writableBucket(hash) {
|
|
8696
|
+
if (this.index.owner !== this.owner)
|
|
8697
|
+
this.index = { owner: this.owner, groups: this.index.groups.slice() };
|
|
8698
|
+
const groupIndex = hash >>> 5 & 31;
|
|
8699
|
+
let group = this.index.groups[groupIndex];
|
|
8700
|
+
if (!group || group.owner !== this.owner) {
|
|
8701
|
+
group = { owner: this.owner, buckets: group?.buckets.slice() ?? [] };
|
|
8702
|
+
this.index.groups[groupIndex] = group;
|
|
8703
|
+
}
|
|
8704
|
+
const at = hash & 31;
|
|
8705
|
+
let bucket = group.buckets[at];
|
|
8706
|
+
if (!bucket || bucket.owner !== this.owner) {
|
|
8707
|
+
bucket = { owner: this.owner, data: bucket ? this.copyBucket(bucket.data) : /* @__PURE__ */ new Map() };
|
|
8708
|
+
group.buckets[at] = bucket;
|
|
8709
|
+
}
|
|
8710
|
+
return bucket.data;
|
|
8711
|
+
}
|
|
8712
|
+
copyBucket(bucket) {
|
|
8713
|
+
return new Map(bucket);
|
|
8714
|
+
}
|
|
8715
|
+
leaf(position) {
|
|
8716
|
+
let node = this.order;
|
|
8717
|
+
for (let shift = this.shift; shift > 0; shift -= 5)
|
|
8718
|
+
node = node.cells[Math.floor(position / 2 ** shift) & 31];
|
|
8719
|
+
return node;
|
|
8720
|
+
}
|
|
8721
|
+
writeOrder(position, entry) {
|
|
8722
|
+
while (position >= 2 ** (this.shift + 5)) {
|
|
8723
|
+
this.order = { owner: this.owner, cells: [this.order] };
|
|
8724
|
+
this.shift += 5;
|
|
8725
|
+
}
|
|
8726
|
+
if (this.order.owner !== this.owner)
|
|
8727
|
+
this.order = { owner: this.owner, cells: this.order.cells.slice() };
|
|
8728
|
+
let node = this.order;
|
|
8729
|
+
for (let shift = this.shift; shift > 0; shift -= 5) {
|
|
8730
|
+
const at = Math.floor(position / 2 ** shift) & 31;
|
|
8731
|
+
let child = node.cells[at];
|
|
8732
|
+
if (!child || child.owner !== this.owner) {
|
|
8733
|
+
child = { owner: this.owner, cells: child?.cells.slice() ?? [] };
|
|
8734
|
+
node.cells[at] = child;
|
|
8735
|
+
}
|
|
8736
|
+
node = child;
|
|
8737
|
+
}
|
|
8738
|
+
node.cells[position & 31] = entry;
|
|
8739
|
+
}
|
|
8740
|
+
compact() {
|
|
8741
|
+
const entries = [];
|
|
8742
|
+
for (let position = 0; position < this.length; position++) {
|
|
8743
|
+
const entry = this.leaf(position).cells[position & 31];
|
|
8744
|
+
if (entry)
|
|
8745
|
+
entries.push(entry);
|
|
8746
|
+
}
|
|
8747
|
+
this.index = { owner: this.owner, groups: [] };
|
|
8748
|
+
this.order = { owner: this.owner, cells: [] };
|
|
8749
|
+
this.shift = this.length = this.count = 0;
|
|
8750
|
+
for (const original of entries) {
|
|
8751
|
+
const entry = { ...original, position: this.length++ };
|
|
8752
|
+
this.writableBucket(hashKey(entry.key)).set(entry.key, entry);
|
|
8753
|
+
this.writeOrder(entry.position, entry);
|
|
8754
|
+
this.count++;
|
|
8755
|
+
}
|
|
8756
|
+
this.layout++;
|
|
8757
|
+
}
|
|
8758
|
+
*iterate(kind) {
|
|
8759
|
+
let position = 0;
|
|
8760
|
+
let layout = this.layout;
|
|
8761
|
+
let cleared = this.cleared;
|
|
8762
|
+
let lastSequence = -1;
|
|
8763
|
+
let version = -1;
|
|
8764
|
+
let leaf;
|
|
8765
|
+
let page = -1;
|
|
8766
|
+
for (; ; ) {
|
|
8767
|
+
if (cleared !== this.cleared) {
|
|
8768
|
+
position = 0;
|
|
8769
|
+
lastSequence = -1;
|
|
8770
|
+
cleared = this.cleared;
|
|
8771
|
+
}
|
|
8772
|
+
if (layout !== this.layout) {
|
|
8773
|
+
position = 0;
|
|
8774
|
+
while (position < this.length) {
|
|
8775
|
+
const entry2 = this.leaf(position).cells[position & 31];
|
|
8776
|
+
if (entry2 && entry2.sequence > lastSequence)
|
|
8777
|
+
break;
|
|
8778
|
+
position++;
|
|
8779
|
+
}
|
|
8780
|
+
layout = this.layout;
|
|
8781
|
+
}
|
|
8782
|
+
if (position >= this.length)
|
|
8783
|
+
return;
|
|
8784
|
+
const nextPage = Math.floor(position / 32);
|
|
8785
|
+
if (page !== nextPage || version !== this.version) {
|
|
8786
|
+
leaf = this.leaf(position);
|
|
8787
|
+
page = nextPage;
|
|
8788
|
+
version = this.version;
|
|
8789
|
+
}
|
|
8790
|
+
const entry = leaf?.cells[position++ & 31];
|
|
8791
|
+
if (!entry)
|
|
8792
|
+
continue;
|
|
8793
|
+
lastSequence = entry.sequence;
|
|
8794
|
+
yield kind === 0 ? [entry.key, entry.value] : kind === 1 ? entry.key : entry.value;
|
|
8795
|
+
}
|
|
8796
|
+
}
|
|
8797
|
+
};
|
|
8798
|
+
function hashKey(key) {
|
|
8799
|
+
if (typeof key === "number" && Number.isInteger(key))
|
|
8800
|
+
return mix2((key | 0) ^ (key / 4294967296 | 0));
|
|
8801
|
+
if (typeof key === "bigint")
|
|
8802
|
+
return mix2(Number(BigInt.asIntN(32, key ^ key >> 32n)));
|
|
8803
|
+
const text = String(key);
|
|
8804
|
+
let hash = 2166136261;
|
|
8805
|
+
for (let i = 0; i < text.length; i++)
|
|
8806
|
+
hash = Math.imul(hash ^ text.charCodeAt(i), 16777619);
|
|
8807
|
+
return hash;
|
|
8808
|
+
}
|
|
8809
|
+
function mix2(value) {
|
|
8810
|
+
value = Math.imul(value ^ value >>> 16, 73244475);
|
|
8811
|
+
value = Math.imul(value ^ value >>> 16, 73244475);
|
|
8812
|
+
return value ^ value >>> 16;
|
|
8813
|
+
}
|
|
8814
|
+
|
|
8569
8815
|
// src/schema/catalog.ts
|
|
8570
8816
|
var builder = null;
|
|
8571
8817
|
function setCatalogBuilder(b) {
|
|
@@ -8614,10 +8860,81 @@ var PG_CATALOG_RELATIONS = /* @__PURE__ */ new Set([
|
|
|
8614
8860
|
|
|
8615
8861
|
// src/storage/database-state.ts
|
|
8616
8862
|
var TableData = class _TableData {
|
|
8863
|
+
/** @internal Optional physical row journal; IDs remain stable across heap splices. */
|
|
8864
|
+
durableChanges = null;
|
|
8865
|
+
durableNextId = 0;
|
|
8866
|
+
durableEpoch;
|
|
8867
|
+
durableUnsafe = false;
|
|
8868
|
+
durableIds;
|
|
8869
|
+
enableDurabilityTracking(ids, nextId) {
|
|
8870
|
+
if (this.durableChanges && !this.durableUnsafe && !ids) return;
|
|
8871
|
+
this.materializeSlab();
|
|
8872
|
+
this.durableIds = /* @__PURE__ */ new WeakMap();
|
|
8873
|
+
this.durableChanges = new ForkMap();
|
|
8874
|
+
this.durableNextId = nextId ?? this.#rows.length;
|
|
8875
|
+
for (let i = 0; i < this.#rows.length; i++) this.durableIds.set(this.#rows[i], ids?.[i] ?? i);
|
|
8876
|
+
this.durableEpoch = {};
|
|
8877
|
+
this.durableUnsafe = false;
|
|
8878
|
+
}
|
|
8879
|
+
durableRowId(row) {
|
|
8880
|
+
const id = this.durableIds?.get(row);
|
|
8881
|
+
if (id === void 0) throw new Error("Untracked durable row");
|
|
8882
|
+
return id;
|
|
8883
|
+
}
|
|
8884
|
+
disableDurabilityTracking() {
|
|
8885
|
+
this.durableChanges = null;
|
|
8886
|
+
this.durableIds = void 0;
|
|
8887
|
+
this.durableEpoch = void 0;
|
|
8888
|
+
this.durableUnsafe = false;
|
|
8889
|
+
}
|
|
8890
|
+
recordDurableRow(row, previous) {
|
|
8891
|
+
if (!this.durableChanges) return;
|
|
8892
|
+
const id = (previous && this.durableIds?.get(previous)) ?? this.durableIds?.get(row) ?? this.durableNextId++;
|
|
8893
|
+
this.durableIds.set(row, id);
|
|
8894
|
+
this.durableChanges.set(id, { row, xmin: this.rowXmins.get(row) ?? 2 });
|
|
8895
|
+
}
|
|
8896
|
+
recordDurableDelete(row) {
|
|
8897
|
+
if (this.durableChanges) this.durableChanges.set(this.durableRowId(row), { row: null, xmin: 0 });
|
|
8898
|
+
}
|
|
8899
|
+
/** @internal Metadata twin with no visits/copies of existing rows or index entries. */
|
|
8900
|
+
emptyForDurability() {
|
|
8901
|
+
const copy = new _TableData(this.schema, this.name, this.columns, this.oid, this.temp);
|
|
8902
|
+
copy.constraints = this.constraints;
|
|
8903
|
+
copy.triggers = this.triggers;
|
|
8904
|
+
copy.unlogged = this.unlogged;
|
|
8905
|
+
return copy;
|
|
8906
|
+
}
|
|
8907
|
+
/** @internal Serialization/SQL scans must not count as public native-array exposure. */
|
|
8908
|
+
serializationRows() {
|
|
8909
|
+
this.materializeSlab();
|
|
8910
|
+
return this.materializedRows();
|
|
8911
|
+
}
|
|
8912
|
+
/** @internal Internal mutable array access, with ordinary public mutableRows kept intact. */
|
|
8913
|
+
writeRows() {
|
|
8914
|
+
return this.serializationRows();
|
|
8915
|
+
}
|
|
8916
|
+
/** @internal Ordinary snapshot branches must not inherit a persistence journal. */
|
|
8917
|
+
untrackedFork() {
|
|
8918
|
+
const copy = this.emptyForDurability();
|
|
8919
|
+
copy.rowXmins = this.rowXmins;
|
|
8920
|
+
copy.slabXmins = this.slabXmins;
|
|
8921
|
+
if (this.slab) copy.slab = this.slab;
|
|
8922
|
+
else {
|
|
8923
|
+
copy.#rows = this.#rows;
|
|
8924
|
+
copy.#rowPatches = this.#rowPatches?.fork() ?? null;
|
|
8925
|
+
copy.#rowsShared = this.#rowsShared = true;
|
|
8926
|
+
copy.tuplesShared = this.tuplesShared = true;
|
|
8927
|
+
}
|
|
8928
|
+
copy.indexStores = this.indexStores ? new Map([...this.indexStores].map(([name, store]) => [name, store.clone()])) : null;
|
|
8929
|
+
return copy;
|
|
8930
|
+
}
|
|
8617
8931
|
name;
|
|
8618
8932
|
schema;
|
|
8619
8933
|
columns;
|
|
8620
|
-
rows;
|
|
8934
|
+
#rows = [];
|
|
8935
|
+
#rowPatches = null;
|
|
8936
|
+
#rowsShared = false;
|
|
8937
|
+
#rowsExposed = false;
|
|
8621
8938
|
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
8622
8939
|
slabXmins = null;
|
|
8623
8940
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
@@ -8633,22 +8950,54 @@ var TableData = class _TableData {
|
|
|
8633
8950
|
shareCount = 0;
|
|
8634
8951
|
/** Derived unique/btree index maps; null until built or invalidated. */
|
|
8635
8952
|
indexStores = null;
|
|
8953
|
+
/** DML replaces tuples; DDL must detach them before changing cells in place. */
|
|
8954
|
+
tuplesShared = false;
|
|
8636
8955
|
constructor(schema, name, columns, oid, temp = false) {
|
|
8637
8956
|
this.schema = schema;
|
|
8638
8957
|
this.name = name;
|
|
8639
8958
|
this.columns = columns;
|
|
8640
|
-
this
|
|
8959
|
+
Object.defineProperty(this, "rows", {
|
|
8960
|
+
enumerable: true,
|
|
8961
|
+
configurable: true,
|
|
8962
|
+
get: this.nativeRows,
|
|
8963
|
+
set: this.setNativeRows
|
|
8964
|
+
});
|
|
8641
8965
|
this.constraints = [];
|
|
8642
8966
|
this.triggers = [];
|
|
8643
8967
|
this.temp = temp;
|
|
8644
8968
|
this.oid = oid;
|
|
8645
8969
|
}
|
|
8646
8970
|
rowCount() {
|
|
8647
|
-
return this.slab ? this.slab.rowCount : this
|
|
8971
|
+
return this.slab ? this.slab.rowCount : this.#rows.length;
|
|
8648
8972
|
}
|
|
8649
8973
|
rowAt(index) {
|
|
8650
8974
|
if (this.slab) return this.slab.rowAt(index);
|
|
8651
|
-
return this
|
|
8975
|
+
return this.#rowPatches?.get(index) ?? this.#rows[index] ?? [];
|
|
8976
|
+
}
|
|
8977
|
+
/** Replace an existing tuple without copying the array of unchanged row references. */
|
|
8978
|
+
replaceRow(index, row) {
|
|
8979
|
+
if (this.durableChanges) this.recordDurableRow(row, this.rowAt(index));
|
|
8980
|
+
if (this.#rowPatches) this.#rowPatches.set(index, row);
|
|
8981
|
+
else this.#rows[index] = row;
|
|
8982
|
+
}
|
|
8983
|
+
materializedRows() {
|
|
8984
|
+
if (this.#rowsShared) this.#rows = this.#rows.slice();
|
|
8985
|
+
if (this.#rowPatches) for (const [index, row] of this.#rowPatches) this.#rows[index] = row;
|
|
8986
|
+
this.#rowPatches = null;
|
|
8987
|
+
this.#rowsShared = false;
|
|
8988
|
+
return this.#rows;
|
|
8989
|
+
}
|
|
8990
|
+
nativeRows() {
|
|
8991
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
8992
|
+
this.#rowsExposed = true;
|
|
8993
|
+
return this.materializedRows();
|
|
8994
|
+
}
|
|
8995
|
+
setNativeRows(rows) {
|
|
8996
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
8997
|
+
this.#rows = rows;
|
|
8998
|
+
this.#rowPatches = null;
|
|
8999
|
+
this.#rowsShared = false;
|
|
9000
|
+
this.#rowsExposed = true;
|
|
8652
9001
|
}
|
|
8653
9002
|
/** All rows for scans; materializes slab once into `rows` when needed. */
|
|
8654
9003
|
allRows() {
|
|
@@ -8657,13 +9006,15 @@ var TableData = class _TableData {
|
|
|
8657
9006
|
}
|
|
8658
9007
|
attachSlab(slab) {
|
|
8659
9008
|
this.slab = slab;
|
|
8660
|
-
this
|
|
9009
|
+
this.#rows = [];
|
|
9010
|
+
this.#rowPatches = null;
|
|
9011
|
+
this.#rowsShared = false;
|
|
8661
9012
|
}
|
|
8662
9013
|
materializeSlab() {
|
|
8663
9014
|
if (!this.slab) return;
|
|
8664
|
-
this
|
|
9015
|
+
this.#rows = this.slab.materialize();
|
|
8665
9016
|
if (this.slabXmins)
|
|
8666
|
-
this
|
|
9017
|
+
this.#rows.forEach((row, index) => {
|
|
8667
9018
|
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
8668
9019
|
});
|
|
8669
9020
|
this.slabXmins = null;
|
|
@@ -8687,7 +9038,7 @@ var TableData = class _TableData {
|
|
|
8687
9038
|
columnIndex(name) {
|
|
8688
9039
|
return this.columns.findIndex((c) => c.name === name);
|
|
8689
9040
|
}
|
|
8690
|
-
|
|
9041
|
+
cloneMetadata() {
|
|
8691
9042
|
const t = new _TableData(
|
|
8692
9043
|
this.schema,
|
|
8693
9044
|
this.name,
|
|
@@ -8695,21 +9046,68 @@ var TableData = class _TableData {
|
|
|
8695
9046
|
this.oid,
|
|
8696
9047
|
this.temp
|
|
8697
9048
|
);
|
|
9049
|
+
t.unlogged = this.unlogged;
|
|
9050
|
+
t.durableChanges = this.durableChanges?.fork() ?? null;
|
|
9051
|
+
t.durableIds = this.durableIds;
|
|
9052
|
+
t.durableNextId = this.durableNextId;
|
|
9053
|
+
t.durableEpoch = this.durableEpoch;
|
|
9054
|
+
t.durableUnsafe = this.durableUnsafe;
|
|
9055
|
+
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
9056
|
+
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
9057
|
+
t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
|
|
9058
|
+
return t;
|
|
9059
|
+
}
|
|
9060
|
+
clone() {
|
|
9061
|
+
const t = this.cloneMetadata();
|
|
9062
|
+
if (t.durableChanges) t.durableUnsafe = true;
|
|
8698
9063
|
if (this.slab) {
|
|
8699
|
-
t
|
|
9064
|
+
t.#rows = this.slab.materialize().map((r) => r.slice());
|
|
8700
9065
|
} else {
|
|
8701
|
-
t
|
|
9066
|
+
t.#rows = this.materializedRows().map((r) => r.slice());
|
|
8702
9067
|
}
|
|
8703
|
-
t
|
|
8704
|
-
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this
|
|
9068
|
+
t.#rows.forEach((row, index) => {
|
|
9069
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.#rows[index]);
|
|
8705
9070
|
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
8706
9071
|
});
|
|
8707
|
-
t.unlogged = this.unlogged;
|
|
8708
|
-
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
8709
|
-
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
8710
|
-
t.indexStores = this.indexStores ? new Map([...this.indexStores].map(([k, v]) => [k, v.clone()])) : null;
|
|
8711
9072
|
return t;
|
|
8712
9073
|
}
|
|
9074
|
+
/** DML creates new tuple arrays; retain existing tuples and xmin bindings until DDL. */
|
|
9075
|
+
cloneForDml() {
|
|
9076
|
+
if (this.triggers.length > 0) return this.cloneForWrite();
|
|
9077
|
+
const t = this.cloneMetadata();
|
|
9078
|
+
t.rowXmins = this.rowXmins;
|
|
9079
|
+
if (this.slab) {
|
|
9080
|
+
t.#rows = this.slab.materialize();
|
|
9081
|
+
if (this.slabXmins) {
|
|
9082
|
+
for (let index = 0; index < t.#rows.length; index++)
|
|
9083
|
+
t.rowXmins.set(t.#rows[index], this.slabXmins[index] ?? 2);
|
|
9084
|
+
}
|
|
9085
|
+
} else {
|
|
9086
|
+
if (this.#rows.length >= 4096 && !this.#rowsExposed) {
|
|
9087
|
+
this.#rowPatches ??= new ForkMap();
|
|
9088
|
+
t.#rowPatches = this.#rowPatches.fork();
|
|
9089
|
+
t.#rows = this.#rows;
|
|
9090
|
+
t.#rowsShared = this.#rowsShared = true;
|
|
9091
|
+
} else t.#rows = this.materializedRows().slice();
|
|
9092
|
+
this.tuplesShared = true;
|
|
9093
|
+
}
|
|
9094
|
+
t.tuplesShared = true;
|
|
9095
|
+
return t;
|
|
9096
|
+
}
|
|
9097
|
+
/** A live DML fork can be unfrozen while its unchanged tuples still belong to history. */
|
|
9098
|
+
ownTuples() {
|
|
9099
|
+
if (this.durableChanges) this.durableUnsafe = true;
|
|
9100
|
+
if (!this.tuplesShared) return;
|
|
9101
|
+
const xmins = /* @__PURE__ */ new WeakMap();
|
|
9102
|
+
this.rows = this.rows.map((row) => {
|
|
9103
|
+
const copy = row.slice();
|
|
9104
|
+
const xmin = this.rowXmins.get(row);
|
|
9105
|
+
if (xmin !== void 0) xmins.set(copy, xmin);
|
|
9106
|
+
return copy;
|
|
9107
|
+
});
|
|
9108
|
+
this.rowXmins = xmins;
|
|
9109
|
+
this.tuplesShared = false;
|
|
9110
|
+
}
|
|
8713
9111
|
/** Independent writable copy (row tuples copied so ALTER COLUMN is isolated). */
|
|
8714
9112
|
cloneForWrite() {
|
|
8715
9113
|
const t = this.clone();
|
|
@@ -9063,12 +9461,21 @@ var DatabaseState = class _DatabaseState {
|
|
|
9063
9461
|
}
|
|
9064
9462
|
}
|
|
9065
9463
|
ensureWritableTable(table) {
|
|
9066
|
-
if (!table.frozen)
|
|
9464
|
+
if (!table.frozen) {
|
|
9465
|
+
table.ownTuples();
|
|
9466
|
+
return table;
|
|
9467
|
+
}
|
|
9067
9468
|
const schema = this.schemas.get(table.schema);
|
|
9068
9469
|
const copy = table.cloneForWrite();
|
|
9069
9470
|
schema?.tables.set(table.name, copy);
|
|
9070
9471
|
return copy;
|
|
9071
9472
|
}
|
|
9473
|
+
ensureWritableTableForDml(table) {
|
|
9474
|
+
if (!table.frozen) return table;
|
|
9475
|
+
const copy = table.cloneForDml();
|
|
9476
|
+
this.schemas.get(table.schema)?.tables.set(table.name, copy);
|
|
9477
|
+
return copy;
|
|
9478
|
+
}
|
|
9072
9479
|
ensureWritableSequence(seq) {
|
|
9073
9480
|
if ((seq.shareCount ?? 0) === 0) return seq;
|
|
9074
9481
|
const schema = this.schemas.get(seq.schema);
|
|
@@ -14716,6 +15123,21 @@ var IndexStore = class _IndexStore {
|
|
|
14716
15123
|
name;
|
|
14717
15124
|
unique;
|
|
14718
15125
|
entries = /* @__PURE__ */ new Map();
|
|
15126
|
+
integerKeys = null;
|
|
15127
|
+
shared = false;
|
|
15128
|
+
ownedBuckets = /* @__PURE__ */ new WeakSet();
|
|
15129
|
+
writableBucket(key, bucket) {
|
|
15130
|
+
if (this.ownedBuckets.has(bucket)) return bucket;
|
|
15131
|
+
const copy = bucket.slice();
|
|
15132
|
+
this.entries.set(key, copy);
|
|
15133
|
+
this.ownedBuckets.add(copy);
|
|
15134
|
+
return copy;
|
|
15135
|
+
}
|
|
15136
|
+
detach() {
|
|
15137
|
+
if (!this.shared) return;
|
|
15138
|
+
if (!(this.entries instanceof ForkMap)) this.entries = new Map(this.entries);
|
|
15139
|
+
this.shared = false;
|
|
15140
|
+
}
|
|
14719
15141
|
constructor(name, unique = false) {
|
|
14720
15142
|
this.name = name;
|
|
14721
15143
|
this.unique = unique;
|
|
@@ -14734,36 +15156,78 @@ var IndexStore = class _IndexStore {
|
|
|
14734
15156
|
}
|
|
14735
15157
|
insert(key, rowIdx) {
|
|
14736
15158
|
if (this.unique) this.checkUnique(key, rowIdx);
|
|
15159
|
+
this.detach();
|
|
15160
|
+
this.integerKeys = null;
|
|
14737
15161
|
const existing = this.entries.get(key);
|
|
14738
15162
|
if (!existing) {
|
|
14739
|
-
|
|
15163
|
+
const bucket = [rowIdx];
|
|
15164
|
+
this.ownedBuckets.add(bucket);
|
|
15165
|
+
this.entries.set(key, bucket);
|
|
14740
15166
|
return;
|
|
14741
15167
|
}
|
|
14742
15168
|
if (existing.includes(rowIdx)) return;
|
|
14743
|
-
existing.push(rowIdx);
|
|
15169
|
+
this.writableBucket(key, existing).push(rowIdx);
|
|
14744
15170
|
}
|
|
14745
15171
|
remove(key, rowIdx) {
|
|
14746
15172
|
const existing = this.entries.get(key);
|
|
14747
15173
|
if (!existing) return;
|
|
14748
15174
|
const at = existing.indexOf(rowIdx);
|
|
14749
15175
|
if (at < 0) return;
|
|
14750
|
-
|
|
14751
|
-
|
|
15176
|
+
this.detach();
|
|
15177
|
+
this.integerKeys = null;
|
|
15178
|
+
if (existing.length === 1) this.entries.delete(key);
|
|
15179
|
+
else {
|
|
15180
|
+
const remaining = this.writableBucket(key, existing);
|
|
15181
|
+
remaining.splice(at, 1);
|
|
15182
|
+
this.entries.set(key, remaining);
|
|
15183
|
+
}
|
|
14752
15184
|
}
|
|
14753
15185
|
lookup(key) {
|
|
14754
15186
|
return this.entries.get(key) ?? [];
|
|
14755
15187
|
}
|
|
15188
|
+
/** Ordered access for a single int2/int4 key (the planner validates the key type). */
|
|
15189
|
+
integerRange(lower, upper, includeLower, includeUpper) {
|
|
15190
|
+
const keys = this.integerKeys ??= [...this.entries].map(([key, rows]) => ({ value: Number(key.slice(1)), rows })).sort((a, b) => a.value - b.value);
|
|
15191
|
+
let lo = 0;
|
|
15192
|
+
let hi = keys.length;
|
|
15193
|
+
while (lo < hi) {
|
|
15194
|
+
const mid = lo + hi >>> 1;
|
|
15195
|
+
const value = keys[mid].value;
|
|
15196
|
+
if (value < lower || !includeLower && value === lower) lo = mid + 1;
|
|
15197
|
+
else hi = mid;
|
|
15198
|
+
}
|
|
15199
|
+
const result = [];
|
|
15200
|
+
for (let i = lo; i < keys.length; i++) {
|
|
15201
|
+
const key = keys[i];
|
|
15202
|
+
if (key.value > upper || !includeUpper && key.value === upper) break;
|
|
15203
|
+
result.push(...key.rows);
|
|
15204
|
+
}
|
|
15205
|
+
return result.sort((a, b) => a - b);
|
|
15206
|
+
}
|
|
14756
15207
|
clear() {
|
|
14757
|
-
this.entries
|
|
15208
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
15209
|
+
this.shared = false;
|
|
15210
|
+
this.integerKeys = null;
|
|
14758
15211
|
}
|
|
14759
15212
|
clone() {
|
|
14760
15213
|
const copy = new _IndexStore(this.name, this.unique);
|
|
14761
|
-
|
|
15214
|
+
if (this.entries.size >= 4096 && !(this.entries instanceof ForkMap)) this.entries = new ForkMap(this.entries);
|
|
15215
|
+
copy.entries = this.entries instanceof ForkMap ? this.entries.fork() : this.entries;
|
|
15216
|
+
copy.integerKeys = this.integerKeys;
|
|
15217
|
+
copy.shared = true;
|
|
15218
|
+
this.shared = true;
|
|
15219
|
+
this.ownedBuckets = /* @__PURE__ */ new WeakSet();
|
|
14762
15220
|
return copy;
|
|
14763
15221
|
}
|
|
14764
15222
|
};
|
|
14765
15223
|
|
|
14766
15224
|
// src/indexes/maintain.ts
|
|
15225
|
+
function prepareDmlIndexStores(env, table) {
|
|
15226
|
+
if (table.indexStores || !table.frozen || table.triggers.length > 0) return;
|
|
15227
|
+
const specs = uniqueSpecsFor(env, table);
|
|
15228
|
+
if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) return;
|
|
15229
|
+
ensureIndexStores(env, table);
|
|
15230
|
+
}
|
|
14767
15231
|
function ensureIndexStores(env, table) {
|
|
14768
15232
|
if (table.indexStores) return table.indexStores;
|
|
14769
15233
|
const stores = /* @__PURE__ */ new Map();
|
|
@@ -14814,8 +15278,19 @@ function indexRemoveRow(env, table, rowIdx, row) {
|
|
|
14814
15278
|
}
|
|
14815
15279
|
}
|
|
14816
15280
|
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
14817
|
-
|
|
14818
|
-
|
|
15281
|
+
const specs = uniqueSpecsFor(env, table);
|
|
15282
|
+
if (specs.some((spec) => spec.where || spec.keys.some((key) => key.expr))) {
|
|
15283
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
15284
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
15285
|
+
return;
|
|
15286
|
+
}
|
|
15287
|
+
for (const spec of specs) {
|
|
15288
|
+
const before = uniqueKeyOf(env, table, spec, oldRow);
|
|
15289
|
+
const after = uniqueKeyOf(env, table, spec, newRow);
|
|
15290
|
+
if (before === after) continue;
|
|
15291
|
+
if (before !== null) table.indexStores?.get(spec.name)?.remove(before, rowIdx);
|
|
15292
|
+
if (after !== null) indexStoreFor(env, table, spec).insert(after, rowIdx);
|
|
15293
|
+
}
|
|
14819
15294
|
}
|
|
14820
15295
|
function rebuildTableIndexes(env, table) {
|
|
14821
15296
|
table.indexStores = null;
|
|
@@ -15032,6 +15507,82 @@ function conjunctions(expr) {
|
|
|
15032
15507
|
}
|
|
15033
15508
|
return [expr];
|
|
15034
15509
|
}
|
|
15510
|
+
function tryPointRowIndices(env, table, alias, where) {
|
|
15511
|
+
const eqs = [];
|
|
15512
|
+
for (const part of conjunctions(where)) {
|
|
15513
|
+
const eq = equalityAgainstConst(part);
|
|
15514
|
+
if (!eq || !["param", "number_lit", "string_lit", "bool_lit", "null_lit"].includes(eq.valueExpr.type)) return null;
|
|
15515
|
+
if (part.type !== "binop") return null;
|
|
15516
|
+
const column = part.left.type === "colref" ? part.left : part.right;
|
|
15517
|
+
if (column.type !== "colref") return null;
|
|
15518
|
+
if (column.parts.length > 1 && column.parts[column.parts.length - 2] !== alias) return null;
|
|
15519
|
+
eqs.push(eq);
|
|
15520
|
+
}
|
|
15521
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15522
|
+
if (spec.where || spec.keys.length !== eqs.length || spec.keys.some((key2) => key2.expr) || !eqs.every((eq, index) => eq.column === spec.columnNames[index]))
|
|
15523
|
+
continue;
|
|
15524
|
+
const values = table.columns.map(() => null);
|
|
15525
|
+
let matches2 = true;
|
|
15526
|
+
for (let index = 0; index < spec.keys.length; index++) {
|
|
15527
|
+
const key2 = spec.keys[index];
|
|
15528
|
+
const column = table.columns[key2.colIdx];
|
|
15529
|
+
const eq = eqs[index];
|
|
15530
|
+
if (!column || !eq || column.domain) {
|
|
15531
|
+
matches2 = false;
|
|
15532
|
+
break;
|
|
15533
|
+
}
|
|
15534
|
+
const value = evalExpr(env.ctx, makeEvalScope(env, null), eq.valueExpr);
|
|
15535
|
+
if (value.t !== column.type.id && !(column.type.id === "text" && value.t === "unknown" && typeof value.v === "string")) {
|
|
15536
|
+
matches2 = false;
|
|
15537
|
+
break;
|
|
15538
|
+
}
|
|
15539
|
+
values[key2.colIdx] = value.v;
|
|
15540
|
+
}
|
|
15541
|
+
if (!matches2) continue;
|
|
15542
|
+
const key = uniqueKeyOf(env, table, spec, values);
|
|
15543
|
+
return { indices: key === null ? [] : indexStoreFor(env, table, spec).lookup(key), indexName: spec.name };
|
|
15544
|
+
}
|
|
15545
|
+
return null;
|
|
15546
|
+
}
|
|
15547
|
+
function recordIndexScan(env, table, name) {
|
|
15548
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
15549
|
+
const index = schema?.indexes.get(name);
|
|
15550
|
+
if (schema && index) {
|
|
15551
|
+
const lastScan = env.ctx.state.clock().getTime();
|
|
15552
|
+
schema.indexes.set(name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
|
|
15553
|
+
}
|
|
15554
|
+
}
|
|
15555
|
+
function tryRangeRowIndices(env, table, alias, where) {
|
|
15556
|
+
const parts = conjunctions(where);
|
|
15557
|
+
if (parts.length !== 2) return null;
|
|
15558
|
+
const bounds = [];
|
|
15559
|
+
for (const part of parts) {
|
|
15560
|
+
if (part.type !== "binop" || ![">", ">=", "<", "<="].includes(part.op)) return null;
|
|
15561
|
+
const column2 = part.left.type === "colref" ? part.left : part.right;
|
|
15562
|
+
const value = part.left.type === "colref" ? part.right : part.left;
|
|
15563
|
+
if (column2.type !== "colref" || column2.parts.length > 2 || column2.parts.length === 2 && column2.parts[0] !== alias || !["param", "number_lit"].includes(value.type))
|
|
15564
|
+
return null;
|
|
15565
|
+
const op = part.left === column2 ? part.op : { ">": "<", ">=": "<=", "<": ">", "<=": ">=" }[part.op];
|
|
15566
|
+
bounds.push({ column: column2.parts.at(-1), op, value });
|
|
15567
|
+
}
|
|
15568
|
+
const lower = bounds.find((bound) => bound.op === ">" || bound.op === ">=");
|
|
15569
|
+
const upper = bounds.find((bound) => bound.op === "<" || bound.op === "<=");
|
|
15570
|
+
if (!lower || !upper || lower.column !== upper.column) return null;
|
|
15571
|
+
const column = table.columns.find((column2) => column2.name === lower.column);
|
|
15572
|
+
if (!column || column.domain || !["int2", "int4"].includes(column.type.id)) return null;
|
|
15573
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15574
|
+
if (spec.where || spec.keys.length !== 1 || spec.keys[0].expr || spec.columnNames[0] !== lower.column) continue;
|
|
15575
|
+
const low = evalExpr(env.ctx, makeEvalScope(env, null), lower.value);
|
|
15576
|
+
const high = evalExpr(env.ctx, makeEvalScope(env, null), upper.value);
|
|
15577
|
+
if (low.t !== column.type.id || high.t !== column.type.id || typeof low.v !== "number" || typeof high.v !== "number")
|
|
15578
|
+
return null;
|
|
15579
|
+
return {
|
|
15580
|
+
indices: indexStoreFor(env, table, spec).integerRange(low.v, high.v, lower.op === ">=", upper.op === "<="),
|
|
15581
|
+
indexName: spec.name
|
|
15582
|
+
};
|
|
15583
|
+
}
|
|
15584
|
+
return null;
|
|
15585
|
+
}
|
|
15035
15586
|
function tryIndexedTableRows(env, table, alias, where) {
|
|
15036
15587
|
const parts = conjunctions(where);
|
|
15037
15588
|
const eqs = [];
|
|
@@ -15068,12 +15619,7 @@ function tryIndexedTableRows(env, table, alias, where) {
|
|
|
15068
15619
|
const key = uniqueKeyOf(env, table, spec, probeRow);
|
|
15069
15620
|
if (key === null) return [];
|
|
15070
15621
|
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
15071
|
-
|
|
15072
|
-
const index = schema?.indexes.get(spec.name);
|
|
15073
|
-
if (schema && index) {
|
|
15074
|
-
const lastScan = env.ctx.state.clock().getTime();
|
|
15075
|
-
schema.indexes.set(spec.name, { ...index, scans: (index.scans ?? 0n) + 1n, lastScan });
|
|
15076
|
-
}
|
|
15622
|
+
recordIndexScan(env, table, spec.name);
|
|
15077
15623
|
return hits.map((i) => table.rowAt(i));
|
|
15078
15624
|
}
|
|
15079
15625
|
function tryIndexedFromItem(env, item, where) {
|
|
@@ -21059,7 +21605,7 @@ function renameWithAliases(rel4, label, colAliases, what) {
|
|
|
21059
21605
|
}));
|
|
21060
21606
|
return { columns, rows: rel4.rows };
|
|
21061
21607
|
}
|
|
21062
|
-
function materializeItem(env, item, scope) {
|
|
21608
|
+
function materializeItem(env, item, scope, shapeOnly = false) {
|
|
21063
21609
|
switch (item.type) {
|
|
21064
21610
|
case "from_table": {
|
|
21065
21611
|
const label = item.alias ?? item.name[item.name.length - 1];
|
|
@@ -21078,7 +21624,7 @@ function materializeItem(env, item, scope) {
|
|
|
21078
21624
|
...table.columns.map((c) => ({ name: c.name, type: c.type.id, mod: c.type.mod, table: label })),
|
|
21079
21625
|
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
21080
21626
|
],
|
|
21081
|
-
rows: table.
|
|
21627
|
+
rows: shapeOnly ? [] : table.serializationRows().map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
21082
21628
|
};
|
|
21083
21629
|
return { rel: renameWithAliases(rel4, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
21084
21630
|
}
|
|
@@ -22351,14 +22897,30 @@ function checkPredicateType(env, columns, rangeVars, e, kind, extras) {
|
|
|
22351
22897
|
function executeCore(env0, core, orderBy, opts) {
|
|
22352
22898
|
const env = env0;
|
|
22353
22899
|
const ctx = env.ctx;
|
|
22354
|
-
const
|
|
22900
|
+
const item = core.from.length === 1 ? core.from[0] : null;
|
|
22901
|
+
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;
|
|
22902
|
+
const point = pointTable && core.where && item?.type === "from_table" ? tryPointRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
|
|
22903
|
+
const range = !point && pointTable && core.where && item?.type === "from_table" ? tryRangeRowIndices(env, pointTable, item.alias ?? item.name[item.name.length - 1], core.where) : null;
|
|
22904
|
+
const access = point ?? range;
|
|
22905
|
+
const source = access && item ? materializeItem(env, item, env.outer, true) : buildFrom(env, core.from, core.where);
|
|
22355
22906
|
const srcCols = source.rel.columns;
|
|
22356
22907
|
const rangeVars = source.rangeVars;
|
|
22357
22908
|
const rowScope = (row) => new RowScope(srcCols, row, env.outer, rangeVars);
|
|
22358
22909
|
let srcRows = source.rel.rows;
|
|
22359
22910
|
if (core.where) {
|
|
22360
22911
|
checkPredicateType(env, srcCols, rangeVars, core.where, "WHERE");
|
|
22361
|
-
if (
|
|
22912
|
+
if (access && pointTable) {
|
|
22913
|
+
pointTable.materializeSlab();
|
|
22914
|
+
srcRows = access.indices.map((index) => {
|
|
22915
|
+
const row = pointTable.rowAt(index);
|
|
22916
|
+
return [...row, pointTable.rowXmins.get(row) ?? 2];
|
|
22917
|
+
});
|
|
22918
|
+
if (range) {
|
|
22919
|
+
const where = core.where;
|
|
22920
|
+
srcRows = srcRows.filter((row) => evalPredicate2(env, rowScope(row), where));
|
|
22921
|
+
}
|
|
22922
|
+
recordIndexScan(env, pointTable, access.indexName);
|
|
22923
|
+
} else if (core.from.length === 1) {
|
|
22362
22924
|
const indexed = tryIndexedFromItem(env, core.from[0], core.where);
|
|
22363
22925
|
if (indexed !== null) {
|
|
22364
22926
|
srcRows = indexed;
|
|
@@ -22539,11 +23101,11 @@ function executeCore(env0, core, orderBy, opts) {
|
|
|
22539
23101
|
}
|
|
22540
23102
|
}
|
|
22541
23103
|
}
|
|
22542
|
-
const
|
|
23104
|
+
const item2 = { name: `__ord${orderExprs.length}`, kind: "expr", colIdx: -1, expr: ob.expr, hidden: true };
|
|
22543
23105
|
const spec = { colIdx: projItems.length, dir, nullsFirst };
|
|
22544
|
-
projItems.push(
|
|
23106
|
+
projItems.push(item2);
|
|
22545
23107
|
sortSpecs.push(spec);
|
|
22546
|
-
orderExprs.push({ item, spec });
|
|
23108
|
+
orderExprs.push({ item: item2, spec });
|
|
22547
23109
|
}
|
|
22548
23110
|
if (core.distinct && !core.distinct.on && sortSpecs.length > 0 && !opts?.hasLimit) {
|
|
22549
23111
|
const used = new Set(sortSpecs.map((s) => s.colIdx));
|
|
@@ -27437,7 +27999,10 @@ function withStatementRollback(env, fn) {
|
|
|
27437
27999
|
function requireTargetTable(env, parts, verb) {
|
|
27438
28000
|
const state = env.ctx.state;
|
|
27439
28001
|
const table = state.findTable(parts);
|
|
27440
|
-
if (table)
|
|
28002
|
+
if (table) {
|
|
28003
|
+
prepareDmlIndexStores(env, table);
|
|
28004
|
+
return state.ensureWritableTableForDml(table);
|
|
28005
|
+
}
|
|
27441
28006
|
const view = state.findView(parts);
|
|
27442
28007
|
if (view) {
|
|
27443
28008
|
throw pgError("wrong_object_type", `cannot ${verb} view "${view.name}"`, "42809");
|
|
@@ -27605,7 +28170,7 @@ function resolveArbiters(env, table, clause) {
|
|
|
27605
28170
|
return matches2.map((spec) => ({ spec }));
|
|
27606
28171
|
}
|
|
27607
28172
|
function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, where) {
|
|
27608
|
-
const rows = table.
|
|
28173
|
+
const rows = table.writeRows();
|
|
27609
28174
|
const existing = rows[existingIdx];
|
|
27610
28175
|
const cols = [
|
|
27611
28176
|
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
@@ -27617,7 +28182,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
27617
28182
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
27618
28183
|
computeGeneratedColumns(env, table, updated);
|
|
27619
28184
|
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
27620
|
-
|
|
28185
|
+
table.replaceRow(existingIdx, updated);
|
|
27621
28186
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
27622
28187
|
checkNotNull(env, table, updated);
|
|
27623
28188
|
checkChecks(env, table, updated);
|
|
@@ -27629,7 +28194,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
27629
28194
|
function executeInsert(env0, stmt) {
|
|
27630
28195
|
const env = applyWith(env0, stmt.with);
|
|
27631
28196
|
const table = requireTargetTable(env, stmt.table, "insert into");
|
|
27632
|
-
const rows = table.
|
|
28197
|
+
const rows = table.writeRows();
|
|
27633
28198
|
const label = stmt.alias ?? table.name;
|
|
27634
28199
|
const colIdxs = insertTargetColumns(env, table, stmt);
|
|
27635
28200
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
@@ -27713,6 +28278,7 @@ function executeInsert(env0, stmt) {
|
|
|
27713
28278
|
checkForeignKeys(env, table, newRow);
|
|
27714
28279
|
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27715
28280
|
rows.push(newRow);
|
|
28281
|
+
table.recordDurableRow(newRow);
|
|
27716
28282
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
27717
28283
|
insertedCount++;
|
|
27718
28284
|
insertedRows.push(newRow);
|
|
@@ -27805,13 +28371,17 @@ function executeUpdate(env0, stmt) {
|
|
|
27805
28371
|
const label = stmt.alias ?? table.name;
|
|
27806
28372
|
fireStatementTriggers(env, table, "before", "update");
|
|
27807
28373
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
27808
|
-
const rows = table.mutableRows();
|
|
27809
28374
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
27810
28375
|
const updatedRows = [];
|
|
27811
28376
|
const replacedRows = [];
|
|
27812
28377
|
let updateCount = 0;
|
|
27813
|
-
|
|
27814
|
-
|
|
28378
|
+
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(
|
|
28379
|
+
(set) => set.columns.every((column) => column.subscripts === null && column.fields.length === 0) && "type" in set.value && isPureUpdateValue(set.value)
|
|
28380
|
+
) && referencingConstraints(env, table).length === 0 ? tryPointRowIndices(env, table, label, stmt.where) : null;
|
|
28381
|
+
const rows = point ? null : table.writeRows();
|
|
28382
|
+
for (let candidate = 0; candidate < (point ? point.indices.length : rows.length); candidate++) {
|
|
28383
|
+
const ri = point ? point.indices[candidate] : candidate;
|
|
28384
|
+
const oldRow = point ? table.rowAt(ri) : rows[ri];
|
|
27815
28385
|
let matchScope = null;
|
|
27816
28386
|
if (fromSource) {
|
|
27817
28387
|
let found = false;
|
|
@@ -27837,14 +28407,14 @@ function executeUpdate(env0, stmt) {
|
|
|
27837
28407
|
const finalRow = fired.row;
|
|
27838
28408
|
computeGeneratedColumns(env, table, finalRow);
|
|
27839
28409
|
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
27840
|
-
|
|
28410
|
+
table.replaceRow(ri, finalRow);
|
|
27841
28411
|
try {
|
|
27842
28412
|
checkNotNull(env, table, finalRow);
|
|
27843
28413
|
checkChecks(env, table, finalRow);
|
|
27844
28414
|
checkUnique(env, table, finalRow, ri);
|
|
27845
28415
|
checkForeignKeys(env, table, finalRow);
|
|
27846
28416
|
} catch (err) {
|
|
27847
|
-
|
|
28417
|
+
table.replaceRow(ri, oldRow);
|
|
27848
28418
|
throw err;
|
|
27849
28419
|
}
|
|
27850
28420
|
indexUpdateRow(env, table, ri, oldRow, finalRow);
|
|
@@ -27862,12 +28432,29 @@ function executeUpdate(env0, stmt) {
|
|
|
27862
28432
|
}
|
|
27863
28433
|
return commandResult("UPDATE", updateCount);
|
|
27864
28434
|
}
|
|
28435
|
+
function isPureUpdateValue(expr) {
|
|
28436
|
+
switch (expr.type) {
|
|
28437
|
+
case "param":
|
|
28438
|
+
case "number_lit":
|
|
28439
|
+
case "string_lit":
|
|
28440
|
+
case "bool_lit":
|
|
28441
|
+
case "null_lit":
|
|
28442
|
+
case "colref":
|
|
28443
|
+
return true;
|
|
28444
|
+
case "binop":
|
|
28445
|
+
return isPureUpdateValue(expr.left) && isPureUpdateValue(expr.right);
|
|
28446
|
+
case "unop":
|
|
28447
|
+
return isPureUpdateValue(expr.operand);
|
|
28448
|
+
default:
|
|
28449
|
+
return false;
|
|
28450
|
+
}
|
|
28451
|
+
}
|
|
27865
28452
|
function executeDelete(env0, stmt) {
|
|
27866
28453
|
const env = applyWith(env0, stmt.with);
|
|
27867
28454
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
27868
28455
|
const label = stmt.alias ?? table.name;
|
|
27869
28456
|
fireStatementTriggers(env, table, "before", "delete");
|
|
27870
|
-
const rows = table.
|
|
28457
|
+
const rows = table.writeRows();
|
|
27871
28458
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
27872
28459
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
27873
28460
|
const toDelete = [];
|
|
@@ -27897,6 +28484,7 @@ function executeDelete(env0, stmt) {
|
|
|
27897
28484
|
if (skipped.has(ri)) continue;
|
|
27898
28485
|
const row = rows[ri];
|
|
27899
28486
|
handleReferencedDelete(env, table, row, 0);
|
|
28487
|
+
table.recordDurableDelete(row);
|
|
27900
28488
|
rows.splice(ri, 1);
|
|
27901
28489
|
deletedRows.unshift(row);
|
|
27902
28490
|
}
|
|
@@ -27943,13 +28531,14 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27943
28531
|
const idxs = referencingRowIdxs(ref, key);
|
|
27944
28532
|
if (idxs.length === 0) continue;
|
|
27945
28533
|
const action = con.onDelete ?? "no_action";
|
|
27946
|
-
const child = env.ctx.state.
|
|
27947
|
-
const childRows = child.
|
|
28534
|
+
const child = env.ctx.state.ensureWritableTableForDml(ref.table);
|
|
28535
|
+
const childRows = child.writeRows();
|
|
27948
28536
|
switch (action) {
|
|
27949
28537
|
case "cascade": {
|
|
27950
28538
|
for (let k = idxs.length - 1; k >= 0; k--) {
|
|
27951
28539
|
const childRow = childRows[idxs[k]];
|
|
27952
28540
|
handleReferencedDelete(env, child, childRow, depth + 1);
|
|
28541
|
+
child.recordDurableDelete(childRow);
|
|
27953
28542
|
childRows.splice(idxs[k], 1);
|
|
27954
28543
|
}
|
|
27955
28544
|
break;
|
|
@@ -27961,7 +28550,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27961
28550
|
newRow[child.columnIndex(c)] = null;
|
|
27962
28551
|
}
|
|
27963
28552
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27964
|
-
|
|
28553
|
+
child.replaceRow(i, newRow);
|
|
27965
28554
|
checkNotNull(env, child, newRow);
|
|
27966
28555
|
checkChecks(env, child, newRow);
|
|
27967
28556
|
}
|
|
@@ -27975,7 +28564,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27975
28564
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
27976
28565
|
}
|
|
27977
28566
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27978
|
-
|
|
28567
|
+
child.replaceRow(i, newRow);
|
|
27979
28568
|
checkNotNull(env, child, newRow);
|
|
27980
28569
|
checkChecks(env, child, newRow);
|
|
27981
28570
|
checkForeignKeys(env, child, newRow);
|
|
@@ -28001,8 +28590,8 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
28001
28590
|
const idxs = referencingRowIdxs(ref, oldKey);
|
|
28002
28591
|
if (idxs.length === 0) continue;
|
|
28003
28592
|
const action = con.onUpdate ?? "no_action";
|
|
28004
|
-
const child = env.ctx.state.
|
|
28005
|
-
const childRows = child.
|
|
28593
|
+
const child = env.ctx.state.ensureWritableTableForDml(ref.table);
|
|
28594
|
+
const childRows = child.writeRows();
|
|
28006
28595
|
switch (action) {
|
|
28007
28596
|
case "cascade": {
|
|
28008
28597
|
for (const i of idxs) {
|
|
@@ -28013,7 +28602,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
28013
28602
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
28014
28603
|
}
|
|
28015
28604
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
28016
|
-
|
|
28605
|
+
child.replaceRow(i, newRow);
|
|
28017
28606
|
checkChecks(env, child, newRow);
|
|
28018
28607
|
}
|
|
28019
28608
|
break;
|
|
@@ -28023,7 +28612,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
28023
28612
|
const newRow = childRows[i].slice();
|
|
28024
28613
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
28025
28614
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
28026
|
-
|
|
28615
|
+
child.replaceRow(i, newRow);
|
|
28027
28616
|
checkNotNull(env, child, newRow);
|
|
28028
28617
|
}
|
|
28029
28618
|
break;
|
|
@@ -28036,7 +28625,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
28036
28625
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
28037
28626
|
}
|
|
28038
28627
|
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
28039
|
-
|
|
28628
|
+
child.replaceRow(i, newRow);
|
|
28040
28629
|
checkForeignKeys(env, child, newRow);
|
|
28041
28630
|
}
|
|
28042
28631
|
break;
|
|
@@ -28199,7 +28788,7 @@ var TransactionManager = class {
|
|
|
28199
28788
|
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
28200
28789
|
}
|
|
28201
28790
|
restore(snap) {
|
|
28202
|
-
this.state.restoreFrom(snap.state);
|
|
28791
|
+
this.state.restoreFrom(snap.state.cloneShallow());
|
|
28203
28792
|
this.state.prng.setState(snap.prngState);
|
|
28204
28793
|
}
|
|
28205
28794
|
thawOnce() {
|