@crvouga/mockingbird-service-postgres 3.4.1 → 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 +18 -0
- package/COMPATIBILITY.md +15 -0
- package/compat/sections/trg.ts +2 -0
- package/dist/admin.js +925 -736
- 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 +1375 -720
- 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 +6336 -2094
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/fleet.d.ts +38 -2
- package/dist/wire/index.js +942 -736
- package/dist/wire/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -254,6 +254,13 @@ function isPostgresError(err) {
|
|
|
254
254
|
return typeof sqlState === "string" && /^[0-9A-Z]{5}$/.test(sqlState);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
// src/storage/guc.ts
|
|
258
|
+
function validateStorageSetting(name, value) {
|
|
259
|
+
if (name === "default_table_access_method" && value !== "heap" || name === "default_tablespace" && value !== "" && value !== "pg_default") {
|
|
260
|
+
throw pgError("invalid_parameter_value", `invalid value for parameter "${name}": "${value}"`, "22023");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
257
264
|
// src/runtime/prng.ts
|
|
258
265
|
var Prng = class _Prng {
|
|
259
266
|
state;
|
|
@@ -3708,6 +3715,9 @@ var DatabaseState = class _DatabaseState {
|
|
|
3708
3715
|
changes = 0;
|
|
3709
3716
|
oidCounter = 16384;
|
|
3710
3717
|
inTransaction = false;
|
|
3718
|
+
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
3719
|
+
pendingTriggers = [];
|
|
3720
|
+
constraintModes = /* @__PURE__ */ new Map();
|
|
3711
3721
|
/** most recent sequence touched by nextval/setval, for lastval() */
|
|
3712
3722
|
lastSequence = null;
|
|
3713
3723
|
/** Session currval per sequence; absent entry means currval is undefined. */
|
|
@@ -3750,6 +3760,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3750
3760
|
this.settings.set("row_security", "on");
|
|
3751
3761
|
this.settings.set("array_nulls", "on");
|
|
3752
3762
|
this.settings.set("backslash_quote", "safe_encoding");
|
|
3763
|
+
this.settings.set("default_tablespace", "");
|
|
3764
|
+
this.settings.set("default_table_access_method", "heap");
|
|
3753
3765
|
}
|
|
3754
3766
|
nextOid() {
|
|
3755
3767
|
return this.oidCounter++;
|
|
@@ -3909,6 +3921,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3909
3921
|
s.prepared = new Map(this.prepared);
|
|
3910
3922
|
s.changes = this.changes;
|
|
3911
3923
|
s.inTransaction = this.inTransaction;
|
|
3924
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
3925
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
3912
3926
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
3913
3927
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3914
3928
|
s.tableStats = new Map(this.tableStats);
|
|
@@ -3926,6 +3940,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3926
3940
|
s.prepared = new Map(this.prepared);
|
|
3927
3941
|
s.changes = this.changes;
|
|
3928
3942
|
s.inTransaction = this.inTransaction;
|
|
3943
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
3944
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
3929
3945
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
3930
3946
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3931
3947
|
s.tableStats = new Map(this.tableStats);
|
|
@@ -3998,6 +4014,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3998
4014
|
this.settings = other.settings;
|
|
3999
4015
|
this.localSettings = other.localSettings;
|
|
4000
4016
|
this.prepared = other.prepared;
|
|
4017
|
+
this.pendingTriggers = other.pendingTriggers.slice();
|
|
4018
|
+
this.constraintModes = new Map(other.constraintModes);
|
|
4001
4019
|
this.changes = other.changes;
|
|
4002
4020
|
this.lastSequence = other.lastSequence;
|
|
4003
4021
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
@@ -4014,90 +4032,189 @@ var DatabaseState = class _DatabaseState {
|
|
|
4014
4032
|
}
|
|
4015
4033
|
};
|
|
4016
4034
|
|
|
4017
|
-
// src/
|
|
4018
|
-
var
|
|
4019
|
-
|
|
4020
|
-
|
|
4035
|
+
// src/types/timezone.ts
|
|
4036
|
+
var intlCache = /* @__PURE__ */ new Map();
|
|
4037
|
+
function intlFor(zone) {
|
|
4038
|
+
const cached = intlCache.get(zone);
|
|
4039
|
+
if (cached) return cached;
|
|
4040
|
+
try {
|
|
4041
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
4042
|
+
timeZone: zone,
|
|
4043
|
+
timeZoneName: "longOffset",
|
|
4044
|
+
year: "numeric"
|
|
4045
|
+
});
|
|
4046
|
+
intlCache.set(zone, fmt);
|
|
4047
|
+
return fmt;
|
|
4048
|
+
} catch {
|
|
4049
|
+
return null;
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
function parseFixedOffset(zone) {
|
|
4053
|
+
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
4054
|
+
if (!m) return null;
|
|
4055
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
4056
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
4057
|
+
}
|
|
4058
|
+
function parsePosixOffset(zone) {
|
|
4059
|
+
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
4060
|
+
if (!m) return null;
|
|
4061
|
+
const sign = m[1] === "-" ? 1 : -1;
|
|
4062
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
4063
|
+
}
|
|
4064
|
+
function pgMicrosToUnixMs(utcMicros) {
|
|
4065
|
+
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
4066
|
+
}
|
|
4067
|
+
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
4068
|
+
const z = zone.trim();
|
|
4069
|
+
const lower = z.toLowerCase();
|
|
4070
|
+
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
4071
|
+
const posix = parsePosixOffset(z);
|
|
4072
|
+
if (posix !== null) return posix;
|
|
4073
|
+
const fixed = parseFixedOffset(z);
|
|
4074
|
+
if (fixed !== null) return fixed;
|
|
4075
|
+
const fmt = intlFor(z);
|
|
4076
|
+
if (fmt) {
|
|
4077
|
+
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
4078
|
+
const parts = fmt.formatToParts(new Date(ms));
|
|
4079
|
+
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
4080
|
+
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
4081
|
+
if (!m) return 0;
|
|
4082
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
4083
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
4021
4084
|
}
|
|
4085
|
+
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
4086
|
+
}
|
|
4087
|
+
function clampDateMs(ms) {
|
|
4088
|
+
const MAX = 864e13;
|
|
4089
|
+
return Math.max(-MAX, Math.min(MAX, ms));
|
|
4090
|
+
}
|
|
4091
|
+
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
4092
|
+
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
4093
|
+
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
4094
|
+
return second;
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4097
|
+
// src/expressions/context.ts
|
|
4098
|
+
var EngineCtx = class {
|
|
4022
4099
|
state;
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4100
|
+
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
4101
|
+
txNow;
|
|
4102
|
+
/** statement timestamp */
|
|
4103
|
+
stmtNow;
|
|
4104
|
+
constructor(state, txNow) {
|
|
4105
|
+
this.state = state;
|
|
4106
|
+
const nowMs = state.clock().getTime();
|
|
4107
|
+
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
4108
|
+
this.txNow = txNow ?? nowMicros;
|
|
4109
|
+
this.stmtNow = nowMicros;
|
|
4028
4110
|
}
|
|
4029
|
-
|
|
4030
|
-
this.state.
|
|
4031
|
-
this.freezeDepth++;
|
|
4032
|
-
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
4111
|
+
timezone() {
|
|
4112
|
+
return this.state.getSetting("timezone") ?? "UTC";
|
|
4033
4113
|
}
|
|
4034
|
-
|
|
4035
|
-
this.state.
|
|
4036
|
-
|
|
4114
|
+
namespaceOid(name) {
|
|
4115
|
+
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
4116
|
+
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
4117
|
+
return oid;
|
|
4037
4118
|
}
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4119
|
+
namespaceName(oid) {
|
|
4120
|
+
const builtin = builtinNamespaceName(oid);
|
|
4121
|
+
if (builtin !== void 0) return builtin;
|
|
4122
|
+
for (const schema of this.state.schemas.values()) {
|
|
4123
|
+
if (schema.oid === oid) return schema.name;
|
|
4042
4124
|
}
|
|
4125
|
+
return null;
|
|
4043
4126
|
}
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
return;
|
|
4047
|
-
}
|
|
4048
|
-
this.base = this.takeSnapshot();
|
|
4049
|
-
this.state.inTransaction = true;
|
|
4050
|
-
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
4127
|
+
zoneOffsetAt(utcMicros) {
|
|
4128
|
+
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
4051
4129
|
}
|
|
4052
|
-
|
|
4053
|
-
this.
|
|
4054
|
-
this.savepoints = [];
|
|
4055
|
-
this.state.inTransaction = false;
|
|
4056
|
-
this.state.localSettings.clear();
|
|
4057
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
4130
|
+
zoneOffsetForNaive(naiveMicros) {
|
|
4131
|
+
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
4058
4132
|
}
|
|
4059
|
-
|
|
4060
|
-
if (
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
this.base = null;
|
|
4064
|
-
this.savepoints = [];
|
|
4065
|
-
this.state.inTransaction = false;
|
|
4066
|
-
this.state.localSettings.clear();
|
|
4067
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
4133
|
+
enumLabels(enumType) {
|
|
4134
|
+
if (!isEnumType(enumType)) return null;
|
|
4135
|
+
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
4136
|
+
return e?.labels ?? null;
|
|
4068
4137
|
}
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
}
|
|
4073
|
-
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
4138
|
+
enumHasLabel(enumType, label) {
|
|
4139
|
+
const labels = this.enumLabels(enumType);
|
|
4140
|
+
return labels === null ? true : labels.includes(label);
|
|
4074
4141
|
}
|
|
4075
|
-
|
|
4076
|
-
const
|
|
4077
|
-
|
|
4142
|
+
enumOrder(enumType, label) {
|
|
4143
|
+
const labels = this.enumLabels(enumType);
|
|
4144
|
+
if (!labels) return 0;
|
|
4145
|
+
const idx = labels.indexOf(label);
|
|
4146
|
+
return idx === -1 ? labels.length : idx;
|
|
4078
4147
|
}
|
|
4079
|
-
|
|
4080
|
-
const
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
this.savepoints.splice(idx + 1);
|
|
4148
|
+
requireEnum(enumType) {
|
|
4149
|
+
const labels = this.enumLabels(enumType);
|
|
4150
|
+
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
4151
|
+
return labels;
|
|
4084
4152
|
}
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4153
|
+
};
|
|
4154
|
+
|
|
4155
|
+
// src/api/bind.ts
|
|
4156
|
+
var INT4_MIN2 = -2147483648;
|
|
4157
|
+
var INT4_MAX2 = 2147483647;
|
|
4158
|
+
function bindValueToTyped(value, index) {
|
|
4159
|
+
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
4160
|
+
switch (typeof value) {
|
|
4161
|
+
case "boolean":
|
|
4162
|
+
return tv("bool", value);
|
|
4163
|
+
case "number":
|
|
4164
|
+
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
4165
|
+
return tv("int4", value);
|
|
4166
|
+
}
|
|
4167
|
+
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
4168
|
+
return tv("int8", BigInt(value));
|
|
4169
|
+
}
|
|
4170
|
+
return tv("float8", value);
|
|
4171
|
+
case "bigint":
|
|
4172
|
+
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
4173
|
+
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
4174
|
+
}
|
|
4175
|
+
return tv("int8", value);
|
|
4176
|
+
case "string":
|
|
4177
|
+
return tv(UNKNOWN, value);
|
|
4178
|
+
case "object": {
|
|
4179
|
+
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
4180
|
+
if (value instanceof Date) {
|
|
4181
|
+
const ms = value.getTime();
|
|
4182
|
+
if (Number.isNaN(ms)) {
|
|
4183
|
+
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
4184
|
+
}
|
|
4185
|
+
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
4186
|
+
}
|
|
4187
|
+
break;
|
|
4091
4188
|
}
|
|
4092
|
-
|
|
4189
|
+
default:
|
|
4190
|
+
break;
|
|
4093
4191
|
}
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4192
|
+
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
4193
|
+
}
|
|
4194
|
+
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
4195
|
+
if (v === null) return null;
|
|
4196
|
+
switch (t) {
|
|
4197
|
+
case "bool":
|
|
4198
|
+
return v;
|
|
4199
|
+
case "int2":
|
|
4200
|
+
case "int4":
|
|
4201
|
+
case "oid":
|
|
4202
|
+
return typeof v === "bigint" ? Number(v) : v;
|
|
4203
|
+
case "int8": {
|
|
4204
|
+
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
4205
|
+
if (int8 === "string") return n.toString();
|
|
4206
|
+
if (int8 === "number") return Number(n);
|
|
4207
|
+
return n;
|
|
4208
|
+
}
|
|
4209
|
+
case "float4":
|
|
4210
|
+
case "float8":
|
|
4211
|
+
return v;
|
|
4212
|
+
case "bytea":
|
|
4213
|
+
return v;
|
|
4214
|
+
default:
|
|
4215
|
+
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
4099
4216
|
}
|
|
4100
|
-
}
|
|
4217
|
+
}
|
|
4101
4218
|
|
|
4102
4219
|
// src/types/cast.ts
|
|
4103
4220
|
var UTC_CAST_ENV = {
|
|
@@ -4575,259 +4692,6 @@ function unifyTypes(a, b) {
|
|
|
4575
4692
|
return null;
|
|
4576
4693
|
}
|
|
4577
4694
|
|
|
4578
|
-
// src/types/resolve.ts
|
|
4579
|
-
var SERIALS = {
|
|
4580
|
-
smallserial: "int2",
|
|
4581
|
-
serial2: "int2",
|
|
4582
|
-
serial: "int4",
|
|
4583
|
-
serial4: "int4",
|
|
4584
|
-
bigserial: "int8",
|
|
4585
|
-
serial8: "int8"
|
|
4586
|
-
};
|
|
4587
|
-
function modOf(t, mods) {
|
|
4588
|
-
if (mods.length === 0) return null;
|
|
4589
|
-
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
4590
|
-
return { a: mods[0] };
|
|
4591
|
-
}
|
|
4592
|
-
function resolveTypeName(state, tn) {
|
|
4593
|
-
const joined = tn.parts.join(".");
|
|
4594
|
-
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
4595
|
-
if (bare !== null) {
|
|
4596
|
-
const serial = SERIALS[bare];
|
|
4597
|
-
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
4598
|
-
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
4599
|
-
}
|
|
4600
|
-
const builtin = normalizeTypeName(bare);
|
|
4601
|
-
if (builtin !== null) {
|
|
4602
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
4603
|
-
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
4604
|
-
}
|
|
4605
|
-
}
|
|
4606
|
-
const enumData = state.findEnum(tn.parts);
|
|
4607
|
-
if (enumData) {
|
|
4608
|
-
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
4609
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
4610
|
-
return { column: { id, mod: null }, domain: null, serial: null };
|
|
4611
|
-
}
|
|
4612
|
-
const domainData = state.findDomain(tn.parts);
|
|
4613
|
-
if (domainData) {
|
|
4614
|
-
if (tn.arrayDims > 0) {
|
|
4615
|
-
const id = arrayTypeOf(domainData.baseType.id);
|
|
4616
|
-
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
4617
|
-
}
|
|
4618
|
-
return {
|
|
4619
|
-
column: domainData.baseType,
|
|
4620
|
-
domain: `${domainData.schema}.${domainData.name}`,
|
|
4621
|
-
serial: null
|
|
4622
|
-
};
|
|
4623
|
-
}
|
|
4624
|
-
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
4625
|
-
}
|
|
4626
|
-
|
|
4627
|
-
// src/executor/relation.ts
|
|
4628
|
-
var RowScope = class {
|
|
4629
|
-
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
4630
|
-
this.columns = columns;
|
|
4631
|
-
this.row = row;
|
|
4632
|
-
this.parent = parent;
|
|
4633
|
-
this.rangeVars = rangeVars;
|
|
4634
|
-
}
|
|
4635
|
-
columns;
|
|
4636
|
-
row;
|
|
4637
|
-
parent;
|
|
4638
|
-
rangeVars;
|
|
4639
|
-
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
4640
|
-
lookup(parts) {
|
|
4641
|
-
if (parts.length === 1) {
|
|
4642
|
-
const name2 = parts[0];
|
|
4643
|
-
let found2;
|
|
4644
|
-
let count2 = 0;
|
|
4645
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4646
|
-
const c = this.columns[i];
|
|
4647
|
-
if (c.name === name2 && !c.hidden) {
|
|
4648
|
-
count2++;
|
|
4649
|
-
if (count2 > 1) {
|
|
4650
|
-
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
4651
|
-
}
|
|
4652
|
-
found2 = tv(c.type, this.row[i] ?? null);
|
|
4653
|
-
}
|
|
4654
|
-
}
|
|
4655
|
-
if (found2 !== void 0) return found2;
|
|
4656
|
-
if (this.rangeVars.has(name2)) {
|
|
4657
|
-
return this.wholeRow(name2);
|
|
4658
|
-
}
|
|
4659
|
-
return this.parent?.lookup(parts);
|
|
4660
|
-
}
|
|
4661
|
-
const table = parts[parts.length - 2];
|
|
4662
|
-
const name = parts[parts.length - 1];
|
|
4663
|
-
let found;
|
|
4664
|
-
let count = 0;
|
|
4665
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4666
|
-
const c = this.columns[i];
|
|
4667
|
-
if (c.table === table && c.name === name) {
|
|
4668
|
-
count++;
|
|
4669
|
-
if (count > 1) {
|
|
4670
|
-
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
4671
|
-
}
|
|
4672
|
-
found = tv(c.type, this.row[i] ?? null);
|
|
4673
|
-
}
|
|
4674
|
-
}
|
|
4675
|
-
if (found !== void 0) return found;
|
|
4676
|
-
return this.parent?.lookup(parts);
|
|
4677
|
-
}
|
|
4678
|
-
/** Build a record value from all columns belonging to a range variable. */
|
|
4679
|
-
wholeRow(rangeVar) {
|
|
4680
|
-
const types = [];
|
|
4681
|
-
const values = [];
|
|
4682
|
-
const names = [];
|
|
4683
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4684
|
-
const c = this.columns[i];
|
|
4685
|
-
if (c.table === rangeVar) {
|
|
4686
|
-
types.push(c.type);
|
|
4687
|
-
values.push(this.row[i] ?? null);
|
|
4688
|
-
names.push(c.name);
|
|
4689
|
-
}
|
|
4690
|
-
}
|
|
4691
|
-
if (types.length === 0) return void 0;
|
|
4692
|
-
return tv("record", { kind: "pgrecord", types, values, names });
|
|
4693
|
-
}
|
|
4694
|
-
hasRangeVar(name) {
|
|
4695
|
-
if (this.rangeVars.has(name)) return true;
|
|
4696
|
-
return this.parent?.hasRangeVar(name) ?? false;
|
|
4697
|
-
}
|
|
4698
|
-
};
|
|
4699
|
-
function childEnv(env, outer) {
|
|
4700
|
-
return {
|
|
4701
|
-
ctx: env.ctx,
|
|
4702
|
-
params: env.params,
|
|
4703
|
-
ctes: env.ctes,
|
|
4704
|
-
outer,
|
|
4705
|
-
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
4706
|
-
};
|
|
4707
|
-
}
|
|
4708
|
-
function relationResult(rel3, command) {
|
|
4709
|
-
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
4710
|
-
return {
|
|
4711
|
-
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
4712
|
-
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
4713
|
-
command,
|
|
4714
|
-
rowCount: rel3.rows.length
|
|
4715
|
-
};
|
|
4716
|
-
}
|
|
4717
|
-
function commandResult(command, rowCount) {
|
|
4718
|
-
return { columns: [], rows: [], command, rowCount };
|
|
4719
|
-
}
|
|
4720
|
-
function inferColumnName(e) {
|
|
4721
|
-
switch (e.type) {
|
|
4722
|
-
case "colref":
|
|
4723
|
-
return e.parts[e.parts.length - 1];
|
|
4724
|
-
case "func":
|
|
4725
|
-
return e.name[e.name.length - 1];
|
|
4726
|
-
case "cast": {
|
|
4727
|
-
const inner = inferColumnName(e.expr);
|
|
4728
|
-
if (inner !== "?column?") return inner;
|
|
4729
|
-
return e.target.parts[e.target.parts.length - 1];
|
|
4730
|
-
}
|
|
4731
|
-
case "collate":
|
|
4732
|
-
return inferColumnName(e.expr);
|
|
4733
|
-
case "case":
|
|
4734
|
-
return "case";
|
|
4735
|
-
case "array_ctor":
|
|
4736
|
-
case "array_query":
|
|
4737
|
-
return "array";
|
|
4738
|
-
case "row":
|
|
4739
|
-
return "row";
|
|
4740
|
-
case "subquery_expr":
|
|
4741
|
-
return e.kind === "exists" ? "exists" : "?column?";
|
|
4742
|
-
case "bool_lit":
|
|
4743
|
-
return "bool";
|
|
4744
|
-
case "extract":
|
|
4745
|
-
return "extract";
|
|
4746
|
-
case "position":
|
|
4747
|
-
return "position";
|
|
4748
|
-
case "substring_sql":
|
|
4749
|
-
return "substring";
|
|
4750
|
-
case "overlay":
|
|
4751
|
-
return "overlay";
|
|
4752
|
-
case "trim":
|
|
4753
|
-
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
4754
|
-
case "field_select":
|
|
4755
|
-
return e.field === "*" ? "?column?" : e.field;
|
|
4756
|
-
case "at_time_zone":
|
|
4757
|
-
return "timezone";
|
|
4758
|
-
case "grouping_func":
|
|
4759
|
-
return "grouping";
|
|
4760
|
-
case "subscript":
|
|
4761
|
-
return inferColumnName(e.base);
|
|
4762
|
-
default:
|
|
4763
|
-
return "?column?";
|
|
4764
|
-
}
|
|
4765
|
-
}
|
|
4766
|
-
|
|
4767
|
-
// src/api/bind.ts
|
|
4768
|
-
var INT4_MIN2 = -2147483648;
|
|
4769
|
-
var INT4_MAX2 = 2147483647;
|
|
4770
|
-
function bindValueToTyped(value, index) {
|
|
4771
|
-
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
4772
|
-
switch (typeof value) {
|
|
4773
|
-
case "boolean":
|
|
4774
|
-
return tv("bool", value);
|
|
4775
|
-
case "number":
|
|
4776
|
-
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
4777
|
-
return tv("int4", value);
|
|
4778
|
-
}
|
|
4779
|
-
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
4780
|
-
return tv("int8", BigInt(value));
|
|
4781
|
-
}
|
|
4782
|
-
return tv("float8", value);
|
|
4783
|
-
case "bigint":
|
|
4784
|
-
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
4785
|
-
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
4786
|
-
}
|
|
4787
|
-
return tv("int8", value);
|
|
4788
|
-
case "string":
|
|
4789
|
-
return tv(UNKNOWN, value);
|
|
4790
|
-
case "object": {
|
|
4791
|
-
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
4792
|
-
if (value instanceof Date) {
|
|
4793
|
-
const ms = value.getTime();
|
|
4794
|
-
if (Number.isNaN(ms)) {
|
|
4795
|
-
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
4796
|
-
}
|
|
4797
|
-
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
4798
|
-
}
|
|
4799
|
-
break;
|
|
4800
|
-
}
|
|
4801
|
-
default:
|
|
4802
|
-
break;
|
|
4803
|
-
}
|
|
4804
|
-
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
4805
|
-
}
|
|
4806
|
-
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
4807
|
-
if (v === null) return null;
|
|
4808
|
-
switch (t) {
|
|
4809
|
-
case "bool":
|
|
4810
|
-
return v;
|
|
4811
|
-
case "int2":
|
|
4812
|
-
case "int4":
|
|
4813
|
-
case "oid":
|
|
4814
|
-
return typeof v === "bigint" ? Number(v) : v;
|
|
4815
|
-
case "int8": {
|
|
4816
|
-
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
4817
|
-
if (int8 === "string") return n.toString();
|
|
4818
|
-
if (int8 === "number") return Number(n);
|
|
4819
|
-
return n;
|
|
4820
|
-
}
|
|
4821
|
-
case "float4":
|
|
4822
|
-
case "float8":
|
|
4823
|
-
return v;
|
|
4824
|
-
case "bytea":
|
|
4825
|
-
return v;
|
|
4826
|
-
default:
|
|
4827
|
-
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
4828
|
-
}
|
|
4829
|
-
}
|
|
4830
|
-
|
|
4831
4695
|
// src/functions/datetime-fns.ts
|
|
4832
4696
|
function extractDatePart(ctx, field0, src0, asNumeric) {
|
|
4833
4697
|
const field = field0.toLowerCase();
|
|
@@ -5742,68 +5606,6 @@ function getArrayFunctions() {
|
|
|
5742
5606
|
return m;
|
|
5743
5607
|
}
|
|
5744
5608
|
|
|
5745
|
-
// src/types/timezone.ts
|
|
5746
|
-
var intlCache = /* @__PURE__ */ new Map();
|
|
5747
|
-
function intlFor(zone) {
|
|
5748
|
-
const cached = intlCache.get(zone);
|
|
5749
|
-
if (cached) return cached;
|
|
5750
|
-
try {
|
|
5751
|
-
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
5752
|
-
timeZone: zone,
|
|
5753
|
-
timeZoneName: "longOffset",
|
|
5754
|
-
year: "numeric"
|
|
5755
|
-
});
|
|
5756
|
-
intlCache.set(zone, fmt);
|
|
5757
|
-
return fmt;
|
|
5758
|
-
} catch {
|
|
5759
|
-
return null;
|
|
5760
|
-
}
|
|
5761
|
-
}
|
|
5762
|
-
function parseFixedOffset(zone) {
|
|
5763
|
-
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
5764
|
-
if (!m) return null;
|
|
5765
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
5766
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
5767
|
-
}
|
|
5768
|
-
function parsePosixOffset(zone) {
|
|
5769
|
-
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
5770
|
-
if (!m) return null;
|
|
5771
|
-
const sign = m[1] === "-" ? 1 : -1;
|
|
5772
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
5773
|
-
}
|
|
5774
|
-
function pgMicrosToUnixMs(utcMicros) {
|
|
5775
|
-
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
5776
|
-
}
|
|
5777
|
-
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
5778
|
-
const z = zone.trim();
|
|
5779
|
-
const lower = z.toLowerCase();
|
|
5780
|
-
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
5781
|
-
const posix = parsePosixOffset(z);
|
|
5782
|
-
if (posix !== null) return posix;
|
|
5783
|
-
const fixed = parseFixedOffset(z);
|
|
5784
|
-
if (fixed !== null) return fixed;
|
|
5785
|
-
const fmt = intlFor(z);
|
|
5786
|
-
if (fmt) {
|
|
5787
|
-
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
5788
|
-
const parts = fmt.formatToParts(new Date(ms));
|
|
5789
|
-
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
5790
|
-
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
5791
|
-
if (!m) return 0;
|
|
5792
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
5793
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
5794
|
-
}
|
|
5795
|
-
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
5796
|
-
}
|
|
5797
|
-
function clampDateMs(ms) {
|
|
5798
|
-
const MAX = 864e13;
|
|
5799
|
-
return Math.max(-MAX, Math.min(MAX, ms));
|
|
5800
|
-
}
|
|
5801
|
-
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
5802
|
-
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
5803
|
-
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
5804
|
-
return second;
|
|
5805
|
-
}
|
|
5806
|
-
|
|
5807
5609
|
// src/functions/datetime-registry.ts
|
|
5808
5610
|
function getDatetimeFunctions() {
|
|
5809
5611
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -7403,6 +7205,28 @@ function exactDegTan(x) {
|
|
|
7403
7205
|
return Math.tan(x * Math.PI / 180);
|
|
7404
7206
|
}
|
|
7405
7207
|
|
|
7208
|
+
// src/storage/indexable-relation.ts
|
|
7209
|
+
function materializedTable(view) {
|
|
7210
|
+
const table = new TableData(
|
|
7211
|
+
view.schema,
|
|
7212
|
+
view.name,
|
|
7213
|
+
(view.matColumns ?? []).map((c) => ({
|
|
7214
|
+
name: c.name,
|
|
7215
|
+
type: { id: c.type, mod: null },
|
|
7216
|
+
notNull: false,
|
|
7217
|
+
defaultExpr: null,
|
|
7218
|
+
identity: null,
|
|
7219
|
+
generated: null,
|
|
7220
|
+
collate: null,
|
|
7221
|
+
domain: null
|
|
7222
|
+
})),
|
|
7223
|
+
view.oid,
|
|
7224
|
+
view.temp
|
|
7225
|
+
);
|
|
7226
|
+
table.rows = view.matRows ?? [];
|
|
7227
|
+
return table;
|
|
7228
|
+
}
|
|
7229
|
+
|
|
7406
7230
|
// src/schema/index-catalog.ts
|
|
7407
7231
|
var isKeyConstraint = (constraint) => constraint.kind === "primary_key" || constraint.kind === "unique";
|
|
7408
7232
|
var ACCESS_METHODS = /* @__PURE__ */ new Map([
|
|
@@ -7431,6 +7255,8 @@ function syncIndexCatalog(state) {
|
|
|
7431
7255
|
const tables = /* @__PURE__ */ new Map();
|
|
7432
7256
|
for (const schema of state.schemas.values()) {
|
|
7433
7257
|
for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
|
|
7258
|
+
for (const view of schema.views.values())
|
|
7259
|
+
if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
|
|
7434
7260
|
}
|
|
7435
7261
|
const backing = /* @__PURE__ */ new Map();
|
|
7436
7262
|
for (const { table } of tables.values()) {
|
|
@@ -7628,6 +7454,55 @@ function deparseExpr(e) {
|
|
|
7628
7454
|
}
|
|
7629
7455
|
}
|
|
7630
7456
|
|
|
7457
|
+
// src/types/resolve.ts
|
|
7458
|
+
var SERIALS = {
|
|
7459
|
+
smallserial: "int2",
|
|
7460
|
+
serial2: "int2",
|
|
7461
|
+
serial: "int4",
|
|
7462
|
+
serial4: "int4",
|
|
7463
|
+
bigserial: "int8",
|
|
7464
|
+
serial8: "int8"
|
|
7465
|
+
};
|
|
7466
|
+
function modOf(t, mods) {
|
|
7467
|
+
if (mods.length === 0) return null;
|
|
7468
|
+
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
7469
|
+
return { a: mods[0] };
|
|
7470
|
+
}
|
|
7471
|
+
function resolveTypeName(state, tn) {
|
|
7472
|
+
const joined = tn.parts.join(".");
|
|
7473
|
+
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
7474
|
+
if (bare !== null) {
|
|
7475
|
+
const serial = SERIALS[bare];
|
|
7476
|
+
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
7477
|
+
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
7478
|
+
}
|
|
7479
|
+
const builtin = normalizeTypeName(bare);
|
|
7480
|
+
if (builtin !== null) {
|
|
7481
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
7482
|
+
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
7483
|
+
}
|
|
7484
|
+
}
|
|
7485
|
+
const enumData = state.findEnum(tn.parts);
|
|
7486
|
+
if (enumData) {
|
|
7487
|
+
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
7488
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
7489
|
+
return { column: { id, mod: null }, domain: null, serial: null };
|
|
7490
|
+
}
|
|
7491
|
+
const domainData = state.findDomain(tn.parts);
|
|
7492
|
+
if (domainData) {
|
|
7493
|
+
if (tn.arrayDims > 0) {
|
|
7494
|
+
const id = arrayTypeOf(domainData.baseType.id);
|
|
7495
|
+
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
7496
|
+
}
|
|
7497
|
+
return {
|
|
7498
|
+
column: domainData.baseType,
|
|
7499
|
+
domain: `${domainData.schema}.${domainData.name}`,
|
|
7500
|
+
serial: null
|
|
7501
|
+
};
|
|
7502
|
+
}
|
|
7503
|
+
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
7504
|
+
}
|
|
7505
|
+
|
|
7631
7506
|
// src/sql/ruleutils.ts
|
|
7632
7507
|
var BOOL = "bool";
|
|
7633
7508
|
var TEXT = "text";
|
|
@@ -8422,7 +8297,11 @@ function getMiscFunctions() {
|
|
|
8422
8297
|
}
|
|
8423
8298
|
const name = argText(ctx, args[0]).toLowerCase();
|
|
8424
8299
|
const value = args[1].v === null ? "" : argText(ctx, args[1]);
|
|
8425
|
-
ctx.state.settings.
|
|
8300
|
+
if (!ctx.state.settings.has(name) && !name.includes("."))
|
|
8301
|
+
throw pgError("undefined_object", `unrecognized configuration parameter "${name}"`, "42704");
|
|
8302
|
+
validateStorageSetting(name, value);
|
|
8303
|
+
const local = args[2]?.v === true;
|
|
8304
|
+
if (!local || ctx.state.inTransaction) (local ? ctx.state.localSettings : ctx.state.settings).set(name, value);
|
|
8426
8305
|
return tv("text", value);
|
|
8427
8306
|
});
|
|
8428
8307
|
m.set(
|
|
@@ -8488,10 +8367,7 @@ function getMiscFunctions() {
|
|
|
8488
8367
|
if (!col)
|
|
8489
8368
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
8490
8369
|
if (!col.identity) return tv("text", null);
|
|
8491
|
-
return tv(
|
|
8492
|
-
"text",
|
|
8493
|
-
col.identity.sequence.split(".").map(quoteIdent).join(".")
|
|
8494
|
-
);
|
|
8370
|
+
return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
|
|
8495
8371
|
})
|
|
8496
8372
|
);
|
|
8497
8373
|
m.set("format_type", (ctx, args) => {
|
|
@@ -13415,6 +13291,146 @@ function isSrfName(name) {
|
|
|
13415
13291
|
return SRFS.has(name);
|
|
13416
13292
|
}
|
|
13417
13293
|
|
|
13294
|
+
// src/executor/relation.ts
|
|
13295
|
+
var RowScope = class {
|
|
13296
|
+
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
13297
|
+
this.columns = columns;
|
|
13298
|
+
this.row = row;
|
|
13299
|
+
this.parent = parent;
|
|
13300
|
+
this.rangeVars = rangeVars;
|
|
13301
|
+
}
|
|
13302
|
+
columns;
|
|
13303
|
+
row;
|
|
13304
|
+
parent;
|
|
13305
|
+
rangeVars;
|
|
13306
|
+
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
13307
|
+
lookup(parts) {
|
|
13308
|
+
if (parts.length === 1) {
|
|
13309
|
+
const name2 = parts[0];
|
|
13310
|
+
let found2;
|
|
13311
|
+
let count2 = 0;
|
|
13312
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
13313
|
+
const c = this.columns[i];
|
|
13314
|
+
if (c.name === name2 && !c.hidden) {
|
|
13315
|
+
count2++;
|
|
13316
|
+
if (count2 > 1) {
|
|
13317
|
+
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
13318
|
+
}
|
|
13319
|
+
found2 = tv(c.type, this.row[i] ?? null);
|
|
13320
|
+
}
|
|
13321
|
+
}
|
|
13322
|
+
if (found2 !== void 0) return found2;
|
|
13323
|
+
if (this.rangeVars.has(name2)) {
|
|
13324
|
+
return this.wholeRow(name2);
|
|
13325
|
+
}
|
|
13326
|
+
return this.parent?.lookup(parts);
|
|
13327
|
+
}
|
|
13328
|
+
const table = parts[parts.length - 2];
|
|
13329
|
+
const name = parts[parts.length - 1];
|
|
13330
|
+
let found;
|
|
13331
|
+
let count = 0;
|
|
13332
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
13333
|
+
const c = this.columns[i];
|
|
13334
|
+
if (c.table === table && c.name === name) {
|
|
13335
|
+
count++;
|
|
13336
|
+
if (count > 1) {
|
|
13337
|
+
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
13338
|
+
}
|
|
13339
|
+
found = tv(c.type, this.row[i] ?? null);
|
|
13340
|
+
}
|
|
13341
|
+
}
|
|
13342
|
+
if (found !== void 0) return found;
|
|
13343
|
+
return this.parent?.lookup(parts);
|
|
13344
|
+
}
|
|
13345
|
+
/** Build a record value from all columns belonging to a range variable. */
|
|
13346
|
+
wholeRow(rangeVar) {
|
|
13347
|
+
const types = [];
|
|
13348
|
+
const values = [];
|
|
13349
|
+
const names = [];
|
|
13350
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
13351
|
+
const c = this.columns[i];
|
|
13352
|
+
if (c.table === rangeVar) {
|
|
13353
|
+
types.push(c.type);
|
|
13354
|
+
values.push(this.row[i] ?? null);
|
|
13355
|
+
names.push(c.name);
|
|
13356
|
+
}
|
|
13357
|
+
}
|
|
13358
|
+
if (types.length === 0) return void 0;
|
|
13359
|
+
return tv("record", { kind: "pgrecord", types, values, names });
|
|
13360
|
+
}
|
|
13361
|
+
hasRangeVar(name) {
|
|
13362
|
+
if (this.rangeVars.has(name)) return true;
|
|
13363
|
+
return this.parent?.hasRangeVar(name) ?? false;
|
|
13364
|
+
}
|
|
13365
|
+
};
|
|
13366
|
+
function childEnv(env, outer) {
|
|
13367
|
+
return {
|
|
13368
|
+
ctx: env.ctx,
|
|
13369
|
+
params: env.params,
|
|
13370
|
+
ctes: env.ctes,
|
|
13371
|
+
outer,
|
|
13372
|
+
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
13373
|
+
};
|
|
13374
|
+
}
|
|
13375
|
+
function relationResult(rel3, command) {
|
|
13376
|
+
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
13377
|
+
return {
|
|
13378
|
+
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
13379
|
+
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
13380
|
+
command,
|
|
13381
|
+
rowCount: rel3.rows.length
|
|
13382
|
+
};
|
|
13383
|
+
}
|
|
13384
|
+
function commandResult(command, rowCount) {
|
|
13385
|
+
return { columns: [], rows: [], command, rowCount };
|
|
13386
|
+
}
|
|
13387
|
+
function inferColumnName(e) {
|
|
13388
|
+
switch (e.type) {
|
|
13389
|
+
case "colref":
|
|
13390
|
+
return e.parts[e.parts.length - 1];
|
|
13391
|
+
case "func":
|
|
13392
|
+
return e.name[e.name.length - 1];
|
|
13393
|
+
case "cast": {
|
|
13394
|
+
const inner = inferColumnName(e.expr);
|
|
13395
|
+
if (inner !== "?column?") return inner;
|
|
13396
|
+
return e.target.parts[e.target.parts.length - 1];
|
|
13397
|
+
}
|
|
13398
|
+
case "collate":
|
|
13399
|
+
return inferColumnName(e.expr);
|
|
13400
|
+
case "case":
|
|
13401
|
+
return "case";
|
|
13402
|
+
case "array_ctor":
|
|
13403
|
+
case "array_query":
|
|
13404
|
+
return "array";
|
|
13405
|
+
case "row":
|
|
13406
|
+
return "row";
|
|
13407
|
+
case "subquery_expr":
|
|
13408
|
+
return e.kind === "exists" ? "exists" : "?column?";
|
|
13409
|
+
case "bool_lit":
|
|
13410
|
+
return "bool";
|
|
13411
|
+
case "extract":
|
|
13412
|
+
return "extract";
|
|
13413
|
+
case "position":
|
|
13414
|
+
return "position";
|
|
13415
|
+
case "substring_sql":
|
|
13416
|
+
return "substring";
|
|
13417
|
+
case "overlay":
|
|
13418
|
+
return "overlay";
|
|
13419
|
+
case "trim":
|
|
13420
|
+
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
13421
|
+
case "field_select":
|
|
13422
|
+
return e.field === "*" ? "?column?" : e.field;
|
|
13423
|
+
case "at_time_zone":
|
|
13424
|
+
return "timezone";
|
|
13425
|
+
case "grouping_func":
|
|
13426
|
+
return "grouping";
|
|
13427
|
+
case "subscript":
|
|
13428
|
+
return inferColumnName(e.base);
|
|
13429
|
+
default:
|
|
13430
|
+
return "?column?";
|
|
13431
|
+
}
|
|
13432
|
+
}
|
|
13433
|
+
|
|
13418
13434
|
// src/indexes/index.ts
|
|
13419
13435
|
var IndexStore = class _IndexStore {
|
|
13420
13436
|
name;
|
|
@@ -13477,53 +13493,228 @@ function ensureIndexStores(env, table) {
|
|
|
13477
13493
|
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
13478
13494
|
if (key !== null) store.insert(key, i);
|
|
13479
13495
|
}
|
|
13480
|
-
stores.set(spec.name, store);
|
|
13481
|
-
}
|
|
13482
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
13483
|
-
if (schema) {
|
|
13484
|
-
for (const idx of schema.indexes.values()) {
|
|
13485
|
-
if (idx.table !== table.name || idx.unique) continue;
|
|
13486
|
-
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
13496
|
+
stores.set(spec.name, store);
|
|
13497
|
+
}
|
|
13498
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
13499
|
+
if (schema) {
|
|
13500
|
+
for (const idx of schema.indexes.values()) {
|
|
13501
|
+
if (idx.table !== table.name || idx.unique) continue;
|
|
13502
|
+
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
13503
|
+
}
|
|
13504
|
+
}
|
|
13505
|
+
table.indexStores = stores;
|
|
13506
|
+
return stores;
|
|
13507
|
+
}
|
|
13508
|
+
function indexStoreFor(env, table, spec) {
|
|
13509
|
+
const stores = ensureIndexStores(env, table);
|
|
13510
|
+
let store = stores.get(spec.name);
|
|
13511
|
+
if (!store) {
|
|
13512
|
+
store = new IndexStore(spec.name, true);
|
|
13513
|
+
for (let i = 0; i < table.rowCount(); i++) {
|
|
13514
|
+
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
13515
|
+
if (key !== null) store.insert(key, i);
|
|
13516
|
+
}
|
|
13517
|
+
stores.set(spec.name, store);
|
|
13518
|
+
}
|
|
13519
|
+
return store;
|
|
13520
|
+
}
|
|
13521
|
+
function indexInsertRow(env, table, rowIdx, row) {
|
|
13522
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13523
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13524
|
+
if (key === null) continue;
|
|
13525
|
+
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
13526
|
+
}
|
|
13527
|
+
}
|
|
13528
|
+
function indexRemoveRow(env, table, rowIdx, row) {
|
|
13529
|
+
if (!table.indexStores) return;
|
|
13530
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13531
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13532
|
+
if (key === null) continue;
|
|
13533
|
+
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
13534
|
+
}
|
|
13535
|
+
}
|
|
13536
|
+
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
13537
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
13538
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
13539
|
+
}
|
|
13540
|
+
function rebuildTableIndexes(env, table) {
|
|
13541
|
+
table.indexStores = null;
|
|
13542
|
+
ensureIndexStores(env, table);
|
|
13543
|
+
}
|
|
13544
|
+
|
|
13545
|
+
// src/constraints/enforce.ts
|
|
13546
|
+
function tableScope(table, row) {
|
|
13547
|
+
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
13548
|
+
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
13549
|
+
}
|
|
13550
|
+
function checkNotNull(env, table, row) {
|
|
13551
|
+
void env;
|
|
13552
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
13553
|
+
const c = table.columns[i];
|
|
13554
|
+
if (c.notNull && (row[i] ?? null) === null) {
|
|
13555
|
+
throw pgError(
|
|
13556
|
+
"not_null_violation",
|
|
13557
|
+
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
13558
|
+
"23502"
|
|
13559
|
+
);
|
|
13560
|
+
}
|
|
13561
|
+
}
|
|
13562
|
+
}
|
|
13563
|
+
function checkChecks(env, table, row) {
|
|
13564
|
+
for (const con of table.constraints) {
|
|
13565
|
+
if (con.kind !== "check") continue;
|
|
13566
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
13567
|
+
const v = evalExpr(env.ctx, scope, con.expr);
|
|
13568
|
+
if (v.v === null) continue;
|
|
13569
|
+
const b = castTo(env.ctx, v, "bool", {});
|
|
13570
|
+
if (b.v !== true) {
|
|
13571
|
+
throw pgError(
|
|
13572
|
+
"check_violation",
|
|
13573
|
+
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
13574
|
+
"23514"
|
|
13575
|
+
);
|
|
13576
|
+
}
|
|
13577
|
+
}
|
|
13578
|
+
}
|
|
13579
|
+
function uniqueSpecsFor(env, table) {
|
|
13580
|
+
const specs = [];
|
|
13581
|
+
for (const con of table.constraints) {
|
|
13582
|
+
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
13583
|
+
specs.push({
|
|
13584
|
+
name: con.name,
|
|
13585
|
+
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
13586
|
+
columnNames: con.columns,
|
|
13587
|
+
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
13588
|
+
where: null,
|
|
13589
|
+
isPrimary: con.kind === "primary_key"
|
|
13590
|
+
});
|
|
13591
|
+
}
|
|
13592
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
13593
|
+
if (schema) {
|
|
13594
|
+
for (const idx of schema.indexes.values()) {
|
|
13595
|
+
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
13596
|
+
specs.push(uniqueSpecOfIndex(table, idx));
|
|
13597
|
+
}
|
|
13598
|
+
}
|
|
13599
|
+
return specs;
|
|
13600
|
+
}
|
|
13601
|
+
function uniqueSpecOfIndex(table, idx) {
|
|
13602
|
+
return {
|
|
13603
|
+
name: idx.name,
|
|
13604
|
+
keys: idx.columns.map((c) => ({
|
|
13605
|
+
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
13606
|
+
expr: c.expr
|
|
13607
|
+
})),
|
|
13608
|
+
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
13609
|
+
nullsNotDistinct: idx.nullsNotDistinct,
|
|
13610
|
+
where: idx.where,
|
|
13611
|
+
isPrimary: false
|
|
13612
|
+
};
|
|
13613
|
+
}
|
|
13614
|
+
function uniqueKeyOf(env, table, spec, row) {
|
|
13615
|
+
if (spec.where) {
|
|
13616
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
13617
|
+
const v = evalExpr(env.ctx, scope, spec.where);
|
|
13618
|
+
if (v.v !== true) return null;
|
|
13619
|
+
}
|
|
13620
|
+
const parts = [];
|
|
13621
|
+
let hasNull = false;
|
|
13622
|
+
for (const k of spec.keys) {
|
|
13623
|
+
let value;
|
|
13624
|
+
let type;
|
|
13625
|
+
if (k.expr) {
|
|
13626
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
13627
|
+
const v = evalExpr(env.ctx, scope, k.expr);
|
|
13628
|
+
value = v.v;
|
|
13629
|
+
type = v.t === "unknown" ? "text" : v.t;
|
|
13630
|
+
} else {
|
|
13631
|
+
value = row[k.colIdx] ?? null;
|
|
13632
|
+
type = table.columns[k.colIdx].type.id;
|
|
13633
|
+
}
|
|
13634
|
+
if (value === null) {
|
|
13635
|
+
hasNull = true;
|
|
13636
|
+
parts.push("\0N");
|
|
13637
|
+
} else {
|
|
13638
|
+
parts.push(datumKey(type, value));
|
|
13639
|
+
}
|
|
13640
|
+
}
|
|
13641
|
+
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
13642
|
+
return parts.join("");
|
|
13643
|
+
}
|
|
13644
|
+
function checkUnique(env, table, row, selfIdx) {
|
|
13645
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13646
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13647
|
+
if (key === null) continue;
|
|
13648
|
+
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
13649
|
+
}
|
|
13650
|
+
}
|
|
13651
|
+
function findConflict(env, table, spec, row) {
|
|
13652
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13653
|
+
if (key === null) return null;
|
|
13654
|
+
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
13655
|
+
return hits.length > 0 ? hits[0] : null;
|
|
13656
|
+
}
|
|
13657
|
+
function checkForeignKeys(env, table, row) {
|
|
13658
|
+
const state = env.ctx.state;
|
|
13659
|
+
for (const con of table.constraints) {
|
|
13660
|
+
if (con.kind !== "foreign_key") continue;
|
|
13661
|
+
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
13662
|
+
const nulls = values.filter((v) => v === null).length;
|
|
13663
|
+
if (con.match === "simple" && nulls > 0) continue;
|
|
13664
|
+
if (con.match === "full") {
|
|
13665
|
+
if (nulls === values.length) continue;
|
|
13666
|
+
if (nulls > 0) {
|
|
13667
|
+
throw pgError(
|
|
13668
|
+
"constraint_foreign_key",
|
|
13669
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
13670
|
+
"23503"
|
|
13671
|
+
);
|
|
13672
|
+
}
|
|
13673
|
+
}
|
|
13674
|
+
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
13675
|
+
if (!refTable) {
|
|
13676
|
+
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
13677
|
+
}
|
|
13678
|
+
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
13679
|
+
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
13680
|
+
const wanted = values.map((v, i) => {
|
|
13681
|
+
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
13682
|
+
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
13683
|
+
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
13684
|
+
}).join("");
|
|
13685
|
+
let found = false;
|
|
13686
|
+
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
13687
|
+
const r = refTable.rowAt(i);
|
|
13688
|
+
const key = refIdxs.map((ri, j) => {
|
|
13689
|
+
const v = r[ri] ?? null;
|
|
13690
|
+
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
13691
|
+
}).join("");
|
|
13692
|
+
if (key === wanted) {
|
|
13693
|
+
found = true;
|
|
13694
|
+
break;
|
|
13695
|
+
}
|
|
13696
|
+
}
|
|
13697
|
+
if (!found) {
|
|
13698
|
+
throw pgError(
|
|
13699
|
+
"constraint_foreign_key",
|
|
13700
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
13701
|
+
"23503"
|
|
13702
|
+
);
|
|
13487
13703
|
}
|
|
13488
13704
|
}
|
|
13489
|
-
table.indexStores = stores;
|
|
13490
|
-
return stores;
|
|
13491
13705
|
}
|
|
13492
|
-
function
|
|
13493
|
-
const
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13706
|
+
function referencingConstraints(env, table) {
|
|
13707
|
+
const out = [];
|
|
13708
|
+
for (const schema of env.ctx.state.schemas.values()) {
|
|
13709
|
+
for (const t of schema.tables.values()) {
|
|
13710
|
+
for (const con of t.constraints) {
|
|
13711
|
+
if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
|
|
13712
|
+
out.push({ table: t, constraint: con });
|
|
13713
|
+
}
|
|
13714
|
+
}
|
|
13500
13715
|
}
|
|
13501
|
-
stores.set(spec.name, store);
|
|
13502
|
-
}
|
|
13503
|
-
return store;
|
|
13504
|
-
}
|
|
13505
|
-
function indexInsertRow(env, table, rowIdx, row) {
|
|
13506
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13507
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
13508
|
-
if (key === null) continue;
|
|
13509
|
-
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
13510
|
-
}
|
|
13511
|
-
}
|
|
13512
|
-
function indexRemoveRow(env, table, rowIdx, row) {
|
|
13513
|
-
if (!table.indexStores) return;
|
|
13514
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13515
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
13516
|
-
if (key === null) continue;
|
|
13517
|
-
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
13518
13716
|
}
|
|
13519
|
-
|
|
13520
|
-
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
13521
|
-
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
13522
|
-
indexInsertRow(env, table, rowIdx, newRow);
|
|
13523
|
-
}
|
|
13524
|
-
function rebuildTableIndexes(env, table) {
|
|
13525
|
-
table.indexStores = null;
|
|
13526
|
-
ensureIndexStores(env, table);
|
|
13717
|
+
return out;
|
|
13527
13718
|
}
|
|
13528
13719
|
|
|
13529
13720
|
// src/planner/access.ts
|
|
@@ -15409,10 +15600,9 @@ var Parser = class {
|
|
|
15409
15600
|
return this.parseCreateFunction(orReplace);
|
|
15410
15601
|
}
|
|
15411
15602
|
if (this.atKw("trigger") || this.atKw("constraint") && this.atKw("trigger", 1)) {
|
|
15412
|
-
|
|
15413
|
-
}
|
|
15603
|
+
const constraint = this.eatKw("constraint");
|
|
15414
15604
|
this.expectKw("trigger");
|
|
15415
|
-
return this.parseCreateTrigger(orReplace);
|
|
15605
|
+
return this.parseCreateTrigger(orReplace, constraint);
|
|
15416
15606
|
}
|
|
15417
15607
|
if (this.atKw("extension")) {
|
|
15418
15608
|
this.pos++;
|
|
@@ -16233,7 +16423,7 @@ var Parser = class {
|
|
|
16233
16423
|
strict: strict2
|
|
16234
16424
|
};
|
|
16235
16425
|
}
|
|
16236
|
-
parseCreateTrigger(orReplace) {
|
|
16426
|
+
parseCreateTrigger(orReplace, constraint) {
|
|
16237
16427
|
const name = this.ident();
|
|
16238
16428
|
let timing;
|
|
16239
16429
|
if (this.eatKw("before")) timing = "before";
|
|
@@ -16263,9 +16453,18 @@ var Parser = class {
|
|
|
16263
16453
|
this.expectKw("on");
|
|
16264
16454
|
const table = this.qualifiedName();
|
|
16265
16455
|
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16456
|
+
let deferrable = false;
|
|
16457
|
+
let initiallyDeferred = false;
|
|
16458
|
+
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
16459
|
+
else if (this.eatKw("deferrable")) deferrable = true;
|
|
16460
|
+
if (this.eatKw("initially")) {
|
|
16461
|
+
if (this.eatKw("deferred")) initiallyDeferred = true;
|
|
16462
|
+
else this.expectKw("immediate");
|
|
16463
|
+
}
|
|
16464
|
+
if ((deferrable || initiallyDeferred) && !constraint)
|
|
16465
|
+
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
16466
|
+
if (initiallyDeferred && !deferrable)
|
|
16467
|
+
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
16269
16468
|
let forEachRow = false;
|
|
16270
16469
|
if (this.eatKw("for")) {
|
|
16271
16470
|
this.eatKw("each");
|
|
@@ -16290,7 +16489,21 @@ var Parser = class {
|
|
|
16290
16489
|
} while (this.eatPunct(","));
|
|
16291
16490
|
}
|
|
16292
16491
|
this.expectPunct(")");
|
|
16293
|
-
return {
|
|
16492
|
+
return {
|
|
16493
|
+
type: "create_trigger",
|
|
16494
|
+
constraint,
|
|
16495
|
+
deferrable,
|
|
16496
|
+
initiallyDeferred,
|
|
16497
|
+
orReplace,
|
|
16498
|
+
name,
|
|
16499
|
+
timing,
|
|
16500
|
+
events,
|
|
16501
|
+
table,
|
|
16502
|
+
forEachRow,
|
|
16503
|
+
when,
|
|
16504
|
+
funcName,
|
|
16505
|
+
funcArgs
|
|
16506
|
+
};
|
|
16294
16507
|
}
|
|
16295
16508
|
// --- ALTER --------------------------------------------------------------------
|
|
16296
16509
|
parseAlter() {
|
|
@@ -16635,9 +16848,15 @@ var Parser = class {
|
|
|
16635
16848
|
this.skipToStatementEnd();
|
|
16636
16849
|
return { type: "no_op", what: "SET TRANSACTION" };
|
|
16637
16850
|
}
|
|
16638
|
-
if (this.
|
|
16639
|
-
this.
|
|
16640
|
-
|
|
16851
|
+
if (this.eatKw("constraints")) {
|
|
16852
|
+
const names = this.eatKw("all") ? null : [];
|
|
16853
|
+
if (names)
|
|
16854
|
+
do {
|
|
16855
|
+
names.push(this.qualifiedName());
|
|
16856
|
+
} while (this.eatPunct(","));
|
|
16857
|
+
const deferred = this.eatKw("deferred");
|
|
16858
|
+
if (!deferred) this.expectKw("immediate");
|
|
16859
|
+
return { type: "set_constraints", names, deferred };
|
|
16641
16860
|
}
|
|
16642
16861
|
if (this.atKw("role") || this.atKw("session", 0) && this.atKw("authorization", 1)) {
|
|
16643
16862
|
this.skipToStatementEnd();
|
|
@@ -19012,12 +19231,12 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19012
19231
|
table: null
|
|
19013
19232
|
}));
|
|
19014
19233
|
const seen = /* @__PURE__ */ new Set();
|
|
19015
|
-
const
|
|
19234
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
|
|
19016
19235
|
let result = [];
|
|
19017
19236
|
let working = [];
|
|
19018
19237
|
for (const row of base.rows) {
|
|
19019
19238
|
if (!body.all) {
|
|
19020
|
-
const k =
|
|
19239
|
+
const k = keyOf2(row);
|
|
19021
19240
|
if (seen.has(k)) continue;
|
|
19022
19241
|
seen.add(k);
|
|
19023
19242
|
}
|
|
@@ -19050,7 +19269,7 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19050
19269
|
return castTo(env.ctx, tv(srcT === UNKNOWN ? "text" : srcT, v), columns[i].type, {}).v;
|
|
19051
19270
|
});
|
|
19052
19271
|
if (!body.all) {
|
|
19053
|
-
const k =
|
|
19272
|
+
const k = keyOf2(row);
|
|
19054
19273
|
if (seen.has(k)) continue;
|
|
19055
19274
|
seen.add(k);
|
|
19056
19275
|
}
|
|
@@ -20230,7 +20449,7 @@ function setOpRelation(env, op) {
|
|
|
20230
20449
|
);
|
|
20231
20450
|
const lrows = normalize(left);
|
|
20232
20451
|
const rrows = normalize(right);
|
|
20233
|
-
const
|
|
20452
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
|
|
20234
20453
|
let rows;
|
|
20235
20454
|
switch (op.op) {
|
|
20236
20455
|
case "union": {
|
|
@@ -20238,7 +20457,7 @@ function setOpRelation(env, op) {
|
|
|
20238
20457
|
if (!op.all) {
|
|
20239
20458
|
const seen = /* @__PURE__ */ new Set();
|
|
20240
20459
|
rows = rows.filter((r) => {
|
|
20241
|
-
const k =
|
|
20460
|
+
const k = keyOf2(r);
|
|
20242
20461
|
if (seen.has(k)) return false;
|
|
20243
20462
|
seen.add(k);
|
|
20244
20463
|
return true;
|
|
@@ -20249,13 +20468,13 @@ function setOpRelation(env, op) {
|
|
|
20249
20468
|
case "intersect": {
|
|
20250
20469
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
20251
20470
|
for (const r of rrows) {
|
|
20252
|
-
const k =
|
|
20471
|
+
const k = keyOf2(r);
|
|
20253
20472
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
20254
20473
|
}
|
|
20255
20474
|
rows = [];
|
|
20256
20475
|
const emitted = /* @__PURE__ */ new Set();
|
|
20257
20476
|
for (const r of lrows) {
|
|
20258
|
-
const k =
|
|
20477
|
+
const k = keyOf2(r);
|
|
20259
20478
|
const avail = rightCounts.get(k) ?? 0;
|
|
20260
20479
|
if (avail <= 0) continue;
|
|
20261
20480
|
if (op.all) {
|
|
@@ -20271,13 +20490,13 @@ function setOpRelation(env, op) {
|
|
|
20271
20490
|
case "except": {
|
|
20272
20491
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
20273
20492
|
for (const r of rrows) {
|
|
20274
|
-
const k =
|
|
20493
|
+
const k = keyOf2(r);
|
|
20275
20494
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
20276
20495
|
}
|
|
20277
20496
|
rows = [];
|
|
20278
20497
|
const emitted = /* @__PURE__ */ new Set();
|
|
20279
20498
|
for (const r of lrows) {
|
|
20280
|
-
const k =
|
|
20499
|
+
const k = keyOf2(r);
|
|
20281
20500
|
if (op.all) {
|
|
20282
20501
|
const avail = rightCounts.get(k) ?? 0;
|
|
20283
20502
|
if (avail > 0) {
|
|
@@ -20725,207 +20944,54 @@ function executeCore(env0, core, orderBy, opts) {
|
|
|
20725
20944
|
}).join("");
|
|
20726
20945
|
if (seen.has(k)) return false;
|
|
20727
20946
|
seen.add(k);
|
|
20728
|
-
return true;
|
|
20729
|
-
});
|
|
20730
|
-
}
|
|
20731
|
-
}
|
|
20732
|
-
rel3 = stripHidden(rel3);
|
|
20733
|
-
return rel3;
|
|
20734
|
-
}
|
|
20735
|
-
function executeSelectStmt(env0, stmt) {
|
|
20736
|
-
const env = applyWith(env0, stmt.with);
|
|
20737
|
-
let rel3;
|
|
20738
|
-
if (stmt.body.type === "select_core") {
|
|
20739
|
-
rel3 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
|
|
20740
|
-
} else {
|
|
20741
|
-
rel3 = executeBody(env, stmt.body);
|
|
20742
|
-
const specs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20743
|
-
if (specs.length > 0) sortRows(env, rel3, specs);
|
|
20744
|
-
rel3 = stripHidden(rel3);
|
|
20745
|
-
}
|
|
20746
|
-
if (stmt.limitWithTies) {
|
|
20747
|
-
if (stmt.orderBy.length === 0) {
|
|
20748
|
-
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
20749
|
-
}
|
|
20750
|
-
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20751
|
-
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
20752
|
-
}
|
|
20753
|
-
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
20754
|
-
}
|
|
20755
|
-
|
|
20756
|
-
// src/constraints/enforce.ts
|
|
20757
|
-
function tableScope(table, row) {
|
|
20758
|
-
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
20759
|
-
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
20760
|
-
}
|
|
20761
|
-
function checkNotNull(env, table, row) {
|
|
20762
|
-
void env;
|
|
20763
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
20764
|
-
const c = table.columns[i];
|
|
20765
|
-
if (c.notNull && (row[i] ?? null) === null) {
|
|
20766
|
-
throw pgError(
|
|
20767
|
-
"not_null_violation",
|
|
20768
|
-
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
20769
|
-
"23502"
|
|
20770
|
-
);
|
|
20771
|
-
}
|
|
20772
|
-
}
|
|
20773
|
-
}
|
|
20774
|
-
function checkChecks(env, table, row) {
|
|
20775
|
-
for (const con of table.constraints) {
|
|
20776
|
-
if (con.kind !== "check") continue;
|
|
20777
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
20778
|
-
const v = evalExpr(env.ctx, scope, con.expr);
|
|
20779
|
-
if (v.v === null) continue;
|
|
20780
|
-
const b = castTo(env.ctx, v, "bool", {});
|
|
20781
|
-
if (b.v !== true) {
|
|
20782
|
-
throw pgError(
|
|
20783
|
-
"check_violation",
|
|
20784
|
-
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
20785
|
-
"23514"
|
|
20786
|
-
);
|
|
20787
|
-
}
|
|
20788
|
-
}
|
|
20789
|
-
}
|
|
20790
|
-
function uniqueSpecsFor(env, table) {
|
|
20791
|
-
const specs = [];
|
|
20792
|
-
for (const con of table.constraints) {
|
|
20793
|
-
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
20794
|
-
specs.push({
|
|
20795
|
-
name: con.name,
|
|
20796
|
-
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
20797
|
-
columnNames: con.columns,
|
|
20798
|
-
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
20799
|
-
where: null,
|
|
20800
|
-
isPrimary: con.kind === "primary_key"
|
|
20801
|
-
});
|
|
20802
|
-
}
|
|
20803
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
20804
|
-
if (schema) {
|
|
20805
|
-
for (const idx of schema.indexes.values()) {
|
|
20806
|
-
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
20807
|
-
specs.push(uniqueSpecOfIndex(table, idx));
|
|
20808
|
-
}
|
|
20809
|
-
}
|
|
20810
|
-
return specs;
|
|
20811
|
-
}
|
|
20812
|
-
function uniqueSpecOfIndex(table, idx) {
|
|
20813
|
-
return {
|
|
20814
|
-
name: idx.name,
|
|
20815
|
-
keys: idx.columns.map((c) => ({
|
|
20816
|
-
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
20817
|
-
expr: c.expr
|
|
20818
|
-
})),
|
|
20819
|
-
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
20820
|
-
nullsNotDistinct: idx.nullsNotDistinct,
|
|
20821
|
-
where: idx.where,
|
|
20822
|
-
isPrimary: false
|
|
20823
|
-
};
|
|
20824
|
-
}
|
|
20825
|
-
function uniqueKeyOf(env, table, spec, row) {
|
|
20826
|
-
if (spec.where) {
|
|
20827
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
20828
|
-
const v = evalExpr(env.ctx, scope, spec.where);
|
|
20829
|
-
if (v.v !== true) return null;
|
|
20830
|
-
}
|
|
20831
|
-
const parts = [];
|
|
20832
|
-
let hasNull = false;
|
|
20833
|
-
for (const k of spec.keys) {
|
|
20834
|
-
let value;
|
|
20835
|
-
let type;
|
|
20836
|
-
if (k.expr) {
|
|
20837
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
20838
|
-
const v = evalExpr(env.ctx, scope, k.expr);
|
|
20839
|
-
value = v.v;
|
|
20840
|
-
type = v.t === "unknown" ? "text" : v.t;
|
|
20841
|
-
} else {
|
|
20842
|
-
value = row[k.colIdx] ?? null;
|
|
20843
|
-
type = table.columns[k.colIdx].type.id;
|
|
20844
|
-
}
|
|
20845
|
-
if (value === null) {
|
|
20846
|
-
hasNull = true;
|
|
20847
|
-
parts.push("\0N");
|
|
20848
|
-
} else {
|
|
20849
|
-
parts.push(datumKey(type, value));
|
|
20850
|
-
}
|
|
20851
|
-
}
|
|
20852
|
-
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
20853
|
-
return parts.join("");
|
|
20854
|
-
}
|
|
20855
|
-
function checkUnique(env, table, row, selfIdx) {
|
|
20856
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
20857
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
20858
|
-
if (key === null) continue;
|
|
20859
|
-
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
20860
|
-
}
|
|
20861
|
-
}
|
|
20862
|
-
function findConflict(env, table, spec, row) {
|
|
20863
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
20864
|
-
if (key === null) return null;
|
|
20865
|
-
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
20866
|
-
return hits.length > 0 ? hits[0] : null;
|
|
20867
|
-
}
|
|
20868
|
-
function checkForeignKeys(env, table, row) {
|
|
20869
|
-
const state = env.ctx.state;
|
|
20870
|
-
for (const con of table.constraints) {
|
|
20871
|
-
if (con.kind !== "foreign_key") continue;
|
|
20872
|
-
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
20873
|
-
const nulls = values.filter((v) => v === null).length;
|
|
20874
|
-
if (con.match === "simple" && nulls > 0) continue;
|
|
20875
|
-
if (con.match === "full") {
|
|
20876
|
-
if (nulls === values.length) continue;
|
|
20877
|
-
if (nulls > 0) {
|
|
20878
|
-
throw pgError(
|
|
20879
|
-
"constraint_foreign_key",
|
|
20880
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
20881
|
-
"23503"
|
|
20882
|
-
);
|
|
20883
|
-
}
|
|
20884
|
-
}
|
|
20885
|
-
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
20886
|
-
if (!refTable) {
|
|
20887
|
-
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
20888
|
-
}
|
|
20889
|
-
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
20890
|
-
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
20891
|
-
const wanted = values.map((v, i) => {
|
|
20892
|
-
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
20893
|
-
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
20894
|
-
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
20895
|
-
}).join("");
|
|
20896
|
-
let found = false;
|
|
20897
|
-
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
20898
|
-
const r = refTable.rowAt(i);
|
|
20899
|
-
const key = refIdxs.map((ri, j) => {
|
|
20900
|
-
const v = r[ri] ?? null;
|
|
20901
|
-
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
20902
|
-
}).join("");
|
|
20903
|
-
if (key === wanted) {
|
|
20904
|
-
found = true;
|
|
20905
|
-
break;
|
|
20906
|
-
}
|
|
20907
|
-
}
|
|
20908
|
-
if (!found) {
|
|
20909
|
-
throw pgError(
|
|
20910
|
-
"constraint_foreign_key",
|
|
20911
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
20912
|
-
"23503"
|
|
20913
|
-
);
|
|
20947
|
+
return true;
|
|
20948
|
+
});
|
|
20914
20949
|
}
|
|
20915
20950
|
}
|
|
20951
|
+
rel3 = stripHidden(rel3);
|
|
20952
|
+
return rel3;
|
|
20916
20953
|
}
|
|
20917
|
-
function
|
|
20918
|
-
const
|
|
20919
|
-
|
|
20920
|
-
|
|
20921
|
-
|
|
20922
|
-
|
|
20923
|
-
|
|
20924
|
-
|
|
20925
|
-
|
|
20954
|
+
function executeSelectStmt(env0, stmt) {
|
|
20955
|
+
const env = applyWith(env0, stmt.with);
|
|
20956
|
+
let rel3;
|
|
20957
|
+
if (stmt.body.type === "select_core") {
|
|
20958
|
+
rel3 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
|
|
20959
|
+
} else {
|
|
20960
|
+
rel3 = executeBody(env, stmt.body);
|
|
20961
|
+
const specs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20962
|
+
if (specs.length > 0) sortRows(env, rel3, specs);
|
|
20963
|
+
rel3 = stripHidden(rel3);
|
|
20964
|
+
}
|
|
20965
|
+
if (stmt.limitWithTies) {
|
|
20966
|
+
if (stmt.orderBy.length === 0) {
|
|
20967
|
+
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
20926
20968
|
}
|
|
20969
|
+
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20970
|
+
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
20927
20971
|
}
|
|
20928
|
-
return
|
|
20972
|
+
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
20973
|
+
}
|
|
20974
|
+
|
|
20975
|
+
// src/executor/triggers-scope.ts
|
|
20976
|
+
function triggerScope(table, newRow, oldRow) {
|
|
20977
|
+
const cols = [];
|
|
20978
|
+
const row = [];
|
|
20979
|
+
const rangeVars = /* @__PURE__ */ new Set();
|
|
20980
|
+
if (newRow) {
|
|
20981
|
+
rangeVars.add("new");
|
|
20982
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
20983
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
20984
|
+
row.push(newRow[i] ?? null);
|
|
20985
|
+
}
|
|
20986
|
+
}
|
|
20987
|
+
if (oldRow) {
|
|
20988
|
+
rangeVars.add("old");
|
|
20989
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
20990
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
20991
|
+
row.push(oldRow[i] ?? null);
|
|
20992
|
+
}
|
|
20993
|
+
}
|
|
20994
|
+
return new RowScope(cols, row, null, rangeVars);
|
|
20929
20995
|
}
|
|
20930
20996
|
|
|
20931
20997
|
// src/executor/triggers.ts
|
|
@@ -20941,6 +21007,18 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
20941
21007
|
for (const t of table.triggers) {
|
|
20942
21008
|
if (t.timing !== timing || !matches(t, event) || !t.forEachRow) continue;
|
|
20943
21009
|
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
21010
|
+
if (t.constraint && timing === "after") {
|
|
21011
|
+
if (t.when && !evalPredicate(env, triggerScope(table, newRow, oldRow), t.when)) continue;
|
|
21012
|
+
env.ctx.state.pendingTriggers.push({
|
|
21013
|
+
schema: table.schema,
|
|
21014
|
+
table: table.name,
|
|
21015
|
+
trigger: t.name,
|
|
21016
|
+
event,
|
|
21017
|
+
oldRow: oldRow?.slice() ?? null,
|
|
21018
|
+
newRow: newRow?.slice() ?? null
|
|
21019
|
+
});
|
|
21020
|
+
continue;
|
|
21021
|
+
}
|
|
20944
21022
|
const result = executor(env, table, t, event, oldRow, timing === "before" ? row : newRow);
|
|
20945
21023
|
if (timing === "before") {
|
|
20946
21024
|
if (result === null) return { row: null };
|
|
@@ -20949,6 +21027,167 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
20949
21027
|
}
|
|
20950
21028
|
return { row };
|
|
20951
21029
|
}
|
|
21030
|
+
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
21031
|
+
function flushConstraintTriggers(state, all = false) {
|
|
21032
|
+
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
21033
|
+
for (let i = 0; i < state.pendingTriggers.length; ) {
|
|
21034
|
+
const pending = state.pendingTriggers[i];
|
|
21035
|
+
const table = state.schemas.get(pending.schema)?.tables.get(pending.table);
|
|
21036
|
+
const trigger = table?.triggers.find((t) => t.name === pending.trigger);
|
|
21037
|
+
if (!table || !trigger) {
|
|
21038
|
+
state.pendingTriggers.splice(i, 1);
|
|
21039
|
+
continue;
|
|
21040
|
+
}
|
|
21041
|
+
const deferred = trigger.deferrable && (state.constraintModes.get(keyOf(table.schema, trigger.name)) ?? trigger.initiallyDeferred);
|
|
21042
|
+
if (!all && state.inTransaction && deferred) {
|
|
21043
|
+
i++;
|
|
21044
|
+
continue;
|
|
21045
|
+
}
|
|
21046
|
+
if (!executor) throw unsupported(`trigger "${trigger.name}" execution`);
|
|
21047
|
+
state.pendingTriggers.splice(i, 1);
|
|
21048
|
+
const changes = state.changes;
|
|
21049
|
+
try {
|
|
21050
|
+
executor(env, table, { ...trigger, when: null }, pending.event, pending.oldRow, pending.newRow);
|
|
21051
|
+
} catch (error) {
|
|
21052
|
+
state.pendingTriggers.splice(i, 0, pending);
|
|
21053
|
+
throw error;
|
|
21054
|
+
} finally {
|
|
21055
|
+
state.changes = changes;
|
|
21056
|
+
}
|
|
21057
|
+
}
|
|
21058
|
+
}
|
|
21059
|
+
function setConstraints(state, stmt) {
|
|
21060
|
+
if (!state.inTransaction) return;
|
|
21061
|
+
const matches2 = [];
|
|
21062
|
+
if (stmt.names) {
|
|
21063
|
+
for (const name of stmt.names) {
|
|
21064
|
+
const schemas = name.length > 1 ? [name[name.length - 2]] : state.effectiveSearchPath();
|
|
21065
|
+
let found = false;
|
|
21066
|
+
for (const schema of schemas) {
|
|
21067
|
+
const items = [...state.schemas.get(schema)?.tables.values() ?? []].flatMap(
|
|
21068
|
+
(table) => table.triggers.filter((t) => t.constraint && t.name === name[name.length - 1])
|
|
21069
|
+
);
|
|
21070
|
+
if (items.length) {
|
|
21071
|
+
for (const trigger of items) matches2.push({ schema, trigger });
|
|
21072
|
+
found = true;
|
|
21073
|
+
break;
|
|
21074
|
+
}
|
|
21075
|
+
}
|
|
21076
|
+
if (!found) throw pgError("undefined_object", `constraint "${name.join(".")}" does not exist`, "42704");
|
|
21077
|
+
}
|
|
21078
|
+
} else {
|
|
21079
|
+
for (const schema of state.schemas.values())
|
|
21080
|
+
for (const table of schema.tables.values())
|
|
21081
|
+
for (const trigger of table.triggers)
|
|
21082
|
+
if (trigger.constraint && trigger.deferrable) matches2.push({ schema: schema.name, trigger });
|
|
21083
|
+
}
|
|
21084
|
+
for (const { trigger } of matches2)
|
|
21085
|
+
if (stmt.deferred && !trigger.deferrable)
|
|
21086
|
+
throw pgError("misuse", `constraint "${trigger.name}" is not deferrable`, "55000");
|
|
21087
|
+
const previous = new Map(state.constraintModes);
|
|
21088
|
+
for (const { schema, trigger } of matches2) state.constraintModes.set(keyOf(schema, trigger.name), stmt.deferred);
|
|
21089
|
+
try {
|
|
21090
|
+
if (!stmt.deferred) flushConstraintTriggers(state);
|
|
21091
|
+
} catch (error) {
|
|
21092
|
+
state.constraintModes = previous;
|
|
21093
|
+
throw error;
|
|
21094
|
+
}
|
|
21095
|
+
}
|
|
21096
|
+
|
|
21097
|
+
// src/transactions/manager.ts
|
|
21098
|
+
var TransactionManager = class {
|
|
21099
|
+
constructor(state) {
|
|
21100
|
+
this.state = state;
|
|
21101
|
+
}
|
|
21102
|
+
state;
|
|
21103
|
+
base = null;
|
|
21104
|
+
savepoints = [];
|
|
21105
|
+
freezeDepth = 0;
|
|
21106
|
+
get inTransaction() {
|
|
21107
|
+
return this.base !== null;
|
|
21108
|
+
}
|
|
21109
|
+
takeSnapshot() {
|
|
21110
|
+
this.state.freezeShared();
|
|
21111
|
+
this.freezeDepth++;
|
|
21112
|
+
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
21113
|
+
}
|
|
21114
|
+
restore(snap) {
|
|
21115
|
+
this.state.restoreFrom(snap.state);
|
|
21116
|
+
this.state.prng.setState(snap.prngState);
|
|
21117
|
+
}
|
|
21118
|
+
thawOnce() {
|
|
21119
|
+
if (this.freezeDepth > 0) {
|
|
21120
|
+
this.state.thawShared();
|
|
21121
|
+
this.freezeDepth--;
|
|
21122
|
+
}
|
|
21123
|
+
}
|
|
21124
|
+
begin() {
|
|
21125
|
+
if (this.base !== null) {
|
|
21126
|
+
return;
|
|
21127
|
+
}
|
|
21128
|
+
this.base = this.takeSnapshot();
|
|
21129
|
+
this.state.inTransaction = true;
|
|
21130
|
+
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
21131
|
+
}
|
|
21132
|
+
commit() {
|
|
21133
|
+
try {
|
|
21134
|
+
flushConstraintTriggers(this.state, true);
|
|
21135
|
+
} catch (error) {
|
|
21136
|
+
this.rollback();
|
|
21137
|
+
throw error;
|
|
21138
|
+
}
|
|
21139
|
+
this.base = null;
|
|
21140
|
+
this.savepoints = [];
|
|
21141
|
+
this.state.inTransaction = false;
|
|
21142
|
+
this.state.localSettings.clear();
|
|
21143
|
+
this.state.pendingTriggers = [];
|
|
21144
|
+
this.state.constraintModes.clear();
|
|
21145
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
21146
|
+
}
|
|
21147
|
+
rollback() {
|
|
21148
|
+
if (this.base !== null) {
|
|
21149
|
+
this.restore(this.base);
|
|
21150
|
+
}
|
|
21151
|
+
this.base = null;
|
|
21152
|
+
this.savepoints = [];
|
|
21153
|
+
this.state.inTransaction = false;
|
|
21154
|
+
this.state.localSettings.clear();
|
|
21155
|
+
this.state.pendingTriggers = [];
|
|
21156
|
+
this.state.constraintModes.clear();
|
|
21157
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
21158
|
+
}
|
|
21159
|
+
savepoint(name) {
|
|
21160
|
+
if (this.base === null) {
|
|
21161
|
+
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
21162
|
+
}
|
|
21163
|
+
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
21164
|
+
}
|
|
21165
|
+
releaseSavepoint(name) {
|
|
21166
|
+
const idx = this.findSavepoint(name);
|
|
21167
|
+
this.savepoints.splice(idx);
|
|
21168
|
+
}
|
|
21169
|
+
rollbackToSavepoint(name) {
|
|
21170
|
+
const idx = this.findSavepoint(name);
|
|
21171
|
+
const sp = this.savepoints[idx];
|
|
21172
|
+
this.restore(sp.snap);
|
|
21173
|
+
this.savepoints.splice(idx + 1);
|
|
21174
|
+
}
|
|
21175
|
+
findSavepoint(name) {
|
|
21176
|
+
if (this.base === null) {
|
|
21177
|
+
throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
|
|
21178
|
+
}
|
|
21179
|
+
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
21180
|
+
if (this.savepoints[i].name === name) return i;
|
|
21181
|
+
}
|
|
21182
|
+
throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
|
|
21183
|
+
}
|
|
21184
|
+
reset() {
|
|
21185
|
+
this.base = null;
|
|
21186
|
+
this.savepoints = [];
|
|
21187
|
+
this.state.inTransaction = false;
|
|
21188
|
+
this.freezeDepth = 0;
|
|
21189
|
+
}
|
|
21190
|
+
};
|
|
20952
21191
|
|
|
20953
21192
|
// src/executor/dml.ts
|
|
20954
21193
|
function withStatementRollback(env, fn) {
|
|
@@ -21638,6 +21877,7 @@ function executeSet(env, stmt) {
|
|
|
21638
21877
|
else target.delete(name);
|
|
21639
21878
|
return commandResult("SET", 0);
|
|
21640
21879
|
}
|
|
21880
|
+
validateStorageSetting(name, stmt.value);
|
|
21641
21881
|
target.set(name, stmt.value);
|
|
21642
21882
|
return commandResult("SET", 0);
|
|
21643
21883
|
}
|
|
@@ -21943,64 +22183,6 @@ function executeCopyFromData(env, stmt, data) {
|
|
|
21943
22183
|
};
|
|
21944
22184
|
}
|
|
21945
22185
|
|
|
21946
|
-
// src/expressions/context.ts
|
|
21947
|
-
var EngineCtx = class {
|
|
21948
|
-
state;
|
|
21949
|
-
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
21950
|
-
txNow;
|
|
21951
|
-
/** statement timestamp */
|
|
21952
|
-
stmtNow;
|
|
21953
|
-
constructor(state, txNow) {
|
|
21954
|
-
this.state = state;
|
|
21955
|
-
const nowMs = state.clock().getTime();
|
|
21956
|
-
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
21957
|
-
this.txNow = txNow ?? nowMicros;
|
|
21958
|
-
this.stmtNow = nowMicros;
|
|
21959
|
-
}
|
|
21960
|
-
timezone() {
|
|
21961
|
-
return this.state.getSetting("timezone") ?? "UTC";
|
|
21962
|
-
}
|
|
21963
|
-
namespaceOid(name) {
|
|
21964
|
-
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
21965
|
-
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
21966
|
-
return oid;
|
|
21967
|
-
}
|
|
21968
|
-
namespaceName(oid) {
|
|
21969
|
-
const builtin = builtinNamespaceName(oid);
|
|
21970
|
-
if (builtin !== void 0) return builtin;
|
|
21971
|
-
for (const schema of this.state.schemas.values()) {
|
|
21972
|
-
if (schema.oid === oid) return schema.name;
|
|
21973
|
-
}
|
|
21974
|
-
return null;
|
|
21975
|
-
}
|
|
21976
|
-
zoneOffsetAt(utcMicros) {
|
|
21977
|
-
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
21978
|
-
}
|
|
21979
|
-
zoneOffsetForNaive(naiveMicros) {
|
|
21980
|
-
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
21981
|
-
}
|
|
21982
|
-
enumLabels(enumType) {
|
|
21983
|
-
if (!isEnumType(enumType)) return null;
|
|
21984
|
-
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
21985
|
-
return e?.labels ?? null;
|
|
21986
|
-
}
|
|
21987
|
-
enumHasLabel(enumType, label) {
|
|
21988
|
-
const labels = this.enumLabels(enumType);
|
|
21989
|
-
return labels === null ? true : labels.includes(label);
|
|
21990
|
-
}
|
|
21991
|
-
enumOrder(enumType, label) {
|
|
21992
|
-
const labels = this.enumLabels(enumType);
|
|
21993
|
-
if (!labels) return 0;
|
|
21994
|
-
const idx = labels.indexOf(label);
|
|
21995
|
-
return idx === -1 ? labels.length : idx;
|
|
21996
|
-
}
|
|
21997
|
-
requireEnum(enumType) {
|
|
21998
|
-
const labels = this.enumLabels(enumType);
|
|
21999
|
-
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
22000
|
-
return labels;
|
|
22001
|
-
}
|
|
22002
|
-
};
|
|
22003
|
-
|
|
22004
22186
|
// src/runtime/clock.ts
|
|
22005
22187
|
var DEFAULT_NOW = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
22006
22188
|
function fixedClock(instant = DEFAULT_NOW) {
|
|
@@ -22968,7 +23150,7 @@ function pgClass(ctx) {
|
|
|
22968
23150
|
v.materialized ? "m" : "v",
|
|
22969
23151
|
v.columns?.length ?? 0,
|
|
22970
23152
|
v.matRows?.length ?? 0,
|
|
22971
|
-
|
|
23153
|
+
v.materialized && [...schemaData.indexes.values()].some((i) => i.tableOid === v.oid),
|
|
22972
23154
|
!v.materialized || v.matRows !== null,
|
|
22973
23155
|
relPersistence(v)
|
|
22974
23156
|
);
|
|
@@ -23234,7 +23416,7 @@ function pgIndex(ctx) {
|
|
|
23234
23416
|
const valid = i.valid !== false;
|
|
23235
23417
|
rows.push([
|
|
23236
23418
|
i.oid ?? 0,
|
|
23237
|
-
table?.oid ?? 0,
|
|
23419
|
+
table?.oid ?? i.tableOid ?? 0,
|
|
23238
23420
|
indexAttributeCount(i),
|
|
23239
23421
|
i.columns.length,
|
|
23240
23422
|
i.unique,
|
|
@@ -23406,7 +23588,7 @@ function pgStatUserIndexes(ctx) {
|
|
|
23406
23588
|
for (const index of schema.indexes.values()) {
|
|
23407
23589
|
const table = schema.tables.get(index.table);
|
|
23408
23590
|
rows.push([
|
|
23409
|
-
table?.oid ?? 0,
|
|
23591
|
+
table?.oid ?? index.tableOid ?? 0,
|
|
23410
23592
|
index.oid ?? 0,
|
|
23411
23593
|
schema.name,
|
|
23412
23594
|
index.table,
|
|
@@ -24001,26 +24183,6 @@ function runTriggerBody(env, table, stmts, vars) {
|
|
|
24001
24183
|
}
|
|
24002
24184
|
}
|
|
24003
24185
|
}
|
|
24004
|
-
function triggerScope(table, newRow, oldRow) {
|
|
24005
|
-
const cols = [];
|
|
24006
|
-
const row = [];
|
|
24007
|
-
const rangeVars = /* @__PURE__ */ new Set();
|
|
24008
|
-
if (newRow) {
|
|
24009
|
-
rangeVars.add("new");
|
|
24010
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
24011
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
24012
|
-
row.push(newRow[i] ?? null);
|
|
24013
|
-
}
|
|
24014
|
-
}
|
|
24015
|
-
if (oldRow) {
|
|
24016
|
-
rangeVars.add("old");
|
|
24017
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
24018
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
24019
|
-
row.push(oldRow[i] ?? null);
|
|
24020
|
-
}
|
|
24021
|
-
}
|
|
24022
|
-
return new RowScope(cols, row, null, rangeVars);
|
|
24023
|
-
}
|
|
24024
24186
|
function executeTrigger(env, table, trigger, _event, oldRow, newRow) {
|
|
24025
24187
|
const state = env.ctx.state;
|
|
24026
24188
|
if (trigger.when !== null && !evalPredicate(env, triggerScope(table, newRow, oldRow), trigger.when)) {
|
|
@@ -24987,7 +25149,8 @@ function executeCreateTableAs(env, stmt) {
|
|
|
24987
25149
|
}
|
|
24988
25150
|
function executeCreateIndex(env, stmt) {
|
|
24989
25151
|
const state = env.ctx.state;
|
|
24990
|
-
const
|
|
25152
|
+
const view = state.findView(stmt.table);
|
|
25153
|
+
const table = state.findTable(stmt.table) ?? (view?.materialized ? materializedTable(view) : void 0);
|
|
24991
25154
|
if (!table) {
|
|
24992
25155
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
24993
25156
|
}
|
|
@@ -25099,13 +25262,22 @@ function executeRefreshMatView(env, stmt) {
|
|
|
25099
25262
|
if (!found?.materialized) {
|
|
25100
25263
|
throw pgError("undefined_table", `materialized view "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
25101
25264
|
}
|
|
25265
|
+
const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), found.query);
|
|
25266
|
+
const next = {
|
|
25267
|
+
...found,
|
|
25268
|
+
matColumns: rel3.columns.map((c, i) => ({
|
|
25269
|
+
name: found.columns?.[i] ?? c.name,
|
|
25270
|
+
type: c.type === UNKNOWN ? "text" : c.type
|
|
25271
|
+
})),
|
|
25272
|
+
matRows: stmt.withData ? rel3.rows : null
|
|
25273
|
+
};
|
|
25274
|
+
const table = materializedTable(next);
|
|
25275
|
+
for (const index of env.ctx.state.getSchema(found.schema).indexes.values()) {
|
|
25276
|
+
if (index.tableOid === found.oid && index.valid !== false) assertUniqueIndexBuildable(env, table, index);
|
|
25277
|
+
}
|
|
25102
25278
|
const view = env.ctx.state.ensureWritableView(found);
|
|
25103
|
-
|
|
25104
|
-
view.
|
|
25105
|
-
name: view.columns?.[i] ?? c.name,
|
|
25106
|
-
type: c.type === UNKNOWN ? "text" : c.type
|
|
25107
|
-
}));
|
|
25108
|
-
view.matRows = stmt.withData ? rel3.rows : null;
|
|
25279
|
+
view.matColumns = next.matColumns;
|
|
25280
|
+
view.matRows = next.matRows;
|
|
25109
25281
|
return commandResult("REFRESH MATERIALIZED VIEW", 0);
|
|
25110
25282
|
}
|
|
25111
25283
|
function executeCreateSchema(env, stmt) {
|
|
@@ -25247,6 +25419,8 @@ function executeCreateFunction(env, stmt) {
|
|
|
25247
25419
|
return commandResult("CREATE FUNCTION", 0);
|
|
25248
25420
|
}
|
|
25249
25421
|
function executeCreateTrigger(env, stmt) {
|
|
25422
|
+
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
25423
|
+
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
25250
25424
|
const state = env.ctx.state;
|
|
25251
25425
|
const found = state.findTable(stmt.table);
|
|
25252
25426
|
if (!found) {
|
|
@@ -25265,6 +25439,9 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25265
25439
|
}
|
|
25266
25440
|
const meta = {
|
|
25267
25441
|
name: stmt.name,
|
|
25442
|
+
constraint: stmt.constraint,
|
|
25443
|
+
deferrable: stmt.deferrable,
|
|
25444
|
+
initiallyDeferred: stmt.initiallyDeferred,
|
|
25268
25445
|
timing: stmt.timing,
|
|
25269
25446
|
events: stmt.events,
|
|
25270
25447
|
forEachRow: stmt.forEachRow,
|
|
@@ -26033,7 +26210,16 @@ function alterTableIsSelfContained(stmt) {
|
|
|
26033
26210
|
return stmt.actions.length === 1 && action !== void 0 && SELF_CONTAINED_ALTER_ACTIONS.has(action.kind);
|
|
26034
26211
|
}
|
|
26035
26212
|
function executeStatement(env, stmt) {
|
|
26036
|
-
if (!RESHAPES_TABLES.has(stmt.type))
|
|
26213
|
+
if (!RESHAPES_TABLES.has(stmt.type)) {
|
|
26214
|
+
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))) {
|
|
26215
|
+
return withStatementRollback(env, () => {
|
|
26216
|
+
const result = dispatchStatement(env, stmt);
|
|
26217
|
+
flushConstraintTriggers(env.ctx.state);
|
|
26218
|
+
return result;
|
|
26219
|
+
});
|
|
26220
|
+
}
|
|
26221
|
+
return dispatchStatement(env, stmt);
|
|
26222
|
+
}
|
|
26037
26223
|
try {
|
|
26038
26224
|
return dispatchStatement(env, stmt);
|
|
26039
26225
|
} finally {
|
|
@@ -26092,6 +26278,9 @@ function dispatchStatement(env, stmt) {
|
|
|
26092
26278
|
return executeRefreshMatView(env, stmt);
|
|
26093
26279
|
case "transaction":
|
|
26094
26280
|
return executeTransaction(env, stmt);
|
|
26281
|
+
case "set_constraints":
|
|
26282
|
+
setConstraints(env.ctx.state, stmt);
|
|
26283
|
+
return commandResult("SET CONSTRAINTS", 0);
|
|
26095
26284
|
case "set":
|
|
26096
26285
|
return executeSet(env, stmt);
|
|
26097
26286
|
case "show":
|