@crvouga/mockingbird-service-postgres 3.5.0 → 3.6.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 +6 -0
- package/COMPATIBILITY.md +3 -0
- package/compat/sections/trg.ts +2 -0
- package/dist/admin.js +924 -735
- package/dist/admin.js.map +4 -4
- package/dist/ast/nodes.d.ts +9 -1
- package/dist/executor/triggers-scope.d.ts +4 -0
- package/dist/executor/triggers.d.ts +4 -0
- package/dist/index.js +924 -735
- package/dist/index.js.map +4 -4
- package/dist/server.js +941 -735
- package/dist/server.js.map +4 -4
- package/dist/storage/database-state.d.ts +13 -0
- package/dist/storage/guc.d.ts +2 -0
- package/dist/storage/indexable-relation.d.ts +3 -0
- package/dist/unstable.js +16938 -16749
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +942 -736
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/index.js +942 -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;
|
|
@@ -5959,6 +5966,9 @@ var DatabaseState = class _DatabaseState {
|
|
|
5959
5966
|
changes = 0;
|
|
5960
5967
|
oidCounter = 16384;
|
|
5961
5968
|
inTransaction = false;
|
|
5969
|
+
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
5970
|
+
pendingTriggers = [];
|
|
5971
|
+
constraintModes = /* @__PURE__ */ new Map();
|
|
5962
5972
|
/** most recent sequence touched by nextval/setval, for lastval() */
|
|
5963
5973
|
lastSequence = null;
|
|
5964
5974
|
/** Session currval per sequence; absent entry means currval is undefined. */
|
|
@@ -6001,6 +6011,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
6001
6011
|
this.settings.set("row_security", "on");
|
|
6002
6012
|
this.settings.set("array_nulls", "on");
|
|
6003
6013
|
this.settings.set("backslash_quote", "safe_encoding");
|
|
6014
|
+
this.settings.set("default_tablespace", "");
|
|
6015
|
+
this.settings.set("default_table_access_method", "heap");
|
|
6004
6016
|
}
|
|
6005
6017
|
nextOid() {
|
|
6006
6018
|
return this.oidCounter++;
|
|
@@ -6160,6 +6172,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
6160
6172
|
s.prepared = new Map(this.prepared);
|
|
6161
6173
|
s.changes = this.changes;
|
|
6162
6174
|
s.inTransaction = this.inTransaction;
|
|
6175
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
6176
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
6163
6177
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
6164
6178
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
6165
6179
|
s.tableStats = new Map(this.tableStats);
|
|
@@ -6177,6 +6191,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
6177
6191
|
s.prepared = new Map(this.prepared);
|
|
6178
6192
|
s.changes = this.changes;
|
|
6179
6193
|
s.inTransaction = this.inTransaction;
|
|
6194
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
6195
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
6180
6196
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
6181
6197
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
6182
6198
|
s.tableStats = new Map(this.tableStats);
|
|
@@ -6249,6 +6265,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
6249
6265
|
this.settings = other.settings;
|
|
6250
6266
|
this.localSettings = other.localSettings;
|
|
6251
6267
|
this.prepared = other.prepared;
|
|
6268
|
+
this.pendingTriggers = other.pendingTriggers.slice();
|
|
6269
|
+
this.constraintModes = new Map(other.constraintModes);
|
|
6252
6270
|
this.changes = other.changes;
|
|
6253
6271
|
this.lastSequence = other.lastSequence;
|
|
6254
6272
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
@@ -6265,90 +6283,189 @@ var DatabaseState = class _DatabaseState {
|
|
|
6265
6283
|
}
|
|
6266
6284
|
};
|
|
6267
6285
|
|
|
6268
|
-
// src/
|
|
6269
|
-
var
|
|
6270
|
-
|
|
6271
|
-
|
|
6286
|
+
// src/types/timezone.ts
|
|
6287
|
+
var intlCache = /* @__PURE__ */ new Map();
|
|
6288
|
+
function intlFor(zone) {
|
|
6289
|
+
const cached = intlCache.get(zone);
|
|
6290
|
+
if (cached) return cached;
|
|
6291
|
+
try {
|
|
6292
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
6293
|
+
timeZone: zone,
|
|
6294
|
+
timeZoneName: "longOffset",
|
|
6295
|
+
year: "numeric"
|
|
6296
|
+
});
|
|
6297
|
+
intlCache.set(zone, fmt);
|
|
6298
|
+
return fmt;
|
|
6299
|
+
} catch {
|
|
6300
|
+
return null;
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6303
|
+
function parseFixedOffset(zone) {
|
|
6304
|
+
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
6305
|
+
if (!m) return null;
|
|
6306
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
6307
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
6308
|
+
}
|
|
6309
|
+
function parsePosixOffset(zone) {
|
|
6310
|
+
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
6311
|
+
if (!m) return null;
|
|
6312
|
+
const sign = m[1] === "-" ? 1 : -1;
|
|
6313
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
6314
|
+
}
|
|
6315
|
+
function pgMicrosToUnixMs(utcMicros) {
|
|
6316
|
+
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
6317
|
+
}
|
|
6318
|
+
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
6319
|
+
const z = zone.trim();
|
|
6320
|
+
const lower = z.toLowerCase();
|
|
6321
|
+
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
6322
|
+
const posix = parsePosixOffset(z);
|
|
6323
|
+
if (posix !== null) return posix;
|
|
6324
|
+
const fixed = parseFixedOffset(z);
|
|
6325
|
+
if (fixed !== null) return fixed;
|
|
6326
|
+
const fmt = intlFor(z);
|
|
6327
|
+
if (fmt) {
|
|
6328
|
+
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
6329
|
+
const parts = fmt.formatToParts(new Date(ms));
|
|
6330
|
+
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
6331
|
+
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
6332
|
+
if (!m) return 0;
|
|
6333
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
6334
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
6272
6335
|
}
|
|
6336
|
+
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
6337
|
+
}
|
|
6338
|
+
function clampDateMs(ms) {
|
|
6339
|
+
const MAX = 864e13;
|
|
6340
|
+
return Math.max(-MAX, Math.min(MAX, ms));
|
|
6341
|
+
}
|
|
6342
|
+
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
6343
|
+
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
6344
|
+
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
6345
|
+
return second;
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6348
|
+
// src/expressions/context.ts
|
|
6349
|
+
var EngineCtx = class {
|
|
6273
6350
|
state;
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6351
|
+
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
6352
|
+
txNow;
|
|
6353
|
+
/** statement timestamp */
|
|
6354
|
+
stmtNow;
|
|
6355
|
+
constructor(state, txNow) {
|
|
6356
|
+
this.state = state;
|
|
6357
|
+
const nowMs = state.clock().getTime();
|
|
6358
|
+
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
6359
|
+
this.txNow = txNow ?? nowMicros;
|
|
6360
|
+
this.stmtNow = nowMicros;
|
|
6279
6361
|
}
|
|
6280
|
-
|
|
6281
|
-
this.state.
|
|
6282
|
-
this.freezeDepth++;
|
|
6283
|
-
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
6362
|
+
timezone() {
|
|
6363
|
+
return this.state.getSetting("timezone") ?? "UTC";
|
|
6284
6364
|
}
|
|
6285
|
-
|
|
6286
|
-
this.state.
|
|
6287
|
-
|
|
6365
|
+
namespaceOid(name) {
|
|
6366
|
+
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
6367
|
+
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
6368
|
+
return oid;
|
|
6288
6369
|
}
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6370
|
+
namespaceName(oid) {
|
|
6371
|
+
const builtin = builtinNamespaceName(oid);
|
|
6372
|
+
if (builtin !== void 0) return builtin;
|
|
6373
|
+
for (const schema of this.state.schemas.values()) {
|
|
6374
|
+
if (schema.oid === oid) return schema.name;
|
|
6293
6375
|
}
|
|
6376
|
+
return null;
|
|
6294
6377
|
}
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
return;
|
|
6298
|
-
}
|
|
6299
|
-
this.base = this.takeSnapshot();
|
|
6300
|
-
this.state.inTransaction = true;
|
|
6301
|
-
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
6378
|
+
zoneOffsetAt(utcMicros) {
|
|
6379
|
+
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
6302
6380
|
}
|
|
6303
|
-
|
|
6304
|
-
this.
|
|
6305
|
-
this.savepoints = [];
|
|
6306
|
-
this.state.inTransaction = false;
|
|
6307
|
-
this.state.localSettings.clear();
|
|
6308
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
6381
|
+
zoneOffsetForNaive(naiveMicros) {
|
|
6382
|
+
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
6309
6383
|
}
|
|
6310
|
-
|
|
6311
|
-
if (
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
this.base = null;
|
|
6315
|
-
this.savepoints = [];
|
|
6316
|
-
this.state.inTransaction = false;
|
|
6317
|
-
this.state.localSettings.clear();
|
|
6318
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
6384
|
+
enumLabels(enumType) {
|
|
6385
|
+
if (!isEnumType(enumType)) return null;
|
|
6386
|
+
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
6387
|
+
return e?.labels ?? null;
|
|
6319
6388
|
}
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
}
|
|
6324
|
-
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
6389
|
+
enumHasLabel(enumType, label) {
|
|
6390
|
+
const labels = this.enumLabels(enumType);
|
|
6391
|
+
return labels === null ? true : labels.includes(label);
|
|
6325
6392
|
}
|
|
6326
|
-
|
|
6327
|
-
const
|
|
6328
|
-
|
|
6393
|
+
enumOrder(enumType, label) {
|
|
6394
|
+
const labels = this.enumLabels(enumType);
|
|
6395
|
+
if (!labels) return 0;
|
|
6396
|
+
const idx = labels.indexOf(label);
|
|
6397
|
+
return idx === -1 ? labels.length : idx;
|
|
6329
6398
|
}
|
|
6330
|
-
|
|
6331
|
-
const
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
this.savepoints.splice(idx + 1);
|
|
6399
|
+
requireEnum(enumType) {
|
|
6400
|
+
const labels = this.enumLabels(enumType);
|
|
6401
|
+
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
6402
|
+
return labels;
|
|
6335
6403
|
}
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6404
|
+
};
|
|
6405
|
+
|
|
6406
|
+
// src/api/bind.ts
|
|
6407
|
+
var INT4_MIN2 = -2147483648;
|
|
6408
|
+
var INT4_MAX2 = 2147483647;
|
|
6409
|
+
function bindValueToTyped(value, index) {
|
|
6410
|
+
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
6411
|
+
switch (typeof value) {
|
|
6412
|
+
case "boolean":
|
|
6413
|
+
return tv("bool", value);
|
|
6414
|
+
case "number":
|
|
6415
|
+
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
6416
|
+
return tv("int4", value);
|
|
6417
|
+
}
|
|
6418
|
+
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
6419
|
+
return tv("int8", BigInt(value));
|
|
6420
|
+
}
|
|
6421
|
+
return tv("float8", value);
|
|
6422
|
+
case "bigint":
|
|
6423
|
+
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
6424
|
+
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
6425
|
+
}
|
|
6426
|
+
return tv("int8", value);
|
|
6427
|
+
case "string":
|
|
6428
|
+
return tv(UNKNOWN, value);
|
|
6429
|
+
case "object": {
|
|
6430
|
+
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
6431
|
+
if (value instanceof Date) {
|
|
6432
|
+
const ms = value.getTime();
|
|
6433
|
+
if (Number.isNaN(ms)) {
|
|
6434
|
+
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
6435
|
+
}
|
|
6436
|
+
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
6437
|
+
}
|
|
6438
|
+
break;
|
|
6342
6439
|
}
|
|
6343
|
-
|
|
6440
|
+
default:
|
|
6441
|
+
break;
|
|
6344
6442
|
}
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6443
|
+
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
6444
|
+
}
|
|
6445
|
+
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
6446
|
+
if (v === null) return null;
|
|
6447
|
+
switch (t) {
|
|
6448
|
+
case "bool":
|
|
6449
|
+
return v;
|
|
6450
|
+
case "int2":
|
|
6451
|
+
case "int4":
|
|
6452
|
+
case "oid":
|
|
6453
|
+
return typeof v === "bigint" ? Number(v) : v;
|
|
6454
|
+
case "int8": {
|
|
6455
|
+
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
6456
|
+
if (int8 === "string") return n.toString();
|
|
6457
|
+
if (int8 === "number") return Number(n);
|
|
6458
|
+
return n;
|
|
6459
|
+
}
|
|
6460
|
+
case "float4":
|
|
6461
|
+
case "float8":
|
|
6462
|
+
return v;
|
|
6463
|
+
case "bytea":
|
|
6464
|
+
return v;
|
|
6465
|
+
default:
|
|
6466
|
+
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
6350
6467
|
}
|
|
6351
|
-
}
|
|
6468
|
+
}
|
|
6352
6469
|
|
|
6353
6470
|
// src/types/cast.ts
|
|
6354
6471
|
var UTC_CAST_ENV = {
|
|
@@ -6826,259 +6943,6 @@ function unifyTypes(a, b) {
|
|
|
6826
6943
|
return null;
|
|
6827
6944
|
}
|
|
6828
6945
|
|
|
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
6946
|
// src/functions/datetime-fns.ts
|
|
7083
6947
|
function extractDatePart(ctx, field0, src0, asNumeric) {
|
|
7084
6948
|
const field = field0.toLowerCase();
|
|
@@ -7993,68 +7857,6 @@ function getArrayFunctions() {
|
|
|
7993
7857
|
return m;
|
|
7994
7858
|
}
|
|
7995
7859
|
|
|
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
7860
|
// src/functions/datetime-registry.ts
|
|
8059
7861
|
function getDatetimeFunctions() {
|
|
8060
7862
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -9654,6 +9456,28 @@ function exactDegTan(x) {
|
|
|
9654
9456
|
return Math.tan(x * Math.PI / 180);
|
|
9655
9457
|
}
|
|
9656
9458
|
|
|
9459
|
+
// src/storage/indexable-relation.ts
|
|
9460
|
+
function materializedTable(view) {
|
|
9461
|
+
const table = new TableData(
|
|
9462
|
+
view.schema,
|
|
9463
|
+
view.name,
|
|
9464
|
+
(view.matColumns ?? []).map((c) => ({
|
|
9465
|
+
name: c.name,
|
|
9466
|
+
type: { id: c.type, mod: null },
|
|
9467
|
+
notNull: false,
|
|
9468
|
+
defaultExpr: null,
|
|
9469
|
+
identity: null,
|
|
9470
|
+
generated: null,
|
|
9471
|
+
collate: null,
|
|
9472
|
+
domain: null
|
|
9473
|
+
})),
|
|
9474
|
+
view.oid,
|
|
9475
|
+
view.temp
|
|
9476
|
+
);
|
|
9477
|
+
table.rows = view.matRows ?? [];
|
|
9478
|
+
return table;
|
|
9479
|
+
}
|
|
9480
|
+
|
|
9657
9481
|
// src/schema/index-catalog.ts
|
|
9658
9482
|
var isKeyConstraint = (constraint) => constraint.kind === "primary_key" || constraint.kind === "unique";
|
|
9659
9483
|
var ACCESS_METHODS = /* @__PURE__ */ new Map([
|
|
@@ -9682,6 +9506,8 @@ function syncIndexCatalog(state) {
|
|
|
9682
9506
|
const tables = /* @__PURE__ */ new Map();
|
|
9683
9507
|
for (const schema of state.schemas.values()) {
|
|
9684
9508
|
for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
|
|
9509
|
+
for (const view of schema.views.values())
|
|
9510
|
+
if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
|
|
9685
9511
|
}
|
|
9686
9512
|
const backing = /* @__PURE__ */ new Map();
|
|
9687
9513
|
for (const { table } of tables.values()) {
|
|
@@ -9879,6 +9705,55 @@ function deparseExpr(e) {
|
|
|
9879
9705
|
}
|
|
9880
9706
|
}
|
|
9881
9707
|
|
|
9708
|
+
// src/types/resolve.ts
|
|
9709
|
+
var SERIALS = {
|
|
9710
|
+
smallserial: "int2",
|
|
9711
|
+
serial2: "int2",
|
|
9712
|
+
serial: "int4",
|
|
9713
|
+
serial4: "int4",
|
|
9714
|
+
bigserial: "int8",
|
|
9715
|
+
serial8: "int8"
|
|
9716
|
+
};
|
|
9717
|
+
function modOf(t, mods) {
|
|
9718
|
+
if (mods.length === 0) return null;
|
|
9719
|
+
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
9720
|
+
return { a: mods[0] };
|
|
9721
|
+
}
|
|
9722
|
+
function resolveTypeName(state, tn) {
|
|
9723
|
+
const joined = tn.parts.join(".");
|
|
9724
|
+
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
9725
|
+
if (bare !== null) {
|
|
9726
|
+
const serial = SERIALS[bare];
|
|
9727
|
+
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
9728
|
+
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
9729
|
+
}
|
|
9730
|
+
const builtin = normalizeTypeName(bare);
|
|
9731
|
+
if (builtin !== null) {
|
|
9732
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
9733
|
+
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
9734
|
+
}
|
|
9735
|
+
}
|
|
9736
|
+
const enumData = state.findEnum(tn.parts);
|
|
9737
|
+
if (enumData) {
|
|
9738
|
+
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
9739
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
9740
|
+
return { column: { id, mod: null }, domain: null, serial: null };
|
|
9741
|
+
}
|
|
9742
|
+
const domainData = state.findDomain(tn.parts);
|
|
9743
|
+
if (domainData) {
|
|
9744
|
+
if (tn.arrayDims > 0) {
|
|
9745
|
+
const id = arrayTypeOf(domainData.baseType.id);
|
|
9746
|
+
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
9747
|
+
}
|
|
9748
|
+
return {
|
|
9749
|
+
column: domainData.baseType,
|
|
9750
|
+
domain: `${domainData.schema}.${domainData.name}`,
|
|
9751
|
+
serial: null
|
|
9752
|
+
};
|
|
9753
|
+
}
|
|
9754
|
+
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
9755
|
+
}
|
|
9756
|
+
|
|
9882
9757
|
// src/sql/ruleutils.ts
|
|
9883
9758
|
var BOOL = "bool";
|
|
9884
9759
|
var TEXT = "text";
|
|
@@ -10673,7 +10548,11 @@ function getMiscFunctions() {
|
|
|
10673
10548
|
}
|
|
10674
10549
|
const name = argText(ctx, args[0]).toLowerCase();
|
|
10675
10550
|
const value = args[1].v === null ? "" : argText(ctx, args[1]);
|
|
10676
|
-
ctx.state.settings.
|
|
10551
|
+
if (!ctx.state.settings.has(name) && !name.includes("."))
|
|
10552
|
+
throw pgError("undefined_object", `unrecognized configuration parameter "${name}"`, "42704");
|
|
10553
|
+
validateStorageSetting(name, value);
|
|
10554
|
+
const local = args[2]?.v === true;
|
|
10555
|
+
if (!local || ctx.state.inTransaction) (local ? ctx.state.localSettings : ctx.state.settings).set(name, value);
|
|
10677
10556
|
return tv("text", value);
|
|
10678
10557
|
});
|
|
10679
10558
|
m.set(
|
|
@@ -10739,10 +10618,7 @@ function getMiscFunctions() {
|
|
|
10739
10618
|
if (!col)
|
|
10740
10619
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
10741
10620
|
if (!col.identity) return tv("text", null);
|
|
10742
|
-
return tv(
|
|
10743
|
-
"text",
|
|
10744
|
-
col.identity.sequence.split(".").map(quoteIdent).join(".")
|
|
10745
|
-
);
|
|
10621
|
+
return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
|
|
10746
10622
|
})
|
|
10747
10623
|
);
|
|
10748
10624
|
m.set("format_type", (ctx, args) => {
|
|
@@ -15666,6 +15542,146 @@ function isSrfName(name) {
|
|
|
15666
15542
|
return SRFS.has(name);
|
|
15667
15543
|
}
|
|
15668
15544
|
|
|
15545
|
+
// src/executor/relation.ts
|
|
15546
|
+
var RowScope = class {
|
|
15547
|
+
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
15548
|
+
this.columns = columns;
|
|
15549
|
+
this.row = row;
|
|
15550
|
+
this.parent = parent;
|
|
15551
|
+
this.rangeVars = rangeVars;
|
|
15552
|
+
}
|
|
15553
|
+
columns;
|
|
15554
|
+
row;
|
|
15555
|
+
parent;
|
|
15556
|
+
rangeVars;
|
|
15557
|
+
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
15558
|
+
lookup(parts) {
|
|
15559
|
+
if (parts.length === 1) {
|
|
15560
|
+
const name2 = parts[0];
|
|
15561
|
+
let found2;
|
|
15562
|
+
let count3 = 0;
|
|
15563
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
15564
|
+
const c = this.columns[i];
|
|
15565
|
+
if (c.name === name2 && !c.hidden) {
|
|
15566
|
+
count3++;
|
|
15567
|
+
if (count3 > 1) {
|
|
15568
|
+
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
15569
|
+
}
|
|
15570
|
+
found2 = tv(c.type, this.row[i] ?? null);
|
|
15571
|
+
}
|
|
15572
|
+
}
|
|
15573
|
+
if (found2 !== void 0) return found2;
|
|
15574
|
+
if (this.rangeVars.has(name2)) {
|
|
15575
|
+
return this.wholeRow(name2);
|
|
15576
|
+
}
|
|
15577
|
+
return this.parent?.lookup(parts);
|
|
15578
|
+
}
|
|
15579
|
+
const table = parts[parts.length - 2];
|
|
15580
|
+
const name = parts[parts.length - 1];
|
|
15581
|
+
let found;
|
|
15582
|
+
let count2 = 0;
|
|
15583
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
15584
|
+
const c = this.columns[i];
|
|
15585
|
+
if (c.table === table && c.name === name) {
|
|
15586
|
+
count2++;
|
|
15587
|
+
if (count2 > 1) {
|
|
15588
|
+
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
15589
|
+
}
|
|
15590
|
+
found = tv(c.type, this.row[i] ?? null);
|
|
15591
|
+
}
|
|
15592
|
+
}
|
|
15593
|
+
if (found !== void 0) return found;
|
|
15594
|
+
return this.parent?.lookup(parts);
|
|
15595
|
+
}
|
|
15596
|
+
/** Build a record value from all columns belonging to a range variable. */
|
|
15597
|
+
wholeRow(rangeVar) {
|
|
15598
|
+
const types = [];
|
|
15599
|
+
const values = [];
|
|
15600
|
+
const names = [];
|
|
15601
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
15602
|
+
const c = this.columns[i];
|
|
15603
|
+
if (c.table === rangeVar) {
|
|
15604
|
+
types.push(c.type);
|
|
15605
|
+
values.push(this.row[i] ?? null);
|
|
15606
|
+
names.push(c.name);
|
|
15607
|
+
}
|
|
15608
|
+
}
|
|
15609
|
+
if (types.length === 0) return void 0;
|
|
15610
|
+
return tv("record", { kind: "pgrecord", types, values, names });
|
|
15611
|
+
}
|
|
15612
|
+
hasRangeVar(name) {
|
|
15613
|
+
if (this.rangeVars.has(name)) return true;
|
|
15614
|
+
return this.parent?.hasRangeVar(name) ?? false;
|
|
15615
|
+
}
|
|
15616
|
+
};
|
|
15617
|
+
function childEnv(env, outer) {
|
|
15618
|
+
return {
|
|
15619
|
+
ctx: env.ctx,
|
|
15620
|
+
params: env.params,
|
|
15621
|
+
ctes: env.ctes,
|
|
15622
|
+
outer,
|
|
15623
|
+
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
15624
|
+
};
|
|
15625
|
+
}
|
|
15626
|
+
function relationResult(rel3, command) {
|
|
15627
|
+
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
15628
|
+
return {
|
|
15629
|
+
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
15630
|
+
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
15631
|
+
command,
|
|
15632
|
+
rowCount: rel3.rows.length
|
|
15633
|
+
};
|
|
15634
|
+
}
|
|
15635
|
+
function commandResult(command, rowCount) {
|
|
15636
|
+
return { columns: [], rows: [], command, rowCount };
|
|
15637
|
+
}
|
|
15638
|
+
function inferColumnName(e) {
|
|
15639
|
+
switch (e.type) {
|
|
15640
|
+
case "colref":
|
|
15641
|
+
return e.parts[e.parts.length - 1];
|
|
15642
|
+
case "func":
|
|
15643
|
+
return e.name[e.name.length - 1];
|
|
15644
|
+
case "cast": {
|
|
15645
|
+
const inner = inferColumnName(e.expr);
|
|
15646
|
+
if (inner !== "?column?") return inner;
|
|
15647
|
+
return e.target.parts[e.target.parts.length - 1];
|
|
15648
|
+
}
|
|
15649
|
+
case "collate":
|
|
15650
|
+
return inferColumnName(e.expr);
|
|
15651
|
+
case "case":
|
|
15652
|
+
return "case";
|
|
15653
|
+
case "array_ctor":
|
|
15654
|
+
case "array_query":
|
|
15655
|
+
return "array";
|
|
15656
|
+
case "row":
|
|
15657
|
+
return "row";
|
|
15658
|
+
case "subquery_expr":
|
|
15659
|
+
return e.kind === "exists" ? "exists" : "?column?";
|
|
15660
|
+
case "bool_lit":
|
|
15661
|
+
return "bool";
|
|
15662
|
+
case "extract":
|
|
15663
|
+
return "extract";
|
|
15664
|
+
case "position":
|
|
15665
|
+
return "position";
|
|
15666
|
+
case "substring_sql":
|
|
15667
|
+
return "substring";
|
|
15668
|
+
case "overlay":
|
|
15669
|
+
return "overlay";
|
|
15670
|
+
case "trim":
|
|
15671
|
+
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
15672
|
+
case "field_select":
|
|
15673
|
+
return e.field === "*" ? "?column?" : e.field;
|
|
15674
|
+
case "at_time_zone":
|
|
15675
|
+
return "timezone";
|
|
15676
|
+
case "grouping_func":
|
|
15677
|
+
return "grouping";
|
|
15678
|
+
case "subscript":
|
|
15679
|
+
return inferColumnName(e.base);
|
|
15680
|
+
default:
|
|
15681
|
+
return "?column?";
|
|
15682
|
+
}
|
|
15683
|
+
}
|
|
15684
|
+
|
|
15669
15685
|
// src/indexes/index.ts
|
|
15670
15686
|
var IndexStore = class _IndexStore {
|
|
15671
15687
|
name;
|
|
@@ -15728,53 +15744,228 @@ function ensureIndexStores(env, table) {
|
|
|
15728
15744
|
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
15729
15745
|
if (key !== null) store.insert(key, i);
|
|
15730
15746
|
}
|
|
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));
|
|
15747
|
+
stores.set(spec.name, store);
|
|
15748
|
+
}
|
|
15749
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
15750
|
+
if (schema) {
|
|
15751
|
+
for (const idx of schema.indexes.values()) {
|
|
15752
|
+
if (idx.table !== table.name || idx.unique) continue;
|
|
15753
|
+
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
15754
|
+
}
|
|
15755
|
+
}
|
|
15756
|
+
table.indexStores = stores;
|
|
15757
|
+
return stores;
|
|
15758
|
+
}
|
|
15759
|
+
function indexStoreFor(env, table, spec) {
|
|
15760
|
+
const stores = ensureIndexStores(env, table);
|
|
15761
|
+
let store = stores.get(spec.name);
|
|
15762
|
+
if (!store) {
|
|
15763
|
+
store = new IndexStore(spec.name, true);
|
|
15764
|
+
for (let i = 0; i < table.rowCount(); i++) {
|
|
15765
|
+
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
15766
|
+
if (key !== null) store.insert(key, i);
|
|
15767
|
+
}
|
|
15768
|
+
stores.set(spec.name, store);
|
|
15769
|
+
}
|
|
15770
|
+
return store;
|
|
15771
|
+
}
|
|
15772
|
+
function indexInsertRow(env, table, rowIdx, row) {
|
|
15773
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15774
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15775
|
+
if (key === null) continue;
|
|
15776
|
+
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
15777
|
+
}
|
|
15778
|
+
}
|
|
15779
|
+
function indexRemoveRow(env, table, rowIdx, row) {
|
|
15780
|
+
if (!table.indexStores) return;
|
|
15781
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15782
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15783
|
+
if (key === null) continue;
|
|
15784
|
+
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
15785
|
+
}
|
|
15786
|
+
}
|
|
15787
|
+
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
15788
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
15789
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
15790
|
+
}
|
|
15791
|
+
function rebuildTableIndexes(env, table) {
|
|
15792
|
+
table.indexStores = null;
|
|
15793
|
+
ensureIndexStores(env, table);
|
|
15794
|
+
}
|
|
15795
|
+
|
|
15796
|
+
// src/constraints/enforce.ts
|
|
15797
|
+
function tableScope(table, row) {
|
|
15798
|
+
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
15799
|
+
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
15800
|
+
}
|
|
15801
|
+
function checkNotNull(env, table, row) {
|
|
15802
|
+
void env;
|
|
15803
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
15804
|
+
const c = table.columns[i];
|
|
15805
|
+
if (c.notNull && (row[i] ?? null) === null) {
|
|
15806
|
+
throw pgError(
|
|
15807
|
+
"not_null_violation",
|
|
15808
|
+
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
15809
|
+
"23502"
|
|
15810
|
+
);
|
|
15811
|
+
}
|
|
15812
|
+
}
|
|
15813
|
+
}
|
|
15814
|
+
function checkChecks(env, table, row) {
|
|
15815
|
+
for (const con of table.constraints) {
|
|
15816
|
+
if (con.kind !== "check") continue;
|
|
15817
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
15818
|
+
const v = evalExpr(env.ctx, scope, con.expr);
|
|
15819
|
+
if (v.v === null) continue;
|
|
15820
|
+
const b = castTo(env.ctx, v, "bool", {});
|
|
15821
|
+
if (b.v !== true) {
|
|
15822
|
+
throw pgError(
|
|
15823
|
+
"check_violation",
|
|
15824
|
+
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
15825
|
+
"23514"
|
|
15826
|
+
);
|
|
15827
|
+
}
|
|
15828
|
+
}
|
|
15829
|
+
}
|
|
15830
|
+
function uniqueSpecsFor(env, table) {
|
|
15831
|
+
const specs = [];
|
|
15832
|
+
for (const con of table.constraints) {
|
|
15833
|
+
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
15834
|
+
specs.push({
|
|
15835
|
+
name: con.name,
|
|
15836
|
+
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
15837
|
+
columnNames: con.columns,
|
|
15838
|
+
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
15839
|
+
where: null,
|
|
15840
|
+
isPrimary: con.kind === "primary_key"
|
|
15841
|
+
});
|
|
15842
|
+
}
|
|
15843
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
15844
|
+
if (schema) {
|
|
15845
|
+
for (const idx of schema.indexes.values()) {
|
|
15846
|
+
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
15847
|
+
specs.push(uniqueSpecOfIndex(table, idx));
|
|
15848
|
+
}
|
|
15849
|
+
}
|
|
15850
|
+
return specs;
|
|
15851
|
+
}
|
|
15852
|
+
function uniqueSpecOfIndex(table, idx) {
|
|
15853
|
+
return {
|
|
15854
|
+
name: idx.name,
|
|
15855
|
+
keys: idx.columns.map((c) => ({
|
|
15856
|
+
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
15857
|
+
expr: c.expr
|
|
15858
|
+
})),
|
|
15859
|
+
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
15860
|
+
nullsNotDistinct: idx.nullsNotDistinct,
|
|
15861
|
+
where: idx.where,
|
|
15862
|
+
isPrimary: false
|
|
15863
|
+
};
|
|
15864
|
+
}
|
|
15865
|
+
function uniqueKeyOf(env, table, spec, row) {
|
|
15866
|
+
if (spec.where) {
|
|
15867
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
15868
|
+
const v = evalExpr(env.ctx, scope, spec.where);
|
|
15869
|
+
if (v.v !== true) return null;
|
|
15870
|
+
}
|
|
15871
|
+
const parts = [];
|
|
15872
|
+
let hasNull = false;
|
|
15873
|
+
for (const k of spec.keys) {
|
|
15874
|
+
let value;
|
|
15875
|
+
let type;
|
|
15876
|
+
if (k.expr) {
|
|
15877
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
15878
|
+
const v = evalExpr(env.ctx, scope, k.expr);
|
|
15879
|
+
value = v.v;
|
|
15880
|
+
type = v.t === "unknown" ? "text" : v.t;
|
|
15881
|
+
} else {
|
|
15882
|
+
value = row[k.colIdx] ?? null;
|
|
15883
|
+
type = table.columns[k.colIdx].type.id;
|
|
15884
|
+
}
|
|
15885
|
+
if (value === null) {
|
|
15886
|
+
hasNull = true;
|
|
15887
|
+
parts.push("\0N");
|
|
15888
|
+
} else {
|
|
15889
|
+
parts.push(datumKey(type, value));
|
|
15890
|
+
}
|
|
15891
|
+
}
|
|
15892
|
+
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
15893
|
+
return parts.join("");
|
|
15894
|
+
}
|
|
15895
|
+
function checkUnique(env, table, row, selfIdx) {
|
|
15896
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
15897
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15898
|
+
if (key === null) continue;
|
|
15899
|
+
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
15900
|
+
}
|
|
15901
|
+
}
|
|
15902
|
+
function findConflict(env, table, spec, row) {
|
|
15903
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
15904
|
+
if (key === null) return null;
|
|
15905
|
+
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
15906
|
+
return hits.length > 0 ? hits[0] : null;
|
|
15907
|
+
}
|
|
15908
|
+
function checkForeignKeys(env, table, row) {
|
|
15909
|
+
const state = env.ctx.state;
|
|
15910
|
+
for (const con of table.constraints) {
|
|
15911
|
+
if (con.kind !== "foreign_key") continue;
|
|
15912
|
+
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
15913
|
+
const nulls = values.filter((v) => v === null).length;
|
|
15914
|
+
if (con.match === "simple" && nulls > 0) continue;
|
|
15915
|
+
if (con.match === "full") {
|
|
15916
|
+
if (nulls === values.length) continue;
|
|
15917
|
+
if (nulls > 0) {
|
|
15918
|
+
throw pgError(
|
|
15919
|
+
"constraint_foreign_key",
|
|
15920
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
15921
|
+
"23503"
|
|
15922
|
+
);
|
|
15923
|
+
}
|
|
15924
|
+
}
|
|
15925
|
+
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
15926
|
+
if (!refTable) {
|
|
15927
|
+
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
15928
|
+
}
|
|
15929
|
+
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
15930
|
+
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
15931
|
+
const wanted = values.map((v, i) => {
|
|
15932
|
+
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
15933
|
+
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
15934
|
+
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
15935
|
+
}).join("");
|
|
15936
|
+
let found = false;
|
|
15937
|
+
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
15938
|
+
const r = refTable.rowAt(i);
|
|
15939
|
+
const key = refIdxs.map((ri, j) => {
|
|
15940
|
+
const v = r[ri] ?? null;
|
|
15941
|
+
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
15942
|
+
}).join("");
|
|
15943
|
+
if (key === wanted) {
|
|
15944
|
+
found = true;
|
|
15945
|
+
break;
|
|
15946
|
+
}
|
|
15947
|
+
}
|
|
15948
|
+
if (!found) {
|
|
15949
|
+
throw pgError(
|
|
15950
|
+
"constraint_foreign_key",
|
|
15951
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
15952
|
+
"23503"
|
|
15953
|
+
);
|
|
15738
15954
|
}
|
|
15739
15955
|
}
|
|
15740
|
-
table.indexStores = stores;
|
|
15741
|
-
return stores;
|
|
15742
15956
|
}
|
|
15743
|
-
function
|
|
15744
|
-
const
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15957
|
+
function referencingConstraints(env, table) {
|
|
15958
|
+
const out = [];
|
|
15959
|
+
for (const schema of env.ctx.state.schemas.values()) {
|
|
15960
|
+
for (const t of schema.tables.values()) {
|
|
15961
|
+
for (const con of t.constraints) {
|
|
15962
|
+
if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
|
|
15963
|
+
out.push({ table: t, constraint: con });
|
|
15964
|
+
}
|
|
15965
|
+
}
|
|
15751
15966
|
}
|
|
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
15967
|
}
|
|
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);
|
|
15968
|
+
return out;
|
|
15778
15969
|
}
|
|
15779
15970
|
|
|
15780
15971
|
// src/planner/access.ts
|
|
@@ -17660,10 +17851,9 @@ var Parser = class {
|
|
|
17660
17851
|
return this.parseCreateFunction(orReplace);
|
|
17661
17852
|
}
|
|
17662
17853
|
if (this.atKw("trigger") || this.atKw("constraint") && this.atKw("trigger", 1)) {
|
|
17663
|
-
|
|
17664
|
-
}
|
|
17854
|
+
const constraint = this.eatKw("constraint");
|
|
17665
17855
|
this.expectKw("trigger");
|
|
17666
|
-
return this.parseCreateTrigger(orReplace);
|
|
17856
|
+
return this.parseCreateTrigger(orReplace, constraint);
|
|
17667
17857
|
}
|
|
17668
17858
|
if (this.atKw("extension")) {
|
|
17669
17859
|
this.pos++;
|
|
@@ -18484,7 +18674,7 @@ var Parser = class {
|
|
|
18484
18674
|
strict: strict2
|
|
18485
18675
|
};
|
|
18486
18676
|
}
|
|
18487
|
-
parseCreateTrigger(orReplace) {
|
|
18677
|
+
parseCreateTrigger(orReplace, constraint) {
|
|
18488
18678
|
const name = this.ident();
|
|
18489
18679
|
let timing;
|
|
18490
18680
|
if (this.eatKw("before")) timing = "before";
|
|
@@ -18514,9 +18704,18 @@ var Parser = class {
|
|
|
18514
18704
|
this.expectKw("on");
|
|
18515
18705
|
const table = this.qualifiedName();
|
|
18516
18706
|
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18707
|
+
let deferrable = false;
|
|
18708
|
+
let initiallyDeferred = false;
|
|
18709
|
+
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
18710
|
+
else if (this.eatKw("deferrable")) deferrable = true;
|
|
18711
|
+
if (this.eatKw("initially")) {
|
|
18712
|
+
if (this.eatKw("deferred")) initiallyDeferred = true;
|
|
18713
|
+
else this.expectKw("immediate");
|
|
18714
|
+
}
|
|
18715
|
+
if ((deferrable || initiallyDeferred) && !constraint)
|
|
18716
|
+
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
18717
|
+
if (initiallyDeferred && !deferrable)
|
|
18718
|
+
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
18520
18719
|
let forEachRow = false;
|
|
18521
18720
|
if (this.eatKw("for")) {
|
|
18522
18721
|
this.eatKw("each");
|
|
@@ -18541,7 +18740,21 @@ var Parser = class {
|
|
|
18541
18740
|
} while (this.eatPunct(","));
|
|
18542
18741
|
}
|
|
18543
18742
|
this.expectPunct(")");
|
|
18544
|
-
return {
|
|
18743
|
+
return {
|
|
18744
|
+
type: "create_trigger",
|
|
18745
|
+
constraint,
|
|
18746
|
+
deferrable,
|
|
18747
|
+
initiallyDeferred,
|
|
18748
|
+
orReplace,
|
|
18749
|
+
name,
|
|
18750
|
+
timing,
|
|
18751
|
+
events,
|
|
18752
|
+
table,
|
|
18753
|
+
forEachRow,
|
|
18754
|
+
when,
|
|
18755
|
+
funcName,
|
|
18756
|
+
funcArgs
|
|
18757
|
+
};
|
|
18545
18758
|
}
|
|
18546
18759
|
// --- ALTER --------------------------------------------------------------------
|
|
18547
18760
|
parseAlter() {
|
|
@@ -18886,9 +19099,15 @@ var Parser = class {
|
|
|
18886
19099
|
this.skipToStatementEnd();
|
|
18887
19100
|
return { type: "no_op", what: "SET TRANSACTION" };
|
|
18888
19101
|
}
|
|
18889
|
-
if (this.
|
|
18890
|
-
this.
|
|
18891
|
-
|
|
19102
|
+
if (this.eatKw("constraints")) {
|
|
19103
|
+
const names = this.eatKw("all") ? null : [];
|
|
19104
|
+
if (names)
|
|
19105
|
+
do {
|
|
19106
|
+
names.push(this.qualifiedName());
|
|
19107
|
+
} while (this.eatPunct(","));
|
|
19108
|
+
const deferred = this.eatKw("deferred");
|
|
19109
|
+
if (!deferred) this.expectKw("immediate");
|
|
19110
|
+
return { type: "set_constraints", names, deferred };
|
|
18892
19111
|
}
|
|
18893
19112
|
if (this.atKw("role") || this.atKw("session", 0) && this.atKw("authorization", 1)) {
|
|
18894
19113
|
this.skipToStatementEnd();
|
|
@@ -21263,12 +21482,12 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
21263
21482
|
table: null
|
|
21264
21483
|
}));
|
|
21265
21484
|
const seen = /* @__PURE__ */ new Set();
|
|
21266
|
-
const
|
|
21485
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
|
|
21267
21486
|
let result = [];
|
|
21268
21487
|
let working = [];
|
|
21269
21488
|
for (const row of base.rows) {
|
|
21270
21489
|
if (!body.all) {
|
|
21271
|
-
const k =
|
|
21490
|
+
const k = keyOf2(row);
|
|
21272
21491
|
if (seen.has(k)) continue;
|
|
21273
21492
|
seen.add(k);
|
|
21274
21493
|
}
|
|
@@ -21301,7 +21520,7 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
21301
21520
|
return castTo(env.ctx, tv(srcT === UNKNOWN ? "text" : srcT, v), columns[i].type, {}).v;
|
|
21302
21521
|
});
|
|
21303
21522
|
if (!body.all) {
|
|
21304
|
-
const k =
|
|
21523
|
+
const k = keyOf2(row);
|
|
21305
21524
|
if (seen.has(k)) continue;
|
|
21306
21525
|
seen.add(k);
|
|
21307
21526
|
}
|
|
@@ -22481,7 +22700,7 @@ function setOpRelation(env, op) {
|
|
|
22481
22700
|
);
|
|
22482
22701
|
const lrows = normalize(left);
|
|
22483
22702
|
const rrows = normalize(right);
|
|
22484
|
-
const
|
|
22703
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
|
|
22485
22704
|
let rows;
|
|
22486
22705
|
switch (op.op) {
|
|
22487
22706
|
case "union": {
|
|
@@ -22489,7 +22708,7 @@ function setOpRelation(env, op) {
|
|
|
22489
22708
|
if (!op.all) {
|
|
22490
22709
|
const seen = /* @__PURE__ */ new Set();
|
|
22491
22710
|
rows = rows.filter((r) => {
|
|
22492
|
-
const k =
|
|
22711
|
+
const k = keyOf2(r);
|
|
22493
22712
|
if (seen.has(k)) return false;
|
|
22494
22713
|
seen.add(k);
|
|
22495
22714
|
return true;
|
|
@@ -22500,13 +22719,13 @@ function setOpRelation(env, op) {
|
|
|
22500
22719
|
case "intersect": {
|
|
22501
22720
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
22502
22721
|
for (const r of rrows) {
|
|
22503
|
-
const k =
|
|
22722
|
+
const k = keyOf2(r);
|
|
22504
22723
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
22505
22724
|
}
|
|
22506
22725
|
rows = [];
|
|
22507
22726
|
const emitted = /* @__PURE__ */ new Set();
|
|
22508
22727
|
for (const r of lrows) {
|
|
22509
|
-
const k =
|
|
22728
|
+
const k = keyOf2(r);
|
|
22510
22729
|
const avail = rightCounts.get(k) ?? 0;
|
|
22511
22730
|
if (avail <= 0) continue;
|
|
22512
22731
|
if (op.all) {
|
|
@@ -22522,13 +22741,13 @@ function setOpRelation(env, op) {
|
|
|
22522
22741
|
case "except": {
|
|
22523
22742
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
22524
22743
|
for (const r of rrows) {
|
|
22525
|
-
const k =
|
|
22744
|
+
const k = keyOf2(r);
|
|
22526
22745
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
22527
22746
|
}
|
|
22528
22747
|
rows = [];
|
|
22529
22748
|
const emitted = /* @__PURE__ */ new Set();
|
|
22530
22749
|
for (const r of lrows) {
|
|
22531
|
-
const k =
|
|
22750
|
+
const k = keyOf2(r);
|
|
22532
22751
|
if (op.all) {
|
|
22533
22752
|
const avail = rightCounts.get(k) ?? 0;
|
|
22534
22753
|
if (avail > 0) {
|
|
@@ -22976,207 +23195,54 @@ function executeCore(env0, core, orderBy, opts) {
|
|
|
22976
23195
|
}).join("");
|
|
22977
23196
|
if (seen.has(k)) return false;
|
|
22978
23197
|
seen.add(k);
|
|
22979
|
-
return true;
|
|
22980
|
-
});
|
|
22981
|
-
}
|
|
22982
|
-
}
|
|
22983
|
-
rel3 = stripHidden(rel3);
|
|
22984
|
-
return rel3;
|
|
22985
|
-
}
|
|
22986
|
-
function executeSelectStmt(env0, stmt) {
|
|
22987
|
-
const env = applyWith(env0, stmt.with);
|
|
22988
|
-
let rel3;
|
|
22989
|
-
if (stmt.body.type === "select_core") {
|
|
22990
|
-
rel3 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
|
|
22991
|
-
} else {
|
|
22992
|
-
rel3 = executeBody(env, stmt.body);
|
|
22993
|
-
const specs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
22994
|
-
if (specs.length > 0) sortRows(env, rel3, specs);
|
|
22995
|
-
rel3 = stripHidden(rel3);
|
|
22996
|
-
}
|
|
22997
|
-
if (stmt.limitWithTies) {
|
|
22998
|
-
if (stmt.orderBy.length === 0) {
|
|
22999
|
-
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
23000
|
-
}
|
|
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
|
-
);
|
|
23198
|
+
return true;
|
|
23199
|
+
});
|
|
23165
23200
|
}
|
|
23166
23201
|
}
|
|
23202
|
+
rel3 = stripHidden(rel3);
|
|
23203
|
+
return rel3;
|
|
23167
23204
|
}
|
|
23168
|
-
function
|
|
23169
|
-
const
|
|
23170
|
-
|
|
23171
|
-
|
|
23172
|
-
|
|
23173
|
-
|
|
23174
|
-
|
|
23175
|
-
|
|
23176
|
-
|
|
23205
|
+
function executeSelectStmt(env0, stmt) {
|
|
23206
|
+
const env = applyWith(env0, stmt.with);
|
|
23207
|
+
let rel3;
|
|
23208
|
+
if (stmt.body.type === "select_core") {
|
|
23209
|
+
rel3 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
|
|
23210
|
+
} else {
|
|
23211
|
+
rel3 = executeBody(env, stmt.body);
|
|
23212
|
+
const specs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
23213
|
+
if (specs.length > 0) sortRows(env, rel3, specs);
|
|
23214
|
+
rel3 = stripHidden(rel3);
|
|
23215
|
+
}
|
|
23216
|
+
if (stmt.limitWithTies) {
|
|
23217
|
+
if (stmt.orderBy.length === 0) {
|
|
23218
|
+
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
23177
23219
|
}
|
|
23220
|
+
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
23221
|
+
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
23178
23222
|
}
|
|
23179
|
-
return
|
|
23223
|
+
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
23224
|
+
}
|
|
23225
|
+
|
|
23226
|
+
// src/executor/triggers-scope.ts
|
|
23227
|
+
function triggerScope(table, newRow, oldRow) {
|
|
23228
|
+
const cols = [];
|
|
23229
|
+
const row = [];
|
|
23230
|
+
const rangeVars = /* @__PURE__ */ new Set();
|
|
23231
|
+
if (newRow) {
|
|
23232
|
+
rangeVars.add("new");
|
|
23233
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
23234
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
23235
|
+
row.push(newRow[i] ?? null);
|
|
23236
|
+
}
|
|
23237
|
+
}
|
|
23238
|
+
if (oldRow) {
|
|
23239
|
+
rangeVars.add("old");
|
|
23240
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
23241
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
23242
|
+
row.push(oldRow[i] ?? null);
|
|
23243
|
+
}
|
|
23244
|
+
}
|
|
23245
|
+
return new RowScope(cols, row, null, rangeVars);
|
|
23180
23246
|
}
|
|
23181
23247
|
|
|
23182
23248
|
// src/executor/triggers.ts
|
|
@@ -23192,6 +23258,18 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
23192
23258
|
for (const t of table.triggers) {
|
|
23193
23259
|
if (t.timing !== timing || !matches2(t, event) || !t.forEachRow) continue;
|
|
23194
23260
|
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
23261
|
+
if (t.constraint && timing === "after") {
|
|
23262
|
+
if (t.when && !evalPredicate(env, triggerScope(table, newRow, oldRow), t.when)) continue;
|
|
23263
|
+
env.ctx.state.pendingTriggers.push({
|
|
23264
|
+
schema: table.schema,
|
|
23265
|
+
table: table.name,
|
|
23266
|
+
trigger: t.name,
|
|
23267
|
+
event,
|
|
23268
|
+
oldRow: oldRow?.slice() ?? null,
|
|
23269
|
+
newRow: newRow?.slice() ?? null
|
|
23270
|
+
});
|
|
23271
|
+
continue;
|
|
23272
|
+
}
|
|
23195
23273
|
const result = executor(env, table, t, event, oldRow, timing === "before" ? row : newRow);
|
|
23196
23274
|
if (timing === "before") {
|
|
23197
23275
|
if (result === null) return { row: null };
|
|
@@ -23200,6 +23278,167 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
23200
23278
|
}
|
|
23201
23279
|
return { row };
|
|
23202
23280
|
}
|
|
23281
|
+
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
23282
|
+
function flushConstraintTriggers(state, all = false) {
|
|
23283
|
+
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
23284
|
+
for (let i = 0; i < state.pendingTriggers.length; ) {
|
|
23285
|
+
const pending = state.pendingTriggers[i];
|
|
23286
|
+
const table = state.schemas.get(pending.schema)?.tables.get(pending.table);
|
|
23287
|
+
const trigger = table?.triggers.find((t) => t.name === pending.trigger);
|
|
23288
|
+
if (!table || !trigger) {
|
|
23289
|
+
state.pendingTriggers.splice(i, 1);
|
|
23290
|
+
continue;
|
|
23291
|
+
}
|
|
23292
|
+
const deferred = trigger.deferrable && (state.constraintModes.get(keyOf(table.schema, trigger.name)) ?? trigger.initiallyDeferred);
|
|
23293
|
+
if (!all && state.inTransaction && deferred) {
|
|
23294
|
+
i++;
|
|
23295
|
+
continue;
|
|
23296
|
+
}
|
|
23297
|
+
if (!executor) throw unsupported(`trigger "${trigger.name}" execution`);
|
|
23298
|
+
state.pendingTriggers.splice(i, 1);
|
|
23299
|
+
const changes = state.changes;
|
|
23300
|
+
try {
|
|
23301
|
+
executor(env, table, { ...trigger, when: null }, pending.event, pending.oldRow, pending.newRow);
|
|
23302
|
+
} catch (error) {
|
|
23303
|
+
state.pendingTriggers.splice(i, 0, pending);
|
|
23304
|
+
throw error;
|
|
23305
|
+
} finally {
|
|
23306
|
+
state.changes = changes;
|
|
23307
|
+
}
|
|
23308
|
+
}
|
|
23309
|
+
}
|
|
23310
|
+
function setConstraints(state, stmt) {
|
|
23311
|
+
if (!state.inTransaction) return;
|
|
23312
|
+
const matches3 = [];
|
|
23313
|
+
if (stmt.names) {
|
|
23314
|
+
for (const name of stmt.names) {
|
|
23315
|
+
const schemas = name.length > 1 ? [name[name.length - 2]] : state.effectiveSearchPath();
|
|
23316
|
+
let found = false;
|
|
23317
|
+
for (const schema of schemas) {
|
|
23318
|
+
const items = [...state.schemas.get(schema)?.tables.values() ?? []].flatMap(
|
|
23319
|
+
(table) => table.triggers.filter((t) => t.constraint && t.name === name[name.length - 1])
|
|
23320
|
+
);
|
|
23321
|
+
if (items.length) {
|
|
23322
|
+
for (const trigger of items) matches3.push({ schema, trigger });
|
|
23323
|
+
found = true;
|
|
23324
|
+
break;
|
|
23325
|
+
}
|
|
23326
|
+
}
|
|
23327
|
+
if (!found) throw pgError("undefined_object", `constraint "${name.join(".")}" does not exist`, "42704");
|
|
23328
|
+
}
|
|
23329
|
+
} else {
|
|
23330
|
+
for (const schema of state.schemas.values())
|
|
23331
|
+
for (const table of schema.tables.values())
|
|
23332
|
+
for (const trigger of table.triggers)
|
|
23333
|
+
if (trigger.constraint && trigger.deferrable) matches3.push({ schema: schema.name, trigger });
|
|
23334
|
+
}
|
|
23335
|
+
for (const { trigger } of matches3)
|
|
23336
|
+
if (stmt.deferred && !trigger.deferrable)
|
|
23337
|
+
throw pgError("misuse", `constraint "${trigger.name}" is not deferrable`, "55000");
|
|
23338
|
+
const previous = new Map(state.constraintModes);
|
|
23339
|
+
for (const { schema, trigger } of matches3) state.constraintModes.set(keyOf(schema, trigger.name), stmt.deferred);
|
|
23340
|
+
try {
|
|
23341
|
+
if (!stmt.deferred) flushConstraintTriggers(state);
|
|
23342
|
+
} catch (error) {
|
|
23343
|
+
state.constraintModes = previous;
|
|
23344
|
+
throw error;
|
|
23345
|
+
}
|
|
23346
|
+
}
|
|
23347
|
+
|
|
23348
|
+
// src/transactions/manager.ts
|
|
23349
|
+
var TransactionManager = class {
|
|
23350
|
+
constructor(state) {
|
|
23351
|
+
this.state = state;
|
|
23352
|
+
}
|
|
23353
|
+
state;
|
|
23354
|
+
base = null;
|
|
23355
|
+
savepoints = [];
|
|
23356
|
+
freezeDepth = 0;
|
|
23357
|
+
get inTransaction() {
|
|
23358
|
+
return this.base !== null;
|
|
23359
|
+
}
|
|
23360
|
+
takeSnapshot() {
|
|
23361
|
+
this.state.freezeShared();
|
|
23362
|
+
this.freezeDepth++;
|
|
23363
|
+
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
23364
|
+
}
|
|
23365
|
+
restore(snap) {
|
|
23366
|
+
this.state.restoreFrom(snap.state);
|
|
23367
|
+
this.state.prng.setState(snap.prngState);
|
|
23368
|
+
}
|
|
23369
|
+
thawOnce() {
|
|
23370
|
+
if (this.freezeDepth > 0) {
|
|
23371
|
+
this.state.thawShared();
|
|
23372
|
+
this.freezeDepth--;
|
|
23373
|
+
}
|
|
23374
|
+
}
|
|
23375
|
+
begin() {
|
|
23376
|
+
if (this.base !== null) {
|
|
23377
|
+
return;
|
|
23378
|
+
}
|
|
23379
|
+
this.base = this.takeSnapshot();
|
|
23380
|
+
this.state.inTransaction = true;
|
|
23381
|
+
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
23382
|
+
}
|
|
23383
|
+
commit() {
|
|
23384
|
+
try {
|
|
23385
|
+
flushConstraintTriggers(this.state, true);
|
|
23386
|
+
} catch (error) {
|
|
23387
|
+
this.rollback();
|
|
23388
|
+
throw error;
|
|
23389
|
+
}
|
|
23390
|
+
this.base = null;
|
|
23391
|
+
this.savepoints = [];
|
|
23392
|
+
this.state.inTransaction = false;
|
|
23393
|
+
this.state.localSettings.clear();
|
|
23394
|
+
this.state.pendingTriggers = [];
|
|
23395
|
+
this.state.constraintModes.clear();
|
|
23396
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
23397
|
+
}
|
|
23398
|
+
rollback() {
|
|
23399
|
+
if (this.base !== null) {
|
|
23400
|
+
this.restore(this.base);
|
|
23401
|
+
}
|
|
23402
|
+
this.base = null;
|
|
23403
|
+
this.savepoints = [];
|
|
23404
|
+
this.state.inTransaction = false;
|
|
23405
|
+
this.state.localSettings.clear();
|
|
23406
|
+
this.state.pendingTriggers = [];
|
|
23407
|
+
this.state.constraintModes.clear();
|
|
23408
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
23409
|
+
}
|
|
23410
|
+
savepoint(name) {
|
|
23411
|
+
if (this.base === null) {
|
|
23412
|
+
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
23413
|
+
}
|
|
23414
|
+
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
23415
|
+
}
|
|
23416
|
+
releaseSavepoint(name) {
|
|
23417
|
+
const idx = this.findSavepoint(name);
|
|
23418
|
+
this.savepoints.splice(idx);
|
|
23419
|
+
}
|
|
23420
|
+
rollbackToSavepoint(name) {
|
|
23421
|
+
const idx = this.findSavepoint(name);
|
|
23422
|
+
const sp = this.savepoints[idx];
|
|
23423
|
+
this.restore(sp.snap);
|
|
23424
|
+
this.savepoints.splice(idx + 1);
|
|
23425
|
+
}
|
|
23426
|
+
findSavepoint(name) {
|
|
23427
|
+
if (this.base === null) {
|
|
23428
|
+
throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
|
|
23429
|
+
}
|
|
23430
|
+
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
23431
|
+
if (this.savepoints[i].name === name) return i;
|
|
23432
|
+
}
|
|
23433
|
+
throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
|
|
23434
|
+
}
|
|
23435
|
+
reset() {
|
|
23436
|
+
this.base = null;
|
|
23437
|
+
this.savepoints = [];
|
|
23438
|
+
this.state.inTransaction = false;
|
|
23439
|
+
this.freezeDepth = 0;
|
|
23440
|
+
}
|
|
23441
|
+
};
|
|
23203
23442
|
|
|
23204
23443
|
// src/executor/dml.ts
|
|
23205
23444
|
function withStatementRollback(env, fn) {
|
|
@@ -23889,6 +24128,7 @@ function executeSet(env, stmt) {
|
|
|
23889
24128
|
else target.delete(name);
|
|
23890
24129
|
return commandResult("SET", 0);
|
|
23891
24130
|
}
|
|
24131
|
+
validateStorageSetting(name, stmt.value);
|
|
23892
24132
|
target.set(name, stmt.value);
|
|
23893
24133
|
return commandResult("SET", 0);
|
|
23894
24134
|
}
|
|
@@ -24194,64 +24434,6 @@ function executeCopyFromData(env, stmt, data) {
|
|
|
24194
24434
|
};
|
|
24195
24435
|
}
|
|
24196
24436
|
|
|
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
24437
|
// src/runtime/clock.ts
|
|
24256
24438
|
var DEFAULT_NOW = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
24257
24439
|
function fixedClock(instant = DEFAULT_NOW) {
|
|
@@ -25219,7 +25401,7 @@ function pgClass(ctx) {
|
|
|
25219
25401
|
v.materialized ? "m" : "v",
|
|
25220
25402
|
v.columns?.length ?? 0,
|
|
25221
25403
|
v.matRows?.length ?? 0,
|
|
25222
|
-
|
|
25404
|
+
v.materialized && [...schemaData.indexes.values()].some((i) => i.tableOid === v.oid),
|
|
25223
25405
|
!v.materialized || v.matRows !== null,
|
|
25224
25406
|
relPersistence(v)
|
|
25225
25407
|
);
|
|
@@ -25485,7 +25667,7 @@ function pgIndex(ctx) {
|
|
|
25485
25667
|
const valid = i.valid !== false;
|
|
25486
25668
|
rows.push([
|
|
25487
25669
|
i.oid ?? 0,
|
|
25488
|
-
table?.oid ?? 0,
|
|
25670
|
+
table?.oid ?? i.tableOid ?? 0,
|
|
25489
25671
|
indexAttributeCount(i),
|
|
25490
25672
|
i.columns.length,
|
|
25491
25673
|
i.unique,
|
|
@@ -25657,7 +25839,7 @@ function pgStatUserIndexes(ctx) {
|
|
|
25657
25839
|
for (const index of schema.indexes.values()) {
|
|
25658
25840
|
const table = schema.tables.get(index.table);
|
|
25659
25841
|
rows.push([
|
|
25660
|
-
table?.oid ?? 0,
|
|
25842
|
+
table?.oid ?? index.tableOid ?? 0,
|
|
25661
25843
|
index.oid ?? 0,
|
|
25662
25844
|
schema.name,
|
|
25663
25845
|
index.table,
|
|
@@ -26252,26 +26434,6 @@ function runTriggerBody(env, table, stmts, vars) {
|
|
|
26252
26434
|
}
|
|
26253
26435
|
}
|
|
26254
26436
|
}
|
|
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
26437
|
function executeTrigger(env, table, trigger, _event, oldRow, newRow) {
|
|
26276
26438
|
const state = env.ctx.state;
|
|
26277
26439
|
if (trigger.when !== null && !evalPredicate(env, triggerScope(table, newRow, oldRow), trigger.when)) {
|
|
@@ -27238,7 +27400,8 @@ function executeCreateTableAs(env, stmt) {
|
|
|
27238
27400
|
}
|
|
27239
27401
|
function executeCreateIndex(env, stmt) {
|
|
27240
27402
|
const state = env.ctx.state;
|
|
27241
|
-
const
|
|
27403
|
+
const view = state.findView(stmt.table);
|
|
27404
|
+
const table = state.findTable(stmt.table) ?? (view?.materialized ? materializedTable(view) : void 0);
|
|
27242
27405
|
if (!table) {
|
|
27243
27406
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
27244
27407
|
}
|
|
@@ -27350,13 +27513,22 @@ function executeRefreshMatView(env, stmt) {
|
|
|
27350
27513
|
if (!found?.materialized) {
|
|
27351
27514
|
throw pgError("undefined_table", `materialized view "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
27352
27515
|
}
|
|
27516
|
+
const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), found.query);
|
|
27517
|
+
const next = {
|
|
27518
|
+
...found,
|
|
27519
|
+
matColumns: rel3.columns.map((c, i) => ({
|
|
27520
|
+
name: found.columns?.[i] ?? c.name,
|
|
27521
|
+
type: c.type === UNKNOWN ? "text" : c.type
|
|
27522
|
+
})),
|
|
27523
|
+
matRows: stmt.withData ? rel3.rows : null
|
|
27524
|
+
};
|
|
27525
|
+
const table = materializedTable(next);
|
|
27526
|
+
for (const index of env.ctx.state.getSchema(found.schema).indexes.values()) {
|
|
27527
|
+
if (index.tableOid === found.oid && index.valid !== false) assertUniqueIndexBuildable(env, table, index);
|
|
27528
|
+
}
|
|
27353
27529
|
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;
|
|
27530
|
+
view.matColumns = next.matColumns;
|
|
27531
|
+
view.matRows = next.matRows;
|
|
27360
27532
|
return commandResult("REFRESH MATERIALIZED VIEW", 0);
|
|
27361
27533
|
}
|
|
27362
27534
|
function executeCreateSchema(env, stmt) {
|
|
@@ -27498,6 +27670,8 @@ function executeCreateFunction(env, stmt) {
|
|
|
27498
27670
|
return commandResult("CREATE FUNCTION", 0);
|
|
27499
27671
|
}
|
|
27500
27672
|
function executeCreateTrigger(env, stmt) {
|
|
27673
|
+
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
27674
|
+
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
27501
27675
|
const state = env.ctx.state;
|
|
27502
27676
|
const found = state.findTable(stmt.table);
|
|
27503
27677
|
if (!found) {
|
|
@@ -27516,6 +27690,9 @@ function executeCreateTrigger(env, stmt) {
|
|
|
27516
27690
|
}
|
|
27517
27691
|
const meta = {
|
|
27518
27692
|
name: stmt.name,
|
|
27693
|
+
constraint: stmt.constraint,
|
|
27694
|
+
deferrable: stmt.deferrable,
|
|
27695
|
+
initiallyDeferred: stmt.initiallyDeferred,
|
|
27519
27696
|
timing: stmt.timing,
|
|
27520
27697
|
events: stmt.events,
|
|
27521
27698
|
forEachRow: stmt.forEachRow,
|
|
@@ -28284,7 +28461,16 @@ function alterTableIsSelfContained(stmt) {
|
|
|
28284
28461
|
return stmt.actions.length === 1 && action !== void 0 && SELF_CONTAINED_ALTER_ACTIONS.has(action.kind);
|
|
28285
28462
|
}
|
|
28286
28463
|
function executeStatement(env, stmt) {
|
|
28287
|
-
if (!RESHAPES_TABLES.has(stmt.type))
|
|
28464
|
+
if (!RESHAPES_TABLES.has(stmt.type)) {
|
|
28465
|
+
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))) {
|
|
28466
|
+
return withStatementRollback(env, () => {
|
|
28467
|
+
const result = dispatchStatement(env, stmt);
|
|
28468
|
+
flushConstraintTriggers(env.ctx.state);
|
|
28469
|
+
return result;
|
|
28470
|
+
});
|
|
28471
|
+
}
|
|
28472
|
+
return dispatchStatement(env, stmt);
|
|
28473
|
+
}
|
|
28288
28474
|
try {
|
|
28289
28475
|
return dispatchStatement(env, stmt);
|
|
28290
28476
|
} finally {
|
|
@@ -28343,6 +28529,9 @@ function dispatchStatement(env, stmt) {
|
|
|
28343
28529
|
return executeRefreshMatView(env, stmt);
|
|
28344
28530
|
case "transaction":
|
|
28345
28531
|
return executeTransaction(env, stmt);
|
|
28532
|
+
case "set_constraints":
|
|
28533
|
+
setConstraints(env.ctx.state, stmt);
|
|
28534
|
+
return commandResult("SET CONSTRAINTS", 0);
|
|
28346
28535
|
case "set":
|
|
28347
28536
|
return executeSet(env, stmt);
|
|
28348
28537
|
case "show":
|