@crvouga/mockingbird-service-postgres 3.6.0 → 3.8.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 +13 -1
- package/COMPATIBILITY.md +33 -1
- package/README.md +5 -0
- package/dist/admin.js +459 -104
- package/dist/admin.js.map +3 -3
- package/dist/api/schema-report.d.ts +32 -0
- package/dist/ast/nodes.d.ts +7 -0
- package/dist/constraints/enforce.d.ts +7 -1
- package/dist/executor/relation.d.ts +1 -0
- package/dist/executor/triggers.d.ts +13 -0
- package/dist/expressions/context.d.ts +4 -0
- package/dist/functions/pgtrgm.d.ts +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +531 -38
- package/dist/index.js.map +4 -4
- package/dist/server.js +355 -38
- package/dist/server.js.map +3 -3
- package/dist/storage/database-state.d.ts +11 -0
- package/dist/types/regnamespace.d.ts +5 -0
- package/dist/types/value.d.ts +2 -0
- package/dist/unstable.js +514 -209
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +692 -102
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/fleet.d.ts +18 -0
- package/dist/wire/index.js +355 -38
- 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) => {
|
|
@@ -9895,7 +9965,7 @@ function evalTrgmWordSimilar(ctx, left, right) {
|
|
|
9895
9965
|
const score = wordSimilarity(a.v, b.v);
|
|
9896
9966
|
return tv("bool", score >= WORD_SIMILARITY_THRESHOLD);
|
|
9897
9967
|
}
|
|
9898
|
-
function assertGinTrgmIndex(state, table, stmt) {
|
|
9968
|
+
function assertGinTrgmIndex(state, table, stmt, expressionType) {
|
|
9899
9969
|
const trgmCols = stmt.columns.filter((col2) => isGinTrgmOpclass(col2.opclass));
|
|
9900
9970
|
if (trgmCols.length === 0) return;
|
|
9901
9971
|
if (trgmCols.length !== stmt.columns.length || stmt.columns.length !== 1) {
|
|
@@ -9915,11 +9985,7 @@ function assertGinTrgmIndex(state, table, stmt) {
|
|
|
9915
9985
|
if (stmt.unique) {
|
|
9916
9986
|
throw pgError("feature_not_supported", `access method "gin" does not support unique indexes`, "0A000");
|
|
9917
9987
|
}
|
|
9918
|
-
|
|
9919
|
-
throw unsupported("expression gin_trgm_ops");
|
|
9920
|
-
}
|
|
9921
|
-
const index = table.columnIndex(col.expr.parts[0]);
|
|
9922
|
-
const typeId = table.columns[index].type.id;
|
|
9988
|
+
const typeId = col.expr.type === "colref" && col.expr.parts.length === 1 ? table.columns[table.columnIndex(col.expr.parts[0])].type.id : expressionType(col.expr);
|
|
9923
9989
|
if (!GIN_TRGM_TYPES.has(typeId)) {
|
|
9924
9990
|
throw pgError(
|
|
9925
9991
|
"datatype_mismatch",
|
|
@@ -13321,7 +13387,7 @@ var RowScope = class {
|
|
|
13321
13387
|
let count2 = 0;
|
|
13322
13388
|
for (let i = 0; i < this.columns.length; i++) {
|
|
13323
13389
|
const c = this.columns[i];
|
|
13324
|
-
if (c.name === name2 && !c.hidden) {
|
|
13390
|
+
if (c.name === name2 && (!c.hidden || c.system)) {
|
|
13325
13391
|
count2++;
|
|
13326
13392
|
if (count2 > 1) {
|
|
13327
13393
|
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
@@ -13359,7 +13425,7 @@ var RowScope = class {
|
|
|
13359
13425
|
const names = [];
|
|
13360
13426
|
for (let i = 0; i < this.columns.length; i++) {
|
|
13361
13427
|
const c = this.columns[i];
|
|
13362
|
-
if (c.table === rangeVar) {
|
|
13428
|
+
if (c.table === rangeVar && !c.system) {
|
|
13363
13429
|
types.push(c.type);
|
|
13364
13430
|
values.push(this.row[i] ?? null);
|
|
13365
13431
|
names.push(c.name);
|
|
@@ -13557,6 +13623,17 @@ function tableScope(table, row) {
|
|
|
13557
13623
|
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
13558
13624
|
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
13559
13625
|
}
|
|
13626
|
+
function expressionTypeOf(env, table, expr) {
|
|
13627
|
+
const scope = makeEvalScope(
|
|
13628
|
+
env,
|
|
13629
|
+
tableScope(
|
|
13630
|
+
table,
|
|
13631
|
+
table.columns.map(() => null)
|
|
13632
|
+
)
|
|
13633
|
+
);
|
|
13634
|
+
const v = evalExpr(env.ctx, scope, expr);
|
|
13635
|
+
return v.t === "unknown" ? "text" : v.t;
|
|
13636
|
+
}
|
|
13560
13637
|
function checkNotNull(env, table, row) {
|
|
13561
13638
|
void env;
|
|
13562
13639
|
for (let i = 0; i < table.columns.length; i++) {
|
|
@@ -13802,7 +13879,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
13802
13879
|
if (!table) return null;
|
|
13803
13880
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
13804
13881
|
table.materializeSlab();
|
|
13805
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
13882
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
13806
13883
|
}
|
|
13807
13884
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
13808
13885
|
const parts = [];
|
|
@@ -16292,6 +16369,7 @@ var Parser = class {
|
|
|
16292
16369
|
let sqlBody = null;
|
|
16293
16370
|
let volatility = null;
|
|
16294
16371
|
let strict2 = false;
|
|
16372
|
+
const settings = {};
|
|
16295
16373
|
for (; ; ) {
|
|
16296
16374
|
if (this.eatKw("language")) {
|
|
16297
16375
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -16349,8 +16427,23 @@ var Parser = class {
|
|
|
16349
16427
|
continue;
|
|
16350
16428
|
}
|
|
16351
16429
|
if (this.eatKw("set")) {
|
|
16352
|
-
this.ident(true);
|
|
16353
|
-
if (this.
|
|
16430
|
+
const key = this.ident(true).toLowerCase();
|
|
16431
|
+
if (this.eatKw("from")) {
|
|
16432
|
+
this.expectKw("current");
|
|
16433
|
+
settings[key] = "__from_current__";
|
|
16434
|
+
} else {
|
|
16435
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
16436
|
+
const values = [];
|
|
16437
|
+
do {
|
|
16438
|
+
const value = this.next();
|
|
16439
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
16440
|
+
this.errorAt(value, "expected setting value");
|
|
16441
|
+
values.push(
|
|
16442
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
16443
|
+
);
|
|
16444
|
+
} while (this.eatPunct(","));
|
|
16445
|
+
settings[key] = values.join(", ");
|
|
16446
|
+
}
|
|
16354
16447
|
continue;
|
|
16355
16448
|
}
|
|
16356
16449
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -16430,7 +16523,8 @@ var Parser = class {
|
|
|
16430
16523
|
body,
|
|
16431
16524
|
sqlBody,
|
|
16432
16525
|
volatility,
|
|
16433
|
-
strict: strict2
|
|
16526
|
+
strict: strict2,
|
|
16527
|
+
settings
|
|
16434
16528
|
};
|
|
16435
16529
|
}
|
|
16436
16530
|
parseCreateTrigger(orReplace, constraint) {
|
|
@@ -16462,7 +16556,6 @@ var Parser = class {
|
|
|
16462
16556
|
} while (this.eatKw("or"));
|
|
16463
16557
|
this.expectKw("on");
|
|
16464
16558
|
const table = this.qualifiedName();
|
|
16465
|
-
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
16466
16559
|
let deferrable = false;
|
|
16467
16560
|
let initiallyDeferred = false;
|
|
16468
16561
|
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
@@ -16475,6 +16568,23 @@ var Parser = class {
|
|
|
16475
16568
|
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
16476
16569
|
if (initiallyDeferred && !deferrable)
|
|
16477
16570
|
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
16571
|
+
const transitions = [];
|
|
16572
|
+
if (!constraint && this.eatKw("referencing")) {
|
|
16573
|
+
do {
|
|
16574
|
+
const isNew = this.eatKw("new");
|
|
16575
|
+
if (!isNew) this.expectKw("old");
|
|
16576
|
+
if (this.eatKw("row")) {
|
|
16577
|
+
throw pgError(
|
|
16578
|
+
"feature_not_supported",
|
|
16579
|
+
"ROW variable naming in the REFERENCING clause is not supported",
|
|
16580
|
+
"0A000"
|
|
16581
|
+
);
|
|
16582
|
+
}
|
|
16583
|
+
this.expectKw("table");
|
|
16584
|
+
this.eatKw("as");
|
|
16585
|
+
transitions.push({ isNew, name: this.ident() });
|
|
16586
|
+
} while (this.atKw("new") || this.atKw("old"));
|
|
16587
|
+
}
|
|
16478
16588
|
let forEachRow = false;
|
|
16479
16589
|
if (this.eatKw("for")) {
|
|
16480
16590
|
this.eatKw("each");
|
|
@@ -16512,7 +16622,8 @@ var Parser = class {
|
|
|
16512
16622
|
forEachRow,
|
|
16513
16623
|
when,
|
|
16514
16624
|
funcName,
|
|
16515
|
-
funcArgs
|
|
16625
|
+
funcArgs,
|
|
16626
|
+
...transitions.length > 0 ? { transitions } : {}
|
|
16516
16627
|
};
|
|
16517
16628
|
}
|
|
16518
16629
|
// --- ALTER --------------------------------------------------------------------
|
|
@@ -16539,8 +16650,8 @@ var Parser = class {
|
|
|
16539
16650
|
type: "alter_sequence",
|
|
16540
16651
|
name,
|
|
16541
16652
|
ifExists,
|
|
16542
|
-
options: {
|
|
16543
|
-
|
|
16653
|
+
options: {},
|
|
16654
|
+
renameTo: to
|
|
16544
16655
|
};
|
|
16545
16656
|
}
|
|
16546
16657
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -19116,7 +19227,20 @@ function runFunctionBody(env, fn, args) {
|
|
|
19116
19227
|
}
|
|
19117
19228
|
return last;
|
|
19118
19229
|
}
|
|
19230
|
+
function withFunctionSettings(env, fn, run) {
|
|
19231
|
+
const state = env.ctx.state;
|
|
19232
|
+
const saved = new Map(state.localSettings);
|
|
19233
|
+
for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
|
|
19234
|
+
try {
|
|
19235
|
+
return run();
|
|
19236
|
+
} finally {
|
|
19237
|
+
state.localSettings = saved;
|
|
19238
|
+
}
|
|
19239
|
+
}
|
|
19119
19240
|
function callSqlFunctionScalar(env, fn, args) {
|
|
19241
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
|
|
19242
|
+
}
|
|
19243
|
+
function callSqlFunctionScalarBody(env, fn, args) {
|
|
19120
19244
|
const retT = fn.returns ?? "text";
|
|
19121
19245
|
if (fn.language === "plpgsql") {
|
|
19122
19246
|
return callPlpgsqlScalar(env, fn, args);
|
|
@@ -19146,6 +19270,9 @@ function callSqlFunctionScalar(env, fn, args) {
|
|
|
19146
19270
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
19147
19271
|
}
|
|
19148
19272
|
function callSqlFunctionSet(env, fn, args) {
|
|
19273
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
|
|
19274
|
+
}
|
|
19275
|
+
function callSqlFunctionSetBody(env, fn, args) {
|
|
19149
19276
|
if (fn.language === "plpgsql") {
|
|
19150
19277
|
return callPlpgsqlSet(env, fn, args);
|
|
19151
19278
|
}
|
|
@@ -19300,15 +19427,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19300
19427
|
return rel3;
|
|
19301
19428
|
}
|
|
19302
19429
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
19303
|
-
|
|
19430
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
19431
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
19304
19432
|
throw pgError(
|
|
19305
19433
|
"invalid_column_reference",
|
|
19306
|
-
`table "${what}" has ${
|
|
19434
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
19307
19435
|
"42P10"
|
|
19308
19436
|
);
|
|
19309
19437
|
}
|
|
19310
19438
|
const columns = rel3.columns.map((c, i) => ({
|
|
19311
|
-
|
|
19439
|
+
...c,
|
|
19440
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
19312
19441
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
19313
19442
|
table: label
|
|
19314
19443
|
}));
|
|
@@ -19329,8 +19458,11 @@ function materializeItem(env, item, scope) {
|
|
|
19329
19458
|
if (table) {
|
|
19330
19459
|
table.materializeSlab();
|
|
19331
19460
|
const rel3 = {
|
|
19332
|
-
columns:
|
|
19333
|
-
|
|
19461
|
+
columns: [
|
|
19462
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
19463
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
19464
|
+
],
|
|
19465
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
19334
19466
|
};
|
|
19335
19467
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
19336
19468
|
}
|
|
@@ -19960,7 +20092,7 @@ function resolveColIdx(columns, parts) {
|
|
|
19960
20092
|
let found = -1;
|
|
19961
20093
|
for (let i = 0; i < columns.length; i++) {
|
|
19962
20094
|
const c = columns[i];
|
|
19963
|
-
if (!c.hidden && c.name === name2) {
|
|
20095
|
+
if ((!c.hidden || c.system) && c.name === name2) {
|
|
19964
20096
|
if (found !== -1) return null;
|
|
19965
20097
|
found = i;
|
|
19966
20098
|
}
|
|
@@ -20544,7 +20676,7 @@ function expandTargets(core, columns) {
|
|
|
20544
20676
|
let any = false;
|
|
20545
20677
|
for (let i = 0; i < columns.length; i++) {
|
|
20546
20678
|
const c = columns[i];
|
|
20547
|
-
if (c.table === label) {
|
|
20679
|
+
if (c.table === label && !c.system) {
|
|
20548
20680
|
any = true;
|
|
20549
20681
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
20550
20682
|
}
|
|
@@ -21037,6 +21169,29 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
21037
21169
|
}
|
|
21038
21170
|
return { row };
|
|
21039
21171
|
}
|
|
21172
|
+
function transitionRelation(table, name, rows) {
|
|
21173
|
+
return {
|
|
21174
|
+
columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: name })),
|
|
21175
|
+
rows
|
|
21176
|
+
};
|
|
21177
|
+
}
|
|
21178
|
+
function fireStatementTriggers(env, table, timing, event, transitions) {
|
|
21179
|
+
const fired = table.triggers.filter((t) => !t.forEachRow && t.timing === timing && matches(t, event)).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
21180
|
+
for (const t of fired) {
|
|
21181
|
+
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
21182
|
+
const ctes = /* @__PURE__ */ new Map();
|
|
21183
|
+
if (t.oldTable !== void 0)
|
|
21184
|
+
ctes.set(t.oldTable, transitionRelation(table, t.oldTable, transitions?.oldRows ?? []));
|
|
21185
|
+
if (t.newTable !== void 0)
|
|
21186
|
+
ctes.set(t.newTable, transitionRelation(table, t.newTable, transitions?.newRows ?? []));
|
|
21187
|
+
const changes = env.ctx.state.changes;
|
|
21188
|
+
try {
|
|
21189
|
+
executor({ ctx: env.ctx, params: null, ctes, outer: null }, table, t, event, null, null);
|
|
21190
|
+
} finally {
|
|
21191
|
+
env.ctx.state.changes = changes;
|
|
21192
|
+
}
|
|
21193
|
+
}
|
|
21194
|
+
}
|
|
21040
21195
|
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
21041
21196
|
function flushConstraintTriggers(state, all = false) {
|
|
21042
21197
|
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
@@ -21149,6 +21304,7 @@ var TransactionManager = class {
|
|
|
21149
21304
|
this.base = null;
|
|
21150
21305
|
this.savepoints = [];
|
|
21151
21306
|
this.state.inTransaction = false;
|
|
21307
|
+
this.state.transactionXid = null;
|
|
21152
21308
|
this.state.localSettings.clear();
|
|
21153
21309
|
this.state.pendingTriggers = [];
|
|
21154
21310
|
this.state.constraintModes.clear();
|
|
@@ -21161,6 +21317,7 @@ var TransactionManager = class {
|
|
|
21161
21317
|
this.base = null;
|
|
21162
21318
|
this.savepoints = [];
|
|
21163
21319
|
this.state.inTransaction = false;
|
|
21320
|
+
this.state.transactionXid = null;
|
|
21164
21321
|
this.state.localSettings.clear();
|
|
21165
21322
|
this.state.pendingTriggers = [];
|
|
21166
21323
|
this.state.constraintModes.clear();
|
|
@@ -21195,6 +21352,7 @@ var TransactionManager = class {
|
|
|
21195
21352
|
this.base = null;
|
|
21196
21353
|
this.savepoints = [];
|
|
21197
21354
|
this.state.inTransaction = false;
|
|
21355
|
+
this.state.transactionXid = null;
|
|
21198
21356
|
this.freezeDepth = 0;
|
|
21199
21357
|
}
|
|
21200
21358
|
};
|
|
@@ -21398,6 +21556,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
21398
21556
|
const updated = existing.slice();
|
|
21399
21557
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
21400
21558
|
computeGeneratedColumns(env, table, updated);
|
|
21559
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
21401
21560
|
rows[existingIdx] = updated;
|
|
21402
21561
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
21403
21562
|
checkNotNull(env, table, updated);
|
|
@@ -21416,7 +21575,13 @@ function executeInsert(env0, stmt) {
|
|
|
21416
21575
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
21417
21576
|
const insertedRows = [];
|
|
21418
21577
|
let insertedCount = 0;
|
|
21578
|
+
const addedRows = [];
|
|
21579
|
+
const conflictOldRows = [];
|
|
21580
|
+
const conflictNewRows = [];
|
|
21581
|
+
const updatesOnConflict = stmt.onConflict !== null && stmt.onConflict.action !== "nothing";
|
|
21419
21582
|
return withStatementRollback(env, () => {
|
|
21583
|
+
fireStatementTriggers(env, table, "before", "insert");
|
|
21584
|
+
if (updatesOnConflict) fireStatementTriggers(env, table, "before", "update");
|
|
21420
21585
|
for (const srcRow of sourceRows) {
|
|
21421
21586
|
const row = table.columns.map(() => null);
|
|
21422
21587
|
const provided = /* @__PURE__ */ new Set();
|
|
@@ -21462,6 +21627,7 @@ function executeInsert(env0, stmt) {
|
|
|
21462
21627
|
}
|
|
21463
21628
|
if (conflictIdx !== null && conflictWhereOk) {
|
|
21464
21629
|
if (stmt.onConflict.action === "nothing") continue;
|
|
21630
|
+
const replaced = rows[conflictIdx];
|
|
21465
21631
|
const did = applyOnConflictUpdate(
|
|
21466
21632
|
env,
|
|
21467
21633
|
table,
|
|
@@ -21474,6 +21640,8 @@ function executeInsert(env0, stmt) {
|
|
|
21474
21640
|
if (did) {
|
|
21475
21641
|
insertedCount++;
|
|
21476
21642
|
insertedRows.push(rows[conflictIdx]);
|
|
21643
|
+
conflictOldRows.push(replaced);
|
|
21644
|
+
conflictNewRows.push(rows[conflictIdx]);
|
|
21477
21645
|
fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
|
|
21478
21646
|
}
|
|
21479
21647
|
continue;
|
|
@@ -21483,12 +21651,18 @@ function executeInsert(env0, stmt) {
|
|
|
21483
21651
|
checkChecks(env, table, newRow);
|
|
21484
21652
|
checkUnique(env, table, newRow, rows.length);
|
|
21485
21653
|
checkForeignKeys(env, table, newRow);
|
|
21654
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21486
21655
|
rows.push(newRow);
|
|
21487
21656
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
21488
21657
|
insertedCount++;
|
|
21489
21658
|
insertedRows.push(newRow);
|
|
21659
|
+
addedRows.push(newRow);
|
|
21490
21660
|
fireRowTriggers(env, table, "after", "insert", null, newRow);
|
|
21491
21661
|
}
|
|
21662
|
+
fireStatementTriggers(env, table, "after", "insert", { oldRows: [], newRows: addedRows });
|
|
21663
|
+
if (updatesOnConflict) {
|
|
21664
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: conflictOldRows, newRows: conflictNewRows });
|
|
21665
|
+
}
|
|
21492
21666
|
env.ctx.state.changes = insertedCount;
|
|
21493
21667
|
if (stmt.returning) {
|
|
21494
21668
|
const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
|
|
@@ -21569,10 +21743,12 @@ function executeUpdate(env0, stmt) {
|
|
|
21569
21743
|
const env = applyWith(env0, stmt.with);
|
|
21570
21744
|
const table = requireTargetTable(env, stmt.table, "update");
|
|
21571
21745
|
const label = stmt.alias ?? table.name;
|
|
21746
|
+
fireStatementTriggers(env, table, "before", "update");
|
|
21572
21747
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
21573
21748
|
const rows = table.mutableRows();
|
|
21574
21749
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
21575
21750
|
const updatedRows = [];
|
|
21751
|
+
const replacedRows = [];
|
|
21576
21752
|
let updateCount = 0;
|
|
21577
21753
|
for (let ri = 0; ri < rows.length; ri++) {
|
|
21578
21754
|
const oldRow = rows[ri];
|
|
@@ -21600,6 +21776,7 @@ function executeUpdate(env0, stmt) {
|
|
|
21600
21776
|
if (fired.row === null) continue;
|
|
21601
21777
|
const finalRow = fired.row;
|
|
21602
21778
|
computeGeneratedColumns(env, table, finalRow);
|
|
21779
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
21603
21780
|
rows[ri] = finalRow;
|
|
21604
21781
|
try {
|
|
21605
21782
|
checkNotNull(env, table, finalRow);
|
|
@@ -21614,8 +21791,10 @@ function executeUpdate(env0, stmt) {
|
|
|
21614
21791
|
handleReferencedUpdate(env, table, [oldRow], [finalRow]);
|
|
21615
21792
|
updateCount++;
|
|
21616
21793
|
updatedRows.push(finalRow);
|
|
21794
|
+
replacedRows.push(oldRow);
|
|
21617
21795
|
fireRowTriggers(env, table, "after", "update", oldRow, finalRow);
|
|
21618
21796
|
}
|
|
21797
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: replacedRows, newRows: updatedRows });
|
|
21619
21798
|
env.ctx.state.changes = updateCount;
|
|
21620
21799
|
if (stmt.returning) {
|
|
21621
21800
|
const res = evalReturning(env, table, label, stmt.returning, updatedRows, "UPDATE");
|
|
@@ -21627,6 +21806,7 @@ function executeDelete(env0, stmt) {
|
|
|
21627
21806
|
const env = applyWith(env0, stmt.with);
|
|
21628
21807
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
21629
21808
|
const label = stmt.alias ?? table.name;
|
|
21809
|
+
fireStatementTriggers(env, table, "before", "delete");
|
|
21630
21810
|
const rows = table.mutableRows();
|
|
21631
21811
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
21632
21812
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
@@ -21664,6 +21844,7 @@ function executeDelete(env0, stmt) {
|
|
|
21664
21844
|
fireRowTriggers(env, table, "after", "delete", row, null);
|
|
21665
21845
|
}
|
|
21666
21846
|
if (deletedRows.length > 0) rebuildTableIndexes(env, table);
|
|
21847
|
+
fireStatementTriggers(env, table, "after", "delete", { oldRows: deletedRows, newRows: [] });
|
|
21667
21848
|
env.ctx.state.changes = deletedRows.length;
|
|
21668
21849
|
if (stmt.returning) {
|
|
21669
21850
|
const res = evalReturning(env, table, label, stmt.returning, deletedRows, "DELETE");
|
|
@@ -21719,6 +21900,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
21719
21900
|
for (const c of con.columns) {
|
|
21720
21901
|
newRow[child.columnIndex(c)] = null;
|
|
21721
21902
|
}
|
|
21903
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21722
21904
|
childRows[i] = newRow;
|
|
21723
21905
|
checkNotNull(env, child, newRow);
|
|
21724
21906
|
checkChecks(env, child, newRow);
|
|
@@ -21732,6 +21914,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
21732
21914
|
const ci = child.columnIndex(c);
|
|
21733
21915
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
21734
21916
|
}
|
|
21917
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21735
21918
|
childRows[i] = newRow;
|
|
21736
21919
|
checkNotNull(env, child, newRow);
|
|
21737
21920
|
checkChecks(env, child, newRow);
|
|
@@ -21769,6 +21952,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21769
21952
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
21770
21953
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
21771
21954
|
}
|
|
21955
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21772
21956
|
childRows[i] = newRow;
|
|
21773
21957
|
checkChecks(env, child, newRow);
|
|
21774
21958
|
}
|
|
@@ -21778,6 +21962,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21778
21962
|
for (const i of idxs) {
|
|
21779
21963
|
const newRow = childRows[i].slice();
|
|
21780
21964
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
21965
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21781
21966
|
childRows[i] = newRow;
|
|
21782
21967
|
checkNotNull(env, child, newRow);
|
|
21783
21968
|
}
|
|
@@ -21790,6 +21975,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21790
21975
|
const ci = child.columnIndex(c);
|
|
21791
21976
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
21792
21977
|
}
|
|
21978
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21793
21979
|
childRows[i] = newRow;
|
|
21794
21980
|
checkForeignKeys(env, child, newRow);
|
|
21795
21981
|
}
|
|
@@ -23801,7 +23987,7 @@ function pgTrigger(ctx) {
|
|
|
23801
23987
|
let oid = 4e4;
|
|
23802
23988
|
for (const t of allTables(ctx.state)) {
|
|
23803
23989
|
for (const tr of t.triggers) {
|
|
23804
|
-
rows.push([oid++, tr.name, t.oid, !tr.forEachRow]);
|
|
23990
|
+
rows.push([oid++, tr.name, t.oid, !tr.forEachRow, tr.oldTable ?? null, tr.newTable ?? null]);
|
|
23805
23991
|
}
|
|
23806
23992
|
}
|
|
23807
23993
|
return rel2(
|
|
@@ -23809,7 +23995,9 @@ function pgTrigger(ctx) {
|
|
|
23809
23995
|
["oid", "oid"],
|
|
23810
23996
|
["tgname", "name"],
|
|
23811
23997
|
["tgrelid", "oid"],
|
|
23812
|
-
["tgisinternal", "bool"]
|
|
23998
|
+
["tgisinternal", "bool"],
|
|
23999
|
+
["tgoldtable", "name"],
|
|
24000
|
+
["tgnewtable", "name"]
|
|
23813
24001
|
],
|
|
23814
24002
|
rows,
|
|
23815
24003
|
"pg_trigger"
|
|
@@ -24837,13 +25025,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
24837
25025
|
schema.sequences.set(name, seq);
|
|
24838
25026
|
return commandResult("CREATE SEQUENCE", 0);
|
|
24839
25027
|
}
|
|
25028
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
25029
|
+
const state = env.ctx.state;
|
|
25030
|
+
const matches2 = (value) => {
|
|
25031
|
+
try {
|
|
25032
|
+
const input = parseRelationInput(value);
|
|
25033
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
25034
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
25035
|
+
} catch {
|
|
25036
|
+
return false;
|
|
25037
|
+
}
|
|
25038
|
+
};
|
|
25039
|
+
const rewrite = (value) => {
|
|
25040
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
25041
|
+
if (value === null || typeof value !== "object") return value;
|
|
25042
|
+
const node = value;
|
|
25043
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
25044
|
+
const rewriteLiteral = (literal2) => {
|
|
25045
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
|
|
25046
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
25047
|
+
}
|
|
25048
|
+
return literal2;
|
|
25049
|
+
};
|
|
25050
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
25051
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
25052
|
+
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")
|
|
25053
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
25054
|
+
return updated;
|
|
25055
|
+
};
|
|
25056
|
+
for (const schema of state.schemas.values()) {
|
|
25057
|
+
for (const table of [...schema.tables.values()]) {
|
|
25058
|
+
const writable = state.ensureWritableTable(table);
|
|
25059
|
+
for (const column of writable.columns) {
|
|
25060
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
25061
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
25062
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
25063
|
+
}
|
|
25064
|
+
}
|
|
25065
|
+
}
|
|
25066
|
+
}
|
|
24840
25067
|
function executeAlterSequence(env, stmt) {
|
|
24841
25068
|
const state = env.ctx.state;
|
|
24842
|
-
const
|
|
24843
|
-
if (!
|
|
25069
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
25070
|
+
if (!foundSequence) {
|
|
24844
25071
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
24845
25072
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
24846
25073
|
}
|
|
25074
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
25075
|
+
if (stmt.renameTo) {
|
|
25076
|
+
const schema = state.getSchema(seq.schema);
|
|
25077
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
25078
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
25079
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
25080
|
+
schema.sequences.delete(seq.name);
|
|
25081
|
+
seq.name = stmt.renameTo;
|
|
25082
|
+
schema.sequences.set(seq.name, seq);
|
|
25083
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
25084
|
+
}
|
|
24847
25085
|
const o = stmt.options;
|
|
24848
25086
|
if (o.logged !== void 0) {
|
|
24849
25087
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -24901,7 +25139,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
24901
25139
|
col.defaultExpr = {
|
|
24902
25140
|
type: "func",
|
|
24903
25141
|
name: ["nextval"],
|
|
24904
|
-
args: [{ type: "string_lit", value:
|
|
25142
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
24905
25143
|
};
|
|
24906
25144
|
}
|
|
24907
25145
|
for (const c of def.constraints) {
|
|
@@ -25154,7 +25392,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
25154
25392
|
const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
|
|
25155
25393
|
table.unlogged = stmt.unlogged === true;
|
|
25156
25394
|
if (stmt.withData) {
|
|
25157
|
-
for (const row of rel3.rows)
|
|
25395
|
+
for (const row of rel3.rows) {
|
|
25396
|
+
const stored = row.slice();
|
|
25397
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
25398
|
+
table.mutableRows().push(stored);
|
|
25399
|
+
}
|
|
25158
25400
|
}
|
|
25159
25401
|
schema.tables.set(name, table);
|
|
25160
25402
|
const count = stmt.withData ? table.rowCount() : 0;
|
|
@@ -25182,7 +25424,7 @@ function executeCreateIndex(env, stmt) {
|
|
|
25182
25424
|
}
|
|
25183
25425
|
}
|
|
25184
25426
|
}
|
|
25185
|
-
assertGinTrgmIndex(state, table, stmt);
|
|
25427
|
+
assertGinTrgmIndex(state, table, stmt, (expr) => expressionTypeOf(env, table, expr));
|
|
25186
25428
|
const method = stmt.using ?? "btree";
|
|
25187
25429
|
if (!ACCESS_METHODS.has(method) || method === "heap") {
|
|
25188
25430
|
throw pgError("undefined_object", `access method "${method}" does not exist`, "42704");
|
|
@@ -25423,6 +25665,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
25423
25665
|
language: lang,
|
|
25424
25666
|
body,
|
|
25425
25667
|
rawBody: stmt.body,
|
|
25668
|
+
settings: Object.fromEntries(
|
|
25669
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
25670
|
+
key,
|
|
25671
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
25672
|
+
])
|
|
25673
|
+
),
|
|
25426
25674
|
strict: stmt.strict,
|
|
25427
25675
|
oid: state.nextOid()
|
|
25428
25676
|
};
|
|
@@ -25431,6 +25679,50 @@ function executeCreateFunction(env, stmt) {
|
|
|
25431
25679
|
schema.functions.set(name, existing);
|
|
25432
25680
|
return commandResult("CREATE FUNCTION", 0);
|
|
25433
25681
|
}
|
|
25682
|
+
function validateTransitionTables(stmt) {
|
|
25683
|
+
const transitions = stmt.transitions ?? [];
|
|
25684
|
+
if (transitions.length === 0) return {};
|
|
25685
|
+
const invalid = (message2) => pgError("invalid_table_definition", message2, "42P17");
|
|
25686
|
+
const unsupportedClause = (message2) => pgError("feature_not_supported", message2, "0A000");
|
|
25687
|
+
if (stmt.timing !== "after") throw invalid("transition table name can only be specified for an AFTER trigger");
|
|
25688
|
+
if (stmt.events.some((e) => e.event === "truncate")) {
|
|
25689
|
+
throw unsupportedClause("TRUNCATE triggers with transition tables are not supported");
|
|
25690
|
+
}
|
|
25691
|
+
if (stmt.events.some((e) => e.columns !== null)) {
|
|
25692
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with column lists");
|
|
25693
|
+
}
|
|
25694
|
+
if (stmt.events.length > 1) {
|
|
25695
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with more than one event");
|
|
25696
|
+
}
|
|
25697
|
+
const event = stmt.events[0].event;
|
|
25698
|
+
let oldTable;
|
|
25699
|
+
let newTable;
|
|
25700
|
+
for (const transition of transitions) {
|
|
25701
|
+
if (transition.isNew) {
|
|
25702
|
+
if (event !== "insert" && event !== "update") {
|
|
25703
|
+
throw invalid("NEW TABLE can only be specified for an INSERT or UPDATE trigger");
|
|
25704
|
+
}
|
|
25705
|
+
if (newTable !== void 0) throw invalid("NEW TABLE cannot be specified multiple times");
|
|
25706
|
+
newTable = transition.name;
|
|
25707
|
+
} else {
|
|
25708
|
+
if (event !== "delete" && event !== "update") {
|
|
25709
|
+
throw invalid("OLD TABLE can only be specified for a DELETE or UPDATE trigger");
|
|
25710
|
+
}
|
|
25711
|
+
if (oldTable !== void 0) throw invalid("OLD TABLE cannot be specified multiple times");
|
|
25712
|
+
oldTable = transition.name;
|
|
25713
|
+
}
|
|
25714
|
+
}
|
|
25715
|
+
if (oldTable !== void 0 && oldTable === newTable) {
|
|
25716
|
+
throw invalid("OLD TABLE name and NEW TABLE name cannot be the same");
|
|
25717
|
+
}
|
|
25718
|
+
if (stmt.forEachRow) {
|
|
25719
|
+
throw pgError("unsupported", "transition tables on FOR EACH ROW triggers are not supported", "0A000");
|
|
25720
|
+
}
|
|
25721
|
+
return {
|
|
25722
|
+
...oldTable !== void 0 ? { oldTable } : {},
|
|
25723
|
+
...newTable !== void 0 ? { newTable } : {}
|
|
25724
|
+
};
|
|
25725
|
+
}
|
|
25434
25726
|
function executeCreateTrigger(env, stmt) {
|
|
25435
25727
|
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
25436
25728
|
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
@@ -25440,6 +25732,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25440
25732
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
25441
25733
|
}
|
|
25442
25734
|
const table = state.ensureWritableTable(found);
|
|
25735
|
+
const transitionTables = validateTransitionTables(stmt);
|
|
25443
25736
|
const fnSchema = stmt.funcName.length >= 2 ? stmt.funcName[stmt.funcName.length - 2] : null;
|
|
25444
25737
|
const fnName = stmt.funcName[stmt.funcName.length - 1];
|
|
25445
25738
|
const fns = state.findFunctions(stmt.funcName);
|
|
@@ -25458,6 +25751,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25458
25751
|
timing: stmt.timing,
|
|
25459
25752
|
events: stmt.events,
|
|
25460
25753
|
forEachRow: stmt.forEachRow,
|
|
25754
|
+
...transitionTables,
|
|
25461
25755
|
when: stmt.when,
|
|
25462
25756
|
funcSchema: fnSchema ?? fns[0].schema,
|
|
25463
25757
|
funcName: fnName,
|
|
@@ -25607,6 +25901,7 @@ function executeAlterTable(env, stmt) {
|
|
|
25607
25901
|
}
|
|
25608
25902
|
const next = row.slice();
|
|
25609
25903
|
next[idx] = nv;
|
|
25904
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
25610
25905
|
rows[i] = next;
|
|
25611
25906
|
}
|
|
25612
25907
|
col.type = resolved.column;
|
|
@@ -25708,6 +26003,11 @@ function executeAlterTable(env, stmt) {
|
|
|
25708
26003
|
);
|
|
25709
26004
|
}
|
|
25710
26005
|
table.columns[idx].name = action.to;
|
|
26006
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
26007
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
26008
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
26009
|
+
}
|
|
26010
|
+
}
|
|
25711
26011
|
for (const con of table.constraints) {
|
|
25712
26012
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
25713
26013
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -25744,6 +26044,11 @@ function executeAlterTable(env, stmt) {
|
|
|
25744
26044
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
25745
26045
|
}
|
|
25746
26046
|
const oldName = table.name;
|
|
26047
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
26048
|
+
if (seq.ownedBy?.table === oldName) {
|
|
26049
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
26050
|
+
}
|
|
26051
|
+
}
|
|
25747
26052
|
schema.tables.delete(table.name);
|
|
25748
26053
|
table.name = action.to;
|
|
25749
26054
|
schema.tables.set(action.to, table);
|
|
@@ -27617,6 +27922,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
27617
27922
|
writeBjv(
|
|
27618
27923
|
w,
|
|
27619
27924
|
{
|
|
27925
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
27620
27926
|
name: table.name,
|
|
27621
27927
|
schema: table.schema,
|
|
27622
27928
|
columns: table.columns,
|
|
@@ -27714,8 +28020,14 @@ function decodeInner(snapshot, prng, clock) {
|
|
|
27714
28020
|
table.constraints = meta.constraints;
|
|
27715
28021
|
table.triggers = meta.triggers;
|
|
27716
28022
|
table.unlogged = meta.unlogged === true;
|
|
28023
|
+
table.slabXmins = meta.xmins ?? null;
|
|
28024
|
+
state.xidCounter = Math.max(
|
|
28025
|
+
state.xidCounter,
|
|
28026
|
+
(meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
|
|
28027
|
+
);
|
|
27717
28028
|
if (meta.stats) state.tableStats.set(table.oid, meta.stats);
|
|
27718
28029
|
const rowCount = readVarintU32(r);
|
|
28030
|
+
if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
|
|
27719
28031
|
const slabColumns = [];
|
|
27720
28032
|
for (let c = 0; c < meta.columns.length; c++)
|
|
27721
28033
|
slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
|
|
@@ -28159,6 +28471,8 @@ function validateTableMetaBjv(value) {
|
|
|
28159
28471
|
if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
28160
28472
|
if (!Array.isArray(value.columns)) throw snapshotError();
|
|
28161
28473
|
for (const col of value.columns) validateColumnMeta(col);
|
|
28474
|
+
if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
|
|
28475
|
+
throw snapshotError();
|
|
28162
28476
|
}
|
|
28163
28477
|
function validateViewMetaBjv(value) {
|
|
28164
28478
|
if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
@@ -28252,6 +28566,7 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
28252
28566
|
pool.forceId(table.name);
|
|
28253
28567
|
pool.forceId(table.schema);
|
|
28254
28568
|
forceBjvStrings(pool, {
|
|
28569
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
28255
28570
|
name: table.name,
|
|
28256
28571
|
schema: table.schema,
|
|
28257
28572
|
columns: table.columns,
|
|
@@ -29882,7 +30197,7 @@ var Connection = class {
|
|
|
29882
30197
|
if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
|
|
29883
30198
|
switch (stmt.action) {
|
|
29884
30199
|
case "begin":
|
|
29885
|
-
this.transaction ??= { statements: [], savepoints: [] };
|
|
30200
|
+
this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
|
|
29886
30201
|
return command("BEGIN");
|
|
29887
30202
|
case "commit": {
|
|
29888
30203
|
const transaction = this.transaction;
|
|
@@ -29891,6 +30206,7 @@ var Connection = class {
|
|
|
29891
30206
|
this.inSession(
|
|
29892
30207
|
this.database,
|
|
29893
30208
|
() => this.database.transaction(() => {
|
|
30209
|
+
this.database.state.transactionXid = transaction.xid;
|
|
29894
30210
|
for (const logged of transaction.statements) this.replay(this.database, logged);
|
|
29895
30211
|
})
|
|
29896
30212
|
);
|
|
@@ -29941,6 +30257,7 @@ var Connection = class {
|
|
|
29941
30257
|
workspace.state.settings = new Map(this.settings);
|
|
29942
30258
|
workspace.state.settingDefaults = this.settingDefaults;
|
|
29943
30259
|
workspace.transactions.begin();
|
|
30260
|
+
workspace.state.transactionXid = this.transaction?.xid ?? null;
|
|
29944
30261
|
for (const logged of this.transaction?.statements ?? []) {
|
|
29945
30262
|
this.replay(workspace, logged);
|
|
29946
30263
|
}
|