@crvouga/mockingbird-service-postgres 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/COMPATIBILITY.md +34 -0
- package/README.md +5 -0
- package/compat/sections/trg.ts +2 -0
- package/dist/admin.js +1114 -735
- package/dist/admin.js.map +4 -4
- package/dist/api/schema-report.d.ts +32 -0
- package/dist/ast/nodes.d.ts +11 -1
- package/dist/executor/relation.d.ts +1 -0
- package/dist/executor/triggers-scope.d.ts +4 -0
- package/dist/executor/triggers.d.ts +4 -0
- package/dist/expressions/context.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1266 -699
- package/dist/index.js.map +4 -4
- package/dist/server.js +1144 -736
- package/dist/server.js.map +4 -4
- package/dist/storage/database-state.d.ts +20 -0
- package/dist/storage/guc.d.ts +2 -0
- package/dist/storage/indexable-relation.d.ts +3 -0
- package/dist/types/regnamespace.d.ts +5 -0
- package/dist/types/value.d.ts +2 -0
- package/dist/unstable.js +17231 -16852
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +1330 -749
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/index.js +1144 -736
- package/dist/wire/index.js.map +4 -4
- package/package.json +1 -1
package/dist/admin.js
CHANGED
|
@@ -2505,6 +2505,13 @@ function isPostgresError(err) {
|
|
|
2505
2505
|
return typeof sqlState === "string" && /^[0-9A-Z]{5}$/.test(sqlState);
|
|
2506
2506
|
}
|
|
2507
2507
|
|
|
2508
|
+
// src/storage/guc.ts
|
|
2509
|
+
function validateStorageSetting(name, value) {
|
|
2510
|
+
if (name === "default_table_access_method" && value !== "heap" || name === "default_tablespace" && value !== "" && value !== "pg_default") {
|
|
2511
|
+
throw pgError("invalid_parameter_value", `invalid value for parameter "${name}": "${value}"`, "22023");
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2508
2515
|
// src/runtime/prng.ts
|
|
2509
2516
|
var Prng = class _Prng {
|
|
2510
2517
|
state;
|
|
@@ -5044,6 +5051,12 @@ var invalidName = () => {
|
|
|
5044
5051
|
throw pgError("syntax", "invalid name syntax", "42602");
|
|
5045
5052
|
};
|
|
5046
5053
|
function parseNamespaceInput(text) {
|
|
5054
|
+
const parsed = parseRelationInput(text);
|
|
5055
|
+
if ("oid" in parsed) return parsed;
|
|
5056
|
+
if (parsed.parts.length !== 1) invalidName();
|
|
5057
|
+
return { name: parsed.parts[0] };
|
|
5058
|
+
}
|
|
5059
|
+
function parseRelationInput(text) {
|
|
5047
5060
|
if (text === "-") return { oid: 0 };
|
|
5048
5061
|
if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
|
|
5049
5062
|
const names = [];
|
|
@@ -5079,8 +5092,8 @@ function parseNamespaceInput(text) {
|
|
|
5079
5092
|
skipSpace();
|
|
5080
5093
|
if (at === text.length) invalidName();
|
|
5081
5094
|
}
|
|
5082
|
-
if (names.length
|
|
5083
|
-
return {
|
|
5095
|
+
if (names.length === 0 || names.length > 3) invalidName();
|
|
5096
|
+
return { parts: names };
|
|
5084
5097
|
}
|
|
5085
5098
|
function namespaceText(oid, name) {
|
|
5086
5099
|
if (oid === 0) return "-";
|
|
@@ -5153,6 +5166,7 @@ var TYPE_ALIASES = {
|
|
|
5153
5166
|
regtype: "regtype",
|
|
5154
5167
|
regproc: "regproc",
|
|
5155
5168
|
regnamespace: "regnamespace",
|
|
5169
|
+
xid: "xid",
|
|
5156
5170
|
oid: "oid",
|
|
5157
5171
|
void: "void",
|
|
5158
5172
|
record: "record",
|
|
@@ -5229,6 +5243,7 @@ var TYPE_OIDS = {
|
|
|
5229
5243
|
regproc: 24,
|
|
5230
5244
|
text: 25,
|
|
5231
5245
|
oid: 26,
|
|
5246
|
+
xid: 28,
|
|
5232
5247
|
json: 114,
|
|
5233
5248
|
float4: 700,
|
|
5234
5249
|
float8: 701,
|
|
@@ -5547,6 +5562,7 @@ function recordText(rec, ctx) {
|
|
|
5547
5562
|
return `(${parts.join(",")})`;
|
|
5548
5563
|
}
|
|
5549
5564
|
function datumText(t, v, ctx) {
|
|
5565
|
+
if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
|
|
5550
5566
|
if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
|
|
5551
5567
|
if (v === null) throw pgError("internal", "datumText called with null");
|
|
5552
5568
|
if (isArrayType(t)) return arrayText(v, ctx);
|
|
@@ -5557,6 +5573,7 @@ function datumText(t, v, ctx) {
|
|
|
5557
5573
|
case "int2":
|
|
5558
5574
|
case "int4":
|
|
5559
5575
|
case "oid":
|
|
5576
|
+
case "xid":
|
|
5560
5577
|
return String(v);
|
|
5561
5578
|
case "int8":
|
|
5562
5579
|
return String(v);
|
|
@@ -5621,6 +5638,12 @@ function datumText(t, v, ctx) {
|
|
|
5621
5638
|
}
|
|
5622
5639
|
var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
|
|
5623
5640
|
function datumFromText(t, text, ctx) {
|
|
5641
|
+
if (t === "regclass") {
|
|
5642
|
+
const parsed = parseRelationInput(text);
|
|
5643
|
+
if ("oid" in parsed) return parsed.oid;
|
|
5644
|
+
if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
|
|
5645
|
+
return ctx.relationOid(parsed.parts);
|
|
5646
|
+
}
|
|
5624
5647
|
if (t === "regnamespace") {
|
|
5625
5648
|
const parsed = parseNamespaceInput(text);
|
|
5626
5649
|
if ("oid" in parsed) return parsed.oid;
|
|
@@ -5642,6 +5665,7 @@ function datumFromText(t, text, ctx) {
|
|
|
5642
5665
|
case "int8":
|
|
5643
5666
|
return parseIntegerText(text, t);
|
|
5644
5667
|
case "oid":
|
|
5668
|
+
case "xid":
|
|
5645
5669
|
return parseOidText(text);
|
|
5646
5670
|
case "float4":
|
|
5647
5671
|
return Math.fround(parseFloatText(text, "float4"));
|
|
@@ -5798,6 +5822,8 @@ var TableData = class _TableData {
|
|
|
5798
5822
|
schema;
|
|
5799
5823
|
columns;
|
|
5800
5824
|
rows;
|
|
5825
|
+
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
5826
|
+
slabXmins = null;
|
|
5801
5827
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
5802
5828
|
slab = null;
|
|
5803
5829
|
constraints;
|
|
@@ -5840,6 +5866,11 @@ var TableData = class _TableData {
|
|
|
5840
5866
|
materializeSlab() {
|
|
5841
5867
|
if (!this.slab) return;
|
|
5842
5868
|
this.rows = this.slab.materialize();
|
|
5869
|
+
if (this.slabXmins)
|
|
5870
|
+
this.rows.forEach((row, index) => {
|
|
5871
|
+
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
5872
|
+
});
|
|
5873
|
+
this.slabXmins = null;
|
|
5843
5874
|
this.slab = null;
|
|
5844
5875
|
this.indexStores = null;
|
|
5845
5876
|
}
|
|
@@ -5873,6 +5904,10 @@ var TableData = class _TableData {
|
|
|
5873
5904
|
} else {
|
|
5874
5905
|
t.rows = this.rows.map((r) => r.slice());
|
|
5875
5906
|
}
|
|
5907
|
+
t.rows.forEach((row, index) => {
|
|
5908
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
|
|
5909
|
+
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
5910
|
+
});
|
|
5876
5911
|
t.unlogged = this.unlogged;
|
|
5877
5912
|
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
5878
5913
|
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
@@ -5958,7 +5993,18 @@ var DatabaseState = class _DatabaseState {
|
|
|
5958
5993
|
clock;
|
|
5959
5994
|
changes = 0;
|
|
5960
5995
|
oidCounter = 16384;
|
|
5996
|
+
/** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
|
|
5997
|
+
xidCounter = 3;
|
|
5998
|
+
transactionXid = null;
|
|
5999
|
+
allocateXid() {
|
|
6000
|
+
if (this.xidCounter > 4294967295)
|
|
6001
|
+
throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
|
|
6002
|
+
return this.xidCounter++;
|
|
6003
|
+
}
|
|
5961
6004
|
inTransaction = false;
|
|
6005
|
+
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
6006
|
+
pendingTriggers = [];
|
|
6007
|
+
constraintModes = /* @__PURE__ */ new Map();
|
|
5962
6008
|
/** most recent sequence touched by nextval/setval, for lastval() */
|
|
5963
6009
|
lastSequence = null;
|
|
5964
6010
|
/** Session currval per sequence; absent entry means currval is undefined. */
|
|
@@ -6001,6 +6047,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
6001
6047
|
this.settings.set("row_security", "on");
|
|
6002
6048
|
this.settings.set("array_nulls", "on");
|
|
6003
6049
|
this.settings.set("backslash_quote", "safe_encoding");
|
|
6050
|
+
this.settings.set("default_tablespace", "");
|
|
6051
|
+
this.settings.set("default_table_access_method", "heap");
|
|
6004
6052
|
}
|
|
6005
6053
|
nextOid() {
|
|
6006
6054
|
return this.oidCounter++;
|
|
@@ -6160,10 +6208,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
6160
6208
|
s.prepared = new Map(this.prepared);
|
|
6161
6209
|
s.changes = this.changes;
|
|
6162
6210
|
s.inTransaction = this.inTransaction;
|
|
6211
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
6212
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
6163
6213
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
6164
6214
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
6165
6215
|
s.tableStats = new Map(this.tableStats);
|
|
6166
6216
|
s.oidCounter = this.oidCounter;
|
|
6217
|
+
s.xidCounter = this.xidCounter;
|
|
6218
|
+
s.transactionXid = this.transactionXid;
|
|
6167
6219
|
for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
|
|
6168
6220
|
return s;
|
|
6169
6221
|
}
|
|
@@ -6177,10 +6229,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
6177
6229
|
s.prepared = new Map(this.prepared);
|
|
6178
6230
|
s.changes = this.changes;
|
|
6179
6231
|
s.inTransaction = this.inTransaction;
|
|
6232
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
6233
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
6180
6234
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
6181
6235
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
6182
6236
|
s.tableStats = new Map(this.tableStats);
|
|
6183
6237
|
s.oidCounter = this.oidCounter;
|
|
6238
|
+
s.xidCounter = this.xidCounter;
|
|
6239
|
+
s.transactionXid = this.transactionXid;
|
|
6184
6240
|
for (const [name, overloads] of this.systemFunctions) s.systemFunctions.set(name, overloads.slice());
|
|
6185
6241
|
return s;
|
|
6186
6242
|
}
|
|
@@ -6249,11 +6305,15 @@ var DatabaseState = class _DatabaseState {
|
|
|
6249
6305
|
this.settings = other.settings;
|
|
6250
6306
|
this.localSettings = other.localSettings;
|
|
6251
6307
|
this.prepared = other.prepared;
|
|
6308
|
+
this.pendingTriggers = other.pendingTriggers.slice();
|
|
6309
|
+
this.constraintModes = new Map(other.constraintModes);
|
|
6252
6310
|
this.changes = other.changes;
|
|
6253
6311
|
this.lastSequence = other.lastSequence;
|
|
6254
6312
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
6255
6313
|
this.tableStats = other.tableStats;
|
|
6256
6314
|
this.oidCounter = other.oidCounter;
|
|
6315
|
+
this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
|
|
6316
|
+
this.transactionXid = other.transactionXid;
|
|
6257
6317
|
}
|
|
6258
6318
|
/** @internal Snapshot codec access to the oid allocator. */
|
|
6259
6319
|
snapshotOidCounter() {
|
|
@@ -6265,91 +6325,212 @@ var DatabaseState = class _DatabaseState {
|
|
|
6265
6325
|
}
|
|
6266
6326
|
};
|
|
6267
6327
|
|
|
6268
|
-
// src/
|
|
6269
|
-
var
|
|
6270
|
-
|
|
6271
|
-
|
|
6328
|
+
// src/types/timezone.ts
|
|
6329
|
+
var intlCache = /* @__PURE__ */ new Map();
|
|
6330
|
+
function intlFor(zone) {
|
|
6331
|
+
const cached = intlCache.get(zone);
|
|
6332
|
+
if (cached) return cached;
|
|
6333
|
+
try {
|
|
6334
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
6335
|
+
timeZone: zone,
|
|
6336
|
+
timeZoneName: "longOffset",
|
|
6337
|
+
year: "numeric"
|
|
6338
|
+
});
|
|
6339
|
+
intlCache.set(zone, fmt);
|
|
6340
|
+
return fmt;
|
|
6341
|
+
} catch {
|
|
6342
|
+
return null;
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
function parseFixedOffset(zone) {
|
|
6346
|
+
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
6347
|
+
if (!m) return null;
|
|
6348
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
6349
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
6350
|
+
}
|
|
6351
|
+
function parsePosixOffset(zone) {
|
|
6352
|
+
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
6353
|
+
if (!m) return null;
|
|
6354
|
+
const sign = m[1] === "-" ? 1 : -1;
|
|
6355
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
6356
|
+
}
|
|
6357
|
+
function pgMicrosToUnixMs(utcMicros) {
|
|
6358
|
+
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
6359
|
+
}
|
|
6360
|
+
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
6361
|
+
const z = zone.trim();
|
|
6362
|
+
const lower = z.toLowerCase();
|
|
6363
|
+
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
6364
|
+
const posix = parsePosixOffset(z);
|
|
6365
|
+
if (posix !== null) return posix;
|
|
6366
|
+
const fixed = parseFixedOffset(z);
|
|
6367
|
+
if (fixed !== null) return fixed;
|
|
6368
|
+
const fmt = intlFor(z);
|
|
6369
|
+
if (fmt) {
|
|
6370
|
+
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
6371
|
+
const parts = fmt.formatToParts(new Date(ms));
|
|
6372
|
+
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
6373
|
+
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
6374
|
+
if (!m) return 0;
|
|
6375
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
6376
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
6272
6377
|
}
|
|
6378
|
+
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
6379
|
+
}
|
|
6380
|
+
function clampDateMs(ms) {
|
|
6381
|
+
const MAX = 864e13;
|
|
6382
|
+
return Math.max(-MAX, Math.min(MAX, ms));
|
|
6383
|
+
}
|
|
6384
|
+
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
6385
|
+
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
6386
|
+
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
6387
|
+
return second;
|
|
6388
|
+
}
|
|
6389
|
+
|
|
6390
|
+
// src/expressions/context.ts
|
|
6391
|
+
var EngineCtx = class {
|
|
6273
6392
|
state;
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
return this.base !== null;
|
|
6393
|
+
writeXid = null;
|
|
6394
|
+
rowVersionXid() {
|
|
6395
|
+
if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
|
|
6396
|
+
return this.writeXid ??= this.state.allocateXid();
|
|
6279
6397
|
}
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6398
|
+
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
6399
|
+
txNow;
|
|
6400
|
+
/** statement timestamp */
|
|
6401
|
+
stmtNow;
|
|
6402
|
+
constructor(state, txNow) {
|
|
6403
|
+
this.state = state;
|
|
6404
|
+
const nowMs = state.clock().getTime();
|
|
6405
|
+
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
6406
|
+
this.txNow = txNow ?? nowMicros;
|
|
6407
|
+
this.stmtNow = nowMicros;
|
|
6284
6408
|
}
|
|
6285
|
-
|
|
6286
|
-
this.state.
|
|
6287
|
-
this.state.prng.setState(snap.prngState);
|
|
6409
|
+
timezone() {
|
|
6410
|
+
return this.state.getSetting("timezone") ?? "UTC";
|
|
6288
6411
|
}
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
}
|
|
6412
|
+
relationOid(parts) {
|
|
6413
|
+
const target = this.state.resolveRelationSchema(parts);
|
|
6414
|
+
const schema = target ? this.state.schemas.get(target.schema) : void 0;
|
|
6415
|
+
const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
|
|
6416
|
+
if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
|
|
6417
|
+
return relation.oid;
|
|
6294
6418
|
}
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6419
|
+
relationName(oid) {
|
|
6420
|
+
for (const schema of this.state.schemas.values()) {
|
|
6421
|
+
for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
|
|
6422
|
+
if (relation.oid !== oid) continue;
|
|
6423
|
+
const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
|
|
6424
|
+
return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
|
|
6425
|
+
}
|
|
6298
6426
|
}
|
|
6299
|
-
|
|
6300
|
-
this.state.inTransaction = true;
|
|
6301
|
-
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
6427
|
+
return null;
|
|
6302
6428
|
}
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
this.state.localSettings.clear();
|
|
6308
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
6429
|
+
namespaceOid(name) {
|
|
6430
|
+
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
6431
|
+
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
6432
|
+
return oid;
|
|
6309
6433
|
}
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6434
|
+
namespaceName(oid) {
|
|
6435
|
+
const builtin = builtinNamespaceName(oid);
|
|
6436
|
+
if (builtin !== void 0) return builtin;
|
|
6437
|
+
for (const schema of this.state.schemas.values()) {
|
|
6438
|
+
if (schema.oid === oid) return schema.name;
|
|
6313
6439
|
}
|
|
6314
|
-
|
|
6315
|
-
this.savepoints = [];
|
|
6316
|
-
this.state.inTransaction = false;
|
|
6317
|
-
this.state.localSettings.clear();
|
|
6318
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
6440
|
+
return null;
|
|
6319
6441
|
}
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
6323
|
-
}
|
|
6324
|
-
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
6442
|
+
zoneOffsetAt(utcMicros) {
|
|
6443
|
+
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
6325
6444
|
}
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
this.savepoints.splice(idx);
|
|
6445
|
+
zoneOffsetForNaive(naiveMicros) {
|
|
6446
|
+
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
6329
6447
|
}
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
const
|
|
6333
|
-
|
|
6334
|
-
this.savepoints.splice(idx + 1);
|
|
6448
|
+
enumLabels(enumType) {
|
|
6449
|
+
if (!isEnumType(enumType)) return null;
|
|
6450
|
+
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
6451
|
+
return e?.labels ?? null;
|
|
6335
6452
|
}
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
}
|
|
6340
|
-
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
6341
|
-
if (this.savepoints[i].name === name) return i;
|
|
6342
|
-
}
|
|
6343
|
-
throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
|
|
6453
|
+
enumHasLabel(enumType, label) {
|
|
6454
|
+
const labels = this.enumLabels(enumType);
|
|
6455
|
+
return labels === null ? true : labels.includes(label);
|
|
6344
6456
|
}
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6457
|
+
enumOrder(enumType, label) {
|
|
6458
|
+
const labels = this.enumLabels(enumType);
|
|
6459
|
+
if (!labels) return 0;
|
|
6460
|
+
const idx = labels.indexOf(label);
|
|
6461
|
+
return idx === -1 ? labels.length : idx;
|
|
6462
|
+
}
|
|
6463
|
+
requireEnum(enumType) {
|
|
6464
|
+
const labels = this.enumLabels(enumType);
|
|
6465
|
+
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
6466
|
+
return labels;
|
|
6350
6467
|
}
|
|
6351
6468
|
};
|
|
6352
6469
|
|
|
6470
|
+
// src/api/bind.ts
|
|
6471
|
+
var INT4_MIN2 = -2147483648;
|
|
6472
|
+
var INT4_MAX2 = 2147483647;
|
|
6473
|
+
function bindValueToTyped(value, index) {
|
|
6474
|
+
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
6475
|
+
switch (typeof value) {
|
|
6476
|
+
case "boolean":
|
|
6477
|
+
return tv("bool", value);
|
|
6478
|
+
case "number":
|
|
6479
|
+
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
6480
|
+
return tv("int4", value);
|
|
6481
|
+
}
|
|
6482
|
+
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
6483
|
+
return tv("int8", BigInt(value));
|
|
6484
|
+
}
|
|
6485
|
+
return tv("float8", value);
|
|
6486
|
+
case "bigint":
|
|
6487
|
+
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
6488
|
+
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
6489
|
+
}
|
|
6490
|
+
return tv("int8", value);
|
|
6491
|
+
case "string":
|
|
6492
|
+
return tv(UNKNOWN, value);
|
|
6493
|
+
case "object": {
|
|
6494
|
+
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
6495
|
+
if (value instanceof Date) {
|
|
6496
|
+
const ms = value.getTime();
|
|
6497
|
+
if (Number.isNaN(ms)) {
|
|
6498
|
+
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
6499
|
+
}
|
|
6500
|
+
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
6501
|
+
}
|
|
6502
|
+
break;
|
|
6503
|
+
}
|
|
6504
|
+
default:
|
|
6505
|
+
break;
|
|
6506
|
+
}
|
|
6507
|
+
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
6508
|
+
}
|
|
6509
|
+
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
6510
|
+
if (v === null) return null;
|
|
6511
|
+
switch (t) {
|
|
6512
|
+
case "bool":
|
|
6513
|
+
return v;
|
|
6514
|
+
case "int2":
|
|
6515
|
+
case "int4":
|
|
6516
|
+
case "oid":
|
|
6517
|
+
return typeof v === "bigint" ? Number(v) : v;
|
|
6518
|
+
case "int8": {
|
|
6519
|
+
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
6520
|
+
if (int8 === "string") return n.toString();
|
|
6521
|
+
if (int8 === "number") return Number(n);
|
|
6522
|
+
return n;
|
|
6523
|
+
}
|
|
6524
|
+
case "float4":
|
|
6525
|
+
case "float8":
|
|
6526
|
+
return v;
|
|
6527
|
+
case "bytea":
|
|
6528
|
+
return v;
|
|
6529
|
+
default:
|
|
6530
|
+
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
|
|
6353
6534
|
// src/types/cast.ts
|
|
6354
6535
|
var UTC_CAST_ENV = {
|
|
6355
6536
|
zoneOffsetAt: () => 0,
|
|
@@ -6545,7 +6726,7 @@ function castTo(env, value, target, opts = {}) {
|
|
|
6545
6726
|
return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
|
|
6546
6727
|
}
|
|
6547
6728
|
if (from === "oid" && target === "regnamespace") return tv(target, v);
|
|
6548
|
-
if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
|
|
6729
|
+
if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
|
|
6549
6730
|
return tv(target, target === "int8" ? BigInt(v) : v);
|
|
6550
6731
|
}
|
|
6551
6732
|
if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
|
|
@@ -6826,259 +7007,6 @@ function unifyTypes(a, b) {
|
|
|
6826
7007
|
return null;
|
|
6827
7008
|
}
|
|
6828
7009
|
|
|
6829
|
-
// src/types/resolve.ts
|
|
6830
|
-
var SERIALS = {
|
|
6831
|
-
smallserial: "int2",
|
|
6832
|
-
serial2: "int2",
|
|
6833
|
-
serial: "int4",
|
|
6834
|
-
serial4: "int4",
|
|
6835
|
-
bigserial: "int8",
|
|
6836
|
-
serial8: "int8"
|
|
6837
|
-
};
|
|
6838
|
-
function modOf(t, mods) {
|
|
6839
|
-
if (mods.length === 0) return null;
|
|
6840
|
-
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
6841
|
-
return { a: mods[0] };
|
|
6842
|
-
}
|
|
6843
|
-
function resolveTypeName(state, tn) {
|
|
6844
|
-
const joined = tn.parts.join(".");
|
|
6845
|
-
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
6846
|
-
if (bare !== null) {
|
|
6847
|
-
const serial = SERIALS[bare];
|
|
6848
|
-
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
6849
|
-
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
6850
|
-
}
|
|
6851
|
-
const builtin = normalizeTypeName(bare);
|
|
6852
|
-
if (builtin !== null) {
|
|
6853
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
6854
|
-
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
6855
|
-
}
|
|
6856
|
-
}
|
|
6857
|
-
const enumData = state.findEnum(tn.parts);
|
|
6858
|
-
if (enumData) {
|
|
6859
|
-
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
6860
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
6861
|
-
return { column: { id, mod: null }, domain: null, serial: null };
|
|
6862
|
-
}
|
|
6863
|
-
const domainData = state.findDomain(tn.parts);
|
|
6864
|
-
if (domainData) {
|
|
6865
|
-
if (tn.arrayDims > 0) {
|
|
6866
|
-
const id = arrayTypeOf(domainData.baseType.id);
|
|
6867
|
-
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
6868
|
-
}
|
|
6869
|
-
return {
|
|
6870
|
-
column: domainData.baseType,
|
|
6871
|
-
domain: `${domainData.schema}.${domainData.name}`,
|
|
6872
|
-
serial: null
|
|
6873
|
-
};
|
|
6874
|
-
}
|
|
6875
|
-
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
6876
|
-
}
|
|
6877
|
-
|
|
6878
|
-
// src/executor/relation.ts
|
|
6879
|
-
var RowScope = class {
|
|
6880
|
-
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
6881
|
-
this.columns = columns;
|
|
6882
|
-
this.row = row;
|
|
6883
|
-
this.parent = parent;
|
|
6884
|
-
this.rangeVars = rangeVars;
|
|
6885
|
-
}
|
|
6886
|
-
columns;
|
|
6887
|
-
row;
|
|
6888
|
-
parent;
|
|
6889
|
-
rangeVars;
|
|
6890
|
-
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
6891
|
-
lookup(parts) {
|
|
6892
|
-
if (parts.length === 1) {
|
|
6893
|
-
const name2 = parts[0];
|
|
6894
|
-
let found2;
|
|
6895
|
-
let count3 = 0;
|
|
6896
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
6897
|
-
const c = this.columns[i];
|
|
6898
|
-
if (c.name === name2 && !c.hidden) {
|
|
6899
|
-
count3++;
|
|
6900
|
-
if (count3 > 1) {
|
|
6901
|
-
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
6902
|
-
}
|
|
6903
|
-
found2 = tv(c.type, this.row[i] ?? null);
|
|
6904
|
-
}
|
|
6905
|
-
}
|
|
6906
|
-
if (found2 !== void 0) return found2;
|
|
6907
|
-
if (this.rangeVars.has(name2)) {
|
|
6908
|
-
return this.wholeRow(name2);
|
|
6909
|
-
}
|
|
6910
|
-
return this.parent?.lookup(parts);
|
|
6911
|
-
}
|
|
6912
|
-
const table = parts[parts.length - 2];
|
|
6913
|
-
const name = parts[parts.length - 1];
|
|
6914
|
-
let found;
|
|
6915
|
-
let count2 = 0;
|
|
6916
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
6917
|
-
const c = this.columns[i];
|
|
6918
|
-
if (c.table === table && c.name === name) {
|
|
6919
|
-
count2++;
|
|
6920
|
-
if (count2 > 1) {
|
|
6921
|
-
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
6922
|
-
}
|
|
6923
|
-
found = tv(c.type, this.row[i] ?? null);
|
|
6924
|
-
}
|
|
6925
|
-
}
|
|
6926
|
-
if (found !== void 0) return found;
|
|
6927
|
-
return this.parent?.lookup(parts);
|
|
6928
|
-
}
|
|
6929
|
-
/** Build a record value from all columns belonging to a range variable. */
|
|
6930
|
-
wholeRow(rangeVar) {
|
|
6931
|
-
const types = [];
|
|
6932
|
-
const values = [];
|
|
6933
|
-
const names = [];
|
|
6934
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
6935
|
-
const c = this.columns[i];
|
|
6936
|
-
if (c.table === rangeVar) {
|
|
6937
|
-
types.push(c.type);
|
|
6938
|
-
values.push(this.row[i] ?? null);
|
|
6939
|
-
names.push(c.name);
|
|
6940
|
-
}
|
|
6941
|
-
}
|
|
6942
|
-
if (types.length === 0) return void 0;
|
|
6943
|
-
return tv("record", { kind: "pgrecord", types, values, names });
|
|
6944
|
-
}
|
|
6945
|
-
hasRangeVar(name) {
|
|
6946
|
-
if (this.rangeVars.has(name)) return true;
|
|
6947
|
-
return this.parent?.hasRangeVar(name) ?? false;
|
|
6948
|
-
}
|
|
6949
|
-
};
|
|
6950
|
-
function childEnv(env, outer) {
|
|
6951
|
-
return {
|
|
6952
|
-
ctx: env.ctx,
|
|
6953
|
-
params: env.params,
|
|
6954
|
-
ctes: env.ctes,
|
|
6955
|
-
outer,
|
|
6956
|
-
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
6957
|
-
};
|
|
6958
|
-
}
|
|
6959
|
-
function relationResult(rel3, command) {
|
|
6960
|
-
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
6961
|
-
return {
|
|
6962
|
-
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
6963
|
-
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
6964
|
-
command,
|
|
6965
|
-
rowCount: rel3.rows.length
|
|
6966
|
-
};
|
|
6967
|
-
}
|
|
6968
|
-
function commandResult(command, rowCount) {
|
|
6969
|
-
return { columns: [], rows: [], command, rowCount };
|
|
6970
|
-
}
|
|
6971
|
-
function inferColumnName(e) {
|
|
6972
|
-
switch (e.type) {
|
|
6973
|
-
case "colref":
|
|
6974
|
-
return e.parts[e.parts.length - 1];
|
|
6975
|
-
case "func":
|
|
6976
|
-
return e.name[e.name.length - 1];
|
|
6977
|
-
case "cast": {
|
|
6978
|
-
const inner = inferColumnName(e.expr);
|
|
6979
|
-
if (inner !== "?column?") return inner;
|
|
6980
|
-
return e.target.parts[e.target.parts.length - 1];
|
|
6981
|
-
}
|
|
6982
|
-
case "collate":
|
|
6983
|
-
return inferColumnName(e.expr);
|
|
6984
|
-
case "case":
|
|
6985
|
-
return "case";
|
|
6986
|
-
case "array_ctor":
|
|
6987
|
-
case "array_query":
|
|
6988
|
-
return "array";
|
|
6989
|
-
case "row":
|
|
6990
|
-
return "row";
|
|
6991
|
-
case "subquery_expr":
|
|
6992
|
-
return e.kind === "exists" ? "exists" : "?column?";
|
|
6993
|
-
case "bool_lit":
|
|
6994
|
-
return "bool";
|
|
6995
|
-
case "extract":
|
|
6996
|
-
return "extract";
|
|
6997
|
-
case "position":
|
|
6998
|
-
return "position";
|
|
6999
|
-
case "substring_sql":
|
|
7000
|
-
return "substring";
|
|
7001
|
-
case "overlay":
|
|
7002
|
-
return "overlay";
|
|
7003
|
-
case "trim":
|
|
7004
|
-
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
7005
|
-
case "field_select":
|
|
7006
|
-
return e.field === "*" ? "?column?" : e.field;
|
|
7007
|
-
case "at_time_zone":
|
|
7008
|
-
return "timezone";
|
|
7009
|
-
case "grouping_func":
|
|
7010
|
-
return "grouping";
|
|
7011
|
-
case "subscript":
|
|
7012
|
-
return inferColumnName(e.base);
|
|
7013
|
-
default:
|
|
7014
|
-
return "?column?";
|
|
7015
|
-
}
|
|
7016
|
-
}
|
|
7017
|
-
|
|
7018
|
-
// src/api/bind.ts
|
|
7019
|
-
var INT4_MIN2 = -2147483648;
|
|
7020
|
-
var INT4_MAX2 = 2147483647;
|
|
7021
|
-
function bindValueToTyped(value, index) {
|
|
7022
|
-
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
7023
|
-
switch (typeof value) {
|
|
7024
|
-
case "boolean":
|
|
7025
|
-
return tv("bool", value);
|
|
7026
|
-
case "number":
|
|
7027
|
-
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
7028
|
-
return tv("int4", value);
|
|
7029
|
-
}
|
|
7030
|
-
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
7031
|
-
return tv("int8", BigInt(value));
|
|
7032
|
-
}
|
|
7033
|
-
return tv("float8", value);
|
|
7034
|
-
case "bigint":
|
|
7035
|
-
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
7036
|
-
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
7037
|
-
}
|
|
7038
|
-
return tv("int8", value);
|
|
7039
|
-
case "string":
|
|
7040
|
-
return tv(UNKNOWN, value);
|
|
7041
|
-
case "object": {
|
|
7042
|
-
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
7043
|
-
if (value instanceof Date) {
|
|
7044
|
-
const ms = value.getTime();
|
|
7045
|
-
if (Number.isNaN(ms)) {
|
|
7046
|
-
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
7047
|
-
}
|
|
7048
|
-
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
7049
|
-
}
|
|
7050
|
-
break;
|
|
7051
|
-
}
|
|
7052
|
-
default:
|
|
7053
|
-
break;
|
|
7054
|
-
}
|
|
7055
|
-
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
7056
|
-
}
|
|
7057
|
-
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
7058
|
-
if (v === null) return null;
|
|
7059
|
-
switch (t) {
|
|
7060
|
-
case "bool":
|
|
7061
|
-
return v;
|
|
7062
|
-
case "int2":
|
|
7063
|
-
case "int4":
|
|
7064
|
-
case "oid":
|
|
7065
|
-
return typeof v === "bigint" ? Number(v) : v;
|
|
7066
|
-
case "int8": {
|
|
7067
|
-
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
7068
|
-
if (int8 === "string") return n.toString();
|
|
7069
|
-
if (int8 === "number") return Number(n);
|
|
7070
|
-
return n;
|
|
7071
|
-
}
|
|
7072
|
-
case "float4":
|
|
7073
|
-
case "float8":
|
|
7074
|
-
return v;
|
|
7075
|
-
case "bytea":
|
|
7076
|
-
return v;
|
|
7077
|
-
default:
|
|
7078
|
-
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
7079
|
-
}
|
|
7080
|
-
}
|
|
7081
|
-
|
|
7082
7010
|
// src/functions/datetime-fns.ts
|
|
7083
7011
|
function extractDatePart(ctx, field0, src0, asNumeric) {
|
|
7084
7012
|
const field = field0.toLowerCase();
|
|
@@ -7499,6 +7427,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
|
|
|
7499
7427
|
case "int2":
|
|
7500
7428
|
case "int4":
|
|
7501
7429
|
case "oid":
|
|
7430
|
+
case "regclass":
|
|
7431
|
+
case "xid":
|
|
7502
7432
|
case "regnamespace":
|
|
7503
7433
|
case "date":
|
|
7504
7434
|
return expectNumber(a, t) - expectNumber(b, t);
|
|
@@ -7618,6 +7548,8 @@ function datumKey(t, v) {
|
|
|
7618
7548
|
case "int2":
|
|
7619
7549
|
case "int4":
|
|
7620
7550
|
case "oid":
|
|
7551
|
+
case "regclass":
|
|
7552
|
+
case "xid":
|
|
7621
7553
|
case "date":
|
|
7622
7554
|
return `i${v}`;
|
|
7623
7555
|
case "float4":
|
|
@@ -7993,68 +7925,6 @@ function getArrayFunctions() {
|
|
|
7993
7925
|
return m;
|
|
7994
7926
|
}
|
|
7995
7927
|
|
|
7996
|
-
// src/types/timezone.ts
|
|
7997
|
-
var intlCache = /* @__PURE__ */ new Map();
|
|
7998
|
-
function intlFor(zone) {
|
|
7999
|
-
const cached = intlCache.get(zone);
|
|
8000
|
-
if (cached) return cached;
|
|
8001
|
-
try {
|
|
8002
|
-
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
8003
|
-
timeZone: zone,
|
|
8004
|
-
timeZoneName: "longOffset",
|
|
8005
|
-
year: "numeric"
|
|
8006
|
-
});
|
|
8007
|
-
intlCache.set(zone, fmt);
|
|
8008
|
-
return fmt;
|
|
8009
|
-
} catch {
|
|
8010
|
-
return null;
|
|
8011
|
-
}
|
|
8012
|
-
}
|
|
8013
|
-
function parseFixedOffset(zone) {
|
|
8014
|
-
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
8015
|
-
if (!m) return null;
|
|
8016
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
8017
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
8018
|
-
}
|
|
8019
|
-
function parsePosixOffset(zone) {
|
|
8020
|
-
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
8021
|
-
if (!m) return null;
|
|
8022
|
-
const sign = m[1] === "-" ? 1 : -1;
|
|
8023
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
8024
|
-
}
|
|
8025
|
-
function pgMicrosToUnixMs(utcMicros) {
|
|
8026
|
-
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
8027
|
-
}
|
|
8028
|
-
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
8029
|
-
const z = zone.trim();
|
|
8030
|
-
const lower = z.toLowerCase();
|
|
8031
|
-
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
8032
|
-
const posix = parsePosixOffset(z);
|
|
8033
|
-
if (posix !== null) return posix;
|
|
8034
|
-
const fixed = parseFixedOffset(z);
|
|
8035
|
-
if (fixed !== null) return fixed;
|
|
8036
|
-
const fmt = intlFor(z);
|
|
8037
|
-
if (fmt) {
|
|
8038
|
-
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
8039
|
-
const parts = fmt.formatToParts(new Date(ms));
|
|
8040
|
-
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
8041
|
-
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
8042
|
-
if (!m) return 0;
|
|
8043
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
8044
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
8045
|
-
}
|
|
8046
|
-
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
8047
|
-
}
|
|
8048
|
-
function clampDateMs(ms) {
|
|
8049
|
-
const MAX = 864e13;
|
|
8050
|
-
return Math.max(-MAX, Math.min(MAX, ms));
|
|
8051
|
-
}
|
|
8052
|
-
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
8053
|
-
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
8054
|
-
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
8055
|
-
return second;
|
|
8056
|
-
}
|
|
8057
|
-
|
|
8058
7928
|
// src/functions/datetime-registry.ts
|
|
8059
7929
|
function getDatetimeFunctions() {
|
|
8060
7930
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -9654,6 +9524,28 @@ function exactDegTan(x) {
|
|
|
9654
9524
|
return Math.tan(x * Math.PI / 180);
|
|
9655
9525
|
}
|
|
9656
9526
|
|
|
9527
|
+
// src/storage/indexable-relation.ts
|
|
9528
|
+
function materializedTable(view) {
|
|
9529
|
+
const table = new TableData(
|
|
9530
|
+
view.schema,
|
|
9531
|
+
view.name,
|
|
9532
|
+
(view.matColumns ?? []).map((c) => ({
|
|
9533
|
+
name: c.name,
|
|
9534
|
+
type: { id: c.type, mod: null },
|
|
9535
|
+
notNull: false,
|
|
9536
|
+
defaultExpr: null,
|
|
9537
|
+
identity: null,
|
|
9538
|
+
generated: null,
|
|
9539
|
+
collate: null,
|
|
9540
|
+
domain: null
|
|
9541
|
+
})),
|
|
9542
|
+
view.oid,
|
|
9543
|
+
view.temp
|
|
9544
|
+
);
|
|
9545
|
+
table.rows = view.matRows ?? [];
|
|
9546
|
+
return table;
|
|
9547
|
+
}
|
|
9548
|
+
|
|
9657
9549
|
// src/schema/index-catalog.ts
|
|
9658
9550
|
var isKeyConstraint = (constraint) => constraint.kind === "primary_key" || constraint.kind === "unique";
|
|
9659
9551
|
var ACCESS_METHODS = /* @__PURE__ */ new Map([
|
|
@@ -9682,6 +9574,8 @@ function syncIndexCatalog(state) {
|
|
|
9682
9574
|
const tables = /* @__PURE__ */ new Map();
|
|
9683
9575
|
for (const schema of state.schemas.values()) {
|
|
9684
9576
|
for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
|
|
9577
|
+
for (const view of schema.views.values())
|
|
9578
|
+
if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
|
|
9685
9579
|
}
|
|
9686
9580
|
const backing = /* @__PURE__ */ new Map();
|
|
9687
9581
|
for (const { table } of tables.values()) {
|
|
@@ -9879,6 +9773,55 @@ function deparseExpr(e) {
|
|
|
9879
9773
|
}
|
|
9880
9774
|
}
|
|
9881
9775
|
|
|
9776
|
+
// src/types/resolve.ts
|
|
9777
|
+
var SERIALS = {
|
|
9778
|
+
smallserial: "int2",
|
|
9779
|
+
serial2: "int2",
|
|
9780
|
+
serial: "int4",
|
|
9781
|
+
serial4: "int4",
|
|
9782
|
+
bigserial: "int8",
|
|
9783
|
+
serial8: "int8"
|
|
9784
|
+
};
|
|
9785
|
+
function modOf(t, mods) {
|
|
9786
|
+
if (mods.length === 0) return null;
|
|
9787
|
+
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
9788
|
+
return { a: mods[0] };
|
|
9789
|
+
}
|
|
9790
|
+
function resolveTypeName(state, tn) {
|
|
9791
|
+
const joined = tn.parts.join(".");
|
|
9792
|
+
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
9793
|
+
if (bare !== null) {
|
|
9794
|
+
const serial = SERIALS[bare];
|
|
9795
|
+
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
9796
|
+
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
9797
|
+
}
|
|
9798
|
+
const builtin = normalizeTypeName(bare);
|
|
9799
|
+
if (builtin !== null) {
|
|
9800
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
9801
|
+
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
9802
|
+
}
|
|
9803
|
+
}
|
|
9804
|
+
const enumData = state.findEnum(tn.parts);
|
|
9805
|
+
if (enumData) {
|
|
9806
|
+
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
9807
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
9808
|
+
return { column: { id, mod: null }, domain: null, serial: null };
|
|
9809
|
+
}
|
|
9810
|
+
const domainData = state.findDomain(tn.parts);
|
|
9811
|
+
if (domainData) {
|
|
9812
|
+
if (tn.arrayDims > 0) {
|
|
9813
|
+
const id = arrayTypeOf(domainData.baseType.id);
|
|
9814
|
+
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
9815
|
+
}
|
|
9816
|
+
return {
|
|
9817
|
+
column: domainData.baseType,
|
|
9818
|
+
domain: `${domainData.schema}.${domainData.name}`,
|
|
9819
|
+
serial: null
|
|
9820
|
+
};
|
|
9821
|
+
}
|
|
9822
|
+
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
9823
|
+
}
|
|
9824
|
+
|
|
9882
9825
|
// src/sql/ruleutils.ts
|
|
9883
9826
|
var BOOL = "bool";
|
|
9884
9827
|
var TEXT = "text";
|
|
@@ -10512,7 +10455,7 @@ function databaseCatalogContext(state) {
|
|
|
10512
10455
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
10513
10456
|
function findSequenceForCall(ctx, name) {
|
|
10514
10457
|
const parts = parseQualifiedName(name);
|
|
10515
|
-
const seq = ctx.state.findSequence(parts);
|
|
10458
|
+
const seq = /^\d+$/.test(name) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name)) : ctx.state.findSequence(parts);
|
|
10516
10459
|
if (!seq) {
|
|
10517
10460
|
throw pgError("undefined_table", `relation "${name}" does not exist`, "42P01");
|
|
10518
10461
|
}
|
|
@@ -10673,7 +10616,11 @@ function getMiscFunctions() {
|
|
|
10673
10616
|
}
|
|
10674
10617
|
const name = argText(ctx, args[0]).toLowerCase();
|
|
10675
10618
|
const value = args[1].v === null ? "" : argText(ctx, args[1]);
|
|
10676
|
-
ctx.state.settings.
|
|
10619
|
+
if (!ctx.state.settings.has(name) && !name.includes("."))
|
|
10620
|
+
throw pgError("undefined_object", `unrecognized configuration parameter "${name}"`, "42704");
|
|
10621
|
+
validateStorageSetting(name, value);
|
|
10622
|
+
const local = args[2]?.v === true;
|
|
10623
|
+
if (!local || ctx.state.inTransaction) (local ? ctx.state.localSettings : ctx.state.settings).set(name, value);
|
|
10677
10624
|
return tv("text", value);
|
|
10678
10625
|
});
|
|
10679
10626
|
m.set(
|
|
@@ -10732,17 +10679,16 @@ function getMiscFunctions() {
|
|
|
10732
10679
|
"pg_get_serial_sequence",
|
|
10733
10680
|
strict("text", (ctx, args) => {
|
|
10734
10681
|
const tableName2 = argText(ctx, args[0]);
|
|
10735
|
-
const column = argText(ctx, args[1])
|
|
10682
|
+
const column = argText(ctx, args[1]);
|
|
10736
10683
|
const table = ctx.state.findTable(parseQualifiedName(tableName2));
|
|
10737
10684
|
if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
|
|
10738
10685
|
const col = table.columns.find((c) => c.name === column);
|
|
10739
10686
|
if (!col)
|
|
10740
10687
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
"text",
|
|
10744
|
-
col.identity.sequence.split(".").map(quoteIdent).join(".")
|
|
10688
|
+
const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
|
|
10689
|
+
(candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
|
|
10745
10690
|
);
|
|
10691
|
+
return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
|
|
10746
10692
|
})
|
|
10747
10693
|
);
|
|
10748
10694
|
m.set("format_type", (ctx, args) => {
|
|
@@ -15666,6 +15612,146 @@ function isSrfName(name) {
|
|
|
15666
15612
|
return SRFS.has(name);
|
|
15667
15613
|
}
|
|
15668
15614
|
|
|
15615
|
+
// src/executor/relation.ts
|
|
15616
|
+
var RowScope = class {
|
|
15617
|
+
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
15618
|
+
this.columns = columns;
|
|
15619
|
+
this.row = row;
|
|
15620
|
+
this.parent = parent;
|
|
15621
|
+
this.rangeVars = rangeVars;
|
|
15622
|
+
}
|
|
15623
|
+
columns;
|
|
15624
|
+
row;
|
|
15625
|
+
parent;
|
|
15626
|
+
rangeVars;
|
|
15627
|
+
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
15628
|
+
lookup(parts) {
|
|
15629
|
+
if (parts.length === 1) {
|
|
15630
|
+
const name2 = parts[0];
|
|
15631
|
+
let found2;
|
|
15632
|
+
let count3 = 0;
|
|
15633
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
15634
|
+
const c = this.columns[i];
|
|
15635
|
+
if (c.name === name2 && (!c.hidden || c.system)) {
|
|
15636
|
+
count3++;
|
|
15637
|
+
if (count3 > 1) {
|
|
15638
|
+
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
15639
|
+
}
|
|
15640
|
+
found2 = tv(c.type, this.row[i] ?? null);
|
|
15641
|
+
}
|
|
15642
|
+
}
|
|
15643
|
+
if (found2 !== void 0) return found2;
|
|
15644
|
+
if (this.rangeVars.has(name2)) {
|
|
15645
|
+
return this.wholeRow(name2);
|
|
15646
|
+
}
|
|
15647
|
+
return this.parent?.lookup(parts);
|
|
15648
|
+
}
|
|
15649
|
+
const table = parts[parts.length - 2];
|
|
15650
|
+
const name = parts[parts.length - 1];
|
|
15651
|
+
let found;
|
|
15652
|
+
let count2 = 0;
|
|
15653
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
15654
|
+
const c = this.columns[i];
|
|
15655
|
+
if (c.table === table && c.name === name) {
|
|
15656
|
+
count2++;
|
|
15657
|
+
if (count2 > 1) {
|
|
15658
|
+
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
15659
|
+
}
|
|
15660
|
+
found = tv(c.type, this.row[i] ?? null);
|
|
15661
|
+
}
|
|
15662
|
+
}
|
|
15663
|
+
if (found !== void 0) return found;
|
|
15664
|
+
return this.parent?.lookup(parts);
|
|
15665
|
+
}
|
|
15666
|
+
/** Build a record value from all columns belonging to a range variable. */
|
|
15667
|
+
wholeRow(rangeVar) {
|
|
15668
|
+
const types = [];
|
|
15669
|
+
const values = [];
|
|
15670
|
+
const names = [];
|
|
15671
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
15672
|
+
const c = this.columns[i];
|
|
15673
|
+
if (c.table === rangeVar && !c.system) {
|
|
15674
|
+
types.push(c.type);
|
|
15675
|
+
values.push(this.row[i] ?? null);
|
|
15676
|
+
names.push(c.name);
|
|
15677
|
+
}
|
|
15678
|
+
}
|
|
15679
|
+
if (types.length === 0) return void 0;
|
|
15680
|
+
return tv("record", { kind: "pgrecord", types, values, names });
|
|
15681
|
+
}
|
|
15682
|
+
hasRangeVar(name) {
|
|
15683
|
+
if (this.rangeVars.has(name)) return true;
|
|
15684
|
+
return this.parent?.hasRangeVar(name) ?? false;
|
|
15685
|
+
}
|
|
15686
|
+
};
|
|
15687
|
+
function childEnv(env, outer) {
|
|
15688
|
+
return {
|
|
15689
|
+
ctx: env.ctx,
|
|
15690
|
+
params: env.params,
|
|
15691
|
+
ctes: env.ctes,
|
|
15692
|
+
outer,
|
|
15693
|
+
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
15694
|
+
};
|
|
15695
|
+
}
|
|
15696
|
+
function relationResult(rel3, command) {
|
|
15697
|
+
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
15698
|
+
return {
|
|
15699
|
+
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
15700
|
+
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
15701
|
+
command,
|
|
15702
|
+
rowCount: rel3.rows.length
|
|
15703
|
+
};
|
|
15704
|
+
}
|
|
15705
|
+
function commandResult(command, rowCount) {
|
|
15706
|
+
return { columns: [], rows: [], command, rowCount };
|
|
15707
|
+
}
|
|
15708
|
+
function inferColumnName(e) {
|
|
15709
|
+
switch (e.type) {
|
|
15710
|
+
case "colref":
|
|
15711
|
+
return e.parts[e.parts.length - 1];
|
|
15712
|
+
case "func":
|
|
15713
|
+
return e.name[e.name.length - 1];
|
|
15714
|
+
case "cast": {
|
|
15715
|
+
const inner = inferColumnName(e.expr);
|
|
15716
|
+
if (inner !== "?column?") return inner;
|
|
15717
|
+
return e.target.parts[e.target.parts.length - 1];
|
|
15718
|
+
}
|
|
15719
|
+
case "collate":
|
|
15720
|
+
return inferColumnName(e.expr);
|
|
15721
|
+
case "case":
|
|
15722
|
+
return "case";
|
|
15723
|
+
case "array_ctor":
|
|
15724
|
+
case "array_query":
|
|
15725
|
+
return "array";
|
|
15726
|
+
case "row":
|
|
15727
|
+
return "row";
|
|
15728
|
+
case "subquery_expr":
|
|
15729
|
+
return e.kind === "exists" ? "exists" : "?column?";
|
|
15730
|
+
case "bool_lit":
|
|
15731
|
+
return "bool";
|
|
15732
|
+
case "extract":
|
|
15733
|
+
return "extract";
|
|
15734
|
+
case "position":
|
|
15735
|
+
return "position";
|
|
15736
|
+
case "substring_sql":
|
|
15737
|
+
return "substring";
|
|
15738
|
+
case "overlay":
|
|
15739
|
+
return "overlay";
|
|
15740
|
+
case "trim":
|
|
15741
|
+
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
15742
|
+
case "field_select":
|
|
15743
|
+
return e.field === "*" ? "?column?" : e.field;
|
|
15744
|
+
case "at_time_zone":
|
|
15745
|
+
return "timezone";
|
|
15746
|
+
case "grouping_func":
|
|
15747
|
+
return "grouping";
|
|
15748
|
+
case "subscript":
|
|
15749
|
+
return inferColumnName(e.base);
|
|
15750
|
+
default:
|
|
15751
|
+
return "?column?";
|
|
15752
|
+
}
|
|
15753
|
+
}
|
|
15754
|
+
|
|
15669
15755
|
// src/indexes/index.ts
|
|
15670
15756
|
var IndexStore = class _IndexStore {
|
|
15671
15757
|
name;
|
|
@@ -15728,53 +15814,228 @@ function ensureIndexStores(env, table) {
|
|
|
15728
15814
|
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
15729
15815
|
if (key !== null) store.insert(key, i);
|
|
15730
15816
|
}
|
|
15731
|
-
stores.set(spec.name, store);
|
|
15732
|
-
}
|
|
15733
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
15734
|
-
if (schema) {
|
|
15735
|
-
for (const idx of schema.indexes.values()) {
|
|
15736
|
-
if (idx.table !== table.name || idx.unique) continue;
|
|
15737
|
-
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
15817
|
+
stores.set(spec.name, store);
|
|
15818
|
+
}
|
|
15819
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
15820
|
+
if (schema) {
|
|
15821
|
+
for (const idx of schema.indexes.values()) {
|
|
15822
|
+
if (idx.table !== table.name || idx.unique) continue;
|
|
15823
|
+
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
15824
|
+
}
|
|
15825
|
+
}
|
|
15826
|
+
table.indexStores = stores;
|
|
15827
|
+
return stores;
|
|
15828
|
+
}
|
|
15829
|
+
function indexStoreFor(env, table, spec) {
|
|
15830
|
+
const stores = ensureIndexStores(env, table);
|
|
15831
|
+
let store = stores.get(spec.name);
|
|
15832
|
+
if (!store) {
|
|
15833
|
+
store = new IndexStore(spec.name, true);
|
|
15834
|
+
for (let i = 0; i < table.rowCount(); i++) {
|
|
15835
|
+
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
15836
|
+
if (key !== null) store.insert(key, i);
|
|
15837
|
+
}
|
|
15838
|
+
stores.set(spec.name, store);
|
|
15839
|
+
}
|
|
15840
|
+
return store;
|
|
15841
|
+
}
|
|
15842
|
+
function indexInsertRow(env, table, rowIdx, row) {
|
|
15843
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15844
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15845
|
+
if (key === null) continue;
|
|
15846
|
+
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
15847
|
+
}
|
|
15848
|
+
}
|
|
15849
|
+
function indexRemoveRow(env, table, rowIdx, row) {
|
|
15850
|
+
if (!table.indexStores) return;
|
|
15851
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15852
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15853
|
+
if (key === null) continue;
|
|
15854
|
+
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
15855
|
+
}
|
|
15856
|
+
}
|
|
15857
|
+
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
15858
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
15859
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
15860
|
+
}
|
|
15861
|
+
function rebuildTableIndexes(env, table) {
|
|
15862
|
+
table.indexStores = null;
|
|
15863
|
+
ensureIndexStores(env, table);
|
|
15864
|
+
}
|
|
15865
|
+
|
|
15866
|
+
// src/constraints/enforce.ts
|
|
15867
|
+
function tableScope(table, row) {
|
|
15868
|
+
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
15869
|
+
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
15870
|
+
}
|
|
15871
|
+
function checkNotNull(env, table, row) {
|
|
15872
|
+
void env;
|
|
15873
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
15874
|
+
const c = table.columns[i];
|
|
15875
|
+
if (c.notNull && (row[i] ?? null) === null) {
|
|
15876
|
+
throw pgError(
|
|
15877
|
+
"not_null_violation",
|
|
15878
|
+
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
15879
|
+
"23502"
|
|
15880
|
+
);
|
|
15881
|
+
}
|
|
15882
|
+
}
|
|
15883
|
+
}
|
|
15884
|
+
function checkChecks(env, table, row) {
|
|
15885
|
+
for (const con of table.constraints) {
|
|
15886
|
+
if (con.kind !== "check") continue;
|
|
15887
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
15888
|
+
const v = evalExpr(env.ctx, scope, con.expr);
|
|
15889
|
+
if (v.v === null) continue;
|
|
15890
|
+
const b = castTo(env.ctx, v, "bool", {});
|
|
15891
|
+
if (b.v !== true) {
|
|
15892
|
+
throw pgError(
|
|
15893
|
+
"check_violation",
|
|
15894
|
+
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
15895
|
+
"23514"
|
|
15896
|
+
);
|
|
15897
|
+
}
|
|
15898
|
+
}
|
|
15899
|
+
}
|
|
15900
|
+
function uniqueSpecsFor(env, table) {
|
|
15901
|
+
const specs = [];
|
|
15902
|
+
for (const con of table.constraints) {
|
|
15903
|
+
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
15904
|
+
specs.push({
|
|
15905
|
+
name: con.name,
|
|
15906
|
+
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
15907
|
+
columnNames: con.columns,
|
|
15908
|
+
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
15909
|
+
where: null,
|
|
15910
|
+
isPrimary: con.kind === "primary_key"
|
|
15911
|
+
});
|
|
15912
|
+
}
|
|
15913
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
15914
|
+
if (schema) {
|
|
15915
|
+
for (const idx of schema.indexes.values()) {
|
|
15916
|
+
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
15917
|
+
specs.push(uniqueSpecOfIndex(table, idx));
|
|
15918
|
+
}
|
|
15919
|
+
}
|
|
15920
|
+
return specs;
|
|
15921
|
+
}
|
|
15922
|
+
function uniqueSpecOfIndex(table, idx) {
|
|
15923
|
+
return {
|
|
15924
|
+
name: idx.name,
|
|
15925
|
+
keys: idx.columns.map((c) => ({
|
|
15926
|
+
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
15927
|
+
expr: c.expr
|
|
15928
|
+
})),
|
|
15929
|
+
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
15930
|
+
nullsNotDistinct: idx.nullsNotDistinct,
|
|
15931
|
+
where: idx.where,
|
|
15932
|
+
isPrimary: false
|
|
15933
|
+
};
|
|
15934
|
+
}
|
|
15935
|
+
function uniqueKeyOf(env, table, spec, row) {
|
|
15936
|
+
if (spec.where) {
|
|
15937
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
15938
|
+
const v = evalExpr(env.ctx, scope, spec.where);
|
|
15939
|
+
if (v.v !== true) return null;
|
|
15940
|
+
}
|
|
15941
|
+
const parts = [];
|
|
15942
|
+
let hasNull = false;
|
|
15943
|
+
for (const k of spec.keys) {
|
|
15944
|
+
let value;
|
|
15945
|
+
let type;
|
|
15946
|
+
if (k.expr) {
|
|
15947
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
15948
|
+
const v = evalExpr(env.ctx, scope, k.expr);
|
|
15949
|
+
value = v.v;
|
|
15950
|
+
type = v.t === "unknown" ? "text" : v.t;
|
|
15951
|
+
} else {
|
|
15952
|
+
value = row[k.colIdx] ?? null;
|
|
15953
|
+
type = table.columns[k.colIdx].type.id;
|
|
15954
|
+
}
|
|
15955
|
+
if (value === null) {
|
|
15956
|
+
hasNull = true;
|
|
15957
|
+
parts.push("\0N");
|
|
15958
|
+
} else {
|
|
15959
|
+
parts.push(datumKey(type, value));
|
|
15960
|
+
}
|
|
15961
|
+
}
|
|
15962
|
+
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
15963
|
+
return parts.join("");
|
|
15964
|
+
}
|
|
15965
|
+
function checkUnique(env, table, row, selfIdx) {
|
|
15966
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15967
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15968
|
+
if (key === null) continue;
|
|
15969
|
+
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
15970
|
+
}
|
|
15971
|
+
}
|
|
15972
|
+
function findConflict(env, table, spec, row) {
|
|
15973
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15974
|
+
if (key === null) return null;
|
|
15975
|
+
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
15976
|
+
return hits.length > 0 ? hits[0] : null;
|
|
15977
|
+
}
|
|
15978
|
+
function checkForeignKeys(env, table, row) {
|
|
15979
|
+
const state = env.ctx.state;
|
|
15980
|
+
for (const con of table.constraints) {
|
|
15981
|
+
if (con.kind !== "foreign_key") continue;
|
|
15982
|
+
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
15983
|
+
const nulls = values.filter((v) => v === null).length;
|
|
15984
|
+
if (con.match === "simple" && nulls > 0) continue;
|
|
15985
|
+
if (con.match === "full") {
|
|
15986
|
+
if (nulls === values.length) continue;
|
|
15987
|
+
if (nulls > 0) {
|
|
15988
|
+
throw pgError(
|
|
15989
|
+
"constraint_foreign_key",
|
|
15990
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
15991
|
+
"23503"
|
|
15992
|
+
);
|
|
15993
|
+
}
|
|
15994
|
+
}
|
|
15995
|
+
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
15996
|
+
if (!refTable) {
|
|
15997
|
+
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
15998
|
+
}
|
|
15999
|
+
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
16000
|
+
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
16001
|
+
const wanted = values.map((v, i) => {
|
|
16002
|
+
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
16003
|
+
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
16004
|
+
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
16005
|
+
}).join("");
|
|
16006
|
+
let found = false;
|
|
16007
|
+
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
16008
|
+
const r = refTable.rowAt(i);
|
|
16009
|
+
const key = refIdxs.map((ri, j) => {
|
|
16010
|
+
const v = r[ri] ?? null;
|
|
16011
|
+
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
16012
|
+
}).join("");
|
|
16013
|
+
if (key === wanted) {
|
|
16014
|
+
found = true;
|
|
16015
|
+
break;
|
|
16016
|
+
}
|
|
16017
|
+
}
|
|
16018
|
+
if (!found) {
|
|
16019
|
+
throw pgError(
|
|
16020
|
+
"constraint_foreign_key",
|
|
16021
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
16022
|
+
"23503"
|
|
16023
|
+
);
|
|
15738
16024
|
}
|
|
15739
16025
|
}
|
|
15740
|
-
table.indexStores = stores;
|
|
15741
|
-
return stores;
|
|
15742
16026
|
}
|
|
15743
|
-
function
|
|
15744
|
-
const
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
16027
|
+
function referencingConstraints(env, table) {
|
|
16028
|
+
const out = [];
|
|
16029
|
+
for (const schema of env.ctx.state.schemas.values()) {
|
|
16030
|
+
for (const t of schema.tables.values()) {
|
|
16031
|
+
for (const con of t.constraints) {
|
|
16032
|
+
if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
|
|
16033
|
+
out.push({ table: t, constraint: con });
|
|
16034
|
+
}
|
|
16035
|
+
}
|
|
15751
16036
|
}
|
|
15752
|
-
stores.set(spec.name, store);
|
|
15753
|
-
}
|
|
15754
|
-
return store;
|
|
15755
|
-
}
|
|
15756
|
-
function indexInsertRow(env, table, rowIdx, row) {
|
|
15757
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15758
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
15759
|
-
if (key === null) continue;
|
|
15760
|
-
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
15761
|
-
}
|
|
15762
|
-
}
|
|
15763
|
-
function indexRemoveRow(env, table, rowIdx, row) {
|
|
15764
|
-
if (!table.indexStores) return;
|
|
15765
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15766
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
15767
|
-
if (key === null) continue;
|
|
15768
|
-
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
15769
16037
|
}
|
|
15770
|
-
|
|
15771
|
-
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
15772
|
-
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
15773
|
-
indexInsertRow(env, table, rowIdx, newRow);
|
|
15774
|
-
}
|
|
15775
|
-
function rebuildTableIndexes(env, table) {
|
|
15776
|
-
table.indexStores = null;
|
|
15777
|
-
ensureIndexStores(env, table);
|
|
16038
|
+
return out;
|
|
15778
16039
|
}
|
|
15779
16040
|
|
|
15780
16041
|
// src/planner/access.ts
|
|
@@ -15852,7 +16113,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
15852
16113
|
if (!table) return null;
|
|
15853
16114
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
15854
16115
|
table.materializeSlab();
|
|
15855
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
16116
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
15856
16117
|
}
|
|
15857
16118
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
15858
16119
|
const parts = [];
|
|
@@ -17660,10 +17921,9 @@ var Parser = class {
|
|
|
17660
17921
|
return this.parseCreateFunction(orReplace);
|
|
17661
17922
|
}
|
|
17662
17923
|
if (this.atKw("trigger") || this.atKw("constraint") && this.atKw("trigger", 1)) {
|
|
17663
|
-
|
|
17664
|
-
}
|
|
17924
|
+
const constraint = this.eatKw("constraint");
|
|
17665
17925
|
this.expectKw("trigger");
|
|
17666
|
-
return this.parseCreateTrigger(orReplace);
|
|
17926
|
+
return this.parseCreateTrigger(orReplace, constraint);
|
|
17667
17927
|
}
|
|
17668
17928
|
if (this.atKw("extension")) {
|
|
17669
17929
|
this.pos++;
|
|
@@ -18343,6 +18603,7 @@ var Parser = class {
|
|
|
18343
18603
|
let sqlBody = null;
|
|
18344
18604
|
let volatility = null;
|
|
18345
18605
|
let strict2 = false;
|
|
18606
|
+
const settings = {};
|
|
18346
18607
|
for (; ; ) {
|
|
18347
18608
|
if (this.eatKw("language")) {
|
|
18348
18609
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -18400,8 +18661,23 @@ var Parser = class {
|
|
|
18400
18661
|
continue;
|
|
18401
18662
|
}
|
|
18402
18663
|
if (this.eatKw("set")) {
|
|
18403
|
-
this.ident(true);
|
|
18404
|
-
if (this.
|
|
18664
|
+
const key = this.ident(true).toLowerCase();
|
|
18665
|
+
if (this.eatKw("from")) {
|
|
18666
|
+
this.expectKw("current");
|
|
18667
|
+
settings[key] = "__from_current__";
|
|
18668
|
+
} else {
|
|
18669
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
18670
|
+
const values = [];
|
|
18671
|
+
do {
|
|
18672
|
+
const value = this.next();
|
|
18673
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
18674
|
+
this.errorAt(value, "expected setting value");
|
|
18675
|
+
values.push(
|
|
18676
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
18677
|
+
);
|
|
18678
|
+
} while (this.eatPunct(","));
|
|
18679
|
+
settings[key] = values.join(", ");
|
|
18680
|
+
}
|
|
18405
18681
|
continue;
|
|
18406
18682
|
}
|
|
18407
18683
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -18481,10 +18757,11 @@ var Parser = class {
|
|
|
18481
18757
|
body,
|
|
18482
18758
|
sqlBody,
|
|
18483
18759
|
volatility,
|
|
18484
|
-
strict: strict2
|
|
18760
|
+
strict: strict2,
|
|
18761
|
+
settings
|
|
18485
18762
|
};
|
|
18486
18763
|
}
|
|
18487
|
-
parseCreateTrigger(orReplace) {
|
|
18764
|
+
parseCreateTrigger(orReplace, constraint) {
|
|
18488
18765
|
const name = this.ident();
|
|
18489
18766
|
let timing;
|
|
18490
18767
|
if (this.eatKw("before")) timing = "before";
|
|
@@ -18514,9 +18791,18 @@ var Parser = class {
|
|
|
18514
18791
|
this.expectKw("on");
|
|
18515
18792
|
const table = this.qualifiedName();
|
|
18516
18793
|
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18794
|
+
let deferrable = false;
|
|
18795
|
+
let initiallyDeferred = false;
|
|
18796
|
+
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
18797
|
+
else if (this.eatKw("deferrable")) deferrable = true;
|
|
18798
|
+
if (this.eatKw("initially")) {
|
|
18799
|
+
if (this.eatKw("deferred")) initiallyDeferred = true;
|
|
18800
|
+
else this.expectKw("immediate");
|
|
18801
|
+
}
|
|
18802
|
+
if ((deferrable || initiallyDeferred) && !constraint)
|
|
18803
|
+
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
18804
|
+
if (initiallyDeferred && !deferrable)
|
|
18805
|
+
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
18520
18806
|
let forEachRow = false;
|
|
18521
18807
|
if (this.eatKw("for")) {
|
|
18522
18808
|
this.eatKw("each");
|
|
@@ -18541,7 +18827,21 @@ var Parser = class {
|
|
|
18541
18827
|
} while (this.eatPunct(","));
|
|
18542
18828
|
}
|
|
18543
18829
|
this.expectPunct(")");
|
|
18544
|
-
return {
|
|
18830
|
+
return {
|
|
18831
|
+
type: "create_trigger",
|
|
18832
|
+
constraint,
|
|
18833
|
+
deferrable,
|
|
18834
|
+
initiallyDeferred,
|
|
18835
|
+
orReplace,
|
|
18836
|
+
name,
|
|
18837
|
+
timing,
|
|
18838
|
+
events,
|
|
18839
|
+
table,
|
|
18840
|
+
forEachRow,
|
|
18841
|
+
when,
|
|
18842
|
+
funcName,
|
|
18843
|
+
funcArgs
|
|
18844
|
+
};
|
|
18545
18845
|
}
|
|
18546
18846
|
// --- ALTER --------------------------------------------------------------------
|
|
18547
18847
|
parseAlter() {
|
|
@@ -18567,8 +18867,8 @@ var Parser = class {
|
|
|
18567
18867
|
type: "alter_sequence",
|
|
18568
18868
|
name,
|
|
18569
18869
|
ifExists,
|
|
18570
|
-
options: {
|
|
18571
|
-
|
|
18870
|
+
options: {},
|
|
18871
|
+
renameTo: to
|
|
18572
18872
|
};
|
|
18573
18873
|
}
|
|
18574
18874
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -18886,9 +19186,15 @@ var Parser = class {
|
|
|
18886
19186
|
this.skipToStatementEnd();
|
|
18887
19187
|
return { type: "no_op", what: "SET TRANSACTION" };
|
|
18888
19188
|
}
|
|
18889
|
-
if (this.
|
|
18890
|
-
this.
|
|
18891
|
-
|
|
19189
|
+
if (this.eatKw("constraints")) {
|
|
19190
|
+
const names = this.eatKw("all") ? null : [];
|
|
19191
|
+
if (names)
|
|
19192
|
+
do {
|
|
19193
|
+
names.push(this.qualifiedName());
|
|
19194
|
+
} while (this.eatPunct(","));
|
|
19195
|
+
const deferred = this.eatKw("deferred");
|
|
19196
|
+
if (!deferred) this.expectKw("immediate");
|
|
19197
|
+
return { type: "set_constraints", names, deferred };
|
|
18892
19198
|
}
|
|
18893
19199
|
if (this.atKw("role") || this.atKw("session", 0) && this.atKw("authorization", 1)) {
|
|
18894
19200
|
this.skipToStatementEnd();
|
|
@@ -21138,7 +21444,20 @@ function runFunctionBody(env, fn, args) {
|
|
|
21138
21444
|
}
|
|
21139
21445
|
return last;
|
|
21140
21446
|
}
|
|
21447
|
+
function withFunctionSettings(env, fn, run) {
|
|
21448
|
+
const state = env.ctx.state;
|
|
21449
|
+
const saved = new Map(state.localSettings);
|
|
21450
|
+
for (const [name, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name, value);
|
|
21451
|
+
try {
|
|
21452
|
+
return run();
|
|
21453
|
+
} finally {
|
|
21454
|
+
state.localSettings = saved;
|
|
21455
|
+
}
|
|
21456
|
+
}
|
|
21141
21457
|
function callSqlFunctionScalar(env, fn, args) {
|
|
21458
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args));
|
|
21459
|
+
}
|
|
21460
|
+
function callSqlFunctionScalarBody(env, fn, args) {
|
|
21142
21461
|
const retT = fn.returns ?? "text";
|
|
21143
21462
|
if (fn.language === "plpgsql") {
|
|
21144
21463
|
return callPlpgsqlScalar(env, fn, args);
|
|
@@ -21168,6 +21487,9 @@ function callSqlFunctionScalar(env, fn, args) {
|
|
|
21168
21487
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
21169
21488
|
}
|
|
21170
21489
|
function callSqlFunctionSet(env, fn, args) {
|
|
21490
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args));
|
|
21491
|
+
}
|
|
21492
|
+
function callSqlFunctionSetBody(env, fn, args) {
|
|
21171
21493
|
if (fn.language === "plpgsql") {
|
|
21172
21494
|
return callPlpgsqlSet(env, fn, args);
|
|
21173
21495
|
}
|
|
@@ -21263,12 +21585,12 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
21263
21585
|
table: null
|
|
21264
21586
|
}));
|
|
21265
21587
|
const seen = /* @__PURE__ */ new Set();
|
|
21266
|
-
const
|
|
21588
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
|
|
21267
21589
|
let result = [];
|
|
21268
21590
|
let working = [];
|
|
21269
21591
|
for (const row of base.rows) {
|
|
21270
21592
|
if (!body.all) {
|
|
21271
|
-
const k =
|
|
21593
|
+
const k = keyOf2(row);
|
|
21272
21594
|
if (seen.has(k)) continue;
|
|
21273
21595
|
seen.add(k);
|
|
21274
21596
|
}
|
|
@@ -21301,7 +21623,7 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
21301
21623
|
return castTo(env.ctx, tv(srcT === UNKNOWN ? "text" : srcT, v), columns[i].type, {}).v;
|
|
21302
21624
|
});
|
|
21303
21625
|
if (!body.all) {
|
|
21304
|
-
const k =
|
|
21626
|
+
const k = keyOf2(row);
|
|
21305
21627
|
if (seen.has(k)) continue;
|
|
21306
21628
|
seen.add(k);
|
|
21307
21629
|
}
|
|
@@ -21322,15 +21644,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
21322
21644
|
return rel3;
|
|
21323
21645
|
}
|
|
21324
21646
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
21325
|
-
|
|
21647
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
21648
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
21326
21649
|
throw pgError(
|
|
21327
21650
|
"invalid_column_reference",
|
|
21328
|
-
`table "${what}" has ${
|
|
21651
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
21329
21652
|
"42P10"
|
|
21330
21653
|
);
|
|
21331
21654
|
}
|
|
21332
21655
|
const columns = rel3.columns.map((c, i) => ({
|
|
21333
|
-
|
|
21656
|
+
...c,
|
|
21657
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
21334
21658
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
21335
21659
|
table: label
|
|
21336
21660
|
}));
|
|
@@ -21351,8 +21675,11 @@ function materializeItem(env, item, scope) {
|
|
|
21351
21675
|
if (table) {
|
|
21352
21676
|
table.materializeSlab();
|
|
21353
21677
|
const rel3 = {
|
|
21354
|
-
columns:
|
|
21355
|
-
|
|
21678
|
+
columns: [
|
|
21679
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
21680
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
21681
|
+
],
|
|
21682
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
21356
21683
|
};
|
|
21357
21684
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
21358
21685
|
}
|
|
@@ -21982,7 +22309,7 @@ function resolveColIdx(columns, parts) {
|
|
|
21982
22309
|
let found = -1;
|
|
21983
22310
|
for (let i = 0; i < columns.length; i++) {
|
|
21984
22311
|
const c = columns[i];
|
|
21985
|
-
if (!c.hidden && c.name === name2) {
|
|
22312
|
+
if ((!c.hidden || c.system) && c.name === name2) {
|
|
21986
22313
|
if (found !== -1) return null;
|
|
21987
22314
|
found = i;
|
|
21988
22315
|
}
|
|
@@ -22481,7 +22808,7 @@ function setOpRelation(env, op) {
|
|
|
22481
22808
|
);
|
|
22482
22809
|
const lrows = normalize(left);
|
|
22483
22810
|
const rrows = normalize(right);
|
|
22484
|
-
const
|
|
22811
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
|
|
22485
22812
|
let rows;
|
|
22486
22813
|
switch (op.op) {
|
|
22487
22814
|
case "union": {
|
|
@@ -22489,7 +22816,7 @@ function setOpRelation(env, op) {
|
|
|
22489
22816
|
if (!op.all) {
|
|
22490
22817
|
const seen = /* @__PURE__ */ new Set();
|
|
22491
22818
|
rows = rows.filter((r) => {
|
|
22492
|
-
const k =
|
|
22819
|
+
const k = keyOf2(r);
|
|
22493
22820
|
if (seen.has(k)) return false;
|
|
22494
22821
|
seen.add(k);
|
|
22495
22822
|
return true;
|
|
@@ -22500,13 +22827,13 @@ function setOpRelation(env, op) {
|
|
|
22500
22827
|
case "intersect": {
|
|
22501
22828
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
22502
22829
|
for (const r of rrows) {
|
|
22503
|
-
const k =
|
|
22830
|
+
const k = keyOf2(r);
|
|
22504
22831
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
22505
22832
|
}
|
|
22506
22833
|
rows = [];
|
|
22507
22834
|
const emitted = /* @__PURE__ */ new Set();
|
|
22508
22835
|
for (const r of lrows) {
|
|
22509
|
-
const k =
|
|
22836
|
+
const k = keyOf2(r);
|
|
22510
22837
|
const avail = rightCounts.get(k) ?? 0;
|
|
22511
22838
|
if (avail <= 0) continue;
|
|
22512
22839
|
if (op.all) {
|
|
@@ -22522,13 +22849,13 @@ function setOpRelation(env, op) {
|
|
|
22522
22849
|
case "except": {
|
|
22523
22850
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
22524
22851
|
for (const r of rrows) {
|
|
22525
|
-
const k =
|
|
22852
|
+
const k = keyOf2(r);
|
|
22526
22853
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
22527
22854
|
}
|
|
22528
22855
|
rows = [];
|
|
22529
22856
|
const emitted = /* @__PURE__ */ new Set();
|
|
22530
22857
|
for (const r of lrows) {
|
|
22531
|
-
const k =
|
|
22858
|
+
const k = keyOf2(r);
|
|
22532
22859
|
if (op.all) {
|
|
22533
22860
|
const avail = rightCounts.get(k) ?? 0;
|
|
22534
22861
|
if (avail > 0) {
|
|
@@ -22566,7 +22893,7 @@ function expandTargets(core, columns) {
|
|
|
22566
22893
|
let any = false;
|
|
22567
22894
|
for (let i = 0; i < columns.length; i++) {
|
|
22568
22895
|
const c = columns[i];
|
|
22569
|
-
if (c.table === label) {
|
|
22896
|
+
if (c.table === label && !c.system) {
|
|
22570
22897
|
any = true;
|
|
22571
22898
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
22572
22899
|
}
|
|
@@ -22998,185 +23325,32 @@ function executeSelectStmt(env0, stmt) {
|
|
|
22998
23325
|
if (stmt.orderBy.length === 0) {
|
|
22999
23326
|
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
23000
23327
|
}
|
|
23001
|
-
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
23002
|
-
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
23003
|
-
}
|
|
23004
|
-
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
23005
|
-
}
|
|
23006
|
-
|
|
23007
|
-
// src/constraints/enforce.ts
|
|
23008
|
-
function tableScope(table, row) {
|
|
23009
|
-
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
23010
|
-
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
23011
|
-
}
|
|
23012
|
-
function checkNotNull(env, table, row) {
|
|
23013
|
-
void env;
|
|
23014
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
23015
|
-
const c = table.columns[i];
|
|
23016
|
-
if (c.notNull && (row[i] ?? null) === null) {
|
|
23017
|
-
throw pgError(
|
|
23018
|
-
"not_null_violation",
|
|
23019
|
-
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
23020
|
-
"23502"
|
|
23021
|
-
);
|
|
23022
|
-
}
|
|
23023
|
-
}
|
|
23024
|
-
}
|
|
23025
|
-
function checkChecks(env, table, row) {
|
|
23026
|
-
for (const con of table.constraints) {
|
|
23027
|
-
if (con.kind !== "check") continue;
|
|
23028
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
23029
|
-
const v = evalExpr(env.ctx, scope, con.expr);
|
|
23030
|
-
if (v.v === null) continue;
|
|
23031
|
-
const b = castTo(env.ctx, v, "bool", {});
|
|
23032
|
-
if (b.v !== true) {
|
|
23033
|
-
throw pgError(
|
|
23034
|
-
"check_violation",
|
|
23035
|
-
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
23036
|
-
"23514"
|
|
23037
|
-
);
|
|
23038
|
-
}
|
|
23039
|
-
}
|
|
23040
|
-
}
|
|
23041
|
-
function uniqueSpecsFor(env, table) {
|
|
23042
|
-
const specs = [];
|
|
23043
|
-
for (const con of table.constraints) {
|
|
23044
|
-
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
23045
|
-
specs.push({
|
|
23046
|
-
name: con.name,
|
|
23047
|
-
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
23048
|
-
columnNames: con.columns,
|
|
23049
|
-
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
23050
|
-
where: null,
|
|
23051
|
-
isPrimary: con.kind === "primary_key"
|
|
23052
|
-
});
|
|
23053
|
-
}
|
|
23054
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
23055
|
-
if (schema) {
|
|
23056
|
-
for (const idx of schema.indexes.values()) {
|
|
23057
|
-
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
23058
|
-
specs.push(uniqueSpecOfIndex(table, idx));
|
|
23059
|
-
}
|
|
23060
|
-
}
|
|
23061
|
-
return specs;
|
|
23062
|
-
}
|
|
23063
|
-
function uniqueSpecOfIndex(table, idx) {
|
|
23064
|
-
return {
|
|
23065
|
-
name: idx.name,
|
|
23066
|
-
keys: idx.columns.map((c) => ({
|
|
23067
|
-
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
23068
|
-
expr: c.expr
|
|
23069
|
-
})),
|
|
23070
|
-
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
23071
|
-
nullsNotDistinct: idx.nullsNotDistinct,
|
|
23072
|
-
where: idx.where,
|
|
23073
|
-
isPrimary: false
|
|
23074
|
-
};
|
|
23075
|
-
}
|
|
23076
|
-
function uniqueKeyOf(env, table, spec, row) {
|
|
23077
|
-
if (spec.where) {
|
|
23078
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
23079
|
-
const v = evalExpr(env.ctx, scope, spec.where);
|
|
23080
|
-
if (v.v !== true) return null;
|
|
23081
|
-
}
|
|
23082
|
-
const parts = [];
|
|
23083
|
-
let hasNull = false;
|
|
23084
|
-
for (const k of spec.keys) {
|
|
23085
|
-
let value;
|
|
23086
|
-
let type;
|
|
23087
|
-
if (k.expr) {
|
|
23088
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
23089
|
-
const v = evalExpr(env.ctx, scope, k.expr);
|
|
23090
|
-
value = v.v;
|
|
23091
|
-
type = v.t === "unknown" ? "text" : v.t;
|
|
23092
|
-
} else {
|
|
23093
|
-
value = row[k.colIdx] ?? null;
|
|
23094
|
-
type = table.columns[k.colIdx].type.id;
|
|
23095
|
-
}
|
|
23096
|
-
if (value === null) {
|
|
23097
|
-
hasNull = true;
|
|
23098
|
-
parts.push("\0N");
|
|
23099
|
-
} else {
|
|
23100
|
-
parts.push(datumKey(type, value));
|
|
23101
|
-
}
|
|
23102
|
-
}
|
|
23103
|
-
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
23104
|
-
return parts.join("");
|
|
23105
|
-
}
|
|
23106
|
-
function checkUnique(env, table, row, selfIdx) {
|
|
23107
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
23108
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
23109
|
-
if (key === null) continue;
|
|
23110
|
-
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
23111
|
-
}
|
|
23112
|
-
}
|
|
23113
|
-
function findConflict(env, table, spec, row) {
|
|
23114
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
23115
|
-
if (key === null) return null;
|
|
23116
|
-
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
23117
|
-
return hits.length > 0 ? hits[0] : null;
|
|
23118
|
-
}
|
|
23119
|
-
function checkForeignKeys(env, table, row) {
|
|
23120
|
-
const state = env.ctx.state;
|
|
23121
|
-
for (const con of table.constraints) {
|
|
23122
|
-
if (con.kind !== "foreign_key") continue;
|
|
23123
|
-
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
23124
|
-
const nulls = values.filter((v) => v === null).length;
|
|
23125
|
-
if (con.match === "simple" && nulls > 0) continue;
|
|
23126
|
-
if (con.match === "full") {
|
|
23127
|
-
if (nulls === values.length) continue;
|
|
23128
|
-
if (nulls > 0) {
|
|
23129
|
-
throw pgError(
|
|
23130
|
-
"constraint_foreign_key",
|
|
23131
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
23132
|
-
"23503"
|
|
23133
|
-
);
|
|
23134
|
-
}
|
|
23135
|
-
}
|
|
23136
|
-
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
23137
|
-
if (!refTable) {
|
|
23138
|
-
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
23139
|
-
}
|
|
23140
|
-
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
23141
|
-
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
23142
|
-
const wanted = values.map((v, i) => {
|
|
23143
|
-
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
23144
|
-
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
23145
|
-
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
23146
|
-
}).join("");
|
|
23147
|
-
let found = false;
|
|
23148
|
-
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
23149
|
-
const r = refTable.rowAt(i);
|
|
23150
|
-
const key = refIdxs.map((ri, j) => {
|
|
23151
|
-
const v = r[ri] ?? null;
|
|
23152
|
-
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
23153
|
-
}).join("");
|
|
23154
|
-
if (key === wanted) {
|
|
23155
|
-
found = true;
|
|
23156
|
-
break;
|
|
23157
|
-
}
|
|
23158
|
-
}
|
|
23159
|
-
if (!found) {
|
|
23160
|
-
throw pgError(
|
|
23161
|
-
"constraint_foreign_key",
|
|
23162
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
23163
|
-
"23503"
|
|
23164
|
-
);
|
|
23165
|
-
}
|
|
23328
|
+
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
23329
|
+
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
23166
23330
|
}
|
|
23331
|
+
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
23167
23332
|
}
|
|
23168
|
-
|
|
23169
|
-
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23333
|
+
|
|
23334
|
+
// src/executor/triggers-scope.ts
|
|
23335
|
+
function triggerScope(table, newRow, oldRow) {
|
|
23336
|
+
const cols = [];
|
|
23337
|
+
const row = [];
|
|
23338
|
+
const rangeVars = /* @__PURE__ */ new Set();
|
|
23339
|
+
if (newRow) {
|
|
23340
|
+
rangeVars.add("new");
|
|
23341
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
23342
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
23343
|
+
row.push(newRow[i] ?? null);
|
|
23177
23344
|
}
|
|
23178
23345
|
}
|
|
23179
|
-
|
|
23346
|
+
if (oldRow) {
|
|
23347
|
+
rangeVars.add("old");
|
|
23348
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
23349
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
23350
|
+
row.push(oldRow[i] ?? null);
|
|
23351
|
+
}
|
|
23352
|
+
}
|
|
23353
|
+
return new RowScope(cols, row, null, rangeVars);
|
|
23180
23354
|
}
|
|
23181
23355
|
|
|
23182
23356
|
// src/executor/triggers.ts
|
|
@@ -23192,6 +23366,18 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
23192
23366
|
for (const t of table.triggers) {
|
|
23193
23367
|
if (t.timing !== timing || !matches2(t, event) || !t.forEachRow) continue;
|
|
23194
23368
|
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
23369
|
+
if (t.constraint && timing === "after") {
|
|
23370
|
+
if (t.when && !evalPredicate(env, triggerScope(table, newRow, oldRow), t.when)) continue;
|
|
23371
|
+
env.ctx.state.pendingTriggers.push({
|
|
23372
|
+
schema: table.schema,
|
|
23373
|
+
table: table.name,
|
|
23374
|
+
trigger: t.name,
|
|
23375
|
+
event,
|
|
23376
|
+
oldRow: oldRow?.slice() ?? null,
|
|
23377
|
+
newRow: newRow?.slice() ?? null
|
|
23378
|
+
});
|
|
23379
|
+
continue;
|
|
23380
|
+
}
|
|
23195
23381
|
const result = executor(env, table, t, event, oldRow, timing === "before" ? row : newRow);
|
|
23196
23382
|
if (timing === "before") {
|
|
23197
23383
|
if (result === null) return { row: null };
|
|
@@ -23200,6 +23386,170 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
23200
23386
|
}
|
|
23201
23387
|
return { row };
|
|
23202
23388
|
}
|
|
23389
|
+
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
23390
|
+
function flushConstraintTriggers(state, all = false) {
|
|
23391
|
+
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
23392
|
+
for (let i = 0; i < state.pendingTriggers.length; ) {
|
|
23393
|
+
const pending = state.pendingTriggers[i];
|
|
23394
|
+
const table = state.schemas.get(pending.schema)?.tables.get(pending.table);
|
|
23395
|
+
const trigger = table?.triggers.find((t) => t.name === pending.trigger);
|
|
23396
|
+
if (!table || !trigger) {
|
|
23397
|
+
state.pendingTriggers.splice(i, 1);
|
|
23398
|
+
continue;
|
|
23399
|
+
}
|
|
23400
|
+
const deferred = trigger.deferrable && (state.constraintModes.get(keyOf(table.schema, trigger.name)) ?? trigger.initiallyDeferred);
|
|
23401
|
+
if (!all && state.inTransaction && deferred) {
|
|
23402
|
+
i++;
|
|
23403
|
+
continue;
|
|
23404
|
+
}
|
|
23405
|
+
if (!executor) throw unsupported(`trigger "${trigger.name}" execution`);
|
|
23406
|
+
state.pendingTriggers.splice(i, 1);
|
|
23407
|
+
const changes = state.changes;
|
|
23408
|
+
try {
|
|
23409
|
+
executor(env, table, { ...trigger, when: null }, pending.event, pending.oldRow, pending.newRow);
|
|
23410
|
+
} catch (error) {
|
|
23411
|
+
state.pendingTriggers.splice(i, 0, pending);
|
|
23412
|
+
throw error;
|
|
23413
|
+
} finally {
|
|
23414
|
+
state.changes = changes;
|
|
23415
|
+
}
|
|
23416
|
+
}
|
|
23417
|
+
}
|
|
23418
|
+
function setConstraints(state, stmt) {
|
|
23419
|
+
if (!state.inTransaction) return;
|
|
23420
|
+
const matches3 = [];
|
|
23421
|
+
if (stmt.names) {
|
|
23422
|
+
for (const name of stmt.names) {
|
|
23423
|
+
const schemas = name.length > 1 ? [name[name.length - 2]] : state.effectiveSearchPath();
|
|
23424
|
+
let found = false;
|
|
23425
|
+
for (const schema of schemas) {
|
|
23426
|
+
const items = [...state.schemas.get(schema)?.tables.values() ?? []].flatMap(
|
|
23427
|
+
(table) => table.triggers.filter((t) => t.constraint && t.name === name[name.length - 1])
|
|
23428
|
+
);
|
|
23429
|
+
if (items.length) {
|
|
23430
|
+
for (const trigger of items) matches3.push({ schema, trigger });
|
|
23431
|
+
found = true;
|
|
23432
|
+
break;
|
|
23433
|
+
}
|
|
23434
|
+
}
|
|
23435
|
+
if (!found) throw pgError("undefined_object", `constraint "${name.join(".")}" does not exist`, "42704");
|
|
23436
|
+
}
|
|
23437
|
+
} else {
|
|
23438
|
+
for (const schema of state.schemas.values())
|
|
23439
|
+
for (const table of schema.tables.values())
|
|
23440
|
+
for (const trigger of table.triggers)
|
|
23441
|
+
if (trigger.constraint && trigger.deferrable) matches3.push({ schema: schema.name, trigger });
|
|
23442
|
+
}
|
|
23443
|
+
for (const { trigger } of matches3)
|
|
23444
|
+
if (stmt.deferred && !trigger.deferrable)
|
|
23445
|
+
throw pgError("misuse", `constraint "${trigger.name}" is not deferrable`, "55000");
|
|
23446
|
+
const previous = new Map(state.constraintModes);
|
|
23447
|
+
for (const { schema, trigger } of matches3) state.constraintModes.set(keyOf(schema, trigger.name), stmt.deferred);
|
|
23448
|
+
try {
|
|
23449
|
+
if (!stmt.deferred) flushConstraintTriggers(state);
|
|
23450
|
+
} catch (error) {
|
|
23451
|
+
state.constraintModes = previous;
|
|
23452
|
+
throw error;
|
|
23453
|
+
}
|
|
23454
|
+
}
|
|
23455
|
+
|
|
23456
|
+
// src/transactions/manager.ts
|
|
23457
|
+
var TransactionManager = class {
|
|
23458
|
+
constructor(state) {
|
|
23459
|
+
this.state = state;
|
|
23460
|
+
}
|
|
23461
|
+
state;
|
|
23462
|
+
base = null;
|
|
23463
|
+
savepoints = [];
|
|
23464
|
+
freezeDepth = 0;
|
|
23465
|
+
get inTransaction() {
|
|
23466
|
+
return this.base !== null;
|
|
23467
|
+
}
|
|
23468
|
+
takeSnapshot() {
|
|
23469
|
+
this.state.freezeShared();
|
|
23470
|
+
this.freezeDepth++;
|
|
23471
|
+
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
23472
|
+
}
|
|
23473
|
+
restore(snap) {
|
|
23474
|
+
this.state.restoreFrom(snap.state);
|
|
23475
|
+
this.state.prng.setState(snap.prngState);
|
|
23476
|
+
}
|
|
23477
|
+
thawOnce() {
|
|
23478
|
+
if (this.freezeDepth > 0) {
|
|
23479
|
+
this.state.thawShared();
|
|
23480
|
+
this.freezeDepth--;
|
|
23481
|
+
}
|
|
23482
|
+
}
|
|
23483
|
+
begin() {
|
|
23484
|
+
if (this.base !== null) {
|
|
23485
|
+
return;
|
|
23486
|
+
}
|
|
23487
|
+
this.base = this.takeSnapshot();
|
|
23488
|
+
this.state.inTransaction = true;
|
|
23489
|
+
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
23490
|
+
}
|
|
23491
|
+
commit() {
|
|
23492
|
+
try {
|
|
23493
|
+
flushConstraintTriggers(this.state, true);
|
|
23494
|
+
} catch (error) {
|
|
23495
|
+
this.rollback();
|
|
23496
|
+
throw error;
|
|
23497
|
+
}
|
|
23498
|
+
this.base = null;
|
|
23499
|
+
this.savepoints = [];
|
|
23500
|
+
this.state.inTransaction = false;
|
|
23501
|
+
this.state.transactionXid = null;
|
|
23502
|
+
this.state.localSettings.clear();
|
|
23503
|
+
this.state.pendingTriggers = [];
|
|
23504
|
+
this.state.constraintModes.clear();
|
|
23505
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
23506
|
+
}
|
|
23507
|
+
rollback() {
|
|
23508
|
+
if (this.base !== null) {
|
|
23509
|
+
this.restore(this.base);
|
|
23510
|
+
}
|
|
23511
|
+
this.base = null;
|
|
23512
|
+
this.savepoints = [];
|
|
23513
|
+
this.state.inTransaction = false;
|
|
23514
|
+
this.state.transactionXid = null;
|
|
23515
|
+
this.state.localSettings.clear();
|
|
23516
|
+
this.state.pendingTriggers = [];
|
|
23517
|
+
this.state.constraintModes.clear();
|
|
23518
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
23519
|
+
}
|
|
23520
|
+
savepoint(name) {
|
|
23521
|
+
if (this.base === null) {
|
|
23522
|
+
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
23523
|
+
}
|
|
23524
|
+
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
23525
|
+
}
|
|
23526
|
+
releaseSavepoint(name) {
|
|
23527
|
+
const idx = this.findSavepoint(name);
|
|
23528
|
+
this.savepoints.splice(idx);
|
|
23529
|
+
}
|
|
23530
|
+
rollbackToSavepoint(name) {
|
|
23531
|
+
const idx = this.findSavepoint(name);
|
|
23532
|
+
const sp = this.savepoints[idx];
|
|
23533
|
+
this.restore(sp.snap);
|
|
23534
|
+
this.savepoints.splice(idx + 1);
|
|
23535
|
+
}
|
|
23536
|
+
findSavepoint(name) {
|
|
23537
|
+
if (this.base === null) {
|
|
23538
|
+
throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
|
|
23539
|
+
}
|
|
23540
|
+
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
23541
|
+
if (this.savepoints[i].name === name) return i;
|
|
23542
|
+
}
|
|
23543
|
+
throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
|
|
23544
|
+
}
|
|
23545
|
+
reset() {
|
|
23546
|
+
this.base = null;
|
|
23547
|
+
this.savepoints = [];
|
|
23548
|
+
this.state.inTransaction = false;
|
|
23549
|
+
this.state.transactionXid = null;
|
|
23550
|
+
this.freezeDepth = 0;
|
|
23551
|
+
}
|
|
23552
|
+
};
|
|
23203
23553
|
|
|
23204
23554
|
// src/executor/dml.ts
|
|
23205
23555
|
function withStatementRollback(env, fn) {
|
|
@@ -23400,6 +23750,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
23400
23750
|
const updated = existing.slice();
|
|
23401
23751
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
23402
23752
|
computeGeneratedColumns(env, table, updated);
|
|
23753
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
23403
23754
|
rows[existingIdx] = updated;
|
|
23404
23755
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
23405
23756
|
checkNotNull(env, table, updated);
|
|
@@ -23485,6 +23836,7 @@ function executeInsert(env0, stmt) {
|
|
|
23485
23836
|
checkChecks(env, table, newRow);
|
|
23486
23837
|
checkUnique(env, table, newRow, rows.length);
|
|
23487
23838
|
checkForeignKeys(env, table, newRow);
|
|
23839
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
23488
23840
|
rows.push(newRow);
|
|
23489
23841
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
23490
23842
|
insertedCount++;
|
|
@@ -23602,6 +23954,7 @@ function executeUpdate(env0, stmt) {
|
|
|
23602
23954
|
if (fired.row === null) continue;
|
|
23603
23955
|
const finalRow = fired.row;
|
|
23604
23956
|
computeGeneratedColumns(env, table, finalRow);
|
|
23957
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
23605
23958
|
rows[ri] = finalRow;
|
|
23606
23959
|
try {
|
|
23607
23960
|
checkNotNull(env, table, finalRow);
|
|
@@ -23721,6 +24074,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
23721
24074
|
for (const c of con.columns) {
|
|
23722
24075
|
newRow[child.columnIndex(c)] = null;
|
|
23723
24076
|
}
|
|
24077
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
23724
24078
|
childRows[i] = newRow;
|
|
23725
24079
|
checkNotNull(env, child, newRow);
|
|
23726
24080
|
checkChecks(env, child, newRow);
|
|
@@ -23734,6 +24088,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
23734
24088
|
const ci = child.columnIndex(c);
|
|
23735
24089
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
23736
24090
|
}
|
|
24091
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
23737
24092
|
childRows[i] = newRow;
|
|
23738
24093
|
checkNotNull(env, child, newRow);
|
|
23739
24094
|
checkChecks(env, child, newRow);
|
|
@@ -23771,6 +24126,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
23771
24126
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
23772
24127
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
23773
24128
|
}
|
|
24129
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
23774
24130
|
childRows[i] = newRow;
|
|
23775
24131
|
checkChecks(env, child, newRow);
|
|
23776
24132
|
}
|
|
@@ -23780,6 +24136,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
23780
24136
|
for (const i of idxs) {
|
|
23781
24137
|
const newRow = childRows[i].slice();
|
|
23782
24138
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
24139
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
23783
24140
|
childRows[i] = newRow;
|
|
23784
24141
|
checkNotNull(env, child, newRow);
|
|
23785
24142
|
}
|
|
@@ -23792,6 +24149,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
23792
24149
|
const ci = child.columnIndex(c);
|
|
23793
24150
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
23794
24151
|
}
|
|
24152
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
23795
24153
|
childRows[i] = newRow;
|
|
23796
24154
|
checkForeignKeys(env, child, newRow);
|
|
23797
24155
|
}
|
|
@@ -23889,6 +24247,7 @@ function executeSet(env, stmt) {
|
|
|
23889
24247
|
else target.delete(name);
|
|
23890
24248
|
return commandResult("SET", 0);
|
|
23891
24249
|
}
|
|
24250
|
+
validateStorageSetting(name, stmt.value);
|
|
23892
24251
|
target.set(name, stmt.value);
|
|
23893
24252
|
return commandResult("SET", 0);
|
|
23894
24253
|
}
|
|
@@ -24194,64 +24553,6 @@ function executeCopyFromData(env, stmt, data) {
|
|
|
24194
24553
|
};
|
|
24195
24554
|
}
|
|
24196
24555
|
|
|
24197
|
-
// src/expressions/context.ts
|
|
24198
|
-
var EngineCtx = class {
|
|
24199
|
-
state;
|
|
24200
|
-
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
24201
|
-
txNow;
|
|
24202
|
-
/** statement timestamp */
|
|
24203
|
-
stmtNow;
|
|
24204
|
-
constructor(state, txNow) {
|
|
24205
|
-
this.state = state;
|
|
24206
|
-
const nowMs = state.clock().getTime();
|
|
24207
|
-
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
24208
|
-
this.txNow = txNow ?? nowMicros;
|
|
24209
|
-
this.stmtNow = nowMicros;
|
|
24210
|
-
}
|
|
24211
|
-
timezone() {
|
|
24212
|
-
return this.state.getSetting("timezone") ?? "UTC";
|
|
24213
|
-
}
|
|
24214
|
-
namespaceOid(name) {
|
|
24215
|
-
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
24216
|
-
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
24217
|
-
return oid;
|
|
24218
|
-
}
|
|
24219
|
-
namespaceName(oid) {
|
|
24220
|
-
const builtin = builtinNamespaceName(oid);
|
|
24221
|
-
if (builtin !== void 0) return builtin;
|
|
24222
|
-
for (const schema of this.state.schemas.values()) {
|
|
24223
|
-
if (schema.oid === oid) return schema.name;
|
|
24224
|
-
}
|
|
24225
|
-
return null;
|
|
24226
|
-
}
|
|
24227
|
-
zoneOffsetAt(utcMicros) {
|
|
24228
|
-
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
24229
|
-
}
|
|
24230
|
-
zoneOffsetForNaive(naiveMicros) {
|
|
24231
|
-
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
24232
|
-
}
|
|
24233
|
-
enumLabels(enumType) {
|
|
24234
|
-
if (!isEnumType(enumType)) return null;
|
|
24235
|
-
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
24236
|
-
return e?.labels ?? null;
|
|
24237
|
-
}
|
|
24238
|
-
enumHasLabel(enumType, label) {
|
|
24239
|
-
const labels = this.enumLabels(enumType);
|
|
24240
|
-
return labels === null ? true : labels.includes(label);
|
|
24241
|
-
}
|
|
24242
|
-
enumOrder(enumType, label) {
|
|
24243
|
-
const labels = this.enumLabels(enumType);
|
|
24244
|
-
if (!labels) return 0;
|
|
24245
|
-
const idx = labels.indexOf(label);
|
|
24246
|
-
return idx === -1 ? labels.length : idx;
|
|
24247
|
-
}
|
|
24248
|
-
requireEnum(enumType) {
|
|
24249
|
-
const labels = this.enumLabels(enumType);
|
|
24250
|
-
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
24251
|
-
return labels;
|
|
24252
|
-
}
|
|
24253
|
-
};
|
|
24254
|
-
|
|
24255
24556
|
// src/runtime/clock.ts
|
|
24256
24557
|
var DEFAULT_NOW = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
24257
24558
|
function fixedClock(instant = DEFAULT_NOW) {
|
|
@@ -25219,7 +25520,7 @@ function pgClass(ctx) {
|
|
|
25219
25520
|
v.materialized ? "m" : "v",
|
|
25220
25521
|
v.columns?.length ?? 0,
|
|
25221
25522
|
v.matRows?.length ?? 0,
|
|
25222
|
-
|
|
25523
|
+
v.materialized && [...schemaData.indexes.values()].some((i) => i.tableOid === v.oid),
|
|
25223
25524
|
!v.materialized || v.matRows !== null,
|
|
25224
25525
|
relPersistence(v)
|
|
25225
25526
|
);
|
|
@@ -25485,7 +25786,7 @@ function pgIndex(ctx) {
|
|
|
25485
25786
|
const valid = i.valid !== false;
|
|
25486
25787
|
rows.push([
|
|
25487
25788
|
i.oid ?? 0,
|
|
25488
|
-
table?.oid ?? 0,
|
|
25789
|
+
table?.oid ?? i.tableOid ?? 0,
|
|
25489
25790
|
indexAttributeCount(i),
|
|
25490
25791
|
i.columns.length,
|
|
25491
25792
|
i.unique,
|
|
@@ -25657,7 +25958,7 @@ function pgStatUserIndexes(ctx) {
|
|
|
25657
25958
|
for (const index of schema.indexes.values()) {
|
|
25658
25959
|
const table = schema.tables.get(index.table);
|
|
25659
25960
|
rows.push([
|
|
25660
|
-
table?.oid ?? 0,
|
|
25961
|
+
table?.oid ?? index.tableOid ?? 0,
|
|
25661
25962
|
index.oid ?? 0,
|
|
25662
25963
|
schema.name,
|
|
25663
25964
|
index.table,
|
|
@@ -26252,26 +26553,6 @@ function runTriggerBody(env, table, stmts, vars) {
|
|
|
26252
26553
|
}
|
|
26253
26554
|
}
|
|
26254
26555
|
}
|
|
26255
|
-
function triggerScope(table, newRow, oldRow) {
|
|
26256
|
-
const cols = [];
|
|
26257
|
-
const row = [];
|
|
26258
|
-
const rangeVars = /* @__PURE__ */ new Set();
|
|
26259
|
-
if (newRow) {
|
|
26260
|
-
rangeVars.add("new");
|
|
26261
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
26262
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
26263
|
-
row.push(newRow[i] ?? null);
|
|
26264
|
-
}
|
|
26265
|
-
}
|
|
26266
|
-
if (oldRow) {
|
|
26267
|
-
rangeVars.add("old");
|
|
26268
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
26269
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
26270
|
-
row.push(oldRow[i] ?? null);
|
|
26271
|
-
}
|
|
26272
|
-
}
|
|
26273
|
-
return new RowScope(cols, row, null, rangeVars);
|
|
26274
|
-
}
|
|
26275
26556
|
function executeTrigger(env, table, trigger, _event, oldRow, newRow) {
|
|
26276
26557
|
const state = env.ctx.state;
|
|
26277
26558
|
if (trigger.when !== null && !evalPredicate(env, triggerScope(table, newRow, oldRow), trigger.when)) {
|
|
@@ -26913,13 +27194,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
26913
27194
|
schema.sequences.set(name, seq);
|
|
26914
27195
|
return commandResult("CREATE SEQUENCE", 0);
|
|
26915
27196
|
}
|
|
27197
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
27198
|
+
const state = env.ctx.state;
|
|
27199
|
+
const matches3 = (value) => {
|
|
27200
|
+
try {
|
|
27201
|
+
const input = parseRelationInput(value);
|
|
27202
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
27203
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
27204
|
+
} catch {
|
|
27205
|
+
return false;
|
|
27206
|
+
}
|
|
27207
|
+
};
|
|
27208
|
+
const rewrite = (value) => {
|
|
27209
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
27210
|
+
if (value === null || typeof value !== "object") return value;
|
|
27211
|
+
const node = value;
|
|
27212
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
27213
|
+
const rewriteLiteral = (literal2) => {
|
|
27214
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches3(literal2.value)) {
|
|
27215
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
27216
|
+
}
|
|
27217
|
+
return literal2;
|
|
27218
|
+
};
|
|
27219
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
27220
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
27221
|
+
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")
|
|
27222
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
27223
|
+
return updated;
|
|
27224
|
+
};
|
|
27225
|
+
for (const schema of state.schemas.values()) {
|
|
27226
|
+
for (const table of [...schema.tables.values()]) {
|
|
27227
|
+
const writable = state.ensureWritableTable(table);
|
|
27228
|
+
for (const column of writable.columns) {
|
|
27229
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
27230
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
27231
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
27232
|
+
}
|
|
27233
|
+
}
|
|
27234
|
+
}
|
|
27235
|
+
}
|
|
26916
27236
|
function executeAlterSequence(env, stmt) {
|
|
26917
27237
|
const state = env.ctx.state;
|
|
26918
|
-
const
|
|
26919
|
-
if (!
|
|
27238
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
27239
|
+
if (!foundSequence) {
|
|
26920
27240
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
26921
27241
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
26922
27242
|
}
|
|
27243
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
27244
|
+
if (stmt.renameTo) {
|
|
27245
|
+
const schema = state.getSchema(seq.schema);
|
|
27246
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
27247
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
27248
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
27249
|
+
schema.sequences.delete(seq.name);
|
|
27250
|
+
seq.name = stmt.renameTo;
|
|
27251
|
+
schema.sequences.set(seq.name, seq);
|
|
27252
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
27253
|
+
}
|
|
26923
27254
|
const o = stmt.options;
|
|
26924
27255
|
if (o.logged !== void 0) {
|
|
26925
27256
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -26977,7 +27308,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
26977
27308
|
col.defaultExpr = {
|
|
26978
27309
|
type: "func",
|
|
26979
27310
|
name: ["nextval"],
|
|
26980
|
-
args: [{ type: "string_lit", value:
|
|
27311
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
26981
27312
|
};
|
|
26982
27313
|
}
|
|
26983
27314
|
for (const c of def.constraints) {
|
|
@@ -27230,7 +27561,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
27230
27561
|
const table = new TableData(schema.name, name, columns, state.nextOid(), stmt.temp);
|
|
27231
27562
|
table.unlogged = stmt.unlogged === true;
|
|
27232
27563
|
if (stmt.withData) {
|
|
27233
|
-
for (const row of rel3.rows)
|
|
27564
|
+
for (const row of rel3.rows) {
|
|
27565
|
+
const stored = row.slice();
|
|
27566
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
27567
|
+
table.mutableRows().push(stored);
|
|
27568
|
+
}
|
|
27234
27569
|
}
|
|
27235
27570
|
schema.tables.set(name, table);
|
|
27236
27571
|
const count2 = stmt.withData ? table.rowCount() : 0;
|
|
@@ -27238,7 +27573,8 @@ function executeCreateTableAs(env, stmt) {
|
|
|
27238
27573
|
}
|
|
27239
27574
|
function executeCreateIndex(env, stmt) {
|
|
27240
27575
|
const state = env.ctx.state;
|
|
27241
|
-
const
|
|
27576
|
+
const view = state.findView(stmt.table);
|
|
27577
|
+
const table = state.findTable(stmt.table) ?? (view?.materialized ? materializedTable(view) : void 0);
|
|
27242
27578
|
if (!table) {
|
|
27243
27579
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
27244
27580
|
}
|
|
@@ -27350,13 +27686,22 @@ function executeRefreshMatView(env, stmt) {
|
|
|
27350
27686
|
if (!found?.materialized) {
|
|
27351
27687
|
throw pgError("undefined_table", `materialized view "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
27352
27688
|
}
|
|
27689
|
+
const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), found.query);
|
|
27690
|
+
const next = {
|
|
27691
|
+
...found,
|
|
27692
|
+
matColumns: rel3.columns.map((c, i) => ({
|
|
27693
|
+
name: found.columns?.[i] ?? c.name,
|
|
27694
|
+
type: c.type === UNKNOWN ? "text" : c.type
|
|
27695
|
+
})),
|
|
27696
|
+
matRows: stmt.withData ? rel3.rows : null
|
|
27697
|
+
};
|
|
27698
|
+
const table = materializedTable(next);
|
|
27699
|
+
for (const index of env.ctx.state.getSchema(found.schema).indexes.values()) {
|
|
27700
|
+
if (index.tableOid === found.oid && index.valid !== false) assertUniqueIndexBuildable(env, table, index);
|
|
27701
|
+
}
|
|
27353
27702
|
const view = env.ctx.state.ensureWritableView(found);
|
|
27354
|
-
|
|
27355
|
-
view.
|
|
27356
|
-
name: view.columns?.[i] ?? c.name,
|
|
27357
|
-
type: c.type === UNKNOWN ? "text" : c.type
|
|
27358
|
-
}));
|
|
27359
|
-
view.matRows = stmt.withData ? rel3.rows : null;
|
|
27703
|
+
view.matColumns = next.matColumns;
|
|
27704
|
+
view.matRows = next.matRows;
|
|
27360
27705
|
return commandResult("REFRESH MATERIALIZED VIEW", 0);
|
|
27361
27706
|
}
|
|
27362
27707
|
function executeCreateSchema(env, stmt) {
|
|
@@ -27489,6 +27834,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
27489
27834
|
language: lang,
|
|
27490
27835
|
body,
|
|
27491
27836
|
rawBody: stmt.body,
|
|
27837
|
+
settings: Object.fromEntries(
|
|
27838
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
27839
|
+
key,
|
|
27840
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
27841
|
+
])
|
|
27842
|
+
),
|
|
27492
27843
|
strict: stmt.strict,
|
|
27493
27844
|
oid: state.nextOid()
|
|
27494
27845
|
};
|
|
@@ -27498,6 +27849,8 @@ function executeCreateFunction(env, stmt) {
|
|
|
27498
27849
|
return commandResult("CREATE FUNCTION", 0);
|
|
27499
27850
|
}
|
|
27500
27851
|
function executeCreateTrigger(env, stmt) {
|
|
27852
|
+
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
27853
|
+
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
27501
27854
|
const state = env.ctx.state;
|
|
27502
27855
|
const found = state.findTable(stmt.table);
|
|
27503
27856
|
if (!found) {
|
|
@@ -27516,6 +27869,9 @@ function executeCreateTrigger(env, stmt) {
|
|
|
27516
27869
|
}
|
|
27517
27870
|
const meta = {
|
|
27518
27871
|
name: stmt.name,
|
|
27872
|
+
constraint: stmt.constraint,
|
|
27873
|
+
deferrable: stmt.deferrable,
|
|
27874
|
+
initiallyDeferred: stmt.initiallyDeferred,
|
|
27519
27875
|
timing: stmt.timing,
|
|
27520
27876
|
events: stmt.events,
|
|
27521
27877
|
forEachRow: stmt.forEachRow,
|
|
@@ -27668,6 +28024,7 @@ function executeAlterTable(env, stmt) {
|
|
|
27668
28024
|
}
|
|
27669
28025
|
const next = row.slice();
|
|
27670
28026
|
next[idx] = nv;
|
|
28027
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
27671
28028
|
rows[i] = next;
|
|
27672
28029
|
}
|
|
27673
28030
|
col.type = resolved.column;
|
|
@@ -27769,6 +28126,11 @@ function executeAlterTable(env, stmt) {
|
|
|
27769
28126
|
);
|
|
27770
28127
|
}
|
|
27771
28128
|
table.columns[idx].name = action.to;
|
|
28129
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
28130
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
28131
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
28132
|
+
}
|
|
28133
|
+
}
|
|
27772
28134
|
for (const con of table.constraints) {
|
|
27773
28135
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
27774
28136
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -27805,6 +28167,11 @@ function executeAlterTable(env, stmt) {
|
|
|
27805
28167
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
27806
28168
|
}
|
|
27807
28169
|
const oldName = table.name;
|
|
28170
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
28171
|
+
if (seq.ownedBy?.table === oldName) {
|
|
28172
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
28173
|
+
}
|
|
28174
|
+
}
|
|
27808
28175
|
schema.tables.delete(table.name);
|
|
27809
28176
|
table.name = action.to;
|
|
27810
28177
|
schema.tables.set(action.to, table);
|
|
@@ -28284,7 +28651,16 @@ function alterTableIsSelfContained(stmt) {
|
|
|
28284
28651
|
return stmt.actions.length === 1 && action !== void 0 && SELF_CONTAINED_ALTER_ACTIONS.has(action.kind);
|
|
28285
28652
|
}
|
|
28286
28653
|
function executeStatement(env, stmt) {
|
|
28287
|
-
if (!RESHAPES_TABLES.has(stmt.type))
|
|
28654
|
+
if (!RESHAPES_TABLES.has(stmt.type)) {
|
|
28655
|
+
if ((stmt.type === "insert" || stmt.type === "update" || stmt.type === "delete") && (env.ctx.state.pendingTriggers.length > 0 || env.ctx.state.findTable(stmt.table)?.triggers.some((t) => t.constraint))) {
|
|
28656
|
+
return withStatementRollback(env, () => {
|
|
28657
|
+
const result = dispatchStatement(env, stmt);
|
|
28658
|
+
flushConstraintTriggers(env.ctx.state);
|
|
28659
|
+
return result;
|
|
28660
|
+
});
|
|
28661
|
+
}
|
|
28662
|
+
return dispatchStatement(env, stmt);
|
|
28663
|
+
}
|
|
28288
28664
|
try {
|
|
28289
28665
|
return dispatchStatement(env, stmt);
|
|
28290
28666
|
} finally {
|
|
@@ -28343,6 +28719,9 @@ function dispatchStatement(env, stmt) {
|
|
|
28343
28719
|
return executeRefreshMatView(env, stmt);
|
|
28344
28720
|
case "transaction":
|
|
28345
28721
|
return executeTransaction(env, stmt);
|
|
28722
|
+
case "set_constraints":
|
|
28723
|
+
setConstraints(env.ctx.state, stmt);
|
|
28724
|
+
return commandResult("SET CONSTRAINTS", 0);
|
|
28346
28725
|
case "set":
|
|
28347
28726
|
return executeSet(env, stmt);
|
|
28348
28727
|
case "show":
|