@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/wire/index.js
CHANGED
|
@@ -257,6 +257,13 @@ function isPostgresError(err) {
|
|
|
257
257
|
return typeof sqlState === "string" && /^[0-9A-Z]{5}$/.test(sqlState);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
// src/storage/guc.ts
|
|
261
|
+
function validateStorageSetting(name, value) {
|
|
262
|
+
if (name === "default_table_access_method" && value !== "heap" || name === "default_tablespace" && value !== "" && value !== "pg_default") {
|
|
263
|
+
throw pgError("invalid_parameter_value", `invalid value for parameter "${name}": "${value}"`, "22023");
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
260
267
|
// src/runtime/prng.ts
|
|
261
268
|
var Prng = class _Prng {
|
|
262
269
|
state;
|
|
@@ -3712,6 +3719,9 @@ var DatabaseState = class _DatabaseState {
|
|
|
3712
3719
|
changes = 0;
|
|
3713
3720
|
oidCounter = 16384;
|
|
3714
3721
|
inTransaction = false;
|
|
3722
|
+
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
3723
|
+
pendingTriggers = [];
|
|
3724
|
+
constraintModes = /* @__PURE__ */ new Map();
|
|
3715
3725
|
/** most recent sequence touched by nextval/setval, for lastval() */
|
|
3716
3726
|
lastSequence = null;
|
|
3717
3727
|
/** Session currval per sequence; absent entry means currval is undefined. */
|
|
@@ -3754,6 +3764,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3754
3764
|
this.settings.set("row_security", "on");
|
|
3755
3765
|
this.settings.set("array_nulls", "on");
|
|
3756
3766
|
this.settings.set("backslash_quote", "safe_encoding");
|
|
3767
|
+
this.settings.set("default_tablespace", "");
|
|
3768
|
+
this.settings.set("default_table_access_method", "heap");
|
|
3757
3769
|
}
|
|
3758
3770
|
nextOid() {
|
|
3759
3771
|
return this.oidCounter++;
|
|
@@ -3913,6 +3925,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3913
3925
|
s.prepared = new Map(this.prepared);
|
|
3914
3926
|
s.changes = this.changes;
|
|
3915
3927
|
s.inTransaction = this.inTransaction;
|
|
3928
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
3929
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
3916
3930
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
3917
3931
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3918
3932
|
s.tableStats = new Map(this.tableStats);
|
|
@@ -3930,6 +3944,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
3930
3944
|
s.prepared = new Map(this.prepared);
|
|
3931
3945
|
s.changes = this.changes;
|
|
3932
3946
|
s.inTransaction = this.inTransaction;
|
|
3947
|
+
s.pendingTriggers = this.pendingTriggers.slice();
|
|
3948
|
+
s.constraintModes = new Map(this.constraintModes);
|
|
3933
3949
|
s.lastSequence = this.lastSequence ? { ...this.lastSequence } : null;
|
|
3934
3950
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
3935
3951
|
s.tableStats = new Map(this.tableStats);
|
|
@@ -4002,6 +4018,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
4002
4018
|
this.settings = other.settings;
|
|
4003
4019
|
this.localSettings = other.localSettings;
|
|
4004
4020
|
this.prepared = other.prepared;
|
|
4021
|
+
this.pendingTriggers = other.pendingTriggers.slice();
|
|
4022
|
+
this.constraintModes = new Map(other.constraintModes);
|
|
4005
4023
|
this.changes = other.changes;
|
|
4006
4024
|
this.lastSequence = other.lastSequence;
|
|
4007
4025
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
@@ -4018,90 +4036,192 @@ var DatabaseState = class _DatabaseState {
|
|
|
4018
4036
|
}
|
|
4019
4037
|
};
|
|
4020
4038
|
|
|
4021
|
-
// src/
|
|
4022
|
-
var
|
|
4023
|
-
|
|
4024
|
-
|
|
4039
|
+
// src/types/timezone.ts
|
|
4040
|
+
var intlCache = /* @__PURE__ */ new Map();
|
|
4041
|
+
function intlFor(zone) {
|
|
4042
|
+
const cached = intlCache.get(zone);
|
|
4043
|
+
if (cached) return cached;
|
|
4044
|
+
try {
|
|
4045
|
+
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
4046
|
+
timeZone: zone,
|
|
4047
|
+
timeZoneName: "longOffset",
|
|
4048
|
+
year: "numeric"
|
|
4049
|
+
});
|
|
4050
|
+
intlCache.set(zone, fmt);
|
|
4051
|
+
return fmt;
|
|
4052
|
+
} catch {
|
|
4053
|
+
return null;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
function parseFixedOffset(zone) {
|
|
4057
|
+
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
4058
|
+
if (!m) return null;
|
|
4059
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
4060
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
4061
|
+
}
|
|
4062
|
+
function parsePosixOffset(zone) {
|
|
4063
|
+
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
4064
|
+
if (!m) return null;
|
|
4065
|
+
const sign = m[1] === "-" ? 1 : -1;
|
|
4066
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
4067
|
+
}
|
|
4068
|
+
function pgMicrosToUnixMs(utcMicros) {
|
|
4069
|
+
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
4070
|
+
}
|
|
4071
|
+
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
4072
|
+
const z = zone.trim();
|
|
4073
|
+
const lower = z.toLowerCase();
|
|
4074
|
+
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
4075
|
+
const posix = parsePosixOffset(z);
|
|
4076
|
+
if (posix !== null) return posix;
|
|
4077
|
+
const fixed = parseFixedOffset(z);
|
|
4078
|
+
if (fixed !== null) return fixed;
|
|
4079
|
+
const fmt = intlFor(z);
|
|
4080
|
+
if (fmt) {
|
|
4081
|
+
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
4082
|
+
const parts = fmt.formatToParts(new Date(ms));
|
|
4083
|
+
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
4084
|
+
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
4085
|
+
if (!m) return 0;
|
|
4086
|
+
const sign = m[1] === "-" ? -1 : 1;
|
|
4087
|
+
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
4025
4088
|
}
|
|
4089
|
+
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
4090
|
+
}
|
|
4091
|
+
function clampDateMs(ms) {
|
|
4092
|
+
const MAX = 864e13;
|
|
4093
|
+
return Math.max(-MAX, Math.min(MAX, ms));
|
|
4094
|
+
}
|
|
4095
|
+
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
4096
|
+
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
4097
|
+
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
4098
|
+
return second;
|
|
4099
|
+
}
|
|
4100
|
+
function validateZone(zone) {
|
|
4101
|
+
zoneOffsetAtUtc(zone, 0n);
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4104
|
+
// src/expressions/context.ts
|
|
4105
|
+
var EngineCtx = class {
|
|
4026
4106
|
state;
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4107
|
+
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
4108
|
+
txNow;
|
|
4109
|
+
/** statement timestamp */
|
|
4110
|
+
stmtNow;
|
|
4111
|
+
constructor(state, txNow) {
|
|
4112
|
+
this.state = state;
|
|
4113
|
+
const nowMs = state.clock().getTime();
|
|
4114
|
+
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
4115
|
+
this.txNow = txNow ?? nowMicros;
|
|
4116
|
+
this.stmtNow = nowMicros;
|
|
4032
4117
|
}
|
|
4033
|
-
|
|
4034
|
-
this.state.
|
|
4035
|
-
this.freezeDepth++;
|
|
4036
|
-
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
4118
|
+
timezone() {
|
|
4119
|
+
return this.state.getSetting("timezone") ?? "UTC";
|
|
4037
4120
|
}
|
|
4038
|
-
|
|
4039
|
-
this.state.
|
|
4040
|
-
|
|
4121
|
+
namespaceOid(name) {
|
|
4122
|
+
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
4123
|
+
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
4124
|
+
return oid;
|
|
4041
4125
|
}
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4126
|
+
namespaceName(oid) {
|
|
4127
|
+
const builtin = builtinNamespaceName(oid);
|
|
4128
|
+
if (builtin !== void 0) return builtin;
|
|
4129
|
+
for (const schema of this.state.schemas.values()) {
|
|
4130
|
+
if (schema.oid === oid) return schema.name;
|
|
4046
4131
|
}
|
|
4132
|
+
return null;
|
|
4047
4133
|
}
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
return;
|
|
4051
|
-
}
|
|
4052
|
-
this.base = this.takeSnapshot();
|
|
4053
|
-
this.state.inTransaction = true;
|
|
4054
|
-
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
4134
|
+
zoneOffsetAt(utcMicros) {
|
|
4135
|
+
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
4055
4136
|
}
|
|
4056
|
-
|
|
4057
|
-
this.
|
|
4058
|
-
this.savepoints = [];
|
|
4059
|
-
this.state.inTransaction = false;
|
|
4060
|
-
this.state.localSettings.clear();
|
|
4061
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
4137
|
+
zoneOffsetForNaive(naiveMicros) {
|
|
4138
|
+
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
4062
4139
|
}
|
|
4063
|
-
|
|
4064
|
-
if (
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
this.base = null;
|
|
4068
|
-
this.savepoints = [];
|
|
4069
|
-
this.state.inTransaction = false;
|
|
4070
|
-
this.state.localSettings.clear();
|
|
4071
|
-
while (this.freezeDepth > 0) this.thawOnce();
|
|
4140
|
+
enumLabels(enumType) {
|
|
4141
|
+
if (!isEnumType(enumType)) return null;
|
|
4142
|
+
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
4143
|
+
return e?.labels ?? null;
|
|
4072
4144
|
}
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
}
|
|
4077
|
-
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
4145
|
+
enumHasLabel(enumType, label) {
|
|
4146
|
+
const labels = this.enumLabels(enumType);
|
|
4147
|
+
return labels === null ? true : labels.includes(label);
|
|
4078
4148
|
}
|
|
4079
|
-
|
|
4080
|
-
const
|
|
4081
|
-
|
|
4149
|
+
enumOrder(enumType, label) {
|
|
4150
|
+
const labels = this.enumLabels(enumType);
|
|
4151
|
+
if (!labels) return 0;
|
|
4152
|
+
const idx = labels.indexOf(label);
|
|
4153
|
+
return idx === -1 ? labels.length : idx;
|
|
4082
4154
|
}
|
|
4083
|
-
|
|
4084
|
-
const
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
this.savepoints.splice(idx + 1);
|
|
4155
|
+
requireEnum(enumType) {
|
|
4156
|
+
const labels = this.enumLabels(enumType);
|
|
4157
|
+
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
4158
|
+
return labels;
|
|
4088
4159
|
}
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4160
|
+
};
|
|
4161
|
+
|
|
4162
|
+
// src/api/bind.ts
|
|
4163
|
+
var INT4_MIN2 = -2147483648;
|
|
4164
|
+
var INT4_MAX2 = 2147483647;
|
|
4165
|
+
function bindValueToTyped(value, index) {
|
|
4166
|
+
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
4167
|
+
switch (typeof value) {
|
|
4168
|
+
case "boolean":
|
|
4169
|
+
return tv("bool", value);
|
|
4170
|
+
case "number":
|
|
4171
|
+
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
4172
|
+
return tv("int4", value);
|
|
4173
|
+
}
|
|
4174
|
+
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
4175
|
+
return tv("int8", BigInt(value));
|
|
4176
|
+
}
|
|
4177
|
+
return tv("float8", value);
|
|
4178
|
+
case "bigint":
|
|
4179
|
+
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
4180
|
+
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
4181
|
+
}
|
|
4182
|
+
return tv("int8", value);
|
|
4183
|
+
case "string":
|
|
4184
|
+
return tv(UNKNOWN, value);
|
|
4185
|
+
case "object": {
|
|
4186
|
+
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
4187
|
+
if (value instanceof Date) {
|
|
4188
|
+
const ms = value.getTime();
|
|
4189
|
+
if (Number.isNaN(ms)) {
|
|
4190
|
+
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
4191
|
+
}
|
|
4192
|
+
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
4193
|
+
}
|
|
4194
|
+
break;
|
|
4095
4195
|
}
|
|
4096
|
-
|
|
4196
|
+
default:
|
|
4197
|
+
break;
|
|
4097
4198
|
}
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4199
|
+
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
4200
|
+
}
|
|
4201
|
+
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
4202
|
+
if (v === null) return null;
|
|
4203
|
+
switch (t) {
|
|
4204
|
+
case "bool":
|
|
4205
|
+
return v;
|
|
4206
|
+
case "int2":
|
|
4207
|
+
case "int4":
|
|
4208
|
+
case "oid":
|
|
4209
|
+
return typeof v === "bigint" ? Number(v) : v;
|
|
4210
|
+
case "int8": {
|
|
4211
|
+
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
4212
|
+
if (int8 === "string") return n.toString();
|
|
4213
|
+
if (int8 === "number") return Number(n);
|
|
4214
|
+
return n;
|
|
4215
|
+
}
|
|
4216
|
+
case "float4":
|
|
4217
|
+
case "float8":
|
|
4218
|
+
return v;
|
|
4219
|
+
case "bytea":
|
|
4220
|
+
return v;
|
|
4221
|
+
default:
|
|
4222
|
+
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
4103
4223
|
}
|
|
4104
|
-
}
|
|
4224
|
+
}
|
|
4105
4225
|
|
|
4106
4226
|
// src/types/cast.ts
|
|
4107
4227
|
var UTC_CAST_ENV = {
|
|
@@ -4579,259 +4699,6 @@ function unifyTypes(a, b) {
|
|
|
4579
4699
|
return null;
|
|
4580
4700
|
}
|
|
4581
4701
|
|
|
4582
|
-
// src/types/resolve.ts
|
|
4583
|
-
var SERIALS = {
|
|
4584
|
-
smallserial: "int2",
|
|
4585
|
-
serial2: "int2",
|
|
4586
|
-
serial: "int4",
|
|
4587
|
-
serial4: "int4",
|
|
4588
|
-
bigserial: "int8",
|
|
4589
|
-
serial8: "int8"
|
|
4590
|
-
};
|
|
4591
|
-
function modOf(t, mods) {
|
|
4592
|
-
if (mods.length === 0) return null;
|
|
4593
|
-
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
4594
|
-
return { a: mods[0] };
|
|
4595
|
-
}
|
|
4596
|
-
function resolveTypeName(state, tn) {
|
|
4597
|
-
const joined = tn.parts.join(".");
|
|
4598
|
-
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
4599
|
-
if (bare !== null) {
|
|
4600
|
-
const serial = SERIALS[bare];
|
|
4601
|
-
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
4602
|
-
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
4603
|
-
}
|
|
4604
|
-
const builtin = normalizeTypeName(bare);
|
|
4605
|
-
if (builtin !== null) {
|
|
4606
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
4607
|
-
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
4608
|
-
}
|
|
4609
|
-
}
|
|
4610
|
-
const enumData = state.findEnum(tn.parts);
|
|
4611
|
-
if (enumData) {
|
|
4612
|
-
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
4613
|
-
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
4614
|
-
return { column: { id, mod: null }, domain: null, serial: null };
|
|
4615
|
-
}
|
|
4616
|
-
const domainData = state.findDomain(tn.parts);
|
|
4617
|
-
if (domainData) {
|
|
4618
|
-
if (tn.arrayDims > 0) {
|
|
4619
|
-
const id = arrayTypeOf(domainData.baseType.id);
|
|
4620
|
-
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
4621
|
-
}
|
|
4622
|
-
return {
|
|
4623
|
-
column: domainData.baseType,
|
|
4624
|
-
domain: `${domainData.schema}.${domainData.name}`,
|
|
4625
|
-
serial: null
|
|
4626
|
-
};
|
|
4627
|
-
}
|
|
4628
|
-
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
4629
|
-
}
|
|
4630
|
-
|
|
4631
|
-
// src/executor/relation.ts
|
|
4632
|
-
var RowScope = class {
|
|
4633
|
-
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
4634
|
-
this.columns = columns;
|
|
4635
|
-
this.row = row;
|
|
4636
|
-
this.parent = parent;
|
|
4637
|
-
this.rangeVars = rangeVars;
|
|
4638
|
-
}
|
|
4639
|
-
columns;
|
|
4640
|
-
row;
|
|
4641
|
-
parent;
|
|
4642
|
-
rangeVars;
|
|
4643
|
-
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
4644
|
-
lookup(parts) {
|
|
4645
|
-
if (parts.length === 1) {
|
|
4646
|
-
const name2 = parts[0];
|
|
4647
|
-
let found2;
|
|
4648
|
-
let count2 = 0;
|
|
4649
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4650
|
-
const c = this.columns[i];
|
|
4651
|
-
if (c.name === name2 && !c.hidden) {
|
|
4652
|
-
count2++;
|
|
4653
|
-
if (count2 > 1) {
|
|
4654
|
-
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
4655
|
-
}
|
|
4656
|
-
found2 = tv(c.type, this.row[i] ?? null);
|
|
4657
|
-
}
|
|
4658
|
-
}
|
|
4659
|
-
if (found2 !== void 0) return found2;
|
|
4660
|
-
if (this.rangeVars.has(name2)) {
|
|
4661
|
-
return this.wholeRow(name2);
|
|
4662
|
-
}
|
|
4663
|
-
return this.parent?.lookup(parts);
|
|
4664
|
-
}
|
|
4665
|
-
const table = parts[parts.length - 2];
|
|
4666
|
-
const name = parts[parts.length - 1];
|
|
4667
|
-
let found;
|
|
4668
|
-
let count = 0;
|
|
4669
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4670
|
-
const c = this.columns[i];
|
|
4671
|
-
if (c.table === table && c.name === name) {
|
|
4672
|
-
count++;
|
|
4673
|
-
if (count > 1) {
|
|
4674
|
-
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
4675
|
-
}
|
|
4676
|
-
found = tv(c.type, this.row[i] ?? null);
|
|
4677
|
-
}
|
|
4678
|
-
}
|
|
4679
|
-
if (found !== void 0) return found;
|
|
4680
|
-
return this.parent?.lookup(parts);
|
|
4681
|
-
}
|
|
4682
|
-
/** Build a record value from all columns belonging to a range variable. */
|
|
4683
|
-
wholeRow(rangeVar) {
|
|
4684
|
-
const types = [];
|
|
4685
|
-
const values = [];
|
|
4686
|
-
const names = [];
|
|
4687
|
-
for (let i = 0; i < this.columns.length; i++) {
|
|
4688
|
-
const c = this.columns[i];
|
|
4689
|
-
if (c.table === rangeVar) {
|
|
4690
|
-
types.push(c.type);
|
|
4691
|
-
values.push(this.row[i] ?? null);
|
|
4692
|
-
names.push(c.name);
|
|
4693
|
-
}
|
|
4694
|
-
}
|
|
4695
|
-
if (types.length === 0) return void 0;
|
|
4696
|
-
return tv("record", { kind: "pgrecord", types, values, names });
|
|
4697
|
-
}
|
|
4698
|
-
hasRangeVar(name) {
|
|
4699
|
-
if (this.rangeVars.has(name)) return true;
|
|
4700
|
-
return this.parent?.hasRangeVar(name) ?? false;
|
|
4701
|
-
}
|
|
4702
|
-
};
|
|
4703
|
-
function childEnv(env, outer) {
|
|
4704
|
-
return {
|
|
4705
|
-
ctx: env.ctx,
|
|
4706
|
-
params: env.params,
|
|
4707
|
-
ctes: env.ctes,
|
|
4708
|
-
outer,
|
|
4709
|
-
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
4710
|
-
};
|
|
4711
|
-
}
|
|
4712
|
-
function relationResult(rel3, command2) {
|
|
4713
|
-
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
4714
|
-
return {
|
|
4715
|
-
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
4716
|
-
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
4717
|
-
command: command2,
|
|
4718
|
-
rowCount: rel3.rows.length
|
|
4719
|
-
};
|
|
4720
|
-
}
|
|
4721
|
-
function commandResult(command2, rowCount) {
|
|
4722
|
-
return { columns: [], rows: [], command: command2, rowCount };
|
|
4723
|
-
}
|
|
4724
|
-
function inferColumnName(e) {
|
|
4725
|
-
switch (e.type) {
|
|
4726
|
-
case "colref":
|
|
4727
|
-
return e.parts[e.parts.length - 1];
|
|
4728
|
-
case "func":
|
|
4729
|
-
return e.name[e.name.length - 1];
|
|
4730
|
-
case "cast": {
|
|
4731
|
-
const inner = inferColumnName(e.expr);
|
|
4732
|
-
if (inner !== "?column?") return inner;
|
|
4733
|
-
return e.target.parts[e.target.parts.length - 1];
|
|
4734
|
-
}
|
|
4735
|
-
case "collate":
|
|
4736
|
-
return inferColumnName(e.expr);
|
|
4737
|
-
case "case":
|
|
4738
|
-
return "case";
|
|
4739
|
-
case "array_ctor":
|
|
4740
|
-
case "array_query":
|
|
4741
|
-
return "array";
|
|
4742
|
-
case "row":
|
|
4743
|
-
return "row";
|
|
4744
|
-
case "subquery_expr":
|
|
4745
|
-
return e.kind === "exists" ? "exists" : "?column?";
|
|
4746
|
-
case "bool_lit":
|
|
4747
|
-
return "bool";
|
|
4748
|
-
case "extract":
|
|
4749
|
-
return "extract";
|
|
4750
|
-
case "position":
|
|
4751
|
-
return "position";
|
|
4752
|
-
case "substring_sql":
|
|
4753
|
-
return "substring";
|
|
4754
|
-
case "overlay":
|
|
4755
|
-
return "overlay";
|
|
4756
|
-
case "trim":
|
|
4757
|
-
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
4758
|
-
case "field_select":
|
|
4759
|
-
return e.field === "*" ? "?column?" : e.field;
|
|
4760
|
-
case "at_time_zone":
|
|
4761
|
-
return "timezone";
|
|
4762
|
-
case "grouping_func":
|
|
4763
|
-
return "grouping";
|
|
4764
|
-
case "subscript":
|
|
4765
|
-
return inferColumnName(e.base);
|
|
4766
|
-
default:
|
|
4767
|
-
return "?column?";
|
|
4768
|
-
}
|
|
4769
|
-
}
|
|
4770
|
-
|
|
4771
|
-
// src/api/bind.ts
|
|
4772
|
-
var INT4_MIN2 = -2147483648;
|
|
4773
|
-
var INT4_MAX2 = 2147483647;
|
|
4774
|
-
function bindValueToTyped(value, index) {
|
|
4775
|
-
if (value === null || value === void 0) return tv(UNKNOWN, null);
|
|
4776
|
-
switch (typeof value) {
|
|
4777
|
-
case "boolean":
|
|
4778
|
-
return tv("bool", value);
|
|
4779
|
-
case "number":
|
|
4780
|
-
if (Number.isInteger(value) && value >= INT4_MIN2 && value <= INT4_MAX2) {
|
|
4781
|
-
return tv("int4", value);
|
|
4782
|
-
}
|
|
4783
|
-
if (Number.isInteger(value) && Number.isSafeInteger(value)) {
|
|
4784
|
-
return tv("int8", BigInt(value));
|
|
4785
|
-
}
|
|
4786
|
-
return tv("float8", value);
|
|
4787
|
-
case "bigint":
|
|
4788
|
-
if (value < -9223372036854775808n || value > 9223372036854775807n) {
|
|
4789
|
-
throw pgError("numeric_value_out_of_range", `bigint parameter $${index + 1} out of int8 range`, "22003");
|
|
4790
|
-
}
|
|
4791
|
-
return tv("int8", value);
|
|
4792
|
-
case "string":
|
|
4793
|
-
return tv(UNKNOWN, value);
|
|
4794
|
-
case "object": {
|
|
4795
|
-
if (value instanceof Uint8Array) return tv("bytea", value);
|
|
4796
|
-
if (value instanceof Date) {
|
|
4797
|
-
const ms = value.getTime();
|
|
4798
|
-
if (Number.isNaN(ms)) {
|
|
4799
|
-
throw pgError("invalid_datetime", `invalid Date parameter $${index + 1}`, "22008");
|
|
4800
|
-
}
|
|
4801
|
-
return tv("timestamptz", BigInt(Math.round(ms)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG);
|
|
4802
|
-
}
|
|
4803
|
-
break;
|
|
4804
|
-
}
|
|
4805
|
-
default:
|
|
4806
|
-
break;
|
|
4807
|
-
}
|
|
4808
|
-
throw pgError("misuse", `unsupported parameter type for $${index + 1}: ${typeof value}`, "XX000");
|
|
4809
|
-
}
|
|
4810
|
-
function datumToJs(t, v, ctx, int8 = "bigint") {
|
|
4811
|
-
if (v === null) return null;
|
|
4812
|
-
switch (t) {
|
|
4813
|
-
case "bool":
|
|
4814
|
-
return v;
|
|
4815
|
-
case "int2":
|
|
4816
|
-
case "int4":
|
|
4817
|
-
case "oid":
|
|
4818
|
-
return typeof v === "bigint" ? Number(v) : v;
|
|
4819
|
-
case "int8": {
|
|
4820
|
-
const n = typeof v === "bigint" ? v : BigInt(v);
|
|
4821
|
-
if (int8 === "string") return n.toString();
|
|
4822
|
-
if (int8 === "number") return Number(n);
|
|
4823
|
-
return n;
|
|
4824
|
-
}
|
|
4825
|
-
case "float4":
|
|
4826
|
-
case "float8":
|
|
4827
|
-
return v;
|
|
4828
|
-
case "bytea":
|
|
4829
|
-
return v;
|
|
4830
|
-
default:
|
|
4831
|
-
return datumText(t === UNKNOWN ? "text" : t, v, ctx);
|
|
4832
|
-
}
|
|
4833
|
-
}
|
|
4834
|
-
|
|
4835
4702
|
// src/functions/datetime-fns.ts
|
|
4836
4703
|
function extractDatePart(ctx, field0, src0, asNumeric) {
|
|
4837
4704
|
const field = field0.toLowerCase();
|
|
@@ -5746,71 +5613,6 @@ function getArrayFunctions() {
|
|
|
5746
5613
|
return m;
|
|
5747
5614
|
}
|
|
5748
5615
|
|
|
5749
|
-
// src/types/timezone.ts
|
|
5750
|
-
var intlCache = /* @__PURE__ */ new Map();
|
|
5751
|
-
function intlFor(zone) {
|
|
5752
|
-
const cached = intlCache.get(zone);
|
|
5753
|
-
if (cached) return cached;
|
|
5754
|
-
try {
|
|
5755
|
-
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
5756
|
-
timeZone: zone,
|
|
5757
|
-
timeZoneName: "longOffset",
|
|
5758
|
-
year: "numeric"
|
|
5759
|
-
});
|
|
5760
|
-
intlCache.set(zone, fmt);
|
|
5761
|
-
return fmt;
|
|
5762
|
-
} catch {
|
|
5763
|
-
return null;
|
|
5764
|
-
}
|
|
5765
|
-
}
|
|
5766
|
-
function parseFixedOffset(zone) {
|
|
5767
|
-
const m = /^([+-]?)(\d{1,2})(?::(\d{2}))?(?::(\d{2}))?$/.exec(zone.trim());
|
|
5768
|
-
if (!m) return null;
|
|
5769
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
5770
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60 + Number(m[4] ?? 0));
|
|
5771
|
-
}
|
|
5772
|
-
function parsePosixOffset(zone) {
|
|
5773
|
-
const m = /^(?:utc|gmt)([+-])(\d{1,2})(?::(\d{2}))?$/i.exec(zone.trim());
|
|
5774
|
-
if (!m) return null;
|
|
5775
|
-
const sign = m[1] === "-" ? 1 : -1;
|
|
5776
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3] ?? 0) * 60);
|
|
5777
|
-
}
|
|
5778
|
-
function pgMicrosToUnixMs(utcMicros) {
|
|
5779
|
-
return Number((utcMicros - UNIX_EPOCH_MICROS_FROM_PG) / 1000n);
|
|
5780
|
-
}
|
|
5781
|
-
function zoneOffsetAtUtc(zone, utcMicros) {
|
|
5782
|
-
const z = zone.trim();
|
|
5783
|
-
const lower = z.toLowerCase();
|
|
5784
|
-
if (lower === "utc" || lower === "gmt" || lower === "z" || lower === "zulu" || lower === "universal") return 0;
|
|
5785
|
-
const posix = parsePosixOffset(z);
|
|
5786
|
-
if (posix !== null) return posix;
|
|
5787
|
-
const fixed = parseFixedOffset(z);
|
|
5788
|
-
if (fixed !== null) return fixed;
|
|
5789
|
-
const fmt = intlFor(z);
|
|
5790
|
-
if (fmt) {
|
|
5791
|
-
const ms = clampDateMs(pgMicrosToUnixMs(utcMicros));
|
|
5792
|
-
const parts = fmt.formatToParts(new Date(ms));
|
|
5793
|
-
const tzName = parts.find((p) => p.type === "timeZoneName")?.value ?? "GMT";
|
|
5794
|
-
const m = /GMT([+-])(\d{2}):(\d{2})(?::(\d{2}))?/.exec(tzName);
|
|
5795
|
-
if (!m) return 0;
|
|
5796
|
-
const sign = m[1] === "-" ? -1 : 1;
|
|
5797
|
-
return sign * (Number(m[2]) * 3600 + Number(m[3]) * 60 + Number(m[4] ?? 0));
|
|
5798
|
-
}
|
|
5799
|
-
throw pgError("invalid_parameter_value", `time zone "${zone}" not recognized`);
|
|
5800
|
-
}
|
|
5801
|
-
function clampDateMs(ms) {
|
|
5802
|
-
const MAX = 864e13;
|
|
5803
|
-
return Math.max(-MAX, Math.min(MAX, ms));
|
|
5804
|
-
}
|
|
5805
|
-
function zoneOffsetForNaive(zone, naiveMicros) {
|
|
5806
|
-
const first = zoneOffsetAtUtc(zone, naiveMicros);
|
|
5807
|
-
const second = zoneOffsetAtUtc(zone, naiveMicros - BigInt(first) * 1000000n);
|
|
5808
|
-
return second;
|
|
5809
|
-
}
|
|
5810
|
-
function validateZone(zone) {
|
|
5811
|
-
zoneOffsetAtUtc(zone, 0n);
|
|
5812
|
-
}
|
|
5813
|
-
|
|
5814
5616
|
// src/functions/datetime-registry.ts
|
|
5815
5617
|
function getDatetimeFunctions() {
|
|
5816
5618
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -7410,6 +7212,28 @@ function exactDegTan(x) {
|
|
|
7410
7212
|
return Math.tan(x * Math.PI / 180);
|
|
7411
7213
|
}
|
|
7412
7214
|
|
|
7215
|
+
// src/storage/indexable-relation.ts
|
|
7216
|
+
function materializedTable(view) {
|
|
7217
|
+
const table = new TableData(
|
|
7218
|
+
view.schema,
|
|
7219
|
+
view.name,
|
|
7220
|
+
(view.matColumns ?? []).map((c) => ({
|
|
7221
|
+
name: c.name,
|
|
7222
|
+
type: { id: c.type, mod: null },
|
|
7223
|
+
notNull: false,
|
|
7224
|
+
defaultExpr: null,
|
|
7225
|
+
identity: null,
|
|
7226
|
+
generated: null,
|
|
7227
|
+
collate: null,
|
|
7228
|
+
domain: null
|
|
7229
|
+
})),
|
|
7230
|
+
view.oid,
|
|
7231
|
+
view.temp
|
|
7232
|
+
);
|
|
7233
|
+
table.rows = view.matRows ?? [];
|
|
7234
|
+
return table;
|
|
7235
|
+
}
|
|
7236
|
+
|
|
7413
7237
|
// src/schema/index-catalog.ts
|
|
7414
7238
|
var isKeyConstraint = (constraint) => constraint.kind === "primary_key" || constraint.kind === "unique";
|
|
7415
7239
|
var ACCESS_METHODS = /* @__PURE__ */ new Map([
|
|
@@ -7438,6 +7262,8 @@ function syncIndexCatalog(state) {
|
|
|
7438
7262
|
const tables = /* @__PURE__ */ new Map();
|
|
7439
7263
|
for (const schema of state.schemas.values()) {
|
|
7440
7264
|
for (const table of schema.tables.values()) tables.set(table.oid, { schema, table });
|
|
7265
|
+
for (const view of schema.views.values())
|
|
7266
|
+
if (view.materialized) tables.set(view.oid, { schema, table: materializedTable(view) });
|
|
7441
7267
|
}
|
|
7442
7268
|
const backing = /* @__PURE__ */ new Map();
|
|
7443
7269
|
for (const { table } of tables.values()) {
|
|
@@ -7635,6 +7461,55 @@ function deparseExpr(e) {
|
|
|
7635
7461
|
}
|
|
7636
7462
|
}
|
|
7637
7463
|
|
|
7464
|
+
// src/types/resolve.ts
|
|
7465
|
+
var SERIALS = {
|
|
7466
|
+
smallserial: "int2",
|
|
7467
|
+
serial2: "int2",
|
|
7468
|
+
serial: "int4",
|
|
7469
|
+
serial4: "int4",
|
|
7470
|
+
bigserial: "int8",
|
|
7471
|
+
serial8: "int8"
|
|
7472
|
+
};
|
|
7473
|
+
function modOf(t, mods) {
|
|
7474
|
+
if (mods.length === 0) return null;
|
|
7475
|
+
if (t === "numeric") return { a: mods[0], b: mods[1] ?? 0 };
|
|
7476
|
+
return { a: mods[0] };
|
|
7477
|
+
}
|
|
7478
|
+
function resolveTypeName(state, tn) {
|
|
7479
|
+
const joined = tn.parts.join(".");
|
|
7480
|
+
const bare = tn.parts.length === 1 ? tn.parts[0] : tn.parts.length === 2 && tn.parts[0] === "pg_catalog" ? tn.parts[1] : null;
|
|
7481
|
+
if (bare !== null) {
|
|
7482
|
+
const serial = SERIALS[bare];
|
|
7483
|
+
if (serial !== void 0 && tn.arrayDims === 0) {
|
|
7484
|
+
return { column: { id: serial, mod: null }, domain: null, serial };
|
|
7485
|
+
}
|
|
7486
|
+
const builtin = normalizeTypeName(bare);
|
|
7487
|
+
if (builtin !== null) {
|
|
7488
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(builtin) : builtin;
|
|
7489
|
+
return { column: { id, mod: modOf(builtin, tn.mods) }, domain: null, serial: null };
|
|
7490
|
+
}
|
|
7491
|
+
}
|
|
7492
|
+
const enumData = state.findEnum(tn.parts);
|
|
7493
|
+
if (enumData) {
|
|
7494
|
+
const elem = `enum:${enumData.schema}.${enumData.name}`;
|
|
7495
|
+
const id = tn.arrayDims > 0 ? arrayTypeOf(elem) : elem;
|
|
7496
|
+
return { column: { id, mod: null }, domain: null, serial: null };
|
|
7497
|
+
}
|
|
7498
|
+
const domainData = state.findDomain(tn.parts);
|
|
7499
|
+
if (domainData) {
|
|
7500
|
+
if (tn.arrayDims > 0) {
|
|
7501
|
+
const id = arrayTypeOf(domainData.baseType.id);
|
|
7502
|
+
return { column: { id, mod: domainData.baseType.mod }, domain: null, serial: null };
|
|
7503
|
+
}
|
|
7504
|
+
return {
|
|
7505
|
+
column: domainData.baseType,
|
|
7506
|
+
domain: `${domainData.schema}.${domainData.name}`,
|
|
7507
|
+
serial: null
|
|
7508
|
+
};
|
|
7509
|
+
}
|
|
7510
|
+
throw pgError("undefined_object", `type "${joined}" does not exist`);
|
|
7511
|
+
}
|
|
7512
|
+
|
|
7638
7513
|
// src/sql/ruleutils.ts
|
|
7639
7514
|
var BOOL = "bool";
|
|
7640
7515
|
var TEXT = "text";
|
|
@@ -8432,7 +8307,11 @@ function getMiscFunctions() {
|
|
|
8432
8307
|
}
|
|
8433
8308
|
const name = argText(ctx, args[0]).toLowerCase();
|
|
8434
8309
|
const value = args[1].v === null ? "" : argText(ctx, args[1]);
|
|
8435
|
-
ctx.state.settings.
|
|
8310
|
+
if (!ctx.state.settings.has(name) && !name.includes("."))
|
|
8311
|
+
throw pgError("undefined_object", `unrecognized configuration parameter "${name}"`, "42704");
|
|
8312
|
+
validateStorageSetting(name, value);
|
|
8313
|
+
const local = args[2]?.v === true;
|
|
8314
|
+
if (!local || ctx.state.inTransaction) (local ? ctx.state.localSettings : ctx.state.settings).set(name, value);
|
|
8436
8315
|
return tv("text", value);
|
|
8437
8316
|
});
|
|
8438
8317
|
m.set(
|
|
@@ -8498,10 +8377,7 @@ function getMiscFunctions() {
|
|
|
8498
8377
|
if (!col)
|
|
8499
8378
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
8500
8379
|
if (!col.identity) return tv("text", null);
|
|
8501
|
-
return tv(
|
|
8502
|
-
"text",
|
|
8503
|
-
col.identity.sequence.split(".").map(quoteIdent).join(".")
|
|
8504
|
-
);
|
|
8380
|
+
return tv("text", col.identity.sequence.split(".").map(quoteIdent).join("."));
|
|
8505
8381
|
})
|
|
8506
8382
|
);
|
|
8507
8383
|
m.set("format_type", (ctx, args) => {
|
|
@@ -13425,6 +13301,146 @@ function isSrfName(name) {
|
|
|
13425
13301
|
return SRFS.has(name);
|
|
13426
13302
|
}
|
|
13427
13303
|
|
|
13304
|
+
// src/executor/relation.ts
|
|
13305
|
+
var RowScope = class {
|
|
13306
|
+
constructor(columns, row, parent = null, rangeVars = /* @__PURE__ */ new Set()) {
|
|
13307
|
+
this.columns = columns;
|
|
13308
|
+
this.row = row;
|
|
13309
|
+
this.parent = parent;
|
|
13310
|
+
this.rangeVars = rangeVars;
|
|
13311
|
+
}
|
|
13312
|
+
columns;
|
|
13313
|
+
row;
|
|
13314
|
+
parent;
|
|
13315
|
+
rangeVars;
|
|
13316
|
+
/** Resolve a (possibly qualified) column reference. undefined = not found. */
|
|
13317
|
+
lookup(parts) {
|
|
13318
|
+
if (parts.length === 1) {
|
|
13319
|
+
const name2 = parts[0];
|
|
13320
|
+
let found2;
|
|
13321
|
+
let count2 = 0;
|
|
13322
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
13323
|
+
const c = this.columns[i];
|
|
13324
|
+
if (c.name === name2 && !c.hidden) {
|
|
13325
|
+
count2++;
|
|
13326
|
+
if (count2 > 1) {
|
|
13327
|
+
throw pgError("ambiguous_column", `column reference "${name2}" is ambiguous`);
|
|
13328
|
+
}
|
|
13329
|
+
found2 = tv(c.type, this.row[i] ?? null);
|
|
13330
|
+
}
|
|
13331
|
+
}
|
|
13332
|
+
if (found2 !== void 0) return found2;
|
|
13333
|
+
if (this.rangeVars.has(name2)) {
|
|
13334
|
+
return this.wholeRow(name2);
|
|
13335
|
+
}
|
|
13336
|
+
return this.parent?.lookup(parts);
|
|
13337
|
+
}
|
|
13338
|
+
const table = parts[parts.length - 2];
|
|
13339
|
+
const name = parts[parts.length - 1];
|
|
13340
|
+
let found;
|
|
13341
|
+
let count = 0;
|
|
13342
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
13343
|
+
const c = this.columns[i];
|
|
13344
|
+
if (c.table === table && c.name === name) {
|
|
13345
|
+
count++;
|
|
13346
|
+
if (count > 1) {
|
|
13347
|
+
throw pgError("ambiguous_column", `column reference "${name}" is ambiguous`);
|
|
13348
|
+
}
|
|
13349
|
+
found = tv(c.type, this.row[i] ?? null);
|
|
13350
|
+
}
|
|
13351
|
+
}
|
|
13352
|
+
if (found !== void 0) return found;
|
|
13353
|
+
return this.parent?.lookup(parts);
|
|
13354
|
+
}
|
|
13355
|
+
/** Build a record value from all columns belonging to a range variable. */
|
|
13356
|
+
wholeRow(rangeVar) {
|
|
13357
|
+
const types = [];
|
|
13358
|
+
const values = [];
|
|
13359
|
+
const names = [];
|
|
13360
|
+
for (let i = 0; i < this.columns.length; i++) {
|
|
13361
|
+
const c = this.columns[i];
|
|
13362
|
+
if (c.table === rangeVar) {
|
|
13363
|
+
types.push(c.type);
|
|
13364
|
+
values.push(this.row[i] ?? null);
|
|
13365
|
+
names.push(c.name);
|
|
13366
|
+
}
|
|
13367
|
+
}
|
|
13368
|
+
if (types.length === 0) return void 0;
|
|
13369
|
+
return tv("record", { kind: "pgrecord", types, values, names });
|
|
13370
|
+
}
|
|
13371
|
+
hasRangeVar(name) {
|
|
13372
|
+
if (this.rangeVars.has(name)) return true;
|
|
13373
|
+
return this.parent?.hasRangeVar(name) ?? false;
|
|
13374
|
+
}
|
|
13375
|
+
};
|
|
13376
|
+
function childEnv(env, outer) {
|
|
13377
|
+
return {
|
|
13378
|
+
ctx: env.ctx,
|
|
13379
|
+
params: env.params,
|
|
13380
|
+
ctes: env.ctes,
|
|
13381
|
+
outer,
|
|
13382
|
+
allowUnpopulatedMatviews: env.allowUnpopulatedMatviews
|
|
13383
|
+
};
|
|
13384
|
+
}
|
|
13385
|
+
function relationResult(rel3, command2) {
|
|
13386
|
+
const visible = rel3.columns.map((c, i) => ({ i, c })).filter(({ c }) => !c.hidden);
|
|
13387
|
+
return {
|
|
13388
|
+
columns: visible.map(({ c }) => ({ name: c.name, type: c.type })),
|
|
13389
|
+
rows: rel3.rows.map((r) => visible.map(({ i }) => r[i] ?? null)),
|
|
13390
|
+
command: command2,
|
|
13391
|
+
rowCount: rel3.rows.length
|
|
13392
|
+
};
|
|
13393
|
+
}
|
|
13394
|
+
function commandResult(command2, rowCount) {
|
|
13395
|
+
return { columns: [], rows: [], command: command2, rowCount };
|
|
13396
|
+
}
|
|
13397
|
+
function inferColumnName(e) {
|
|
13398
|
+
switch (e.type) {
|
|
13399
|
+
case "colref":
|
|
13400
|
+
return e.parts[e.parts.length - 1];
|
|
13401
|
+
case "func":
|
|
13402
|
+
return e.name[e.name.length - 1];
|
|
13403
|
+
case "cast": {
|
|
13404
|
+
const inner = inferColumnName(e.expr);
|
|
13405
|
+
if (inner !== "?column?") return inner;
|
|
13406
|
+
return e.target.parts[e.target.parts.length - 1];
|
|
13407
|
+
}
|
|
13408
|
+
case "collate":
|
|
13409
|
+
return inferColumnName(e.expr);
|
|
13410
|
+
case "case":
|
|
13411
|
+
return "case";
|
|
13412
|
+
case "array_ctor":
|
|
13413
|
+
case "array_query":
|
|
13414
|
+
return "array";
|
|
13415
|
+
case "row":
|
|
13416
|
+
return "row";
|
|
13417
|
+
case "subquery_expr":
|
|
13418
|
+
return e.kind === "exists" ? "exists" : "?column?";
|
|
13419
|
+
case "bool_lit":
|
|
13420
|
+
return "bool";
|
|
13421
|
+
case "extract":
|
|
13422
|
+
return "extract";
|
|
13423
|
+
case "position":
|
|
13424
|
+
return "position";
|
|
13425
|
+
case "substring_sql":
|
|
13426
|
+
return "substring";
|
|
13427
|
+
case "overlay":
|
|
13428
|
+
return "overlay";
|
|
13429
|
+
case "trim":
|
|
13430
|
+
return e.side === "leading" ? "ltrim" : e.side === "trailing" ? "rtrim" : "btrim";
|
|
13431
|
+
case "field_select":
|
|
13432
|
+
return e.field === "*" ? "?column?" : e.field;
|
|
13433
|
+
case "at_time_zone":
|
|
13434
|
+
return "timezone";
|
|
13435
|
+
case "grouping_func":
|
|
13436
|
+
return "grouping";
|
|
13437
|
+
case "subscript":
|
|
13438
|
+
return inferColumnName(e.base);
|
|
13439
|
+
default:
|
|
13440
|
+
return "?column?";
|
|
13441
|
+
}
|
|
13442
|
+
}
|
|
13443
|
+
|
|
13428
13444
|
// src/indexes/index.ts
|
|
13429
13445
|
var IndexStore = class _IndexStore {
|
|
13430
13446
|
name;
|
|
@@ -13487,53 +13503,228 @@ function ensureIndexStores(env, table) {
|
|
|
13487
13503
|
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
13488
13504
|
if (key !== null) store.insert(key, i);
|
|
13489
13505
|
}
|
|
13490
|
-
stores.set(spec.name, store);
|
|
13491
|
-
}
|
|
13492
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
13493
|
-
if (schema) {
|
|
13494
|
-
for (const idx of schema.indexes.values()) {
|
|
13495
|
-
if (idx.table !== table.name || idx.unique) continue;
|
|
13496
|
-
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
13506
|
+
stores.set(spec.name, store);
|
|
13507
|
+
}
|
|
13508
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
13509
|
+
if (schema) {
|
|
13510
|
+
for (const idx of schema.indexes.values()) {
|
|
13511
|
+
if (idx.table !== table.name || idx.unique) continue;
|
|
13512
|
+
stores.set(idx.name, new IndexStore(idx.name, false));
|
|
13513
|
+
}
|
|
13514
|
+
}
|
|
13515
|
+
table.indexStores = stores;
|
|
13516
|
+
return stores;
|
|
13517
|
+
}
|
|
13518
|
+
function indexStoreFor(env, table, spec) {
|
|
13519
|
+
const stores = ensureIndexStores(env, table);
|
|
13520
|
+
let store = stores.get(spec.name);
|
|
13521
|
+
if (!store) {
|
|
13522
|
+
store = new IndexStore(spec.name, true);
|
|
13523
|
+
for (let i = 0; i < table.rowCount(); i++) {
|
|
13524
|
+
const key = uniqueKeyOf(env, table, spec, table.rowAt(i));
|
|
13525
|
+
if (key !== null) store.insert(key, i);
|
|
13526
|
+
}
|
|
13527
|
+
stores.set(spec.name, store);
|
|
13528
|
+
}
|
|
13529
|
+
return store;
|
|
13530
|
+
}
|
|
13531
|
+
function indexInsertRow(env, table, rowIdx, row) {
|
|
13532
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13533
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13534
|
+
if (key === null) continue;
|
|
13535
|
+
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
13536
|
+
}
|
|
13537
|
+
}
|
|
13538
|
+
function indexRemoveRow(env, table, rowIdx, row) {
|
|
13539
|
+
if (!table.indexStores) return;
|
|
13540
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13541
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13542
|
+
if (key === null) continue;
|
|
13543
|
+
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
13544
|
+
}
|
|
13545
|
+
}
|
|
13546
|
+
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
13547
|
+
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
13548
|
+
indexInsertRow(env, table, rowIdx, newRow);
|
|
13549
|
+
}
|
|
13550
|
+
function rebuildTableIndexes(env, table) {
|
|
13551
|
+
table.indexStores = null;
|
|
13552
|
+
ensureIndexStores(env, table);
|
|
13553
|
+
}
|
|
13554
|
+
|
|
13555
|
+
// src/constraints/enforce.ts
|
|
13556
|
+
function tableScope(table, row) {
|
|
13557
|
+
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
13558
|
+
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
13559
|
+
}
|
|
13560
|
+
function checkNotNull(env, table, row) {
|
|
13561
|
+
void env;
|
|
13562
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
13563
|
+
const c = table.columns[i];
|
|
13564
|
+
if (c.notNull && (row[i] ?? null) === null) {
|
|
13565
|
+
throw pgError(
|
|
13566
|
+
"not_null_violation",
|
|
13567
|
+
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
13568
|
+
"23502"
|
|
13569
|
+
);
|
|
13570
|
+
}
|
|
13571
|
+
}
|
|
13572
|
+
}
|
|
13573
|
+
function checkChecks(env, table, row) {
|
|
13574
|
+
for (const con of table.constraints) {
|
|
13575
|
+
if (con.kind !== "check") continue;
|
|
13576
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
13577
|
+
const v = evalExpr(env.ctx, scope, con.expr);
|
|
13578
|
+
if (v.v === null) continue;
|
|
13579
|
+
const b = castTo(env.ctx, v, "bool", {});
|
|
13580
|
+
if (b.v !== true) {
|
|
13581
|
+
throw pgError(
|
|
13582
|
+
"check_violation",
|
|
13583
|
+
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
13584
|
+
"23514"
|
|
13585
|
+
);
|
|
13586
|
+
}
|
|
13587
|
+
}
|
|
13588
|
+
}
|
|
13589
|
+
function uniqueSpecsFor(env, table) {
|
|
13590
|
+
const specs = [];
|
|
13591
|
+
for (const con of table.constraints) {
|
|
13592
|
+
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
13593
|
+
specs.push({
|
|
13594
|
+
name: con.name,
|
|
13595
|
+
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
13596
|
+
columnNames: con.columns,
|
|
13597
|
+
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
13598
|
+
where: null,
|
|
13599
|
+
isPrimary: con.kind === "primary_key"
|
|
13600
|
+
});
|
|
13601
|
+
}
|
|
13602
|
+
const schema = env.ctx.state.schemas.get(table.schema);
|
|
13603
|
+
if (schema) {
|
|
13604
|
+
for (const idx of schema.indexes.values()) {
|
|
13605
|
+
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
13606
|
+
specs.push(uniqueSpecOfIndex(table, idx));
|
|
13607
|
+
}
|
|
13608
|
+
}
|
|
13609
|
+
return specs;
|
|
13610
|
+
}
|
|
13611
|
+
function uniqueSpecOfIndex(table, idx) {
|
|
13612
|
+
return {
|
|
13613
|
+
name: idx.name,
|
|
13614
|
+
keys: idx.columns.map((c) => ({
|
|
13615
|
+
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
13616
|
+
expr: c.expr
|
|
13617
|
+
})),
|
|
13618
|
+
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
13619
|
+
nullsNotDistinct: idx.nullsNotDistinct,
|
|
13620
|
+
where: idx.where,
|
|
13621
|
+
isPrimary: false
|
|
13622
|
+
};
|
|
13623
|
+
}
|
|
13624
|
+
function uniqueKeyOf(env, table, spec, row) {
|
|
13625
|
+
if (spec.where) {
|
|
13626
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
13627
|
+
const v = evalExpr(env.ctx, scope, spec.where);
|
|
13628
|
+
if (v.v !== true) return null;
|
|
13629
|
+
}
|
|
13630
|
+
const parts = [];
|
|
13631
|
+
let hasNull = false;
|
|
13632
|
+
for (const k of spec.keys) {
|
|
13633
|
+
let value;
|
|
13634
|
+
let type;
|
|
13635
|
+
if (k.expr) {
|
|
13636
|
+
const scope = makeEvalScope(env, tableScope(table, row));
|
|
13637
|
+
const v = evalExpr(env.ctx, scope, k.expr);
|
|
13638
|
+
value = v.v;
|
|
13639
|
+
type = v.t === "unknown" ? "text" : v.t;
|
|
13640
|
+
} else {
|
|
13641
|
+
value = row[k.colIdx] ?? null;
|
|
13642
|
+
type = table.columns[k.colIdx].type.id;
|
|
13643
|
+
}
|
|
13644
|
+
if (value === null) {
|
|
13645
|
+
hasNull = true;
|
|
13646
|
+
parts.push("\0N");
|
|
13647
|
+
} else {
|
|
13648
|
+
parts.push(datumKey(type, value));
|
|
13649
|
+
}
|
|
13650
|
+
}
|
|
13651
|
+
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
13652
|
+
return parts.join("");
|
|
13653
|
+
}
|
|
13654
|
+
function checkUnique(env, table, row, selfIdx) {
|
|
13655
|
+
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13656
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13657
|
+
if (key === null) continue;
|
|
13658
|
+
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
13659
|
+
}
|
|
13660
|
+
}
|
|
13661
|
+
function findConflict(env, table, spec, row) {
|
|
13662
|
+
const key = uniqueKeyOf(env, table, spec, row);
|
|
13663
|
+
if (key === null) return null;
|
|
13664
|
+
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
13665
|
+
return hits.length > 0 ? hits[0] : null;
|
|
13666
|
+
}
|
|
13667
|
+
function checkForeignKeys(env, table, row) {
|
|
13668
|
+
const state = env.ctx.state;
|
|
13669
|
+
for (const con of table.constraints) {
|
|
13670
|
+
if (con.kind !== "foreign_key") continue;
|
|
13671
|
+
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
13672
|
+
const nulls = values.filter((v) => v === null).length;
|
|
13673
|
+
if (con.match === "simple" && nulls > 0) continue;
|
|
13674
|
+
if (con.match === "full") {
|
|
13675
|
+
if (nulls === values.length) continue;
|
|
13676
|
+
if (nulls > 0) {
|
|
13677
|
+
throw pgError(
|
|
13678
|
+
"constraint_foreign_key",
|
|
13679
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
13680
|
+
"23503"
|
|
13681
|
+
);
|
|
13682
|
+
}
|
|
13683
|
+
}
|
|
13684
|
+
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
13685
|
+
if (!refTable) {
|
|
13686
|
+
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
13687
|
+
}
|
|
13688
|
+
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
13689
|
+
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
13690
|
+
const wanted = values.map((v, i) => {
|
|
13691
|
+
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
13692
|
+
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
13693
|
+
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
13694
|
+
}).join("");
|
|
13695
|
+
let found = false;
|
|
13696
|
+
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
13697
|
+
const r = refTable.rowAt(i);
|
|
13698
|
+
const key = refIdxs.map((ri, j) => {
|
|
13699
|
+
const v = r[ri] ?? null;
|
|
13700
|
+
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
13701
|
+
}).join("");
|
|
13702
|
+
if (key === wanted) {
|
|
13703
|
+
found = true;
|
|
13704
|
+
break;
|
|
13705
|
+
}
|
|
13706
|
+
}
|
|
13707
|
+
if (!found) {
|
|
13708
|
+
throw pgError(
|
|
13709
|
+
"constraint_foreign_key",
|
|
13710
|
+
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
13711
|
+
"23503"
|
|
13712
|
+
);
|
|
13497
13713
|
}
|
|
13498
13714
|
}
|
|
13499
|
-
table.indexStores = stores;
|
|
13500
|
-
return stores;
|
|
13501
13715
|
}
|
|
13502
|
-
function
|
|
13503
|
-
const
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
|
|
13716
|
+
function referencingConstraints(env, table) {
|
|
13717
|
+
const out = [];
|
|
13718
|
+
for (const schema of env.ctx.state.schemas.values()) {
|
|
13719
|
+
for (const t of schema.tables.values()) {
|
|
13720
|
+
for (const con of t.constraints) {
|
|
13721
|
+
if (con.kind === "foreign_key" && con.refSchema === table.schema && con.refTable === table.name) {
|
|
13722
|
+
out.push({ table: t, constraint: con });
|
|
13723
|
+
}
|
|
13724
|
+
}
|
|
13510
13725
|
}
|
|
13511
|
-
stores.set(spec.name, store);
|
|
13512
|
-
}
|
|
13513
|
-
return store;
|
|
13514
|
-
}
|
|
13515
|
-
function indexInsertRow(env, table, rowIdx, row) {
|
|
13516
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13517
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
13518
|
-
if (key === null) continue;
|
|
13519
|
-
indexStoreFor(env, table, spec).insert(key, rowIdx);
|
|
13520
|
-
}
|
|
13521
|
-
}
|
|
13522
|
-
function indexRemoveRow(env, table, rowIdx, row) {
|
|
13523
|
-
if (!table.indexStores) return;
|
|
13524
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
13525
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
13526
|
-
if (key === null) continue;
|
|
13527
|
-
table.indexStores.get(spec.name)?.remove(key, rowIdx);
|
|
13528
13726
|
}
|
|
13529
|
-
|
|
13530
|
-
function indexUpdateRow(env, table, rowIdx, oldRow, newRow) {
|
|
13531
|
-
indexRemoveRow(env, table, rowIdx, oldRow);
|
|
13532
|
-
indexInsertRow(env, table, rowIdx, newRow);
|
|
13533
|
-
}
|
|
13534
|
-
function rebuildTableIndexes(env, table) {
|
|
13535
|
-
table.indexStores = null;
|
|
13536
|
-
ensureIndexStores(env, table);
|
|
13727
|
+
return out;
|
|
13537
13728
|
}
|
|
13538
13729
|
|
|
13539
13730
|
// src/planner/access.ts
|
|
@@ -15419,10 +15610,9 @@ var Parser = class {
|
|
|
15419
15610
|
return this.parseCreateFunction(orReplace);
|
|
15420
15611
|
}
|
|
15421
15612
|
if (this.atKw("trigger") || this.atKw("constraint") && this.atKw("trigger", 1)) {
|
|
15422
|
-
|
|
15423
|
-
}
|
|
15613
|
+
const constraint = this.eatKw("constraint");
|
|
15424
15614
|
this.expectKw("trigger");
|
|
15425
|
-
return this.parseCreateTrigger(orReplace);
|
|
15615
|
+
return this.parseCreateTrigger(orReplace, constraint);
|
|
15426
15616
|
}
|
|
15427
15617
|
if (this.atKw("extension")) {
|
|
15428
15618
|
this.pos++;
|
|
@@ -16243,7 +16433,7 @@ var Parser = class {
|
|
|
16243
16433
|
strict: strict2
|
|
16244
16434
|
};
|
|
16245
16435
|
}
|
|
16246
|
-
parseCreateTrigger(orReplace) {
|
|
16436
|
+
parseCreateTrigger(orReplace, constraint) {
|
|
16247
16437
|
const name = this.ident();
|
|
16248
16438
|
let timing;
|
|
16249
16439
|
if (this.eatKw("before")) timing = "before";
|
|
@@ -16273,9 +16463,18 @@ var Parser = class {
|
|
|
16273
16463
|
this.expectKw("on");
|
|
16274
16464
|
const table = this.qualifiedName();
|
|
16275
16465
|
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16466
|
+
let deferrable = false;
|
|
16467
|
+
let initiallyDeferred = false;
|
|
16468
|
+
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
16469
|
+
else if (this.eatKw("deferrable")) deferrable = true;
|
|
16470
|
+
if (this.eatKw("initially")) {
|
|
16471
|
+
if (this.eatKw("deferred")) initiallyDeferred = true;
|
|
16472
|
+
else this.expectKw("immediate");
|
|
16473
|
+
}
|
|
16474
|
+
if ((deferrable || initiallyDeferred) && !constraint)
|
|
16475
|
+
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
16476
|
+
if (initiallyDeferred && !deferrable)
|
|
16477
|
+
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
16279
16478
|
let forEachRow = false;
|
|
16280
16479
|
if (this.eatKw("for")) {
|
|
16281
16480
|
this.eatKw("each");
|
|
@@ -16300,7 +16499,21 @@ var Parser = class {
|
|
|
16300
16499
|
} while (this.eatPunct(","));
|
|
16301
16500
|
}
|
|
16302
16501
|
this.expectPunct(")");
|
|
16303
|
-
return {
|
|
16502
|
+
return {
|
|
16503
|
+
type: "create_trigger",
|
|
16504
|
+
constraint,
|
|
16505
|
+
deferrable,
|
|
16506
|
+
initiallyDeferred,
|
|
16507
|
+
orReplace,
|
|
16508
|
+
name,
|
|
16509
|
+
timing,
|
|
16510
|
+
events,
|
|
16511
|
+
table,
|
|
16512
|
+
forEachRow,
|
|
16513
|
+
when,
|
|
16514
|
+
funcName,
|
|
16515
|
+
funcArgs
|
|
16516
|
+
};
|
|
16304
16517
|
}
|
|
16305
16518
|
// --- ALTER --------------------------------------------------------------------
|
|
16306
16519
|
parseAlter() {
|
|
@@ -16645,9 +16858,15 @@ var Parser = class {
|
|
|
16645
16858
|
this.skipToStatementEnd();
|
|
16646
16859
|
return { type: "no_op", what: "SET TRANSACTION" };
|
|
16647
16860
|
}
|
|
16648
|
-
if (this.
|
|
16649
|
-
this.
|
|
16650
|
-
|
|
16861
|
+
if (this.eatKw("constraints")) {
|
|
16862
|
+
const names = this.eatKw("all") ? null : [];
|
|
16863
|
+
if (names)
|
|
16864
|
+
do {
|
|
16865
|
+
names.push(this.qualifiedName());
|
|
16866
|
+
} while (this.eatPunct(","));
|
|
16867
|
+
const deferred = this.eatKw("deferred");
|
|
16868
|
+
if (!deferred) this.expectKw("immediate");
|
|
16869
|
+
return { type: "set_constraints", names, deferred };
|
|
16651
16870
|
}
|
|
16652
16871
|
if (this.atKw("role") || this.atKw("session", 0) && this.atKw("authorization", 1)) {
|
|
16653
16872
|
this.skipToStatementEnd();
|
|
@@ -19022,12 +19241,12 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19022
19241
|
table: null
|
|
19023
19242
|
}));
|
|
19024
19243
|
const seen = /* @__PURE__ */ new Set();
|
|
19025
|
-
const
|
|
19244
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(columns[i].type, v)).join("");
|
|
19026
19245
|
let result = [];
|
|
19027
19246
|
let working = [];
|
|
19028
19247
|
for (const row of base.rows) {
|
|
19029
19248
|
if (!body.all) {
|
|
19030
|
-
const k =
|
|
19249
|
+
const k = keyOf2(row);
|
|
19031
19250
|
if (seen.has(k)) continue;
|
|
19032
19251
|
seen.add(k);
|
|
19033
19252
|
}
|
|
@@ -19060,7 +19279,7 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
19060
19279
|
return castTo(env.ctx, tv(srcT === UNKNOWN ? "text" : srcT, v), columns[i].type, {}).v;
|
|
19061
19280
|
});
|
|
19062
19281
|
if (!body.all) {
|
|
19063
|
-
const k =
|
|
19282
|
+
const k = keyOf2(row);
|
|
19064
19283
|
if (seen.has(k)) continue;
|
|
19065
19284
|
seen.add(k);
|
|
19066
19285
|
}
|
|
@@ -20240,7 +20459,7 @@ function setOpRelation(env, op) {
|
|
|
20240
20459
|
);
|
|
20241
20460
|
const lrows = normalize2(left);
|
|
20242
20461
|
const rrows = normalize2(right);
|
|
20243
|
-
const
|
|
20462
|
+
const keyOf2 = (row) => row.map((v, i) => v === null ? "\0N" : datumKey(types[i], v)).join("");
|
|
20244
20463
|
let rows;
|
|
20245
20464
|
switch (op.op) {
|
|
20246
20465
|
case "union": {
|
|
@@ -20248,7 +20467,7 @@ function setOpRelation(env, op) {
|
|
|
20248
20467
|
if (!op.all) {
|
|
20249
20468
|
const seen = /* @__PURE__ */ new Set();
|
|
20250
20469
|
rows = rows.filter((r) => {
|
|
20251
|
-
const k =
|
|
20470
|
+
const k = keyOf2(r);
|
|
20252
20471
|
if (seen.has(k)) return false;
|
|
20253
20472
|
seen.add(k);
|
|
20254
20473
|
return true;
|
|
@@ -20259,13 +20478,13 @@ function setOpRelation(env, op) {
|
|
|
20259
20478
|
case "intersect": {
|
|
20260
20479
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
20261
20480
|
for (const r of rrows) {
|
|
20262
|
-
const k =
|
|
20481
|
+
const k = keyOf2(r);
|
|
20263
20482
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
20264
20483
|
}
|
|
20265
20484
|
rows = [];
|
|
20266
20485
|
const emitted = /* @__PURE__ */ new Set();
|
|
20267
20486
|
for (const r of lrows) {
|
|
20268
|
-
const k =
|
|
20487
|
+
const k = keyOf2(r);
|
|
20269
20488
|
const avail = rightCounts.get(k) ?? 0;
|
|
20270
20489
|
if (avail <= 0) continue;
|
|
20271
20490
|
if (op.all) {
|
|
@@ -20281,13 +20500,13 @@ function setOpRelation(env, op) {
|
|
|
20281
20500
|
case "except": {
|
|
20282
20501
|
const rightCounts = /* @__PURE__ */ new Map();
|
|
20283
20502
|
for (const r of rrows) {
|
|
20284
|
-
const k =
|
|
20503
|
+
const k = keyOf2(r);
|
|
20285
20504
|
rightCounts.set(k, (rightCounts.get(k) ?? 0) + 1);
|
|
20286
20505
|
}
|
|
20287
20506
|
rows = [];
|
|
20288
20507
|
const emitted = /* @__PURE__ */ new Set();
|
|
20289
20508
|
for (const r of lrows) {
|
|
20290
|
-
const k =
|
|
20509
|
+
const k = keyOf2(r);
|
|
20291
20510
|
if (op.all) {
|
|
20292
20511
|
const avail = rightCounts.get(k) ?? 0;
|
|
20293
20512
|
if (avail > 0) {
|
|
@@ -20740,202 +20959,49 @@ function executeCore(env0, core, orderBy, opts) {
|
|
|
20740
20959
|
}
|
|
20741
20960
|
}
|
|
20742
20961
|
rel3 = stripHidden(rel3);
|
|
20743
|
-
return rel3;
|
|
20744
|
-
}
|
|
20745
|
-
function executeSelectStmt(env0, stmt) {
|
|
20746
|
-
const env = applyWith(env0, stmt.with);
|
|
20747
|
-
let rel3;
|
|
20748
|
-
if (stmt.body.type === "select_core") {
|
|
20749
|
-
rel3 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
|
|
20750
|
-
} else {
|
|
20751
|
-
rel3 = executeBody(env, stmt.body);
|
|
20752
|
-
const specs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20753
|
-
if (specs.length > 0) sortRows(env, rel3, specs);
|
|
20754
|
-
rel3 = stripHidden(rel3);
|
|
20755
|
-
}
|
|
20756
|
-
if (stmt.limitWithTies) {
|
|
20757
|
-
if (stmt.orderBy.length === 0) {
|
|
20758
|
-
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
20759
|
-
}
|
|
20760
|
-
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20761
|
-
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
20762
|
-
}
|
|
20763
|
-
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
20764
|
-
}
|
|
20765
|
-
|
|
20766
|
-
// src/constraints/enforce.ts
|
|
20767
|
-
function tableScope(table, row) {
|
|
20768
|
-
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
20769
|
-
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
20770
|
-
}
|
|
20771
|
-
function checkNotNull(env, table, row) {
|
|
20772
|
-
void env;
|
|
20773
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
20774
|
-
const c = table.columns[i];
|
|
20775
|
-
if (c.notNull && (row[i] ?? null) === null) {
|
|
20776
|
-
throw pgError(
|
|
20777
|
-
"not_null_violation",
|
|
20778
|
-
`null value in column "${c.name}" of relation "${table.name}" violates not-null constraint`,
|
|
20779
|
-
"23502"
|
|
20780
|
-
);
|
|
20781
|
-
}
|
|
20782
|
-
}
|
|
20783
|
-
}
|
|
20784
|
-
function checkChecks(env, table, row) {
|
|
20785
|
-
for (const con of table.constraints) {
|
|
20786
|
-
if (con.kind !== "check") continue;
|
|
20787
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
20788
|
-
const v = evalExpr(env.ctx, scope, con.expr);
|
|
20789
|
-
if (v.v === null) continue;
|
|
20790
|
-
const b = castTo(env.ctx, v, "bool", {});
|
|
20791
|
-
if (b.v !== true) {
|
|
20792
|
-
throw pgError(
|
|
20793
|
-
"check_violation",
|
|
20794
|
-
`new row for relation "${table.name}" violates check constraint "${con.name}"`,
|
|
20795
|
-
"23514"
|
|
20796
|
-
);
|
|
20797
|
-
}
|
|
20798
|
-
}
|
|
20799
|
-
}
|
|
20800
|
-
function uniqueSpecsFor(env, table) {
|
|
20801
|
-
const specs = [];
|
|
20802
|
-
for (const con of table.constraints) {
|
|
20803
|
-
if (con.kind !== "primary_key" && con.kind !== "unique") continue;
|
|
20804
|
-
specs.push({
|
|
20805
|
-
name: con.name,
|
|
20806
|
-
keys: con.columns.map((c) => ({ colIdx: table.columnIndex(c), expr: null })),
|
|
20807
|
-
columnNames: con.columns,
|
|
20808
|
-
nullsNotDistinct: con.kind === "unique" ? con.nullsNotDistinct : false,
|
|
20809
|
-
where: null,
|
|
20810
|
-
isPrimary: con.kind === "primary_key"
|
|
20811
|
-
});
|
|
20812
|
-
}
|
|
20813
|
-
const schema = env.ctx.state.schemas.get(table.schema);
|
|
20814
|
-
if (schema) {
|
|
20815
|
-
for (const idx of schema.indexes.values()) {
|
|
20816
|
-
if (idx.table !== table.name || !idx.unique || idx.isConstraint || idx.valid === false) continue;
|
|
20817
|
-
specs.push(uniqueSpecOfIndex(table, idx));
|
|
20818
|
-
}
|
|
20819
|
-
}
|
|
20820
|
-
return specs;
|
|
20821
|
-
}
|
|
20822
|
-
function uniqueSpecOfIndex(table, idx) {
|
|
20823
|
-
return {
|
|
20824
|
-
name: idx.name,
|
|
20825
|
-
keys: idx.columns.map((c) => ({
|
|
20826
|
-
colIdx: c.column !== null ? table.columnIndex(c.column) : -1,
|
|
20827
|
-
expr: c.expr
|
|
20828
|
-
})),
|
|
20829
|
-
columnNames: idx.columns.map((c) => c.column ?? "expr"),
|
|
20830
|
-
nullsNotDistinct: idx.nullsNotDistinct,
|
|
20831
|
-
where: idx.where,
|
|
20832
|
-
isPrimary: false
|
|
20833
|
-
};
|
|
20834
|
-
}
|
|
20835
|
-
function uniqueKeyOf(env, table, spec, row) {
|
|
20836
|
-
if (spec.where) {
|
|
20837
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
20838
|
-
const v = evalExpr(env.ctx, scope, spec.where);
|
|
20839
|
-
if (v.v !== true) return null;
|
|
20840
|
-
}
|
|
20841
|
-
const parts = [];
|
|
20842
|
-
let hasNull = false;
|
|
20843
|
-
for (const k of spec.keys) {
|
|
20844
|
-
let value;
|
|
20845
|
-
let type;
|
|
20846
|
-
if (k.expr) {
|
|
20847
|
-
const scope = makeEvalScope(env, tableScope(table, row));
|
|
20848
|
-
const v = evalExpr(env.ctx, scope, k.expr);
|
|
20849
|
-
value = v.v;
|
|
20850
|
-
type = v.t === "unknown" ? "text" : v.t;
|
|
20851
|
-
} else {
|
|
20852
|
-
value = row[k.colIdx] ?? null;
|
|
20853
|
-
type = table.columns[k.colIdx].type.id;
|
|
20854
|
-
}
|
|
20855
|
-
if (value === null) {
|
|
20856
|
-
hasNull = true;
|
|
20857
|
-
parts.push("\0N");
|
|
20858
|
-
} else {
|
|
20859
|
-
parts.push(datumKey(type, value));
|
|
20860
|
-
}
|
|
20861
|
-
}
|
|
20862
|
-
if (hasNull && !spec.nullsNotDistinct) return null;
|
|
20863
|
-
return parts.join("");
|
|
20864
|
-
}
|
|
20865
|
-
function checkUnique(env, table, row, selfIdx) {
|
|
20866
|
-
for (const spec of uniqueSpecsFor(env, table)) {
|
|
20867
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
20868
|
-
if (key === null) continue;
|
|
20869
|
-
indexStoreFor(env, table, spec).checkUnique(key, selfIdx);
|
|
20870
|
-
}
|
|
20871
|
-
}
|
|
20872
|
-
function findConflict(env, table, spec, row) {
|
|
20873
|
-
const key = uniqueKeyOf(env, table, spec, row);
|
|
20874
|
-
if (key === null) return null;
|
|
20875
|
-
const hits = indexStoreFor(env, table, spec).lookup(key);
|
|
20876
|
-
return hits.length > 0 ? hits[0] : null;
|
|
20877
|
-
}
|
|
20878
|
-
function checkForeignKeys(env, table, row) {
|
|
20879
|
-
const state = env.ctx.state;
|
|
20880
|
-
for (const con of table.constraints) {
|
|
20881
|
-
if (con.kind !== "foreign_key") continue;
|
|
20882
|
-
const values = con.columns.map((c) => row[table.columnIndex(c)] ?? null);
|
|
20883
|
-
const nulls = values.filter((v) => v === null).length;
|
|
20884
|
-
if (con.match === "simple" && nulls > 0) continue;
|
|
20885
|
-
if (con.match === "full") {
|
|
20886
|
-
if (nulls === values.length) continue;
|
|
20887
|
-
if (nulls > 0) {
|
|
20888
|
-
throw pgError(
|
|
20889
|
-
"constraint_foreign_key",
|
|
20890
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
20891
|
-
"23503"
|
|
20892
|
-
);
|
|
20893
|
-
}
|
|
20894
|
-
}
|
|
20895
|
-
const refTable = state.schemas.get(con.refSchema)?.tables.get(con.refTable);
|
|
20896
|
-
if (!refTable) {
|
|
20897
|
-
throw pgError("undefined_table", `relation "${con.refSchema}.${con.refTable}" does not exist`, "42P01");
|
|
20898
|
-
}
|
|
20899
|
-
const refIdxs = con.refColumns.map((c) => refTable.columnIndex(c));
|
|
20900
|
-
const keyTypes = con.refColumns.map((_c, i) => refTable.columns[refIdxs[i]].type.id);
|
|
20901
|
-
const wanted = values.map((v, i) => {
|
|
20902
|
-
const localT = table.columns[table.columnIndex(con.columns[i])].type.id;
|
|
20903
|
-
const cast = castTo(env.ctx, tv(localT, v), keyTypes[i], {});
|
|
20904
|
-
return cast.v === null ? "\0N" : datumKey(keyTypes[i], cast.v);
|
|
20905
|
-
}).join("");
|
|
20906
|
-
let found = false;
|
|
20907
|
-
for (let i = 0; i < refTable.rowCount(); i++) {
|
|
20908
|
-
const r = refTable.rowAt(i);
|
|
20909
|
-
const key = refIdxs.map((ri, j) => {
|
|
20910
|
-
const v = r[ri] ?? null;
|
|
20911
|
-
return v === null ? "\0N" : datumKey(keyTypes[j], v);
|
|
20912
|
-
}).join("");
|
|
20913
|
-
if (key === wanted) {
|
|
20914
|
-
found = true;
|
|
20915
|
-
break;
|
|
20916
|
-
}
|
|
20917
|
-
}
|
|
20918
|
-
if (!found) {
|
|
20919
|
-
throw pgError(
|
|
20920
|
-
"constraint_foreign_key",
|
|
20921
|
-
`insert or update on table "${table.name}" violates foreign key constraint "${con.name}"`,
|
|
20922
|
-
"23503"
|
|
20923
|
-
);
|
|
20962
|
+
return rel3;
|
|
20963
|
+
}
|
|
20964
|
+
function executeSelectStmt(env0, stmt) {
|
|
20965
|
+
const env = applyWith(env0, stmt.with);
|
|
20966
|
+
let rel3;
|
|
20967
|
+
if (stmt.body.type === "select_core") {
|
|
20968
|
+
rel3 = executeCore(env, stmt.body, stmt.orderBy, { hasLimit: stmt.limit !== null });
|
|
20969
|
+
} else {
|
|
20970
|
+
rel3 = executeBody(env, stmt.body);
|
|
20971
|
+
const specs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20972
|
+
if (specs.length > 0) sortRows(env, rel3, specs);
|
|
20973
|
+
rel3 = stripHidden(rel3);
|
|
20974
|
+
}
|
|
20975
|
+
if (stmt.limitWithTies) {
|
|
20976
|
+
if (stmt.orderBy.length === 0) {
|
|
20977
|
+
throw pgError("syntax", "WITH TIES cannot be specified without ORDER BY clause", "42601");
|
|
20924
20978
|
}
|
|
20979
|
+
const tieSpecs = outputOrderSpecs(env, rel3, stmt.orderBy);
|
|
20980
|
+
return stripHidden(applyLimitOffset(env, rel3, stmt.limit, stmt.offset, tieSpecs));
|
|
20925
20981
|
}
|
|
20982
|
+
return applyLimitOffset(env, rel3, stmt.limit, stmt.offset);
|
|
20926
20983
|
}
|
|
20927
|
-
|
|
20928
|
-
|
|
20929
|
-
|
|
20930
|
-
|
|
20931
|
-
|
|
20932
|
-
|
|
20933
|
-
|
|
20934
|
-
|
|
20935
|
-
|
|
20984
|
+
|
|
20985
|
+
// src/executor/triggers-scope.ts
|
|
20986
|
+
function triggerScope(table, newRow, oldRow) {
|
|
20987
|
+
const cols = [];
|
|
20988
|
+
const row = [];
|
|
20989
|
+
const rangeVars = /* @__PURE__ */ new Set();
|
|
20990
|
+
if (newRow) {
|
|
20991
|
+
rangeVars.add("new");
|
|
20992
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
20993
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
20994
|
+
row.push(newRow[i] ?? null);
|
|
20936
20995
|
}
|
|
20937
20996
|
}
|
|
20938
|
-
|
|
20997
|
+
if (oldRow) {
|
|
20998
|
+
rangeVars.add("old");
|
|
20999
|
+
for (let i = 0; i < table.columns.length; i++) {
|
|
21000
|
+
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
21001
|
+
row.push(oldRow[i] ?? null);
|
|
21002
|
+
}
|
|
21003
|
+
}
|
|
21004
|
+
return new RowScope(cols, row, null, rangeVars);
|
|
20939
21005
|
}
|
|
20940
21006
|
|
|
20941
21007
|
// src/executor/triggers.ts
|
|
@@ -20951,6 +21017,18 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
20951
21017
|
for (const t of table.triggers) {
|
|
20952
21018
|
if (t.timing !== timing || !matches(t, event) || !t.forEachRow) continue;
|
|
20953
21019
|
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
21020
|
+
if (t.constraint && timing === "after") {
|
|
21021
|
+
if (t.when && !evalPredicate(env, triggerScope(table, newRow, oldRow), t.when)) continue;
|
|
21022
|
+
env.ctx.state.pendingTriggers.push({
|
|
21023
|
+
schema: table.schema,
|
|
21024
|
+
table: table.name,
|
|
21025
|
+
trigger: t.name,
|
|
21026
|
+
event,
|
|
21027
|
+
oldRow: oldRow?.slice() ?? null,
|
|
21028
|
+
newRow: newRow?.slice() ?? null
|
|
21029
|
+
});
|
|
21030
|
+
continue;
|
|
21031
|
+
}
|
|
20954
21032
|
const result = executor(env, table, t, event, oldRow, timing === "before" ? row : newRow);
|
|
20955
21033
|
if (timing === "before") {
|
|
20956
21034
|
if (result === null) return { row: null };
|
|
@@ -20959,6 +21037,167 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
20959
21037
|
}
|
|
20960
21038
|
return { row };
|
|
20961
21039
|
}
|
|
21040
|
+
var keyOf = (schema, name) => JSON.stringify([schema, name]);
|
|
21041
|
+
function flushConstraintTriggers(state, all = false) {
|
|
21042
|
+
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
21043
|
+
for (let i = 0; i < state.pendingTriggers.length; ) {
|
|
21044
|
+
const pending = state.pendingTriggers[i];
|
|
21045
|
+
const table = state.schemas.get(pending.schema)?.tables.get(pending.table);
|
|
21046
|
+
const trigger = table?.triggers.find((t) => t.name === pending.trigger);
|
|
21047
|
+
if (!table || !trigger) {
|
|
21048
|
+
state.pendingTriggers.splice(i, 1);
|
|
21049
|
+
continue;
|
|
21050
|
+
}
|
|
21051
|
+
const deferred = trigger.deferrable && (state.constraintModes.get(keyOf(table.schema, trigger.name)) ?? trigger.initiallyDeferred);
|
|
21052
|
+
if (!all && state.inTransaction && deferred) {
|
|
21053
|
+
i++;
|
|
21054
|
+
continue;
|
|
21055
|
+
}
|
|
21056
|
+
if (!executor) throw unsupported(`trigger "${trigger.name}" execution`);
|
|
21057
|
+
state.pendingTriggers.splice(i, 1);
|
|
21058
|
+
const changes = state.changes;
|
|
21059
|
+
try {
|
|
21060
|
+
executor(env, table, { ...trigger, when: null }, pending.event, pending.oldRow, pending.newRow);
|
|
21061
|
+
} catch (error) {
|
|
21062
|
+
state.pendingTriggers.splice(i, 0, pending);
|
|
21063
|
+
throw error;
|
|
21064
|
+
} finally {
|
|
21065
|
+
state.changes = changes;
|
|
21066
|
+
}
|
|
21067
|
+
}
|
|
21068
|
+
}
|
|
21069
|
+
function setConstraints(state, stmt) {
|
|
21070
|
+
if (!state.inTransaction) return;
|
|
21071
|
+
const matches2 = [];
|
|
21072
|
+
if (stmt.names) {
|
|
21073
|
+
for (const name of stmt.names) {
|
|
21074
|
+
const schemas = name.length > 1 ? [name[name.length - 2]] : state.effectiveSearchPath();
|
|
21075
|
+
let found = false;
|
|
21076
|
+
for (const schema of schemas) {
|
|
21077
|
+
const items = [...state.schemas.get(schema)?.tables.values() ?? []].flatMap(
|
|
21078
|
+
(table) => table.triggers.filter((t) => t.constraint && t.name === name[name.length - 1])
|
|
21079
|
+
);
|
|
21080
|
+
if (items.length) {
|
|
21081
|
+
for (const trigger of items) matches2.push({ schema, trigger });
|
|
21082
|
+
found = true;
|
|
21083
|
+
break;
|
|
21084
|
+
}
|
|
21085
|
+
}
|
|
21086
|
+
if (!found) throw pgError("undefined_object", `constraint "${name.join(".")}" does not exist`, "42704");
|
|
21087
|
+
}
|
|
21088
|
+
} else {
|
|
21089
|
+
for (const schema of state.schemas.values())
|
|
21090
|
+
for (const table of schema.tables.values())
|
|
21091
|
+
for (const trigger of table.triggers)
|
|
21092
|
+
if (trigger.constraint && trigger.deferrable) matches2.push({ schema: schema.name, trigger });
|
|
21093
|
+
}
|
|
21094
|
+
for (const { trigger } of matches2)
|
|
21095
|
+
if (stmt.deferred && !trigger.deferrable)
|
|
21096
|
+
throw pgError("misuse", `constraint "${trigger.name}" is not deferrable`, "55000");
|
|
21097
|
+
const previous = new Map(state.constraintModes);
|
|
21098
|
+
for (const { schema, trigger } of matches2) state.constraintModes.set(keyOf(schema, trigger.name), stmt.deferred);
|
|
21099
|
+
try {
|
|
21100
|
+
if (!stmt.deferred) flushConstraintTriggers(state);
|
|
21101
|
+
} catch (error) {
|
|
21102
|
+
state.constraintModes = previous;
|
|
21103
|
+
throw error;
|
|
21104
|
+
}
|
|
21105
|
+
}
|
|
21106
|
+
|
|
21107
|
+
// src/transactions/manager.ts
|
|
21108
|
+
var TransactionManager = class {
|
|
21109
|
+
constructor(state) {
|
|
21110
|
+
this.state = state;
|
|
21111
|
+
}
|
|
21112
|
+
state;
|
|
21113
|
+
base = null;
|
|
21114
|
+
savepoints = [];
|
|
21115
|
+
freezeDepth = 0;
|
|
21116
|
+
get inTransaction() {
|
|
21117
|
+
return this.base !== null;
|
|
21118
|
+
}
|
|
21119
|
+
takeSnapshot() {
|
|
21120
|
+
this.state.freezeShared();
|
|
21121
|
+
this.freezeDepth++;
|
|
21122
|
+
return { state: this.state.cloneShallow(), prngState: this.state.prng.getState() };
|
|
21123
|
+
}
|
|
21124
|
+
restore(snap) {
|
|
21125
|
+
this.state.restoreFrom(snap.state);
|
|
21126
|
+
this.state.prng.setState(snap.prngState);
|
|
21127
|
+
}
|
|
21128
|
+
thawOnce() {
|
|
21129
|
+
if (this.freezeDepth > 0) {
|
|
21130
|
+
this.state.thawShared();
|
|
21131
|
+
this.freezeDepth--;
|
|
21132
|
+
}
|
|
21133
|
+
}
|
|
21134
|
+
begin() {
|
|
21135
|
+
if (this.base !== null) {
|
|
21136
|
+
return;
|
|
21137
|
+
}
|
|
21138
|
+
this.base = this.takeSnapshot();
|
|
21139
|
+
this.state.inTransaction = true;
|
|
21140
|
+
assert(this.freezeDepth === 1, "BEGIN freeze depth");
|
|
21141
|
+
}
|
|
21142
|
+
commit() {
|
|
21143
|
+
try {
|
|
21144
|
+
flushConstraintTriggers(this.state, true);
|
|
21145
|
+
} catch (error) {
|
|
21146
|
+
this.rollback();
|
|
21147
|
+
throw error;
|
|
21148
|
+
}
|
|
21149
|
+
this.base = null;
|
|
21150
|
+
this.savepoints = [];
|
|
21151
|
+
this.state.inTransaction = false;
|
|
21152
|
+
this.state.localSettings.clear();
|
|
21153
|
+
this.state.pendingTriggers = [];
|
|
21154
|
+
this.state.constraintModes.clear();
|
|
21155
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
21156
|
+
}
|
|
21157
|
+
rollback() {
|
|
21158
|
+
if (this.base !== null) {
|
|
21159
|
+
this.restore(this.base);
|
|
21160
|
+
}
|
|
21161
|
+
this.base = null;
|
|
21162
|
+
this.savepoints = [];
|
|
21163
|
+
this.state.inTransaction = false;
|
|
21164
|
+
this.state.localSettings.clear();
|
|
21165
|
+
this.state.pendingTriggers = [];
|
|
21166
|
+
this.state.constraintModes.clear();
|
|
21167
|
+
while (this.freezeDepth > 0) this.thawOnce();
|
|
21168
|
+
}
|
|
21169
|
+
savepoint(name) {
|
|
21170
|
+
if (this.base === null) {
|
|
21171
|
+
throw pgError("transaction_state", "SAVEPOINT can only be used in transaction blocks", "25P01");
|
|
21172
|
+
}
|
|
21173
|
+
this.savepoints.push({ name, snap: this.takeSnapshot() });
|
|
21174
|
+
}
|
|
21175
|
+
releaseSavepoint(name) {
|
|
21176
|
+
const idx = this.findSavepoint(name);
|
|
21177
|
+
this.savepoints.splice(idx);
|
|
21178
|
+
}
|
|
21179
|
+
rollbackToSavepoint(name) {
|
|
21180
|
+
const idx = this.findSavepoint(name);
|
|
21181
|
+
const sp = this.savepoints[idx];
|
|
21182
|
+
this.restore(sp.snap);
|
|
21183
|
+
this.savepoints.splice(idx + 1);
|
|
21184
|
+
}
|
|
21185
|
+
findSavepoint(name) {
|
|
21186
|
+
if (this.base === null) {
|
|
21187
|
+
throw pgError("transaction_state", `SAVEPOINT can only be used in transaction blocks`, "25P01");
|
|
21188
|
+
}
|
|
21189
|
+
for (let i = this.savepoints.length - 1; i >= 0; i--) {
|
|
21190
|
+
if (this.savepoints[i].name === name) return i;
|
|
21191
|
+
}
|
|
21192
|
+
throw pgError("invalid_savepoint_specification", `savepoint "${name}" does not exist`, "3B001");
|
|
21193
|
+
}
|
|
21194
|
+
reset() {
|
|
21195
|
+
this.base = null;
|
|
21196
|
+
this.savepoints = [];
|
|
21197
|
+
this.state.inTransaction = false;
|
|
21198
|
+
this.freezeDepth = 0;
|
|
21199
|
+
}
|
|
21200
|
+
};
|
|
20962
21201
|
|
|
20963
21202
|
// src/executor/dml.ts
|
|
20964
21203
|
function withStatementRollback(env, fn) {
|
|
@@ -21648,6 +21887,7 @@ function executeSet(env, stmt) {
|
|
|
21648
21887
|
else target.delete(name);
|
|
21649
21888
|
return commandResult("SET", 0);
|
|
21650
21889
|
}
|
|
21890
|
+
validateStorageSetting(name, stmt.value);
|
|
21651
21891
|
target.set(name, stmt.value);
|
|
21652
21892
|
return commandResult("SET", 0);
|
|
21653
21893
|
}
|
|
@@ -21953,64 +22193,6 @@ function executeCopyFromData(env, stmt, data) {
|
|
|
21953
22193
|
};
|
|
21954
22194
|
}
|
|
21955
22195
|
|
|
21956
|
-
// src/expressions/context.ts
|
|
21957
|
-
var EngineCtx = class {
|
|
21958
|
-
state;
|
|
21959
|
-
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
21960
|
-
txNow;
|
|
21961
|
-
/** statement timestamp */
|
|
21962
|
-
stmtNow;
|
|
21963
|
-
constructor(state, txNow) {
|
|
21964
|
-
this.state = state;
|
|
21965
|
-
const nowMs = state.clock().getTime();
|
|
21966
|
-
const nowMicros = BigInt(Math.round(nowMs)) * 1000n + UNIX_EPOCH_MICROS_FROM_PG;
|
|
21967
|
-
this.txNow = txNow ?? nowMicros;
|
|
21968
|
-
this.stmtNow = nowMicros;
|
|
21969
|
-
}
|
|
21970
|
-
timezone() {
|
|
21971
|
-
return this.state.getSetting("timezone") ?? "UTC";
|
|
21972
|
-
}
|
|
21973
|
-
namespaceOid(name) {
|
|
21974
|
-
const oid = builtinNamespaceOid(name) ?? this.state.schemas.get(name)?.oid;
|
|
21975
|
-
if (oid === void 0) throw pgError("undefined_object", `schema "${name}" does not exist`, "3F000");
|
|
21976
|
-
return oid;
|
|
21977
|
-
}
|
|
21978
|
-
namespaceName(oid) {
|
|
21979
|
-
const builtin = builtinNamespaceName(oid);
|
|
21980
|
-
if (builtin !== void 0) return builtin;
|
|
21981
|
-
for (const schema of this.state.schemas.values()) {
|
|
21982
|
-
if (schema.oid === oid) return schema.name;
|
|
21983
|
-
}
|
|
21984
|
-
return null;
|
|
21985
|
-
}
|
|
21986
|
-
zoneOffsetAt(utcMicros) {
|
|
21987
|
-
return zoneOffsetAtUtc(this.timezone(), utcMicros);
|
|
21988
|
-
}
|
|
21989
|
-
zoneOffsetForNaive(naiveMicros) {
|
|
21990
|
-
return zoneOffsetForNaive(this.timezone(), naiveMicros);
|
|
21991
|
-
}
|
|
21992
|
-
enumLabels(enumType) {
|
|
21993
|
-
if (!isEnumType(enumType)) return null;
|
|
21994
|
-
const e = this.state.findEnumByKey(enumType.slice(5));
|
|
21995
|
-
return e?.labels ?? null;
|
|
21996
|
-
}
|
|
21997
|
-
enumHasLabel(enumType, label) {
|
|
21998
|
-
const labels = this.enumLabels(enumType);
|
|
21999
|
-
return labels === null ? true : labels.includes(label);
|
|
22000
|
-
}
|
|
22001
|
-
enumOrder(enumType, label) {
|
|
22002
|
-
const labels = this.enumLabels(enumType);
|
|
22003
|
-
if (!labels) return 0;
|
|
22004
|
-
const idx = labels.indexOf(label);
|
|
22005
|
-
return idx === -1 ? labels.length : idx;
|
|
22006
|
-
}
|
|
22007
|
-
requireEnum(enumType) {
|
|
22008
|
-
const labels = this.enumLabels(enumType);
|
|
22009
|
-
if (!labels) throw pgError("undefined_object", `type "${enumType.slice(5)}" does not exist`);
|
|
22010
|
-
return labels;
|
|
22011
|
-
}
|
|
22012
|
-
};
|
|
22013
|
-
|
|
22014
22196
|
// src/runtime/clock.ts
|
|
22015
22197
|
var DEFAULT_NOW = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
22016
22198
|
function fixedClock(instant = DEFAULT_NOW) {
|
|
@@ -22978,7 +23160,7 @@ function pgClass(ctx) {
|
|
|
22978
23160
|
v.materialized ? "m" : "v",
|
|
22979
23161
|
v.columns?.length ?? 0,
|
|
22980
23162
|
v.matRows?.length ?? 0,
|
|
22981
|
-
|
|
23163
|
+
v.materialized && [...schemaData.indexes.values()].some((i) => i.tableOid === v.oid),
|
|
22982
23164
|
!v.materialized || v.matRows !== null,
|
|
22983
23165
|
relPersistence(v)
|
|
22984
23166
|
);
|
|
@@ -23244,7 +23426,7 @@ function pgIndex(ctx) {
|
|
|
23244
23426
|
const valid = i.valid !== false;
|
|
23245
23427
|
rows.push([
|
|
23246
23428
|
i.oid ?? 0,
|
|
23247
|
-
table?.oid ?? 0,
|
|
23429
|
+
table?.oid ?? i.tableOid ?? 0,
|
|
23248
23430
|
indexAttributeCount(i),
|
|
23249
23431
|
i.columns.length,
|
|
23250
23432
|
i.unique,
|
|
@@ -23416,7 +23598,7 @@ function pgStatUserIndexes(ctx) {
|
|
|
23416
23598
|
for (const index of schema.indexes.values()) {
|
|
23417
23599
|
const table = schema.tables.get(index.table);
|
|
23418
23600
|
rows.push([
|
|
23419
|
-
table?.oid ?? 0,
|
|
23601
|
+
table?.oid ?? index.tableOid ?? 0,
|
|
23420
23602
|
index.oid ?? 0,
|
|
23421
23603
|
schema.name,
|
|
23422
23604
|
index.table,
|
|
@@ -24011,26 +24193,6 @@ function runTriggerBody(env, table, stmts, vars) {
|
|
|
24011
24193
|
}
|
|
24012
24194
|
}
|
|
24013
24195
|
}
|
|
24014
|
-
function triggerScope(table, newRow, oldRow) {
|
|
24015
|
-
const cols = [];
|
|
24016
|
-
const row = [];
|
|
24017
|
-
const rangeVars = /* @__PURE__ */ new Set();
|
|
24018
|
-
if (newRow) {
|
|
24019
|
-
rangeVars.add("new");
|
|
24020
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
24021
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "new" });
|
|
24022
|
-
row.push(newRow[i] ?? null);
|
|
24023
|
-
}
|
|
24024
|
-
}
|
|
24025
|
-
if (oldRow) {
|
|
24026
|
-
rangeVars.add("old");
|
|
24027
|
-
for (let i = 0; i < table.columns.length; i++) {
|
|
24028
|
-
cols.push({ name: table.columns[i].name, type: table.columns[i].type.id, table: "old" });
|
|
24029
|
-
row.push(oldRow[i] ?? null);
|
|
24030
|
-
}
|
|
24031
|
-
}
|
|
24032
|
-
return new RowScope(cols, row, null, rangeVars);
|
|
24033
|
-
}
|
|
24034
24196
|
function executeTrigger(env, table, trigger, _event, oldRow, newRow) {
|
|
24035
24197
|
const state = env.ctx.state;
|
|
24036
24198
|
if (trigger.when !== null && !evalPredicate(env, triggerScope(table, newRow, oldRow), trigger.when)) {
|
|
@@ -25000,7 +25162,8 @@ function executeCreateTableAs(env, stmt) {
|
|
|
25000
25162
|
}
|
|
25001
25163
|
function executeCreateIndex(env, stmt) {
|
|
25002
25164
|
const state = env.ctx.state;
|
|
25003
|
-
const
|
|
25165
|
+
const view = state.findView(stmt.table);
|
|
25166
|
+
const table = state.findTable(stmt.table) ?? (view?.materialized ? materializedTable(view) : void 0);
|
|
25004
25167
|
if (!table) {
|
|
25005
25168
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
25006
25169
|
}
|
|
@@ -25112,13 +25275,22 @@ function executeRefreshMatView(env, stmt) {
|
|
|
25112
25275
|
if (!found?.materialized) {
|
|
25113
25276
|
throw pgError("undefined_table", `materialized view "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
25114
25277
|
}
|
|
25278
|
+
const rel3 = executeSelectStmt(matviewQueryEnv(env, !stmt.withData), found.query);
|
|
25279
|
+
const next = {
|
|
25280
|
+
...found,
|
|
25281
|
+
matColumns: rel3.columns.map((c, i) => ({
|
|
25282
|
+
name: found.columns?.[i] ?? c.name,
|
|
25283
|
+
type: c.type === UNKNOWN ? "text" : c.type
|
|
25284
|
+
})),
|
|
25285
|
+
matRows: stmt.withData ? rel3.rows : null
|
|
25286
|
+
};
|
|
25287
|
+
const table = materializedTable(next);
|
|
25288
|
+
for (const index of env.ctx.state.getSchema(found.schema).indexes.values()) {
|
|
25289
|
+
if (index.tableOid === found.oid && index.valid !== false) assertUniqueIndexBuildable(env, table, index);
|
|
25290
|
+
}
|
|
25115
25291
|
const view = env.ctx.state.ensureWritableView(found);
|
|
25116
|
-
|
|
25117
|
-
view.
|
|
25118
|
-
name: view.columns?.[i] ?? c.name,
|
|
25119
|
-
type: c.type === UNKNOWN ? "text" : c.type
|
|
25120
|
-
}));
|
|
25121
|
-
view.matRows = stmt.withData ? rel3.rows : null;
|
|
25292
|
+
view.matColumns = next.matColumns;
|
|
25293
|
+
view.matRows = next.matRows;
|
|
25122
25294
|
return commandResult("REFRESH MATERIALIZED VIEW", 0);
|
|
25123
25295
|
}
|
|
25124
25296
|
function executeCreateSchema(env, stmt) {
|
|
@@ -25260,6 +25432,8 @@ function executeCreateFunction(env, stmt) {
|
|
|
25260
25432
|
return commandResult("CREATE FUNCTION", 0);
|
|
25261
25433
|
}
|
|
25262
25434
|
function executeCreateTrigger(env, stmt) {
|
|
25435
|
+
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
25436
|
+
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
25263
25437
|
const state = env.ctx.state;
|
|
25264
25438
|
const found = state.findTable(stmt.table);
|
|
25265
25439
|
if (!found) {
|
|
@@ -25278,6 +25452,9 @@ function executeCreateTrigger(env, stmt) {
|
|
|
25278
25452
|
}
|
|
25279
25453
|
const meta = {
|
|
25280
25454
|
name: stmt.name,
|
|
25455
|
+
constraint: stmt.constraint,
|
|
25456
|
+
deferrable: stmt.deferrable,
|
|
25457
|
+
initiallyDeferred: stmt.initiallyDeferred,
|
|
25281
25458
|
timing: stmt.timing,
|
|
25282
25459
|
events: stmt.events,
|
|
25283
25460
|
forEachRow: stmt.forEachRow,
|
|
@@ -26046,7 +26223,16 @@ function alterTableIsSelfContained(stmt) {
|
|
|
26046
26223
|
return stmt.actions.length === 1 && action !== void 0 && SELF_CONTAINED_ALTER_ACTIONS.has(action.kind);
|
|
26047
26224
|
}
|
|
26048
26225
|
function executeStatement(env, stmt) {
|
|
26049
|
-
if (!RESHAPES_TABLES.has(stmt.type))
|
|
26226
|
+
if (!RESHAPES_TABLES.has(stmt.type)) {
|
|
26227
|
+
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))) {
|
|
26228
|
+
return withStatementRollback(env, () => {
|
|
26229
|
+
const result = dispatchStatement(env, stmt);
|
|
26230
|
+
flushConstraintTriggers(env.ctx.state);
|
|
26231
|
+
return result;
|
|
26232
|
+
});
|
|
26233
|
+
}
|
|
26234
|
+
return dispatchStatement(env, stmt);
|
|
26235
|
+
}
|
|
26050
26236
|
try {
|
|
26051
26237
|
return dispatchStatement(env, stmt);
|
|
26052
26238
|
} finally {
|
|
@@ -26105,6 +26291,9 @@ function dispatchStatement(env, stmt) {
|
|
|
26105
26291
|
return executeRefreshMatView(env, stmt);
|
|
26106
26292
|
case "transaction":
|
|
26107
26293
|
return executeTransaction(env, stmt);
|
|
26294
|
+
case "set_constraints":
|
|
26295
|
+
setConstraints(env.ctx.state, stmt);
|
|
26296
|
+
return commandResult("SET CONSTRAINTS", 0);
|
|
26108
26297
|
case "set":
|
|
26109
26298
|
return executeSet(env, stmt);
|
|
26110
26299
|
case "show":
|
|
@@ -28543,11 +28732,13 @@ var ScramServer = class {
|
|
|
28543
28732
|
var splitStatements = (script) => {
|
|
28544
28733
|
const out = [];
|
|
28545
28734
|
let start2 = 0;
|
|
28735
|
+
let hasSql = false;
|
|
28546
28736
|
let i = 0;
|
|
28547
28737
|
const n = script.length;
|
|
28548
28738
|
const push = (end) => {
|
|
28549
28739
|
const text = script.slice(start2, end).trim();
|
|
28550
|
-
if (
|
|
28740
|
+
if (hasSql) out.push(text);
|
|
28741
|
+
hasSql = false;
|
|
28551
28742
|
};
|
|
28552
28743
|
while (i < n) {
|
|
28553
28744
|
const c = script[i];
|
|
@@ -28569,9 +28760,11 @@ var splitStatements = (script) => {
|
|
|
28569
28760
|
i += 2;
|
|
28570
28761
|
} else i++;
|
|
28571
28762
|
}
|
|
28763
|
+
if (depth > 0) hasSql = true;
|
|
28572
28764
|
continue;
|
|
28573
28765
|
}
|
|
28574
28766
|
if (c === "'" || c === '"') {
|
|
28767
|
+
hasSql = true;
|
|
28575
28768
|
const escaped = c === "'" && /[eE]/.test(script[i - 1] ?? "") && !/[\w$]/.test(script[i - 2] ?? "");
|
|
28576
28769
|
i++;
|
|
28577
28770
|
while (i < n) {
|
|
@@ -28594,6 +28787,7 @@ var splitStatements = (script) => {
|
|
|
28594
28787
|
if (c === "$") {
|
|
28595
28788
|
const m = /^\$([A-Za-z_][A-Za-z0-9_]*)?\$/.exec(script.slice(i, i + 64));
|
|
28596
28789
|
if (m) {
|
|
28790
|
+
hasSql = true;
|
|
28597
28791
|
const tag = m[0];
|
|
28598
28792
|
const end = script.indexOf(tag, i + tag.length);
|
|
28599
28793
|
i = end === -1 ? n : end + tag.length;
|
|
@@ -28604,6 +28798,7 @@ var splitStatements = (script) => {
|
|
|
28604
28798
|
push(i);
|
|
28605
28799
|
start2 = i + 1;
|
|
28606
28800
|
}
|
|
28801
|
+
if (c !== ";" && !/\s/.test(c)) hasSql = true;
|
|
28607
28802
|
i++;
|
|
28608
28803
|
}
|
|
28609
28804
|
push(n);
|
|
@@ -29036,7 +29231,16 @@ var binaryValue = (type, text) => {
|
|
|
29036
29231
|
}
|
|
29037
29232
|
};
|
|
29038
29233
|
var binaryEncodable = (type) => TEXT_TYPES2.has(type) || ["bool", "int2", "int4", "oid", "int8", "float4", "float8", "bytea", "uuid"].includes(type);
|
|
29039
|
-
var
|
|
29234
|
+
var setsSessionConfig = (node) => {
|
|
29235
|
+
if (Array.isArray(node)) return node.some(setsSessionConfig);
|
|
29236
|
+
if (typeof node !== "object" || node === null) return false;
|
|
29237
|
+
const call = node;
|
|
29238
|
+
if (call.type === "func" && call.name?.at(-1) === "set_config") return true;
|
|
29239
|
+
return Object.values(node).some(setsSessionConfig);
|
|
29240
|
+
};
|
|
29241
|
+
var mutatesDatabase = (sql) => parse(sql).some(
|
|
29242
|
+
(stmt) => !["select", "show", "explain", "transaction", "no_op"].includes(stmt.type) || stmt.type === "select" && setsSessionConfig(stmt)
|
|
29243
|
+
);
|
|
29040
29244
|
var NEVER_WRITES = /* @__PURE__ */ new Set(["show", "set", "reset", "transaction", "no_op", "prepare", "deallocate"]);
|
|
29041
29245
|
var WRITE_NODES = /* @__PURE__ */ new Set(["insert", "update", "delete"]);
|
|
29042
29246
|
var containsWrite = (db, node) => {
|
|
@@ -29661,6 +29865,7 @@ var Connection = class {
|
|
|
29661
29865
|
}
|
|
29662
29866
|
return outcome;
|
|
29663
29867
|
} finally {
|
|
29868
|
+
workspace?.transactions.rollback();
|
|
29664
29869
|
workspace?.close();
|
|
29665
29870
|
}
|
|
29666
29871
|
}
|
|
@@ -29735,8 +29940,9 @@ var Connection = class {
|
|
|
29735
29940
|
});
|
|
29736
29941
|
workspace.state.settings = new Map(this.settings);
|
|
29737
29942
|
workspace.state.settingDefaults = this.settingDefaults;
|
|
29943
|
+
workspace.transactions.begin();
|
|
29738
29944
|
for (const logged of this.transaction?.statements ?? []) {
|
|
29739
|
-
|
|
29945
|
+
this.replay(workspace, logged);
|
|
29740
29946
|
}
|
|
29741
29947
|
return workspace;
|
|
29742
29948
|
}
|