@crvouga/mockingbird-service-postgres 3.6.0 → 3.7.0
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 +7 -1
- package/COMPATIBILITY.md +31 -0
- package/README.md +5 -0
- package/dist/admin.js +216 -26
- package/dist/admin.js.map +3 -3
- package/dist/api/schema-report.d.ts +32 -0
- package/dist/ast/nodes.d.ts +2 -0
- package/dist/executor/relation.d.ts +1 -0
- package/dist/expressions/context.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +405 -27
- package/dist/index.js.map +4 -4
- package/dist/server.js +229 -27
- package/dist/server.js.map +3 -3
- package/dist/storage/database-state.d.ts +7 -0
- package/dist/types/regnamespace.d.ts +5 -0
- package/dist/types/value.d.ts +2 -0
- package/dist/unstable.js +388 -198
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +457 -82
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/index.js +229 -27
- package/dist/wire/index.js.map +3 -3
- package/package.json +1 -1
package/dist/wire/index.js
CHANGED
|
@@ -2803,6 +2803,12 @@ var invalidName = () => {
|
|
|
2803
2803
|
throw pgError("syntax", "invalid name syntax", "42602");
|
|
2804
2804
|
};
|
|
2805
2805
|
function parseNamespaceInput(text) {
|
|
2806
|
+
const parsed = parseRelationInput(text);
|
|
2807
|
+
if ("oid" in parsed) return parsed;
|
|
2808
|
+
if (parsed.parts.length !== 1) invalidName();
|
|
2809
|
+
return { name: parsed.parts[0] };
|
|
2810
|
+
}
|
|
2811
|
+
function parseRelationInput(text) {
|
|
2806
2812
|
if (text === "-") return { oid: 0 };
|
|
2807
2813
|
if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
|
|
2808
2814
|
const names = [];
|
|
@@ -2838,8 +2844,8 @@ function parseNamespaceInput(text) {
|
|
|
2838
2844
|
skipSpace();
|
|
2839
2845
|
if (at === text.length) invalidName();
|
|
2840
2846
|
}
|
|
2841
|
-
if (names.length
|
|
2842
|
-
return {
|
|
2847
|
+
if (names.length === 0 || names.length > 3) invalidName();
|
|
2848
|
+
return { parts: names };
|
|
2843
2849
|
}
|
|
2844
2850
|
function namespaceText(oid, name) {
|
|
2845
2851
|
if (oid === 0) return "-";
|
|
@@ -2912,6 +2918,7 @@ var TYPE_ALIASES = {
|
|
|
2912
2918
|
regtype: "regtype",
|
|
2913
2919
|
regproc: "regproc",
|
|
2914
2920
|
regnamespace: "regnamespace",
|
|
2921
|
+
xid: "xid",
|
|
2915
2922
|
oid: "oid",
|
|
2916
2923
|
void: "void",
|
|
2917
2924
|
record: "record",
|
|
@@ -2988,6 +2995,7 @@ var TYPE_OIDS = {
|
|
|
2988
2995
|
regproc: 24,
|
|
2989
2996
|
text: 25,
|
|
2990
2997
|
oid: 26,
|
|
2998
|
+
xid: 28,
|
|
2991
2999
|
json: 114,
|
|
2992
3000
|
float4: 700,
|
|
2993
3001
|
float8: 701,
|
|
@@ -3307,6 +3315,7 @@ function recordText(rec, ctx) {
|
|
|
3307
3315
|
return `(${parts.join(",")})`;
|
|
3308
3316
|
}
|
|
3309
3317
|
function datumText(t, v, ctx) {
|
|
3318
|
+
if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
|
|
3310
3319
|
if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
|
|
3311
3320
|
if (v === null) throw pgError("internal", "datumText called with null");
|
|
3312
3321
|
if (isArrayType(t)) return arrayText(v, ctx);
|
|
@@ -3317,6 +3326,7 @@ function datumText(t, v, ctx) {
|
|
|
3317
3326
|
case "int2":
|
|
3318
3327
|
case "int4":
|
|
3319
3328
|
case "oid":
|
|
3329
|
+
case "xid":
|
|
3320
3330
|
return String(v);
|
|
3321
3331
|
case "int8":
|
|
3322
3332
|
return String(v);
|
|
@@ -3381,6 +3391,12 @@ function datumText(t, v, ctx) {
|
|
|
3381
3391
|
}
|
|
3382
3392
|
var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
|
|
3383
3393
|
function datumFromText(t, text, ctx) {
|
|
3394
|
+
if (t === "regclass") {
|
|
3395
|
+
const parsed = parseRelationInput(text);
|
|
3396
|
+
if ("oid" in parsed) return parsed.oid;
|
|
3397
|
+
if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
|
|
3398
|
+
return ctx.relationOid(parsed.parts);
|
|
3399
|
+
}
|
|
3384
3400
|
if (t === "regnamespace") {
|
|
3385
3401
|
const parsed = parseNamespaceInput(text);
|
|
3386
3402
|
if ("oid" in parsed) return parsed.oid;
|
|
@@ -3402,6 +3418,7 @@ function datumFromText(t, text, ctx) {
|
|
|
3402
3418
|
case "int8":
|
|
3403
3419
|
return parseIntegerText(text, t);
|
|
3404
3420
|
case "oid":
|
|
3421
|
+
case "xid":
|
|
3405
3422
|
return parseOidText(text);
|
|
3406
3423
|
case "float4":
|
|
3407
3424
|
return Math.fround(parseFloatText(text, "float4"));
|
|
@@ -3558,6 +3575,8 @@ var TableData = class _TableData {
|
|
|
3558
3575
|
schema;
|
|
3559
3576
|
columns;
|
|
3560
3577
|
rows;
|
|
3578
|
+
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
3579
|
+
slabXmins = null;
|
|
3561
3580
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
3562
3581
|
slab = null;
|
|
3563
3582
|
constraints;
|
|
@@ -3600,6 +3619,11 @@ var TableData = class _TableData {
|
|
|
3600
3619
|
materializeSlab() {
|
|
3601
3620
|
if (!this.slab) return;
|
|
3602
3621
|
this.rows = this.slab.materialize();
|
|
3622
|
+
if (this.slabXmins)
|
|
3623
|
+
this.rows.forEach((row, index) => {
|
|
3624
|
+
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
3625
|
+
});
|
|
3626
|
+
this.slabXmins = null;
|
|
3603
3627
|
this.slab = null;
|
|
3604
3628
|
this.indexStores = null;
|
|
3605
3629
|
}
|
|
@@ -3633,6 +3657,10 @@ var TableData = class _TableData {
|
|
|
3633
3657
|
} else {
|
|
3634
3658
|
t.rows = this.rows.map((r) => r.slice());
|
|
3635
3659
|
}
|
|
3660
|
+
t.rows.forEach((row, index) => {
|
|
3661
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
|
|
3662
|
+
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
3663
|
+
});
|
|
3636
3664
|
t.unlogged = this.unlogged;
|
|
3637
3665
|
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
3638
3666
|
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
@@ -3718,6 +3746,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
3718
3746
|
clock;
|
|
3719
3747
|
changes = 0;
|
|
3720
3748
|
oidCounter = 16384;
|
|
3749
|
+
/** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
|
|
3750
|
+
xidCounter = 3;
|
|
3751
|
+
transactionXid = null;
|
|
3752
|
+
allocateXid() {
|
|
3753
|
+
if (this.xidCounter > 4294967295)
|
|
3754
|
+
throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
|
|
3755
|
+
return this.xidCounter++;
|
|
3756
|
+
}
|
|
3721
3757
|
inTransaction = false;
|
|
3722
3758
|
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
3723
3759
|
pendingTriggers = [];
|
|
@@ -3931,6 +3967,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3931
3967
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3932
3968
|
s.tableStats = new Map(this.tableStats);
|
|
3933
3969
|
s.oidCounter = this.oidCounter;
|
|
3970
|
+
s.xidCounter = this.xidCounter;
|
|
3971
|
+
s.transactionXid = this.transactionXid;
|
|
3934
3972
|
for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
|
|
3935
3973
|
return s;
|
|
3936
3974
|
}
|
|
@@ -3950,6 +3988,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3950
3988
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3951
3989
|
s.tableStats = new Map(this.tableStats);
|
|
3952
3990
|
s.oidCounter = this.oidCounter;
|
|
3991
|
+
s.xidCounter = this.xidCounter;
|
|
3992
|
+
s.transactionXid = this.transactionXid;
|
|
3953
3993
|
for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
|
|
3954
3994
|
return s;
|
|
3955
3995
|
}
|
|
@@ -4025,6 +4065,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
4025
4065
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
4026
4066
|
this.tableStats = other.tableStats;
|
|
4027
4067
|
this.oidCounter = other.oidCounter;
|
|
4068
|
+
this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
|
|
4069
|
+
this.transactionXid = other.transactionXid;
|
|
4028
4070
|
}
|
|
4029
4071
|
/** @internal Snapshot codec access to the oid allocator. */
|
|
4030
4072
|
snapshotOidCounter() {
|
|
@@ -4104,6 +4146,11 @@ function validateZone(zone) {
|
|
|
4104
4146
|
// src/expressions/context.ts
|
|
4105
4147
|
var EngineCtx = class {
|
|
4106
4148
|
state;
|
|
4149
|
+
writeXid = null;
|
|
4150
|
+
rowVersionXid() {
|
|
4151
|
+
if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
|
|
4152
|
+
return this.writeXid ??= this.state.allocateXid();
|
|
4153
|
+
}
|
|
4107
4154
|
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
4108
4155
|
txNow;
|
|
4109
4156
|
/** statement timestamp */
|
|
@@ -4118,6 +4165,23 @@ var EngineCtx = class {
|
|
|
4118
4165
|
timezone() {
|
|
4119
4166
|
return this.state.getSetting("timezone") ?? "UTC";
|
|
4120
4167
|
}
|
|
4168
|
+
relationOid(parts) {
|
|
4169
|
+
const target = this.state.resolveRelationSchema(parts);
|
|
4170
|
+
const schema = target ? this.state.schemas.get(target.schema) : void 0;
|
|
4171
|
+
const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
|
|
4172
|
+
if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
|
|
4173
|
+
return relation.oid;
|
|
4174
|
+
}
|
|
4175
|
+
relationName(oid) {
|
|
4176
|
+
for (const schema of this.state.schemas.values()) {
|
|
4177
|
+
for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
|
|
4178
|
+
if (relation.oid !== oid) continue;
|
|
4179
|
+
const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
|
|
4180
|
+
return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
return null;
|
|
4184
|
+
}
|
|
4121
4185
|
namespaceOid(name) {
|
|
4122
4186
|
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
4123
4187
|
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
@@ -4418,7 +4482,7 @@ function castTo(env, value, target, opts = {}) {
|
|
|
4418
4482
|
return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
|
|
4419
4483
|
}
|
|
4420
4484
|
if (from === "oid" && target === "regnamespace") return tv(target, v);
|
|
4421
|
-
if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
|
|
4485
|
+
if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
|
|
4422
4486
|
return tv(target, target === "int8" ? BigInt(v) : v);
|
|
4423
4487
|
}
|
|
4424
4488
|
if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
|
|
@@ -5119,6 +5183,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
|
|
|
5119
5183
|
case "int2":
|
|
5120
5184
|
case "int4":
|
|
5121
5185
|
case "oid":
|
|
5186
|
+
case "regclass":
|
|
5187
|
+
case "xid":
|
|
5122
5188
|
case "regnamespace":
|
|
5123
5189
|
case "date":
|
|
5124
5190
|
return expectNumber(a, t) - expectNumber(b, t);
|
|
@@ -5238,6 +5304,8 @@ function datumKey(t, v) {
|
|
|
5238
5304
|
case "int2":
|
|
5239
5305
|
case "int4":
|
|
5240
5306
|
case "oid":
|
|
5307
|
+
case "regclass":
|
|
5308
|
+
case "xid":
|
|
5241
5309
|
case "date":
|
|
5242
5310
|
return `i${v}`;
|
|
5243
5311
|
case "float4":
|
|
@@ -8146,7 +8214,7 @@ function setDatabaseCatalogContext(state, context) {
|
|
|
8146
8214
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
8147
8215
|
function findSequenceForCall(ctx, name) {
|
|
8148
8216
|
const parts = parseQualifiedName(name);
|
|
8149
|
-
const seq = ctx.state.findSequence(parts);
|
|
8217
|
+
const seq = /^\d+$/.test(name) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name)) : ctx.state.findSequence(parts);
|
|
8150
8218
|
if (!seq) {
|
|
8151
8219
|
throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
|
|
8152
8220
|
}
|
|
@@ -8370,14 +8438,16 @@ function getMiscFunctions() {
|
|
|
8370
8438
|
"pg_get_serial_sequence",
|
|
8371
8439
|
strict("text", (ctx, args) => {
|
|
8372
8440
|
const tableName2 = argText(ctx, args[0]);
|
|
8373
|
-
const column = argText(ctx, args[1])
|
|
8441
|
+
const column = argText(ctx, args[1]);
|
|
8374
8442
|
const table = ctx.state.findTable(parseQualifiedName(tableName2));
|
|
8375
8443
|
if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
|
|
8376
8444
|
const col = table.columns.find((c) => c.name === column);
|
|
8377
8445
|
if (!col)
|
|
8378
8446
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
8379
|
-
|
|
8380
|
-
|
|
8447
|
+
const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
|
|
8448
|
+
(candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
|
|
8449
|
+
);
|
|
8450
|
+
return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
|
|
8381
8451
|
})
|
|
8382
8452
|
);
|
|
8383
8453
|
m.set("format_type", (ctx, args) => {
|
|
@@ -13321,7 +13391,7 @@ var RowScope = class {
|
|
|
13321
13391
|
let count2 = 0;
|
|
13322
13392
|
for (let i = 0; i < this.columns.length; i++) {
|
|
13323
13393
|
const c = this.columns[i];
|
|
13324
|
-
if (c.name === name2 && !c.hidden) {
|
|
13394
|
+
if (c.name === name2 && (!c.hidden || c.system)) {
|
|
13325
13395
|
count2++;
|
|
13326
13396
|
if (count2 > 1) {
|
|
13327
13397
|
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
@@ -13359,7 +13429,7 @@ var RowScope = class {
|
|
|
13359
13429
|
const names = [];
|
|
13360
13430
|
for (let i = 0; i < this.columns.length; i++) {
|
|
13361
13431
|
const c = this.columns[i];
|
|
13362
|
-
if (c.table === rangeVar) {
|
|
13432
|
+
if (c.table === rangeVar && !c.system) {
|
|
13363
13433
|
types.push(c.type);
|
|
13364
13434
|
values.push(this.row[i] ?? null);
|
|
13365
13435
|
names.push(c.name);
|
|
@@ -13802,7 +13872,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
13802
13872
|
if (!table) return null;
|
|
13803
13873
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
13804
13874
|
table.materializeSlab();
|
|
13805
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
13875
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
13806
13876
|
}
|
|
13807
13877
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
13808
13878
|
const parts = [];
|
|
@@ -16292,6 +16362,7 @@ var Parser = class {
|
|
|
16292
16362
|
let sqlBody = null;
|
|
16293
16363
|
let volatility = null;
|
|
16294
16364
|
let strict2 = false;
|
|
16365
|
+
const settings = {};
|
|
16295
16366
|
for (; ; ) {
|
|
16296
16367
|
if (this.eatKw("language")) {
|
|
16297
16368
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -16349,8 +16420,23 @@ var Parser = class {
|
|
|
16349
16420
|
continue;
|
|
16350
16421
|
}
|
|
16351
16422
|
if (this.eatKw("set")) {
|
|
16352
|
-
this.ident(true);
|
|
16353
|
-
if (this.
|
|
16423
|
+
const key = this.ident(true).toLowerCase();
|
|
16424
|
+
if (this.eatKw("from")) {
|
|
16425
|
+
this.expectKw("current");
|
|
16426
|
+
settings[key] = "__from_current__";
|
|
16427
|
+
} else {
|
|
16428
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
16429
|
+
const values = [];
|
|
16430
|
+
do {
|
|
16431
|
+
const value = this.next();
|
|
16432
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
16433
|
+
this.errorAt(value, "expected setting value");
|
|
16434
|
+
values.push(
|
|
16435
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
16436
|
+
);
|
|
16437
|
+
} while (this.eatPunct(","));
|
|
16438
|
+
settings[key] = values.join(", ");
|
|
16439
|
+
}
|
|
16354
16440
|
continue;
|
|
16355
16441
|
}
|
|
16356
16442
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -16430,7 +16516,8 @@ var Parser = class {
|
|
|
16430
16516
|
body,
|
|
16431
16517
|
sqlBody,
|
|
16432
16518
|
volatility,
|
|
16433
|
-
strict: strict2
|
|
16519
|
+
strict: strict2,
|
|
16520
|
+
settings
|
|
16434
16521
|
};
|
|
16435
16522
|
}
|
|
16436
16523
|
parseCreateTrigger(orReplace, constraint) {
|
|
@@ -16539,8 +16626,8 @@ var Parser = class {
|
|
|
16539
16626
|
type: "alter_sequence",
|
|
16540
16627
|
name,
|
|
16541
16628
|
ifExists,
|
|
16542
|
-
options: {
|
|
16543
|
-
|
|
16629
|
+
options: {},
|
|
16630
|
+
renameTo: to
|
|
16544
16631
|
};
|
|
16545
16632
|
}
|
|
16546
16633
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -19116,7 +19203,20 @@ function runFunctionBody(env, fn, args) {
|
|
|
19116
19203
|
}
|
|
19117
19204
|
return last;
|
|
19118
19205
|
}
|
|
19206
|
+
function withFunctionSettings(env, fn, run) {
|
|
19207
|
+
const state = env.ctx.state;
|
|
19208
|
+
const saved = new Map(state.localSettings);
|
|
19209
|
+
for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
|
|
19210
|
+
try {
|
|
19211
|
+
return run();
|
|
19212
|
+
} finally {
|
|
19213
|
+
state.localSettings = saved;
|
|
19214
|
+
}
|
|
19215
|
+
}
|
|
19119
19216
|
function callSqlFunctionScalar(env, fn, args) {
|
|
19217
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
|
|
19218
|
+
}
|
|
19219
|
+
function callSqlFunctionScalarBody(env, fn, args) {
|
|
19120
19220
|
const retT = fn.returns ?? "text";
|
|
19121
19221
|
if (fn.language === "plpgsql") {
|
|
19122
19222
|
return callPlpgsqlScalar(env, fn, args);
|
|
@@ -19146,6 +19246,9 @@ function callSqlFunctionScalar(env, fn, args) {
|
|
|
19146
19246
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
19147
19247
|
}
|
|
19148
19248
|
function callSqlFunctionSet(env, fn, args) {
|
|
19249
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
|
|
19250
|
+
}
|
|
19251
|
+
function callSqlFunctionSetBody(env, fn, args) {
|
|
19149
19252
|
if (fn.language === "plpgsql") {
|
|
19150
19253
|
return callPlpgsqlSet(env, fn, args);
|
|
19151
19254
|
}
|
|
@@ -19300,15 +19403,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19300
19403
|
return rel3;
|
|
19301
19404
|
}
|
|
19302
19405
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
19303
|
-
|
|
19406
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
19407
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
19304
19408
|
throw pgError(
|
|
19305
19409
|
"invalid_column_reference",
|
|
19306
|
-
`table "${what}" has ${
|
|
19410
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
19307
19411
|
"42P10"
|
|
19308
19412
|
);
|
|
19309
19413
|
}
|
|
19310
19414
|
const columns = rel3.columns.map((c, i) => ({
|
|
19311
|
-
|
|
19415
|
+
...c,
|
|
19416
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
19312
19417
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
19313
19418
|
table: label
|
|
19314
19419
|
}));
|
|
@@ -19329,8 +19434,11 @@ function materializeItem(env, item, scope) {
|
|
|
19329
19434
|
if (table) {
|
|
19330
19435
|
table.materializeSlab();
|
|
19331
19436
|
const rel3 = {
|
|
19332
|
-
columns:
|
|
19333
|
-
|
|
19437
|
+
columns: [
|
|
19438
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
19439
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
19440
|
+
],
|
|
19441
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
19334
19442
|
};
|
|
19335
19443
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
19336
19444
|
}
|
|
@@ -19960,7 +20068,7 @@ function resolveColIdx(columns, parts) {
|
|
|
19960
20068
|
let found = -1;
|
|
19961
20069
|
for (let i = 0; i < columns.length; i++) {
|
|
19962
20070
|
const c = columns[i];
|
|
19963
|
-
if (!c.hidden && c.name === name2) {
|
|
20071
|
+
if ((!c.hidden || c.system) && c.name === name2) {
|
|
19964
20072
|
if (found !== -1) return null;
|
|
19965
20073
|
found = i;
|
|
19966
20074
|
}
|
|
@@ -20544,7 +20652,7 @@ function expandTargets(core, columns) {
|
|
|
20544
20652
|
let any = false;
|
|
20545
20653
|
for (let i = 0; i < columns.length; i++) {
|
|
20546
20654
|
const c = columns[i];
|
|
20547
|
-
if (c.table === label) {
|
|
20655
|
+
if (c.table === label && !c.system) {
|
|
20548
20656
|
any = true;
|
|
20549
20657
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
20550
20658
|
}
|
|
@@ -21149,6 +21257,7 @@ var TransactionManager = class {
|
|
|
21149
21257
|
this.base = null;
|
|
21150
21258
|
this.savepoints = [];
|
|
21151
21259
|
this.state.inTransaction = false;
|
|
21260
|
+
this.state.transactionXid = null;
|
|
21152
21261
|
this.state.localSettings.clear();
|
|
21153
21262
|
this.state.pendingTriggers = [];
|
|
21154
21263
|
this.state.constraintModes.clear();
|
|
@@ -21161,6 +21270,7 @@ var TransactionManager = class {
|
|
|
21161
21270
|
this.base = null;
|
|
21162
21271
|
this.savepoints = [];
|
|
21163
21272
|
this.state.inTransaction = false;
|
|
21273
|
+
this.state.transactionXid = null;
|
|
21164
21274
|
this.state.localSettings.clear();
|
|
21165
21275
|
this.state.pendingTriggers = [];
|
|
21166
21276
|
this.state.constraintModes.clear();
|
|
@@ -21195,6 +21305,7 @@ var TransactionManager = class {
|
|
|
21195
21305
|
this.base = null;
|
|
21196
21306
|
this.savepoints = [];
|
|
21197
21307
|
this.state.inTransaction = false;
|
|
21308
|
+
this.state.transactionXid = null;
|
|
21198
21309
|
this.freezeDepth = 0;
|
|
21199
21310
|
}
|
|
21200
21311
|
};
|
|
@@ -21398,6 +21509,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
21398
21509
|
const updated = existing.slice();
|
|
21399
21510
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
21400
21511
|
computeGeneratedColumns(env, table, updated);
|
|
21512
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
21401
21513
|
rows[existingIdx] = updated;
|
|
21402
21514
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
21403
21515
|
checkNotNull(env, table, updated);
|
|
@@ -21483,6 +21595,7 @@ function executeInsert(env0, stmt) {
|
|
|
21483
21595
|
checkChecks(env, table, newRow);
|
|
21484
21596
|
checkUnique(env, table, newRow, rows.length);
|
|
21485
21597
|
checkForeignKeys(env, table, newRow);
|
|
21598
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21486
21599
|
rows.push(newRow);
|
|
21487
21600
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
21488
21601
|
insertedCount++;
|
|
@@ -21600,6 +21713,7 @@ function executeUpdate(env0, stmt) {
|
|
|
21600
21713
|
if (fired.row === null) continue;
|
|
21601
21714
|
const finalRow = fired.row;
|
|
21602
21715
|
computeGeneratedColumns(env, table, finalRow);
|
|
21716
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
21603
21717
|
rows[ri] = finalRow;
|
|
21604
21718
|
try {
|
|
21605
21719
|
checkNotNull(env, table, finalRow);
|
|
@@ -21719,6 +21833,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
21719
21833
|
for (const c of con.columns) {
|
|
21720
21834
|
newRow[child.columnIndex(c)] = null;
|
|
21721
21835
|
}
|
|
21836
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21722
21837
|
childRows[i] = newRow;
|
|
21723
21838
|
checkNotNull(env, child, newRow);
|
|
21724
21839
|
checkChecks(env, child, newRow);
|
|
@@ -21732,6 +21847,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
21732
21847
|
const ci = child.columnIndex(c);
|
|
21733
21848
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
21734
21849
|
}
|
|
21850
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21735
21851
|
childRows[i] = newRow;
|
|
21736
21852
|
checkNotNull(env, child, newRow);
|
|
21737
21853
|
checkChecks(env, child, newRow);
|
|
@@ -21769,6 +21885,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21769
21885
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
21770
21886
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
21771
21887
|
}
|
|
21888
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21772
21889
|
childRows[i] = newRow;
|
|
21773
21890
|
checkChecks(env, child, newRow);
|
|
21774
21891
|
}
|
|
@@ -21778,6 +21895,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21778
21895
|
for (const i of idxs) {
|
|
21779
21896
|
const newRow = childRows[i].slice();
|
|
21780
21897
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
21898
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21781
21899
|
childRows[i] = newRow;
|
|
21782
21900
|
checkNotNull(env, child, newRow);
|
|
21783
21901
|
}
|
|
@@ -21790,6 +21908,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21790
21908
|
const ci = child.columnIndex(c);
|
|
21791
21909
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
21792
21910
|
}
|
|
21911
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21793
21912
|
childRows[i] = newRow;
|
|
21794
21913
|
checkForeignKeys(env, child, newRow);
|
|
21795
21914
|
}
|
|
@@ -24837,13 +24956,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
24837
24956
|
schema.sequences.set(name, seq);
|
|
24838
24957
|
return commandResult("CREATE SEQUENCE", 0);
|
|
24839
24958
|
}
|
|
24959
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
24960
|
+
const state = env.ctx.state;
|
|
24961
|
+
const matches2 = (value) => {
|
|
24962
|
+
try {
|
|
24963
|
+
const input = parseRelationInput(value);
|
|
24964
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
24965
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
24966
|
+
} catch {
|
|
24967
|
+
return false;
|
|
24968
|
+
}
|
|
24969
|
+
};
|
|
24970
|
+
const rewrite = (value) => {
|
|
24971
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
24972
|
+
if (value === null || typeof value !== "object") return value;
|
|
24973
|
+
const node = value;
|
|
24974
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
24975
|
+
const rewriteLiteral = (literal2) => {
|
|
24976
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
|
|
24977
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
24978
|
+
}
|
|
24979
|
+
return literal2;
|
|
24980
|
+
};
|
|
24981
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
24982
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
24983
|
+
if (node.type === "cast" && node.target && typeof node.target === "object" && "parts" in node.target && Array.isArray(node.target.parts) && node.target.parts.at(-1) === "regclass")
|
|
24984
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
24985
|
+
return updated;
|
|
24986
|
+
};
|
|
24987
|
+
for (const schema of state.schemas.values()) {
|
|
24988
|
+
for (const table of [...schema.tables.values()]) {
|
|
24989
|
+
const writable = state.ensureWritableTable(table);
|
|
24990
|
+
for (const column of writable.columns) {
|
|
24991
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
24992
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
24993
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
24994
|
+
}
|
|
24995
|
+
}
|
|
24996
|
+
}
|
|
24997
|
+
}
|
|
24840
24998
|
function executeAlterSequence(env, stmt) {
|
|
24841
24999
|
const state = env.ctx.state;
|
|
24842
|
-
const
|
|
24843
|
-
if (!
|
|
25000
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
25001
|
+
if (!foundSequence) {
|
|
24844
25002
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
24845
25003
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
24846
25004
|
}
|
|
25005
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
25006
|
+
if (stmt.renameTo) {
|
|
25007
|
+
const schema = state.getSchema(seq.schema);
|
|
25008
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
25009
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
25010
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
25011
|
+
schema.sequences.delete(seq.name);
|
|
25012
|
+
seq.name = stmt.renameTo;
|
|
25013
|
+
schema.sequences.set(seq.name, seq);
|
|
25014
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
25015
|
+
}
|
|
24847
25016
|
const o = stmt.options;
|
|
24848
25017
|
if (o.logged !== void 0) {
|
|
24849
25018
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -24901,7 +25070,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
24901
25070
|
col.defaultExpr = {
|
|
24902
25071
|
type: "func",
|
|
24903
25072
|
name: ["nextval"],
|
|
24904
|
-
args: [{ type: "string_lit", value:
|
|
25073
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
24905
25074
|
};
|
|
24906
25075
|
}
|
|
24907
25076
|
for (const c of def.constraints) {
|
|
@@ -25154,7 +25323,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
25154
25323
|
const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
|
|
25155
25324
|
table.unlogged = stmt.unlogged === true;
|
|
25156
25325
|
if (stmt.withData) {
|
|
25157
|
-
for (const row of rel3.rows)
|
|
25326
|
+
for (const row of rel3.rows) {
|
|
25327
|
+
const stored = row.slice();
|
|
25328
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
25329
|
+
table.mutableRows().push(stored);
|
|
25330
|
+
}
|
|
25158
25331
|
}
|
|
25159
25332
|
schema.tables.set(name, table);
|
|
25160
25333
|
const count = stmt.withData ? table.rowCount() : 0;
|
|
@@ -25423,6 +25596,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
25423
25596
|
language: lang,
|
|
25424
25597
|
body,
|
|
25425
25598
|
rawBody: stmt.body,
|
|
25599
|
+
settings: Object.fromEntries(
|
|
25600
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
25601
|
+
key,
|
|
25602
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
25603
|
+
])
|
|
25604
|
+
),
|
|
25426
25605
|
strict: stmt.strict,
|
|
25427
25606
|
oid: state.nextOid()
|
|
25428
25607
|
};
|
|
@@ -25607,6 +25786,7 @@ function executeAlterTable(env, stmt) {
|
|
|
25607
25786
|
}
|
|
25608
25787
|
const next = row.slice();
|
|
25609
25788
|
next[idx] = nv;
|
|
25789
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
25610
25790
|
rows[i] = next;
|
|
25611
25791
|
}
|
|
25612
25792
|
col.type = resolved.column;
|
|
@@ -25708,6 +25888,11 @@ function executeAlterTable(env, stmt) {
|
|
|
25708
25888
|
);
|
|
25709
25889
|
}
|
|
25710
25890
|
table.columns[idx].name = action.to;
|
|
25891
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
25892
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
25893
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
25894
|
+
}
|
|
25895
|
+
}
|
|
25711
25896
|
for (const con of table.constraints) {
|
|
25712
25897
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
25713
25898
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -25744,6 +25929,11 @@ function executeAlterTable(env, stmt) {
|
|
|
25744
25929
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
25745
25930
|
}
|
|
25746
25931
|
const oldName = table.name;
|
|
25932
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
25933
|
+
if (seq.ownedBy?.table === oldName) {
|
|
25934
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
25935
|
+
}
|
|
25936
|
+
}
|
|
25747
25937
|
schema.tables.delete(table.name);
|
|
25748
25938
|
table.name = action.to;
|
|
25749
25939
|
schema.tables.set(action.to, table);
|
|
@@ -27617,6 +27807,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
27617
27807
|
writeBjv(
|
|
27618
27808
|
w,
|
|
27619
27809
|
{
|
|
27810
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
27620
27811
|
name: table.name,
|
|
27621
27812
|
schema: table.schema,
|
|
27622
27813
|
columns: table.columns,
|
|
@@ -27714,8 +27905,14 @@ function decodeInner(snapshot, prng, clock) {
|
|
|
27714
27905
|
table.constraints = meta.constraints;
|
|
27715
27906
|
table.triggers = meta.triggers;
|
|
27716
27907
|
table.unlogged = meta.unlogged === true;
|
|
27908
|
+
table.slabXmins = meta.xmins ?? null;
|
|
27909
|
+
state.xidCounter = Math.max(
|
|
27910
|
+
state.xidCounter,
|
|
27911
|
+
(meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
|
|
27912
|
+
);
|
|
27717
27913
|
if (meta.stats) state.tableStats.set(table.oid, meta.stats);
|
|
27718
27914
|
const rowCount = readVarintU32(r);
|
|
27915
|
+
if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
|
|
27719
27916
|
const slabColumns = [];
|
|
27720
27917
|
for (let c = 0; c < meta.columns.length; c++)
|
|
27721
27918
|
slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
|
|
@@ -28159,6 +28356,8 @@ function validateTableMetaBjv(value) {
|
|
|
28159
28356
|
if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
28160
28357
|
if (!Array.isArray(value.columns)) throw snapshotError();
|
|
28161
28358
|
for (const col of value.columns) validateColumnMeta(col);
|
|
28359
|
+
if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
|
|
28360
|
+
throw snapshotError();
|
|
28162
28361
|
}
|
|
28163
28362
|
function validateViewMetaBjv(value) {
|
|
28164
28363
|
if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
@@ -28252,6 +28451,7 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
28252
28451
|
pool.forceId(table.name);
|
|
28253
28452
|
pool.forceId(table.schema);
|
|
28254
28453
|
forceBjvStrings(pool, {
|
|
28454
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
28255
28455
|
name: table.name,
|
|
28256
28456
|
schema: table.schema,
|
|
28257
28457
|
columns: table.columns,
|
|
@@ -29882,7 +30082,7 @@ var Connection = class {
|
|
|
29882
30082
|
if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
|
|
29883
30083
|
switch (stmt.action) {
|
|
29884
30084
|
case "begin":
|
|
29885
|
-
this.transaction ??= { statements: [], savepoints: [] };
|
|
30085
|
+
this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
|
|
29886
30086
|
return command("BEGIN");
|
|
29887
30087
|
case "commit": {
|
|
29888
30088
|
const transaction = this.transaction;
|
|
@@ -29891,6 +30091,7 @@ var Connection = class {
|
|
|
29891
30091
|
this.inSession(
|
|
29892
30092
|
this.database,
|
|
29893
30093
|
() => this.database.transaction(() => {
|
|
30094
|
+
this.database.state.transactionXid = transaction.xid;
|
|
29894
30095
|
for (const logged of transaction.statements) this.replay(this.database, logged);
|
|
29895
30096
|
})
|
|
29896
30097
|
);
|
|
@@ -29941,6 +30142,7 @@ var Connection = class {
|
|
|
29941
30142
|
workspace.state.settings = new Map(this.settings);
|
|
29942
30143
|
workspace.state.settingDefaults = this.settingDefaults;
|
|
29943
30144
|
workspace.transactions.begin();
|
|
30145
|
+
workspace.state.transactionXid = this.transaction?.xid ?? null;
|
|
29944
30146
|
for (const logged of this.transaction?.statements ?? []) {
|
|
29945
30147
|
this.replay(workspace, logged);
|
|
29946
30148
|
}
|