@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/index.js
CHANGED
|
@@ -2800,6 +2800,12 @@ var invalidName = () => {
|
|
|
2800
2800
|
throw pgError("syntax", "invalid name syntax", "42602");
|
|
2801
2801
|
};
|
|
2802
2802
|
function parseNamespaceInput(text) {
|
|
2803
|
+
const parsed = parseRelationInput(text);
|
|
2804
|
+
if ("oid" in parsed) return parsed;
|
|
2805
|
+
if (parsed.parts.length !== 1) invalidName();
|
|
2806
|
+
return { name: parsed.parts[0] };
|
|
2807
|
+
}
|
|
2808
|
+
function parseRelationInput(text) {
|
|
2803
2809
|
if (text === "-") return { oid: 0 };
|
|
2804
2810
|
if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
|
|
2805
2811
|
const names = [];
|
|
@@ -2835,8 +2841,8 @@ function parseNamespaceInput(text) {
|
|
|
2835
2841
|
skipSpace();
|
|
2836
2842
|
if (at === text.length) invalidName();
|
|
2837
2843
|
}
|
|
2838
|
-
if (names.length
|
|
2839
|
-
return {
|
|
2844
|
+
if (names.length === 0 || names.length > 3) invalidName();
|
|
2845
|
+
return { parts: names };
|
|
2840
2846
|
}
|
|
2841
2847
|
function namespaceText(oid, name) {
|
|
2842
2848
|
if (oid === 0) return "-";
|
|
@@ -2909,6 +2915,7 @@ var TYPE_ALIASES = {
|
|
|
2909
2915
|
regtype: "regtype",
|
|
2910
2916
|
regproc: "regproc",
|
|
2911
2917
|
regnamespace: "regnamespace",
|
|
2918
|
+
xid: "xid",
|
|
2912
2919
|
oid: "oid",
|
|
2913
2920
|
void: "void",
|
|
2914
2921
|
record: "record",
|
|
@@ -2985,6 +2992,7 @@ var TYPE_OIDS = {
|
|
|
2985
2992
|
regproc: 24,
|
|
2986
2993
|
text: 25,
|
|
2987
2994
|
oid: 26,
|
|
2995
|
+
xid: 28,
|
|
2988
2996
|
json: 114,
|
|
2989
2997
|
float4: 700,
|
|
2990
2998
|
float8: 701,
|
|
@@ -3303,6 +3311,7 @@ function recordText(rec, ctx) {
|
|
|
3303
3311
|
return `(${parts.join(",")})`;
|
|
3304
3312
|
}
|
|
3305
3313
|
function datumText(t, v, ctx) {
|
|
3314
|
+
if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
|
|
3306
3315
|
if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
|
|
3307
3316
|
if (v === null) throw pgError("internal", "datumText called with null");
|
|
3308
3317
|
if (isArrayType(t)) return arrayText(v, ctx);
|
|
@@ -3313,6 +3322,7 @@ function datumText(t, v, ctx) {
|
|
|
3313
3322
|
case "int2":
|
|
3314
3323
|
case "int4":
|
|
3315
3324
|
case "oid":
|
|
3325
|
+
case "xid":
|
|
3316
3326
|
return String(v);
|
|
3317
3327
|
case "int8":
|
|
3318
3328
|
return String(v);
|
|
@@ -3377,6 +3387,12 @@ function datumText(t, v, ctx) {
|
|
|
3377
3387
|
}
|
|
3378
3388
|
var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
|
|
3379
3389
|
function datumFromText(t, text, ctx) {
|
|
3390
|
+
if (t === "regclass") {
|
|
3391
|
+
const parsed = parseRelationInput(text);
|
|
3392
|
+
if ("oid" in parsed) return parsed.oid;
|
|
3393
|
+
if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
|
|
3394
|
+
return ctx.relationOid(parsed.parts);
|
|
3395
|
+
}
|
|
3380
3396
|
if (t === "regnamespace") {
|
|
3381
3397
|
const parsed = parseNamespaceInput(text);
|
|
3382
3398
|
if ("oid" in parsed) return parsed.oid;
|
|
@@ -3398,6 +3414,7 @@ function datumFromText(t, text, ctx) {
|
|
|
3398
3414
|
case "int8":
|
|
3399
3415
|
return parseIntegerText(text, t);
|
|
3400
3416
|
case "oid":
|
|
3417
|
+
case "xid":
|
|
3401
3418
|
return parseOidText(text);
|
|
3402
3419
|
case "float4":
|
|
3403
3420
|
return Math.fround(parseFloatText(text, "float4"));
|
|
@@ -3554,6 +3571,8 @@ var TableData = class _TableData {
|
|
|
3554
3571
|
schema;
|
|
3555
3572
|
columns;
|
|
3556
3573
|
rows;
|
|
3574
|
+
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
3575
|
+
slabXmins = null;
|
|
3557
3576
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
3558
3577
|
slab = null;
|
|
3559
3578
|
constraints;
|
|
@@ -3596,6 +3615,11 @@ var TableData = class _TableData {
|
|
|
3596
3615
|
materializeSlab() {
|
|
3597
3616
|
if (!this.slab) return;
|
|
3598
3617
|
this.rows = this.slab.materialize();
|
|
3618
|
+
if (this.slabXmins)
|
|
3619
|
+
this.rows.forEach((row, index) => {
|
|
3620
|
+
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
3621
|
+
});
|
|
3622
|
+
this.slabXmins = null;
|
|
3599
3623
|
this.slab = null;
|
|
3600
3624
|
this.indexStores = null;
|
|
3601
3625
|
}
|
|
@@ -3629,6 +3653,10 @@ var TableData = class _TableData {
|
|
|
3629
3653
|
} else {
|
|
3630
3654
|
t.rows = this.rows.map((r) => r.slice());
|
|
3631
3655
|
}
|
|
3656
|
+
t.rows.forEach((row, index) => {
|
|
3657
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
|
|
3658
|
+
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
3659
|
+
});
|
|
3632
3660
|
t.unlogged = this.unlogged;
|
|
3633
3661
|
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
3634
3662
|
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
@@ -3714,6 +3742,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
3714
3742
|
clock;
|
|
3715
3743
|
changes = 0;
|
|
3716
3744
|
oidCounter = 16384;
|
|
3745
|
+
/** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
|
|
3746
|
+
xidCounter = 3;
|
|
3747
|
+
transactionXid = null;
|
|
3748
|
+
allocateXid() {
|
|
3749
|
+
if (this.xidCounter > 4294967295)
|
|
3750
|
+
throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
|
|
3751
|
+
return this.xidCounter++;
|
|
3752
|
+
}
|
|
3717
3753
|
inTransaction = false;
|
|
3718
3754
|
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
3719
3755
|
pendingTriggers = [];
|
|
@@ -3927,6 +3963,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3927
3963
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3928
3964
|
s.tableStats = new Map(this.tableStats);
|
|
3929
3965
|
s.oidCounter = this.oidCounter;
|
|
3966
|
+
s.xidCounter = this.xidCounter;
|
|
3967
|
+
s.transactionXid = this.transactionXid;
|
|
3930
3968
|
for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
|
|
3931
3969
|
return s;
|
|
3932
3970
|
}
|
|
@@ -3946,6 +3984,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3946
3984
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3947
3985
|
s.tableStats = new Map(this.tableStats);
|
|
3948
3986
|
s.oidCounter = this.oidCounter;
|
|
3987
|
+
s.xidCounter = this.xidCounter;
|
|
3988
|
+
s.transactionXid = this.transactionXid;
|
|
3949
3989
|
for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
|
|
3950
3990
|
return s;
|
|
3951
3991
|
}
|
|
@@ -4021,6 +4061,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
4021
4061
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
4022
4062
|
this.tableStats = other.tableStats;
|
|
4023
4063
|
this.oidCounter = other.oidCounter;
|
|
4064
|
+
this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
|
|
4065
|
+
this.transactionXid = other.transactionXid;
|
|
4024
4066
|
}
|
|
4025
4067
|
/** @internal Snapshot codec access to the oid allocator. */
|
|
4026
4068
|
snapshotOidCounter() {
|
|
@@ -4097,6 +4139,11 @@ function zoneOffsetForNaive(zone, naiveMicros) {
|
|
|
4097
4139
|
// src/expressions/context.ts
|
|
4098
4140
|
var EngineCtx = class {
|
|
4099
4141
|
state;
|
|
4142
|
+
writeXid = null;
|
|
4143
|
+
rowVersionXid() {
|
|
4144
|
+
if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
|
|
4145
|
+
return this.writeXid ??= this.state.allocateXid();
|
|
4146
|
+
}
|
|
4100
4147
|
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
4101
4148
|
txNow;
|
|
4102
4149
|
/** statement timestamp */
|
|
@@ -4111,6 +4158,23 @@ var EngineCtx = class {
|
|
|
4111
4158
|
timezone() {
|
|
4112
4159
|
return this.state.getSetting("timezone") ?? "UTC";
|
|
4113
4160
|
}
|
|
4161
|
+
relationOid(parts) {
|
|
4162
|
+
const target = this.state.resolveRelationSchema(parts);
|
|
4163
|
+
const schema = target ? this.state.schemas.get(target.schema) : void 0;
|
|
4164
|
+
const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
|
|
4165
|
+
if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
|
|
4166
|
+
return relation.oid;
|
|
4167
|
+
}
|
|
4168
|
+
relationName(oid) {
|
|
4169
|
+
for (const schema of this.state.schemas.values()) {
|
|
4170
|
+
for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
|
|
4171
|
+
if (relation.oid !== oid) continue;
|
|
4172
|
+
const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
|
|
4173
|
+
return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
return null;
|
|
4177
|
+
}
|
|
4114
4178
|
namespaceOid(name) {
|
|
4115
4179
|
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
4116
4180
|
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
@@ -4411,7 +4475,7 @@ function castTo(env, value, target, opts = {}) {
|
|
|
4411
4475
|
return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
|
|
4412
4476
|
}
|
|
4413
4477
|
if (from === "oid" && target === "regnamespace") return tv(target, v);
|
|
4414
|
-
if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
|
|
4478
|
+
if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
|
|
4415
4479
|
return tv(target, target === "int8" ? BigInt(v) : v);
|
|
4416
4480
|
}
|
|
4417
4481
|
if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
|
|
@@ -5112,6 +5176,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
|
|
|
5112
5176
|
case "int2":
|
|
5113
5177
|
case "int4":
|
|
5114
5178
|
case "oid":
|
|
5179
|
+
case "regclass":
|
|
5180
|
+
case "xid":
|
|
5115
5181
|
case "regnamespace":
|
|
5116
5182
|
case "date":
|
|
5117
5183
|
return expectNumber(a, t) - expectNumber(b, t);
|
|
@@ -5231,6 +5297,8 @@ function datumKey(t, v) {
|
|
|
5231
5297
|
case "int2":
|
|
5232
5298
|
case "int4":
|
|
5233
5299
|
case "oid":
|
|
5300
|
+
case "regclass":
|
|
5301
|
+
case "xid":
|
|
5234
5302
|
case "date":
|
|
5235
5303
|
return `i${v}`;
|
|
5236
5304
|
case "float4":
|
|
@@ -8136,7 +8204,7 @@ function databaseCatalogContext(state) {
|
|
|
8136
8204
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
8137
8205
|
function findSequenceForCall(ctx, name) {
|
|
8138
8206
|
const parts = parseQualifiedName(name);
|
|
8139
|
-
const seq = ctx.state.findSequence(parts);
|
|
8207
|
+
const seq = /^\d+$/.test(name) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name)) : ctx.state.findSequence(parts);
|
|
8140
8208
|
if (!seq) {
|
|
8141
8209
|
throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
|
|
8142
8210
|
}
|
|
@@ -8360,14 +8428,16 @@ function getMiscFunctions() {
|
|
|
8360
8428
|
"pg_get_serial_sequence",
|
|
8361
8429
|
strict("text", (ctx, args) => {
|
|
8362
8430
|
const tableName2 = argText(ctx, args[0]);
|
|
8363
|
-
const column = argText(ctx, args[1])
|
|
8431
|
+
const column = argText(ctx, args[1]);
|
|
8364
8432
|
const table = ctx.state.findTable(parseQualifiedName(tableName2));
|
|
8365
8433
|
if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
|
|
8366
8434
|
const col = table.columns.find((c) => c.name === column);
|
|
8367
8435
|
if (!col)
|
|
8368
8436
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
8369
|
-
|
|
8370
|
-
|
|
8437
|
+
const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
|
|
8438
|
+
(candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
|
|
8439
|
+
);
|
|
8440
|
+
return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
|
|
8371
8441
|
})
|
|
8372
8442
|
);
|
|
8373
8443
|
m.set("format_type", (ctx, args) => {
|
|
@@ -9885,7 +9955,7 @@ function evalTrgmWordSimilar(ctx, left, right) {
|
|
|
9885
9955
|
const score = wordSimilarity(a.v, b.v);
|
|
9886
9956
|
return tv("bool", score >= WORD_SIMILARITY_THRESHOLD);
|
|
9887
9957
|
}
|
|
9888
|
-
function assertGinTrgmIndex(state, table, stmt) {
|
|
9958
|
+
function assertGinTrgmIndex(state, table, stmt, expressionType) {
|
|
9889
9959
|
const trgmCols = stmt.columns.filter((col2) => isGinTrgmOpclass(col2.opclass));
|
|
9890
9960
|
if (trgmCols.length === 0) return;
|
|
9891
9961
|
if (trgmCols.length !== stmt.columns.length || stmt.columns.length !== 1) {
|
|
@@ -9905,11 +9975,7 @@ function assertGinTrgmIndex(state, table, stmt) {
|
|
|
9905
9975
|
if (stmt.unique) {
|
|
9906
9976
|
throw pgError("feature_not_supported", `access method "gin" does not support unique indexes`, "0A000");
|
|
9907
9977
|
}
|
|
9908
|
-
|
|
9909
|
-
throw unsupported("expression gin_trgm_ops");
|
|
9910
|
-
}
|
|
9911
|
-
const index = table.columnIndex(col.expr.parts[0]);
|
|
9912
|
-
const typeId = table.columns[index].type.id;
|
|
9978
|
+
const typeId = col.expr.type === "colref" && col.expr.parts.length === 1 ? table.columns[table.columnIndex(col.expr.parts[0])].type.id : expressionType(col.expr);
|
|
9913
9979
|
if (!GIN_TRGM_TYPES.has(typeId)) {
|
|
9914
9980
|
throw pgError(
|
|
9915
9981
|
"datatype_mismatch",
|
|
@@ -13311,7 +13377,7 @@ var RowScope = class {
|
|
|
13311
13377
|
let count2 = 0;
|
|
13312
13378
|
for (let i = 0; i < this.columns.length; i++) {
|
|
13313
13379
|
const c = this.columns[i];
|
|
13314
|
-
if (c.name === name2 && !c.hidden) {
|
|
13380
|
+
if (c.name === name2 && (!c.hidden || c.system)) {
|
|
13315
13381
|
count2++;
|
|
13316
13382
|
if (count2 > 1) {
|
|
13317
13383
|
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
@@ -13349,7 +13415,7 @@ var RowScope = class {
|
|
|
13349
13415
|
const names = [];
|
|
13350
13416
|
for (let i = 0; i < this.columns.length; i++) {
|
|
13351
13417
|
const c = this.columns[i];
|
|
13352
|
-
if (c.table === rangeVar) {
|
|
13418
|
+
if (c.table === rangeVar && !c.system) {
|
|
13353
13419
|
types.push(c.type);
|
|
13354
13420
|
values.push(this.row[i] ?? null);
|
|
13355
13421
|
names.push(c.name);
|
|
@@ -13547,6 +13613,17 @@ function tableScope(table, row) {
|
|
|
13547
13613
|
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
13548
13614
|
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
13549
13615
|
}
|
|
13616
|
+
function expressionTypeOf(env, table, expr) {
|
|
13617
|
+
const scope = makeEvalScope(
|
|
13618
|
+
env,
|
|
13619
|
+
tableScope(
|
|
13620
|
+
table,
|
|
13621
|
+
table.columns.map(() => null)
|
|
13622
|
+
)
|
|
13623
|
+
);
|
|
13624
|
+
const v = evalExpr(env.ctx, scope, expr);
|
|
13625
|
+
return v.t === "unknown" ? "text" : v.t;
|
|
13626
|
+
}
|
|
13550
13627
|
function checkNotNull(env, table, row) {
|
|
13551
13628
|
void env;
|
|
13552
13629
|
for (let i = 0; i < table.columns.length; i++) {
|
|
@@ -13792,7 +13869,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
13792
13869
|
if (!table) return null;
|
|
13793
13870
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
13794
13871
|
table.materializeSlab();
|
|
13795
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
13872
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
13796
13873
|
}
|
|
13797
13874
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
13798
13875
|
const parts = [];
|
|
@@ -16282,6 +16359,7 @@ var Parser = class {
|
|
|
16282
16359
|
let sqlBody = null;
|
|
16283
16360
|
let volatility = null;
|
|
16284
16361
|
let strict2 = false;
|
|
16362
|
+
const settings = {};
|
|
16285
16363
|
for (; ; ) {
|
|
16286
16364
|
if (this.eatKw("language")) {
|
|
16287
16365
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -16339,8 +16417,23 @@ var Parser = class {
|
|
|
16339
16417
|
continue;
|
|
16340
16418
|
}
|
|
16341
16419
|
if (this.eatKw("set")) {
|
|
16342
|
-
this.ident(true);
|
|
16343
|
-
if (this.
|
|
16420
|
+
const key = this.ident(true).toLowerCase();
|
|
16421
|
+
if (this.eatKw("from")) {
|
|
16422
|
+
this.expectKw("current");
|
|
16423
|
+
settings[key] = "__from_current__";
|
|
16424
|
+
} else {
|
|
16425
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
16426
|
+
const values = [];
|
|
16427
|
+
do {
|
|
16428
|
+
const value = this.next();
|
|
16429
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
16430
|
+
this.errorAt(value, "expected setting value");
|
|
16431
|
+
values.push(
|
|
16432
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
16433
|
+
);
|
|
16434
|
+
} while (this.eatPunct(","));
|
|
16435
|
+
settings[key] = values.join(", ");
|
|
16436
|
+
}
|
|
16344
16437
|
continue;
|
|
16345
16438
|
}
|
|
16346
16439
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -16420,7 +16513,8 @@ var Parser = class {
|
|
|
16420
16513
|
body,
|
|
16421
16514
|
sqlBody,
|
|
16422
16515
|
volatility,
|
|
16423
|
-
strict: strict2
|
|
16516
|
+
strict: strict2,
|
|
16517
|
+
settings
|
|
16424
16518
|
};
|
|
16425
16519
|
}
|
|
16426
16520
|
parseCreateTrigger(orReplace, constraint) {
|
|
@@ -16452,7 +16546,6 @@ var Parser = class {
|
|
|
16452
16546
|
} while (this.eatKw("or"));
|
|
16453
16547
|
this.expectKw("on");
|
|
16454
16548
|
const table = this.qualifiedName();
|
|
16455
|
-
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
16456
16549
|
let deferrable = false;
|
|
16457
16550
|
let initiallyDeferred = false;
|
|
16458
16551
|
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
@@ -16465,6 +16558,23 @@ var Parser = class {
|
|
|
16465
16558
|
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
16466
16559
|
if (initiallyDeferred && !deferrable)
|
|
16467
16560
|
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
16561
|
+
const transitions = [];
|
|
16562
|
+
if (!constraint && this.eatKw("referencing")) {
|
|
16563
|
+
do {
|
|
16564
|
+
const isNew = this.eatKw("new");
|
|
16565
|
+
if (!isNew) this.expectKw("old");
|
|
16566
|
+
if (this.eatKw("row")) {
|
|
16567
|
+
throw pgError(
|
|
16568
|
+
"feature_not_supported",
|
|
16569
|
+
"ROW variable naming in the REFERENCING clause is not supported",
|
|
16570
|
+
"0A000"
|
|
16571
|
+
);
|
|
16572
|
+
}
|
|
16573
|
+
this.expectKw("table");
|
|
16574
|
+
this.eatKw("as");
|
|
16575
|
+
transitions.push({ isNew, name: this.ident() });
|
|
16576
|
+
} while (this.atKw("new") || this.atKw("old"));
|
|
16577
|
+
}
|
|
16468
16578
|
let forEachRow = false;
|
|
16469
16579
|
if (this.eatKw("for")) {
|
|
16470
16580
|
this.eatKw("each");
|
|
@@ -16502,7 +16612,8 @@ var Parser = class {
|
|
|
16502
16612
|
forEachRow,
|
|
16503
16613
|
when,
|
|
16504
16614
|
funcName,
|
|
16505
|
-
funcArgs
|
|
16615
|
+
funcArgs,
|
|
16616
|
+
...transitions.length > 0 ? { transitions } : {}
|
|
16506
16617
|
};
|
|
16507
16618
|
}
|
|
16508
16619
|
// --- ALTER --------------------------------------------------------------------
|
|
@@ -16529,8 +16640,8 @@ var Parser = class {
|
|
|
16529
16640
|
type: "alter_sequence",
|
|
16530
16641
|
name,
|
|
16531
16642
|
ifExists,
|
|
16532
|
-
options: {
|
|
16533
|
-
|
|
16643
|
+
options: {},
|
|
16644
|
+
renameTo: to
|
|
16534
16645
|
};
|
|
16535
16646
|
}
|
|
16536
16647
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -19106,7 +19217,20 @@ function runFunctionBody(env, fn, args) {
|
|
|
19106
19217
|
}
|
|
19107
19218
|
return last;
|
|
19108
19219
|
}
|
|
19220
|
+
function withFunctionSettings(env, fn, run) {
|
|
19221
|
+
const state = env.ctx.state;
|
|
19222
|
+
const saved = new Map(state.localSettings);
|
|
19223
|
+
for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
|
|
19224
|
+
try {
|
|
19225
|
+
return run();
|
|
19226
|
+
} finally {
|
|
19227
|
+
state.localSettings = saved;
|
|
19228
|
+
}
|
|
19229
|
+
}
|
|
19109
19230
|
function callSqlFunctionScalar(env, fn, args) {
|
|
19231
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
|
|
19232
|
+
}
|
|
19233
|
+
function callSqlFunctionScalarBody(env, fn, args) {
|
|
19110
19234
|
const retT = fn.returns ?? "text";
|
|
19111
19235
|
if (fn.language === "plpgsql") {
|
|
19112
19236
|
return callPlpgsqlScalar(env, fn, args);
|
|
@@ -19136,6 +19260,9 @@ function callSqlFunctionScalar(env, fn, args) {
|
|
|
19136
19260
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
19137
19261
|
}
|
|
19138
19262
|
function callSqlFunctionSet(env, fn, args) {
|
|
19263
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
|
|
19264
|
+
}
|
|
19265
|
+
function callSqlFunctionSetBody(env, fn, args) {
|
|
19139
19266
|
if (fn.language === "plpgsql") {
|
|
19140
19267
|
return callPlpgsqlSet(env, fn, args);
|
|
19141
19268
|
}
|
|
@@ -19290,15 +19417,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19290
19417
|
return rel3;
|
|
19291
19418
|
}
|
|
19292
19419
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
19293
|
-
|
|
19420
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
19421
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
19294
19422
|
throw pgError(
|
|
19295
19423
|
"invalid_column_reference",
|
|
19296
|
-
`table "${what}" has ${
|
|
19424
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
19297
19425
|
"42P10"
|
|
19298
19426
|
);
|
|
19299
19427
|
}
|
|
19300
19428
|
const columns = rel3.columns.map((c, i) => ({
|
|
19301
|
-
|
|
19429
|
+
...c,
|
|
19430
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
19302
19431
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
19303
19432
|
table: label
|
|
19304
19433
|
}));
|
|
@@ -19319,8 +19448,11 @@ function materializeItem(env, item, scope) {
|
|
|
19319
19448
|
if (table) {
|
|
19320
19449
|
table.materializeSlab();
|
|
19321
19450
|
const rel3 = {
|
|
19322
|
-
columns:
|
|
19323
|
-
|
|
19451
|
+
columns: [
|
|
19452
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
19453
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
19454
|
+
],
|
|
19455
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
19324
19456
|
};
|
|
19325
19457
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
19326
19458
|
}
|
|
@@ -19950,7 +20082,7 @@ function resolveColIdx(columns, parts) {
|
|
|
19950
20082
|
let found = -1;
|
|
19951
20083
|
for (let i = 0; i < columns.length; i++) {
|
|
19952
20084
|
const c = columns[i];
|
|
19953
|
-
if (!c.hidden && c.name === name2) {
|
|
20085
|
+
if ((!c.hidden || c.system) && c.name === name2) {
|
|
19954
20086
|
if (found !== -1) return null;
|
|
19955
20087
|
found = i;
|
|
19956
20088
|
}
|
|
@@ -20534,7 +20666,7 @@ function expandTargets(core, columns) {
|
|
|
20534
20666
|
let any = false;
|
|
20535
20667
|
for (let i = 0; i < columns.length; i++) {
|
|
20536
20668
|
const c = columns[i];
|
|
20537
|
-
if (c.table === label) {
|
|
20669
|
+
if (c.table === label && !c.system) {
|
|
20538
20670
|
any = true;
|
|
20539
20671
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
20540
20672
|
}
|
|
@@ -21027,6 +21159,29 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
21027
21159
|
}
|
|
21028
21160
|
return { row };
|
|
21029
21161
|
}
|
|
21162
|
+
function transitionRelation(table, name, rows) {
|
|
21163
|
+
return {
|
|
21164
|
+
columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: name })),
|
|
21165
|
+
rows
|
|
21166
|
+
};
|
|
21167
|
+
}
|
|
21168
|
+
function fireStatementTriggers(env, table, timing, event, transitions) {
|
|
21169
|
+
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);
|
|
21170
|
+
for (const t of fired) {
|
|
21171
|
+
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
21172
|
+
const ctes = /* @__PURE__ */ new Map();
|
|
21173
|
+
if (t.oldTable !== void 0)
|
|
21174
|
+
ctes.set(t.oldTable, transitionRelation(table, t.oldTable, transitions?.oldRows ?? []));
|
|
21175
|
+
if (t.newTable !== void 0)
|
|
21176
|
+
ctes.set(t.newTable, transitionRelation(table, t.newTable, transitions?.newRows ?? []));
|
|
21177
|
+
const changes = env.ctx.state.changes;
|
|
21178
|
+
try {
|
|
21179
|
+
executor({ ctx: env.ctx, params: null, ctes, outer: null }, table, t, event, null, null);
|
|
21180
|
+
} finally {
|
|
21181
|
+
env.ctx.state.changes = changes;
|
|
21182
|
+
}
|
|
21183
|
+
}
|
|
21184
|
+
}
|
|
21030
21185
|
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
21031
21186
|
function flushConstraintTriggers(state, all = false) {
|
|
21032
21187
|
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
@@ -21139,6 +21294,7 @@ var TransactionManager = class {
|
|
|
21139
21294
|
this.base = null;
|
|
21140
21295
|
this.savepoints = [];
|
|
21141
21296
|
this.state.inTransaction = false;
|
|
21297
|
+
this.state.transactionXid = null;
|
|
21142
21298
|
this.state.localSettings.clear();
|
|
21143
21299
|
this.state.pendingTriggers = [];
|
|
21144
21300
|
this.state.constraintModes.clear();
|
|
@@ -21151,6 +21307,7 @@ var TransactionManager = class {
|
|
|
21151
21307
|
this.base = null;
|
|
21152
21308
|
this.savepoints = [];
|
|
21153
21309
|
this.state.inTransaction = false;
|
|
21310
|
+
this.state.transactionXid = null;
|
|
21154
21311
|
this.state.localSettings.clear();
|
|
21155
21312
|
this.state.pendingTriggers = [];
|
|
21156
21313
|
this.state.constraintModes.clear();
|
|
@@ -21185,6 +21342,7 @@ var TransactionManager = class {
|
|
|
21185
21342
|
this.base = null;
|
|
21186
21343
|
this.savepoints = [];
|
|
21187
21344
|
this.state.inTransaction = false;
|
|
21345
|
+
this.state.transactionXid = null;
|
|
21188
21346
|
this.freezeDepth = 0;
|
|
21189
21347
|
}
|
|
21190
21348
|
};
|
|
@@ -21388,6 +21546,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
21388
21546
|
const updated = existing.slice();
|
|
21389
21547
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
21390
21548
|
computeGeneratedColumns(env, table, updated);
|
|
21549
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
21391
21550
|
rows[existingIdx] = updated;
|
|
21392
21551
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
21393
21552
|
checkNotNull(env, table, updated);
|
|
@@ -21406,7 +21565,13 @@ function executeInsert(env0, stmt) {
|
|
|
21406
21565
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
21407
21566
|
const insertedRows = [];
|
|
21408
21567
|
let insertedCount = 0;
|
|
21568
|
+
const addedRows = [];
|
|
21569
|
+
const conflictOldRows = [];
|
|
21570
|
+
const conflictNewRows = [];
|
|
21571
|
+
const updatesOnConflict = stmt.onConflict !== null && stmt.onConflict.action !== "nothing";
|
|
21409
21572
|
return withStatementRollback(env, () => {
|
|
21573
|
+
fireStatementTriggers(env, table, "before", "insert");
|
|
21574
|
+
if (updatesOnConflict) fireStatementTriggers(env, table, "before", "update");
|
|
21410
21575
|
for (const srcRow of sourceRows) {
|
|
21411
21576
|
const row = table.columns.map(() => null);
|
|
21412
21577
|
const provided = /* @__PURE__ */ new Set();
|
|
@@ -21452,6 +21617,7 @@ function executeInsert(env0, stmt) {
|
|
|
21452
21617
|
}
|
|
21453
21618
|
if (conflictIdx !== null && conflictWhereOk) {
|
|
21454
21619
|
if (stmt.onConflict.action === "nothing") continue;
|
|
21620
|
+
const replaced = rows[conflictIdx];
|
|
21455
21621
|
const did = applyOnConflictUpdate(
|
|
21456
21622
|
env,
|
|
21457
21623
|
table,
|
|
@@ -21464,6 +21630,8 @@ function executeInsert(env0, stmt) {
|
|
|
21464
21630
|
if (did) {
|
|
21465
21631
|
insertedCount++;
|
|
21466
21632
|
insertedRows.push(rows[conflictIdx]);
|
|
21633
|
+
conflictOldRows.push(replaced);
|
|
21634
|
+
conflictNewRows.push(rows[conflictIdx]);
|
|
21467
21635
|
fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
|
|
21468
21636
|
}
|
|
21469
21637
|
continue;
|
|
@@ -21473,12 +21641,18 @@ function executeInsert(env0, stmt) {
|
|
|
21473
21641
|
checkChecks(env, table, newRow);
|
|
21474
21642
|
checkUnique(env, table, newRow, rows.length);
|
|
21475
21643
|
checkForeignKeys(env, table, newRow);
|
|
21644
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21476
21645
|
rows.push(newRow);
|
|
21477
21646
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
21478
21647
|
insertedCount++;
|
|
21479
21648
|
insertedRows.push(newRow);
|
|
21649
|
+
addedRows.push(newRow);
|
|
21480
21650
|
fireRowTriggers(env, table, "after", "insert", null, newRow);
|
|
21481
21651
|
}
|
|
21652
|
+
fireStatementTriggers(env, table, "after", "insert", { oldRows: [], newRows: addedRows });
|
|
21653
|
+
if (updatesOnConflict) {
|
|
21654
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: conflictOldRows, newRows: conflictNewRows });
|
|
21655
|
+
}
|
|
21482
21656
|
env.ctx.state.changes = insertedCount;
|
|
21483
21657
|
if (stmt.returning) {
|
|
21484
21658
|
const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
|
|
@@ -21559,10 +21733,12 @@ function executeUpdate(env0, stmt) {
|
|
|
21559
21733
|
const env = applyWith(env0, stmt.with);
|
|
21560
21734
|
const table = requireTargetTable(env, stmt.table, "update");
|
|
21561
21735
|
const label = stmt.alias ?? table.name;
|
|
21736
|
+
fireStatementTriggers(env, table, "before", "update");
|
|
21562
21737
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
21563
21738
|
const rows = table.mutableRows();
|
|
21564
21739
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
21565
21740
|
const updatedRows = [];
|
|
21741
|
+
const replacedRows = [];
|
|
21566
21742
|
let updateCount = 0;
|
|
21567
21743
|
for (let ri = 0; ri < rows.length; ri++) {
|
|
21568
21744
|
const oldRow = rows[ri];
|
|
@@ -21590,6 +21766,7 @@ function executeUpdate(env0, stmt) {
|
|
|
21590
21766
|
if (fired.row === null) continue;
|
|
21591
21767
|
const finalRow = fired.row;
|
|
21592
21768
|
computeGeneratedColumns(env, table, finalRow);
|
|
21769
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
21593
21770
|
rows[ri] = finalRow;
|
|
21594
21771
|
try {
|
|
21595
21772
|
checkNotNull(env, table, finalRow);
|
|
@@ -21604,8 +21781,10 @@ function executeUpdate(env0, stmt) {
|
|
|
21604
21781
|
handleReferencedUpdate(env, table, [oldRow], [finalRow]);
|
|
21605
21782
|
updateCount++;
|
|
21606
21783
|
updatedRows.push(finalRow);
|
|
21784
|
+
replacedRows.push(oldRow);
|
|
21607
21785
|
fireRowTriggers(env, table, "after", "update", oldRow, finalRow);
|
|
21608
21786
|
}
|
|
21787
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: replacedRows, newRows: updatedRows });
|
|
21609
21788
|
env.ctx.state.changes = updateCount;
|
|
21610
21789
|
if (stmt.returning) {
|
|
21611
21790
|
const res = evalReturning(env, table, label, stmt.returning, updatedRows, "UPDATE");
|
|
@@ -21617,6 +21796,7 @@ function executeDelete(env0, stmt) {
|
|
|
21617
21796
|
const env = applyWith(env0, stmt.with);
|
|
21618
21797
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
21619
21798
|
const label = stmt.alias ?? table.name;
|
|
21799
|
+
fireStatementTriggers(env, table, "before", "delete");
|
|
21620
21800
|
const rows = table.mutableRows();
|
|
21621
21801
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
21622
21802
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
@@ -21654,6 +21834,7 @@ function executeDelete(env0, stmt) {
|
|
|
21654
21834
|
fireRowTriggers(env, table, "after", "delete", row, null);
|
|
21655
21835
|
}
|
|
21656
21836
|
if (deletedRows.length > 0) rebuildTableIndexes(env, table);
|
|
21837
|
+
fireStatementTriggers(env, table, "after", "delete", { oldRows: deletedRows, newRows: [] });
|
|
21657
21838
|
env.ctx.state.changes = deletedRows.length;
|
|
21658
21839
|
if (stmt.returning) {
|
|
21659
21840
|
const res = evalReturning(env, table, label, stmt.returning, deletedRows, "DELETE");
|
|
@@ -21709,6 +21890,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
21709
21890
|
for (const c of con.columns) {
|
|
21710
21891
|
newRow[child.columnIndex(c)] = null;
|
|
21711
21892
|
}
|
|
21893
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21712
21894
|
childRows[i] = newRow;
|
|
21713
21895
|
checkNotNull(env, child, newRow);
|
|
21714
21896
|
checkChecks(env, child, newRow);
|
|
@@ -21722,6 +21904,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
21722
21904
|
const ci = child.columnIndex(c);
|
|
21723
21905
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
21724
21906
|
}
|
|
21907
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21725
21908
|
childRows[i] = newRow;
|
|
21726
21909
|
checkNotNull(env, child, newRow);
|
|
21727
21910
|
checkChecks(env, child, newRow);
|
|
@@ -21759,6 +21942,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21759
21942
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
21760
21943
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
21761
21944
|
}
|
|
21945
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21762
21946
|
childRows[i] = newRow;
|
|
21763
21947
|
checkChecks(env, child, newRow);
|
|
21764
21948
|
}
|
|
@@ -21768,6 +21952,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21768
21952
|
for (const i of idxs) {
|
|
21769
21953
|
const newRow = childRows[i].slice();
|
|
21770
21954
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
21955
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21771
21956
|
childRows[i] = newRow;
|
|
21772
21957
|
checkNotNull(env, child, newRow);
|
|
21773
21958
|
}
|
|
@@ -21780,6 +21965,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
21780
21965
|
const ci = child.columnIndex(c);
|
|
21781
21966
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
21782
21967
|
}
|
|
21968
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
21783
21969
|
childRows[i] = newRow;
|
|
21784
21970
|
checkForeignKeys(env, child, newRow);
|
|
21785
21971
|
}
|
|
@@ -23791,7 +23977,7 @@ function pgTrigger(ctx) {
|
|
|
23791
23977
|
let oid = 4e4;
|
|
23792
23978
|
for (const t of allTables(ctx.state)) {
|
|
23793
23979
|
for (const tr of t.triggers) {
|
|
23794
|
-
rows.push([oid++, tr.name, t.oid, !tr.forEachRow]);
|
|
23980
|
+
rows.push([oid++, tr.name, t.oid, !tr.forEachRow, tr.oldTable ?? null, tr.newTable ?? null]);
|
|
23795
23981
|
}
|
|
23796
23982
|
}
|
|
23797
23983
|
return rel2(
|
|
@@ -23799,7 +23985,9 @@ function pgTrigger(ctx) {
|
|
|
23799
23985
|
["oid", "oid"],
|
|
23800
23986
|
["tgname", "name"],
|
|
23801
23987
|
["tgrelid", "oid"],
|
|
23802
|
-
["tgisinternal", "bool"]
|
|
23988
|
+
["tgisinternal", "bool"],
|
|
23989
|
+
["tgoldtable", "name"],
|
|
23990
|
+
["tgnewtable", "name"]
|
|
23803
23991
|
],
|
|
23804
23992
|
rows,
|
|
23805
23993
|
"pg_trigger"
|
|
@@ -24824,13 +25012,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
24824
25012
|
schema.sequences.set(name, seq);
|
|
24825
25013
|
return commandResult("CREATE SEQUENCE", 0);
|
|
24826
25014
|
}
|
|
25015
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
25016
|
+
const state = env.ctx.state;
|
|
25017
|
+
const matches2 = (value) => {
|
|
25018
|
+
try {
|
|
25019
|
+
const input = parseRelationInput(value);
|
|
25020
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
25021
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
25022
|
+
} catch {
|
|
25023
|
+
return false;
|
|
25024
|
+
}
|
|
25025
|
+
};
|
|
25026
|
+
const rewrite = (value) => {
|
|
25027
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
25028
|
+
if (value === null || typeof value !== "object") return value;
|
|
25029
|
+
const node = value;
|
|
25030
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
25031
|
+
const rewriteLiteral = (literal2) => {
|
|
25032
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
|
|
25033
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
25034
|
+
}
|
|
25035
|
+
return literal2;
|
|
25036
|
+
};
|
|
25037
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
25038
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
25039
|
+
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")
|
|
25040
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
25041
|
+
return updated;
|
|
25042
|
+
};
|
|
25043
|
+
for (const schema of state.schemas.values()) {
|
|
25044
|
+
for (const table of [...schema.tables.values()]) {
|
|
25045
|
+
const writable = state.ensureWritableTable(table);
|
|
25046
|
+
for (const column of writable.columns) {
|
|
25047
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
25048
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
25049
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
25050
|
+
}
|
|
25051
|
+
}
|
|
25052
|
+
}
|
|
25053
|
+
}
|
|
24827
25054
|
function executeAlterSequence(env, stmt) {
|
|
24828
25055
|
const state = env.ctx.state;
|
|
24829
|
-
const
|
|
24830
|
-
if (!
|
|
25056
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
25057
|
+
if (!foundSequence) {
|
|
24831
25058
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
24832
25059
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
24833
25060
|
}
|
|
25061
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
25062
|
+
if (stmt.renameTo) {
|
|
25063
|
+
const schema = state.getSchema(seq.schema);
|
|
25064
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
25065
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
25066
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
25067
|
+
schema.sequences.delete(seq.name);
|
|
25068
|
+
seq.name = stmt.renameTo;
|
|
25069
|
+
schema.sequences.set(seq.name, seq);
|
|
25070
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
25071
|
+
}
|
|
24834
25072
|
const o = stmt.options;
|
|
24835
25073
|
if (o.logged !== void 0) {
|
|
24836
25074
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -24888,7 +25126,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
24888
25126
|
col.defaultExpr = {
|
|
24889
25127
|
type: "func",
|
|
24890
25128
|
name: ["nextval"],
|
|
24891
|
-
args: [{ type: "string_lit", value:
|
|
25129
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
24892
25130
|
};
|
|
24893
25131
|
}
|
|
24894
25132
|
for (const c of def.constraints) {
|
|
@@ -25141,7 +25379,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
25141
25379
|
const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
|
|
25142
25380
|
table.unlogged = stmt.unlogged === true;
|
|
25143
25381
|
if (stmt.withData) {
|
|
25144
|
-
for (const row of rel3.rows)
|
|
25382
|
+
for (const row of rel3.rows) {
|
|
25383
|
+
const stored = row.slice();
|
|
25384
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
25385
|
+
table.mutableRows().push(stored);
|
|
25386
|
+
}
|
|
25145
25387
|
}
|
|
25146
25388
|
schema.tables.set(name, table);
|
|
25147
25389
|
const count = stmt.withData ? table.rowCount() : 0;
|
|
@@ -25169,7 +25411,7 @@ function executeCreateIndex(env, stmt) {
|
|
|
25169
25411
|
}
|
|
25170
25412
|
}
|
|
25171
25413
|
}
|
|
25172
|
-
assertGinTrgmIndex(state, table, stmt);
|
|
25414
|
+
assertGinTrgmIndex(state, table, stmt, (expr) => expressionTypeOf(env, table, expr));
|
|
25173
25415
|
const method = stmt.using ?? "btree";
|
|
25174
25416
|
if (!ACCESS_METHODS.has(method) || method === "heap") {
|
|
25175
25417
|
throw pgError("undefined_object", `access method "${method}" does not exist`, "42704");
|
|
@@ -25410,6 +25652,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
25410
25652
|
language: lang,
|
|
25411
25653
|
body,
|
|
25412
25654
|
rawBody: stmt.body,
|
|
25655
|
+
settings: Object.fromEntries(
|
|
25656
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
25657
|
+
key,
|
|
25658
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
25659
|
+
])
|
|
25660
|
+
),
|
|
25413
25661
|
strict: stmt.strict,
|
|
25414
25662
|
oid: state.nextOid()
|
|
25415
25663
|
};
|
|
@@ -25418,6 +25666,50 @@ function executeCreateFunction(env, stmt) {
|
|
|
25418
25666
|
schema.functions.set(name, existing);
|
|
25419
25667
|
return commandResult("CREATE FUNCTION", 0);
|
|
25420
25668
|
}
|
|
25669
|
+
function validateTransitionTables(stmt) {
|
|
25670
|
+
const transitions = stmt.transitions ?? [];
|
|
25671
|
+
if (transitions.length === 0) return {};
|
|
25672
|
+
const invalid = (message) => pgError("invalid_table_definition", message, "42P17");
|
|
25673
|
+
const unsupportedClause = (message) => pgError("feature_not_supported", message, "0A000");
|
|
25674
|
+
if (stmt.timing !== "after") throw invalid("transition table name can only be specified for an AFTER trigger");
|
|
25675
|
+
if (stmt.events.some((e) => e.event === "truncate")) {
|
|
25676
|
+
throw unsupportedClause("TRUNCATE triggers with transition tables are not supported");
|
|
25677
|
+
}
|
|
25678
|
+
if (stmt.events.some((e) => e.columns !== null)) {
|
|
25679
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with column lists");
|
|
25680
|
+
}
|
|
25681
|
+
if (stmt.events.length > 1) {
|
|
25682
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with more than one event");
|
|
25683
|
+
}
|
|
25684
|
+
const event = stmt.events[0].event;
|
|
25685
|
+
let oldTable;
|
|
25686
|
+
let newTable;
|
|
25687
|
+
for (const transition of transitions) {
|
|
25688
|
+
if (transition.isNew) {
|
|
25689
|
+
if (event !== "insert" && event !== "update") {
|
|
25690
|
+
throw invalid("NEW TABLE can only be specified for an INSERT or UPDATE trigger");
|
|
25691
|
+
}
|
|
25692
|
+
if (newTable !== void 0) throw invalid("NEW TABLE cannot be specified multiple times");
|
|
25693
|
+
newTable = transition.name;
|
|
25694
|
+
} else {
|
|
25695
|
+
if (event !== "delete" && event !== "update") {
|
|
25696
|
+
throw invalid("OLD TABLE can only be specified for a DELETE or UPDATE trigger");
|
|
25697
|
+
}
|
|
25698
|
+
if (oldTable !== void 0) throw invalid("OLD TABLE cannot be specified multiple times");
|
|
25699
|
+
oldTable = transition.name;
|
|
25700
|
+
}
|
|
25701
|
+
}
|
|
25702
|
+
if (oldTable !== void 0 && oldTable === newTable) {
|
|
25703
|
+
throw invalid("OLD TABLE name and NEW TABLE name cannot be the same");
|
|
25704
|
+
}
|
|
25705
|
+
if (stmt.forEachRow) {
|
|
25706
|
+
throw pgError("unsupported", "transition tables on FOR EACH ROW triggers are not supported", "0A000");
|
|
25707
|
+
}
|
|
25708
|
+
return {
|
|
25709
|
+
...oldTable !== void 0 ? { oldTable } : {},
|
|
25710
|
+
...newTable !== void 0 ? { newTable } : {}
|
|
25711
|
+
};
|
|
25712
|
+
}
|
|
25421
25713
|
function executeCreateTrigger(env, stmt) {
|
|
25422
25714
|
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
25423
25715
|
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
@@ -25427,6 +25719,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25427
25719
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
25428
25720
|
}
|
|
25429
25721
|
const table = state.ensureWritableTable(found);
|
|
25722
|
+
const transitionTables = validateTransitionTables(stmt);
|
|
25430
25723
|
const fnSchema = stmt.funcName.length >= 2 ? stmt.funcName[stmt.funcName.length - 2] : null;
|
|
25431
25724
|
const fnName = stmt.funcName[stmt.funcName.length - 1];
|
|
25432
25725
|
const fns = state.findFunctions(stmt.funcName);
|
|
@@ -25445,6 +25738,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25445
25738
|
timing: stmt.timing,
|
|
25446
25739
|
events: stmt.events,
|
|
25447
25740
|
forEachRow: stmt.forEachRow,
|
|
25741
|
+
...transitionTables,
|
|
25448
25742
|
when: stmt.when,
|
|
25449
25743
|
funcSchema: fnSchema ?? fns[0].schema,
|
|
25450
25744
|
funcName: fnName,
|
|
@@ -25594,6 +25888,7 @@ function executeAlterTable(env, stmt) {
|
|
|
25594
25888
|
}
|
|
25595
25889
|
const next = row.slice();
|
|
25596
25890
|
next[idx] = nv;
|
|
25891
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
25597
25892
|
rows[i] = next;
|
|
25598
25893
|
}
|
|
25599
25894
|
col.type = resolved.column;
|
|
@@ -25695,6 +25990,11 @@ function executeAlterTable(env, stmt) {
|
|
|
25695
25990
|
);
|
|
25696
25991
|
}
|
|
25697
25992
|
table.columns[idx].name = action.to;
|
|
25993
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
25994
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
25995
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
25996
|
+
}
|
|
25997
|
+
}
|
|
25698
25998
|
for (const con of table.constraints) {
|
|
25699
25999
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
25700
26000
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -25731,6 +26031,11 @@ function executeAlterTable(env, stmt) {
|
|
|
25731
26031
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
25732
26032
|
}
|
|
25733
26033
|
const oldName = table.name;
|
|
26034
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
26035
|
+
if (seq.ownedBy?.table === oldName) {
|
|
26036
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
26037
|
+
}
|
|
26038
|
+
}
|
|
25734
26039
|
schema.tables.delete(table.name);
|
|
25735
26040
|
table.name = action.to;
|
|
25736
26041
|
schema.tables.set(action.to, table);
|
|
@@ -27320,6 +27625,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
27320
27625
|
writeBjv(
|
|
27321
27626
|
w,
|
|
27322
27627
|
{
|
|
27628
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
27323
27629
|
name: table.name,
|
|
27324
27630
|
schema: table.schema,
|
|
27325
27631
|
columns: table.columns,
|
|
@@ -27417,8 +27723,14 @@ function decodeInner(snapshot, prng, clock) {
|
|
|
27417
27723
|
table.constraints = meta.constraints;
|
|
27418
27724
|
table.triggers = meta.triggers;
|
|
27419
27725
|
table.unlogged = meta.unlogged === true;
|
|
27726
|
+
table.slabXmins = meta.xmins ?? null;
|
|
27727
|
+
state.xidCounter = Math.max(
|
|
27728
|
+
state.xidCounter,
|
|
27729
|
+
(meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
|
|
27730
|
+
);
|
|
27420
27731
|
if (meta.stats) state.tableStats.set(table.oid, meta.stats);
|
|
27421
27732
|
const rowCount = readVarintU32(r);
|
|
27733
|
+
if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
|
|
27422
27734
|
const slabColumns = [];
|
|
27423
27735
|
for (let c = 0; c < meta.columns.length; c++)
|
|
27424
27736
|
slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
|
|
@@ -27862,6 +28174,8 @@ function validateTableMetaBjv(value) {
|
|
|
27862
28174
|
if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
27863
28175
|
if (!Array.isArray(value.columns)) throw snapshotError();
|
|
27864
28176
|
for (const col of value.columns) validateColumnMeta(col);
|
|
28177
|
+
if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
|
|
28178
|
+
throw snapshotError();
|
|
27865
28179
|
}
|
|
27866
28180
|
function validateViewMetaBjv(value) {
|
|
27867
28181
|
if (!isRecord(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
@@ -27955,6 +28269,7 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
27955
28269
|
pool.forceId(table.name);
|
|
27956
28270
|
pool.forceId(table.schema);
|
|
27957
28271
|
forceBjvStrings(pool, {
|
|
28272
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
27958
28273
|
name: table.name,
|
|
27959
28274
|
schema: table.schema,
|
|
27960
28275
|
columns: table.columns,
|
|
@@ -28032,10 +28347,188 @@ function forceBjvStrings(pool, value) {
|
|
|
28032
28347
|
}
|
|
28033
28348
|
}
|
|
28034
28349
|
registerCodec({ encodeDatabaseState, decodeDatabaseState });
|
|
28350
|
+
|
|
28351
|
+
// src/api/schema-report.ts
|
|
28352
|
+
var bounded = (value, fallback2, max) => {
|
|
28353
|
+
if (value === void 0) return fallback2;
|
|
28354
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > max)
|
|
28355
|
+
throw new RangeError(`limit must be an integer between 1 and ${max}`);
|
|
28356
|
+
return value;
|
|
28357
|
+
};
|
|
28358
|
+
function analyzeSchema(sql, options = {}) {
|
|
28359
|
+
const inputLimit = bounded(options.maxInputBytes, 1024 * 1024, 4 * 1024 * 1024);
|
|
28360
|
+
const statementLimit = bounded(options.maxStatements, 1e3, 1e4);
|
|
28361
|
+
const diagnosticLimit = bounded(options.maxDiagnostics, 100, 1e3);
|
|
28362
|
+
const report = {
|
|
28363
|
+
engine: "mockingbird-postgres",
|
|
28364
|
+
version: true ? "3.8.0" : "source-tree",
|
|
28365
|
+
statements: 0,
|
|
28366
|
+
accepted: 0,
|
|
28367
|
+
compatible: null,
|
|
28368
|
+
truncated: false,
|
|
28369
|
+
diagnostics: []
|
|
28370
|
+
};
|
|
28371
|
+
const add = (diagnostic) => {
|
|
28372
|
+
if (report.diagnostics.length >= diagnosticLimit) {
|
|
28373
|
+
report.truncated = true;
|
|
28374
|
+
return false;
|
|
28375
|
+
}
|
|
28376
|
+
report.diagnostics.push({
|
|
28377
|
+
...diagnostic,
|
|
28378
|
+
...diagnostic.object ? { object: diagnostic.object.slice(0, 200) } : {}
|
|
28379
|
+
});
|
|
28380
|
+
if (diagnostic.category !== "unknown") report.compatible = false;
|
|
28381
|
+
return true;
|
|
28382
|
+
};
|
|
28383
|
+
const location = (offset) => {
|
|
28384
|
+
const prefix = sql.slice(0, offset);
|
|
28385
|
+
return { offset, line: prefix.split("\n").length, column: offset - prefix.lastIndexOf("\n") };
|
|
28386
|
+
};
|
|
28387
|
+
if (sql.length > inputLimit || new TextEncoder().encode(sql).length > inputLimit) {
|
|
28388
|
+
add({
|
|
28389
|
+
statement: 0,
|
|
28390
|
+
...location(0),
|
|
28391
|
+
sqlstate: null,
|
|
28392
|
+
category: "limit",
|
|
28393
|
+
message: `Input exceeds ${inputLimit} bytes`
|
|
28394
|
+
});
|
|
28395
|
+
report.truncated = true;
|
|
28396
|
+
return report;
|
|
28397
|
+
}
|
|
28398
|
+
let tokens;
|
|
28399
|
+
try {
|
|
28400
|
+
tokens = tokenize(sql);
|
|
28401
|
+
} catch (error) {
|
|
28402
|
+
add({
|
|
28403
|
+
statement: 1,
|
|
28404
|
+
...location(0),
|
|
28405
|
+
sqlstate: isPostgresError(error) ? error.code : null,
|
|
28406
|
+
category: "syntax",
|
|
28407
|
+
message: error instanceof Error ? error.message.slice(0, 500) : "Cannot tokenize input"
|
|
28408
|
+
});
|
|
28409
|
+
return report;
|
|
28410
|
+
}
|
|
28411
|
+
const db = new Database();
|
|
28412
|
+
const failed = /* @__PURE__ */ new Map();
|
|
28413
|
+
let start = 0;
|
|
28414
|
+
let tokenStart = 0;
|
|
28415
|
+
let atomicDepth = 0;
|
|
28416
|
+
const run = (end, tokenEnd) => {
|
|
28417
|
+
const statementTokens = tokens.slice(tokenStart, tokenEnd);
|
|
28418
|
+
tokenStart = tokenEnd + 1;
|
|
28419
|
+
const offset = statementTokens[0]?.pos;
|
|
28420
|
+
const statementSql = sql.slice(start, end);
|
|
28421
|
+
start = end + 1;
|
|
28422
|
+
if (offset === void 0) return;
|
|
28423
|
+
if (report.statements >= statementLimit) {
|
|
28424
|
+
report.truncated = true;
|
|
28425
|
+
add({
|
|
28426
|
+
statement: report.statements + 1,
|
|
28427
|
+
...location(offset),
|
|
28428
|
+
sqlstate: null,
|
|
28429
|
+
category: "limit",
|
|
28430
|
+
message: `Statement limit ${statementLimit} reached`
|
|
28431
|
+
});
|
|
28432
|
+
return;
|
|
28433
|
+
}
|
|
28434
|
+
report.statements++;
|
|
28435
|
+
let object;
|
|
28436
|
+
const candidate = statementTokens.findIndex(
|
|
28437
|
+
(token) => ["table", "view", "function", "sequence", "schema", "type", "index"].includes(token.value)
|
|
28438
|
+
);
|
|
28439
|
+
if (candidate >= 0) {
|
|
28440
|
+
const name = statementTokens[candidate + 1];
|
|
28441
|
+
if (name?.type === "ident" || name?.type === "quoted_ident") object = name.value;
|
|
28442
|
+
}
|
|
28443
|
+
try {
|
|
28444
|
+
const ast = parse(statementSql);
|
|
28445
|
+
const statement = ast[0];
|
|
28446
|
+
if (statement && "name" in statement && Array.isArray(statement.name)) object = statement.name.join(".");
|
|
28447
|
+
if (statement && !/^(create_|alter_|comment|grant|revoke|set|reset)/.test(statement.type)) {
|
|
28448
|
+
add({
|
|
28449
|
+
statement: report.statements,
|
|
28450
|
+
...location(offset),
|
|
28451
|
+
object,
|
|
28452
|
+
sqlstate: null,
|
|
28453
|
+
category: "unknown",
|
|
28454
|
+
message: "Only schema statements are analyzed; data, queries and dynamic commands are unknown"
|
|
28455
|
+
});
|
|
28456
|
+
return;
|
|
28457
|
+
}
|
|
28458
|
+
const references = statementTokens.flatMap((token, index) => {
|
|
28459
|
+
if (!["from", "join", "references"].includes(token.value)) return [];
|
|
28460
|
+
const parts = [];
|
|
28461
|
+
for (let at = index + 1; at < statementTokens.length; at += 2) {
|
|
28462
|
+
const part = statementTokens[at];
|
|
28463
|
+
if (!part || part.type !== "ident" && part.type !== "quoted_ident") break;
|
|
28464
|
+
parts.push(part.value);
|
|
28465
|
+
if (statementTokens[at + 1]?.value !== ".") break;
|
|
28466
|
+
}
|
|
28467
|
+
return parts.length ? [parts.join(".")] : [];
|
|
28468
|
+
});
|
|
28469
|
+
const missing = [...failed].find(
|
|
28470
|
+
([name]) => references.some(
|
|
28471
|
+
(reference) => reference === name || !reference.includes(".") && reference === name.split(".").at(-1) || !name.includes(".") && name === reference.split(".").at(-1)
|
|
28472
|
+
)
|
|
28473
|
+
);
|
|
28474
|
+
if (missing) {
|
|
28475
|
+
add({
|
|
28476
|
+
statement: report.statements,
|
|
28477
|
+
...location(offset),
|
|
28478
|
+
object,
|
|
28479
|
+
sqlstate: "42P01",
|
|
28480
|
+
category: "prerequisite",
|
|
28481
|
+
message: `Prerequisite ${missing[0]} was not created`,
|
|
28482
|
+
prerequisiteStatement: missing[1]
|
|
28483
|
+
});
|
|
28484
|
+
if (object) failed.set(object, report.statements);
|
|
28485
|
+
return;
|
|
28486
|
+
}
|
|
28487
|
+
db.exec(statementSql);
|
|
28488
|
+
report.accepted++;
|
|
28489
|
+
add({
|
|
28490
|
+
statement: report.statements,
|
|
28491
|
+
...location(offset),
|
|
28492
|
+
object,
|
|
28493
|
+
sqlstate: null,
|
|
28494
|
+
category: "unknown",
|
|
28495
|
+
message: "Accepted by the ephemeral engine; semantics, function bodies and dynamic SQL require oracle verification"
|
|
28496
|
+
});
|
|
28497
|
+
} catch (error) {
|
|
28498
|
+
const code = isPostgresError(error) ? error.code : null;
|
|
28499
|
+
const message = error instanceof Error ? error.message.slice(0, 500) : "Schema analysis failed";
|
|
28500
|
+
const prerequisite = code?.startsWith("42") ? [...failed].find(([name]) => message.includes(`"${name}"`) || message.includes(`"${name.split(".").at(-1)}"`)) : void 0;
|
|
28501
|
+
add({
|
|
28502
|
+
statement: report.statements,
|
|
28503
|
+
...location(offset),
|
|
28504
|
+
object,
|
|
28505
|
+
sqlstate: code,
|
|
28506
|
+
category: prerequisite ? "prerequisite" : code === "0A000" ? "unsupported" : code?.startsWith("426") ? "syntax" : "execution",
|
|
28507
|
+
message,
|
|
28508
|
+
...prerequisite ? { prerequisiteStatement: prerequisite[1] } : {}
|
|
28509
|
+
});
|
|
28510
|
+
if (object) failed.set(object, report.statements);
|
|
28511
|
+
}
|
|
28512
|
+
};
|
|
28513
|
+
try {
|
|
28514
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
28515
|
+
const token = tokens[index];
|
|
28516
|
+
if (token.value === "begin" && tokens[index + 1]?.value === "atomic") atomicDepth++;
|
|
28517
|
+
if (token.value === "end" && atomicDepth > 0) atomicDepth--;
|
|
28518
|
+
if (token.type === "punct" && token.value === ";" && atomicDepth === 0 || token.type === "eof")
|
|
28519
|
+
run(token.pos, index);
|
|
28520
|
+
if (report.truncated) break;
|
|
28521
|
+
}
|
|
28522
|
+
} finally {
|
|
28523
|
+
db.close();
|
|
28524
|
+
}
|
|
28525
|
+
return report;
|
|
28526
|
+
}
|
|
28035
28527
|
export {
|
|
28036
28528
|
Database,
|
|
28037
28529
|
PostgresError,
|
|
28038
28530
|
Snapshot,
|
|
28039
|
-
Statement
|
|
28531
|
+
Statement,
|
|
28532
|
+
analyzeSchema
|
|
28040
28533
|
};
|
|
28041
28534
|
//# sourceMappingURL=index.js.map
|