@crvouga/mockingbird-service-postgres 3.6.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/COMPATIBILITY.md +33 -1
- package/README.md +5 -0
- package/dist/admin.js +459 -104
- package/dist/admin.js.map +3 -3
- package/dist/api/schema-report.d.ts +32 -0
- package/dist/ast/nodes.d.ts +7 -0
- package/dist/constraints/enforce.d.ts +7 -1
- package/dist/executor/relation.d.ts +1 -0
- package/dist/executor/triggers.d.ts +13 -0
- package/dist/expressions/context.d.ts +4 -0
- package/dist/functions/pgtrgm.d.ts +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +531 -38
- package/dist/index.js.map +4 -4
- package/dist/server.js +355 -38
- package/dist/server.js.map +3 -3
- package/dist/storage/database-state.d.ts +11 -0
- package/dist/types/regnamespace.d.ts +5 -0
- package/dist/types/value.d.ts +2 -0
- package/dist/unstable.js +514 -209
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +692 -102
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/fleet.d.ts +18 -0
- package/dist/wire/index.js +355 -38
- package/dist/wire/index.js.map +3 -3
- package/package.json +1 -1
package/dist/wire/cli.js
CHANGED
|
@@ -161,6 +161,16 @@ var Timeline = class {
|
|
|
161
161
|
}
|
|
162
162
|
};
|
|
163
163
|
|
|
164
|
+
// ../core/dist/ids.js
|
|
165
|
+
var normalizeIdBase = (value, label = "idBase", wallNow = Date.now) => {
|
|
166
|
+
if (value === "boot")
|
|
167
|
+
return wallNow();
|
|
168
|
+
const base = typeof value === "string" && /^\d+$/.test(value.trim()) ? Number(value.trim()) : typeof value === "number" ? value : Number.NaN;
|
|
169
|
+
if (!Number.isSafeInteger(base) || base < 0)
|
|
170
|
+
throw new RangeError(`${label} must be a non-negative integer or "boot" (got ${JSON.stringify(value)})`);
|
|
171
|
+
return base;
|
|
172
|
+
};
|
|
173
|
+
|
|
164
174
|
// ../core/dist/clock.js
|
|
165
175
|
var createClock = (source = Date.now) => {
|
|
166
176
|
let offsetMs = 0;
|
|
@@ -744,11 +754,21 @@ function ownedTransport(policy) {
|
|
|
744
754
|
|
|
745
755
|
// ../../adapters/node/dist/cli.js
|
|
746
756
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
747
|
-
import { createRequire as createRequire3 } from "node:module";
|
|
748
|
-
import { resolve as resolve3 } from "node:path";
|
|
749
|
-
import { pathToFileURL } from "node:url";
|
|
750
757
|
import { parseArgs } from "node:util";
|
|
751
758
|
|
|
759
|
+
// ../../adapters/node/dist/boot-settings.js
|
|
760
|
+
var checkSettings = (target, settings, label) => {
|
|
761
|
+
if (!target.parseSettings)
|
|
762
|
+
throw new Error(`${label}: ${target.name} takes no boot settings`);
|
|
763
|
+
try {
|
|
764
|
+
return target.parseSettings(settings);
|
|
765
|
+
} catch (error) {
|
|
766
|
+
throw new Error(`${label}: ${error instanceof Error ? error.message : String(error)}`, {
|
|
767
|
+
cause: error
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
};
|
|
771
|
+
|
|
752
772
|
// ../../adapters/node/dist/fleet.js
|
|
753
773
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
754
774
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -760,6 +780,31 @@ import { createHash as createHash3, randomBytes, randomUUID as randomUUID3 } fro
|
|
|
760
780
|
|
|
761
781
|
// ../../adapters/node/dist/fleet-archive.js
|
|
762
782
|
import { createHash } from "node:crypto";
|
|
783
|
+
function validateCompatibilityTags(tags) {
|
|
784
|
+
if (!tags || typeof tags !== "object" || Array.isArray(tags))
|
|
785
|
+
throw new Error("invalid archive compatibility tags");
|
|
786
|
+
const entries = Object.entries(tags);
|
|
787
|
+
if (entries.length > 32 || entries.some(([key, value]) => !/^[A-Za-z0-9_.-]{1,64}$/.test(key) || typeof value !== "string" || value.length < 1 || value.length > 256 || [...value].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127)))
|
|
788
|
+
throw new Error("invalid archive compatibility tags");
|
|
789
|
+
}
|
|
790
|
+
function assertCompatibilityTags(tags, policy) {
|
|
791
|
+
if (tags !== void 0)
|
|
792
|
+
validateCompatibilityTags(tags);
|
|
793
|
+
if (!policy)
|
|
794
|
+
return;
|
|
795
|
+
validateCompatibilityTags(policy.tags);
|
|
796
|
+
if (policy.missing !== void 0 && !["allow", "reject"].includes(policy.missing))
|
|
797
|
+
throw new Error("invalid missing compatibility policy");
|
|
798
|
+
if (tags === void 0 && policy.missing === "allow")
|
|
799
|
+
return;
|
|
800
|
+
if (canonical(tags) !== canonical(policy.tags))
|
|
801
|
+
throw new Error("application archive compatibility mismatch");
|
|
802
|
+
}
|
|
803
|
+
function assertArchiveCompatibility(input, policy) {
|
|
804
|
+
const archive = validateArchive(input);
|
|
805
|
+
assertCompatibilityTags(archive.compatibility, policy);
|
|
806
|
+
return archive;
|
|
807
|
+
}
|
|
763
808
|
var canonical = (value) => {
|
|
764
809
|
if (Array.isArray(value))
|
|
765
810
|
return `[${value.map(canonical).join(",")}]`;
|
|
@@ -779,6 +824,8 @@ function validateArchive(value) {
|
|
|
779
824
|
const { sha256: sha2563, ...content } = doc;
|
|
780
825
|
if (doc.format !== "mockingbird.fleet/v1" || typeof doc.sourceId !== "string" || typeof doc.createdAt !== "string" || !doc.namespaces || typeof doc.namespaces !== "object" || Array.isArray(doc.namespaces) || sha2563 !== digest(content))
|
|
781
826
|
throw new Error("unsupported or corrupt fleet archive");
|
|
827
|
+
if (doc.compatibility !== void 0)
|
|
828
|
+
validateCompatibilityTags(doc.compatibility);
|
|
782
829
|
for (const [namespace, entry] of Object.entries(doc.namespaces)) {
|
|
783
830
|
if (!/^[A-Za-z0-9_.-]{1,64}$/.test(namespace) || !entry || !Number.isFinite(entry.clock?.now) || typeof entry.clock?.frozen !== "boolean" || !entry.services || !Object.keys(entry.services).length)
|
|
784
831
|
throw new Error("invalid archive namespace");
|
|
@@ -794,6 +841,7 @@ function inspectArchive(input) {
|
|
|
794
841
|
format: archive.format,
|
|
795
842
|
createdAt: archive.createdAt,
|
|
796
843
|
sha256: archive.sha256,
|
|
844
|
+
...archive.compatibility ? { compatibility: archive.compatibility } : {},
|
|
797
845
|
namespaces: Object.fromEntries(Object.entries(archive.namespaces).map(([name2, ns]) => [
|
|
798
846
|
name2,
|
|
799
847
|
{
|
|
@@ -1436,11 +1484,28 @@ var ingressSupport = {
|
|
|
1436
1484
|
streaming: true,
|
|
1437
1485
|
signing: "vendor request signing is not used; webhook signatures remain payload based"
|
|
1438
1486
|
},
|
|
1487
|
+
cognito: {
|
|
1488
|
+
publicOrigin: true,
|
|
1489
|
+
pathPrefix: true,
|
|
1490
|
+
namespaces: "path-or-header",
|
|
1491
|
+
streaming: true,
|
|
1492
|
+
signing: "JWT issuer and JWKS use the configured public namespace; SigV4 verification is not modelled"
|
|
1493
|
+
},
|
|
1494
|
+
medplum: {
|
|
1495
|
+
publicOrigin: true,
|
|
1496
|
+
pathPrefix: true,
|
|
1497
|
+
namespaces: "path-or-header",
|
|
1498
|
+
streaming: true,
|
|
1499
|
+
signing: "FHIR, OAuth and storage URLs use the configured public namespace"
|
|
1500
|
+
},
|
|
1439
1501
|
other: {
|
|
1440
1502
|
publicOrigin: false,
|
|
1441
1503
|
reason: "host/path-sensitive signing and hosted URL rewriting are not certified; use a direct endpoint"
|
|
1442
1504
|
}
|
|
1443
1505
|
};
|
|
1506
|
+
function supportsPublicIngress(service) {
|
|
1507
|
+
return service === "stripe" || service === "cognito" || service === "medplum";
|
|
1508
|
+
}
|
|
1444
1509
|
function advertisedHttpBase(entry) {
|
|
1445
1510
|
if (entry.publicPath !== void 0 && !entry.publicOrigin)
|
|
1446
1511
|
throw new Error("publicPath requires publicOrigin");
|
|
@@ -1979,7 +2044,7 @@ data: ${JSON.stringify(data)}
|
|
|
1979
2044
|
{
|
|
1980
2045
|
protocol: c.protocol,
|
|
1981
2046
|
coverage: c.coverage,
|
|
1982
|
-
ingress: c.targetName
|
|
2047
|
+
ingress: supportsPublicIngress(c.targetName ?? "") ? ingressSupport[c.targetName] : ingressSupport.other,
|
|
1983
2048
|
target: c.targetName,
|
|
1984
2049
|
outboundPolicy: c.outboundPolicy ?? "unsupported",
|
|
1985
2050
|
version: 1,
|
|
@@ -3063,11 +3128,12 @@ data: ${JSON.stringify(data)}
|
|
|
3063
3128
|
format: "mockingbird.fleet/v1",
|
|
3064
3129
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3065
3130
|
sourceId: this.ctx.id,
|
|
3131
|
+
...this.ctx.options.archiveCompatibility ? { compatibility: structuredClone(this.ctx.options.archiveCompatibility.tags) } : {},
|
|
3066
3132
|
namespaces: contents
|
|
3067
3133
|
});
|
|
3068
3134
|
}
|
|
3069
3135
|
async restoreArchive(input, selectedNamespace) {
|
|
3070
|
-
const archive =
|
|
3136
|
+
const archive = assertArchiveCompatibility(input, this.ctx.options.archiveCompatibility);
|
|
3071
3137
|
const entries = Object.entries(archive.namespaces).filter(([ns]) => selectedNamespace === void 0 || ns === selectedNamespace);
|
|
3072
3138
|
if (!entries.length)
|
|
3073
3139
|
throw new Error("selected namespace absent from archive");
|
|
@@ -3352,6 +3418,9 @@ var fleet_config_schema_default = {
|
|
|
3352
3418
|
adminControls: {
|
|
3353
3419
|
$ref: "#/$defs/controls"
|
|
3354
3420
|
},
|
|
3421
|
+
idBase: {
|
|
3422
|
+
$ref: "#/$defs/idBase"
|
|
3423
|
+
},
|
|
3355
3424
|
namespace: {
|
|
3356
3425
|
type: "string",
|
|
3357
3426
|
pattern: "^[A-Za-z0-9_.-]{1,64}$"
|
|
@@ -3441,6 +3510,12 @@ var fleet_config_schema_default = {
|
|
|
3441
3510
|
adminControls: {
|
|
3442
3511
|
$ref: "#/$defs/controls"
|
|
3443
3512
|
},
|
|
3513
|
+
idBase: {
|
|
3514
|
+
$ref: "#/$defs/idBase"
|
|
3515
|
+
},
|
|
3516
|
+
settings: {
|
|
3517
|
+
type: "object"
|
|
3518
|
+
},
|
|
3444
3519
|
fixtures: {
|
|
3445
3520
|
type: "object"
|
|
3446
3521
|
},
|
|
@@ -3487,6 +3562,18 @@ var fleet_config_schema_default = {
|
|
|
3487
3562
|
}
|
|
3488
3563
|
}
|
|
3489
3564
|
},
|
|
3565
|
+
idBase: {
|
|
3566
|
+
anyOf: [
|
|
3567
|
+
{
|
|
3568
|
+
type: "integer",
|
|
3569
|
+
minimum: 0
|
|
3570
|
+
},
|
|
3571
|
+
{
|
|
3572
|
+
type: "string",
|
|
3573
|
+
pattern: "^(boot|[0-9]+)$"
|
|
3574
|
+
}
|
|
3575
|
+
]
|
|
3576
|
+
},
|
|
3490
3577
|
controls: {
|
|
3491
3578
|
type: "object",
|
|
3492
3579
|
additionalProperties: false,
|
|
@@ -3636,6 +3723,8 @@ async function preflightFleet(config, options2) {
|
|
|
3636
3723
|
throw new Error("protected archive policy requires a protected repository; configure its protector before startup");
|
|
3637
3724
|
resolveAdminPrefix(config.adminPrefix);
|
|
3638
3725
|
normalizeBootControls(config.adminControls);
|
|
3726
|
+
if (config.idBase !== void 0)
|
|
3727
|
+
normalizeIdBase(config.idBase, "idBase");
|
|
3639
3728
|
const targets = /* @__PURE__ */ new Map();
|
|
3640
3729
|
const ports = /* @__PURE__ */ new Set();
|
|
3641
3730
|
for (const [name2, entry] of Object.entries(config.services)) {
|
|
@@ -3651,7 +3740,7 @@ async function preflightFleet(config, options2) {
|
|
|
3651
3740
|
if (entry.target !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.target))
|
|
3652
3741
|
throw new Error("target must name a supported service suffix");
|
|
3653
3742
|
const service = entry.target ?? name2;
|
|
3654
|
-
if (advertisedHttpBase(entry) && service
|
|
3743
|
+
if (advertisedHttpBase(entry) && !supportsPublicIngress(service))
|
|
3655
3744
|
throw new Error(`public ingress unsupported for ${service}; use a direct endpoint to preserve signed targets`);
|
|
3656
3745
|
const target = await options2.load(service);
|
|
3657
3746
|
const protocol = "protocol" in target ? target.protocol : "http";
|
|
@@ -3667,6 +3756,13 @@ async function preflightFleet(config, options2) {
|
|
|
3667
3756
|
throw new Error("invalid protocol namespace selector");
|
|
3668
3757
|
}
|
|
3669
3758
|
}
|
|
3759
|
+
if (entry.idBase !== void 0)
|
|
3760
|
+
normalizeIdBase(entry.idBase, "idBase");
|
|
3761
|
+
if (entry.settings !== void 0) {
|
|
3762
|
+
if (protocol !== "http" || !("create" in target))
|
|
3763
|
+
throw new Error("settings: only HTTP services take boot settings");
|
|
3764
|
+
checkSettings(target, entry.settings, "settings");
|
|
3765
|
+
}
|
|
3670
3766
|
const port = entry.port ?? target.defaultPort;
|
|
3671
3767
|
if (port !== 0) {
|
|
3672
3768
|
const key = `${entry.host ?? "127.0.0.1"}:${port}`;
|
|
@@ -3702,7 +3798,7 @@ async function preflightFleet(config, options2) {
|
|
|
3702
3798
|
break;
|
|
3703
3799
|
}
|
|
3704
3800
|
}
|
|
3705
|
-
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.
|
|
3801
|
+
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.8.0" });
|
|
3706
3802
|
} catch (error) {
|
|
3707
3803
|
throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3708
3804
|
}
|
|
@@ -3746,6 +3842,11 @@ async function preflightFleet(config, options2) {
|
|
|
3746
3842
|
return ordered;
|
|
3747
3843
|
}
|
|
3748
3844
|
function validateFleetPolicies(options2) {
|
|
3845
|
+
if (options2.archiveCompatibility) {
|
|
3846
|
+
validateCompatibilityTags(options2.archiveCompatibility.tags);
|
|
3847
|
+
if (options2.archiveCompatibility.missing !== void 0 && !["allow", "reject"].includes(options2.archiveCompatibility.missing))
|
|
3848
|
+
throw new Error("archiveCompatibility.missing must be allow or reject");
|
|
3849
|
+
}
|
|
3749
3850
|
if (options2.journal && !options2.repository)
|
|
3750
3851
|
throw new Error("durable operation journal requires an archive repository");
|
|
3751
3852
|
if (options2.cors) {
|
|
@@ -4017,6 +4118,7 @@ var httpChild = async (target, entry, options2, admission, generation, privateAc
|
|
|
4017
4118
|
options2.onLog?.(entry2);
|
|
4018
4119
|
},
|
|
4019
4120
|
...entry.adminControls !== void 0 ? { adminControls: entry.adminControls } : {},
|
|
4121
|
+
...entry.settings !== void 0 ? { settings: checkSettings(target, entry.settings, "settings") } : {},
|
|
4020
4122
|
...entry.fixtures !== void 0 ? { fixtures: entry.fixtures } : {},
|
|
4021
4123
|
...(advertisedHttpBase(entry) ?? entry.baseUrl) !== void 0 ? { baseUrl: advertisedHttpBase(entry) ?? entry.baseUrl } : {}
|
|
4022
4124
|
});
|
|
@@ -4035,6 +4137,8 @@ var httpChild = async (target, entry, options2, admission, generation, privateAc
|
|
|
4035
4137
|
].some((method) => typeof created[method] !== "function"))
|
|
4036
4138
|
throw new Error("HTTP target does not implement the fleet runtime protocol; build/install matching supported service versions");
|
|
4037
4139
|
const runtime = created;
|
|
4140
|
+
if (entry.idBase !== void 0)
|
|
4141
|
+
runtime.setIdBase?.(entry.idBase);
|
|
4038
4142
|
const unobserve = runtime.webhooks?.observeDeliveries(observer.delivery);
|
|
4039
4143
|
if (options2.outbound && runtime.webhooks)
|
|
4040
4144
|
runtime.webhooks.setTransportPolicy(ownedTransport(options2.outbound));
|
|
@@ -4633,6 +4737,7 @@ async function startFleet(config, options2) {
|
|
|
4633
4737
|
...entry,
|
|
4634
4738
|
adminPrefix: resolveAdminPrefix(entry.adminPrefix ?? adminPrefix),
|
|
4635
4739
|
...adminKey !== void 0 ? { adminKey } : {},
|
|
4740
|
+
...(entry.idBase ?? config.idBase) !== void 0 ? { idBase: entry.idBase ?? config.idBase } : {},
|
|
4636
4741
|
// Fleet-wide controls, with the service's own keys replacing them.
|
|
4637
4742
|
...config.adminControls !== void 0 || entry.adminControls !== void 0 ? { adminControls: { ...config.adminControls, ...entry.adminControls } } : {}
|
|
4638
4743
|
}, options2, (namespace, request) => management?.admit(namespace, request), (namespace) => management?.generation(namespace), (namespace, request) => management?.privateRequest(namespace, request) ?? false, {
|
|
@@ -4738,10 +4843,44 @@ async function startFleet(config, options2) {
|
|
|
4738
4843
|
}
|
|
4739
4844
|
}
|
|
4740
4845
|
|
|
4741
|
-
// ../../adapters/node/dist/fleet-
|
|
4742
|
-
import { readFile as readFile4 } from "node:fs/promises";
|
|
4846
|
+
// ../../adapters/node/dist/fleet-loader.js
|
|
4743
4847
|
import { createRequire as createRequire2 } from "node:module";
|
|
4744
4848
|
import { resolve as resolve2 } from "node:path";
|
|
4849
|
+
import { pathToFileURL } from "node:url";
|
|
4850
|
+
var suffix = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4851
|
+
function createInstalledServiceLoader(options2) {
|
|
4852
|
+
if (!options2.projectRoot)
|
|
4853
|
+
throw new Error("consumer projectRoot required");
|
|
4854
|
+
const allowed = new Set(options2.services);
|
|
4855
|
+
for (const name2 of allowed)
|
|
4856
|
+
if (!suffix.test(name2))
|
|
4857
|
+
throw new Error("invalid service suffix");
|
|
4858
|
+
const require2 = createRequire2(resolve2(options2.projectRoot, "package.json"));
|
|
4859
|
+
const targets = new Map((options2.targets ?? []).map((target) => [target.name, target]));
|
|
4860
|
+
return async (name2) => {
|
|
4861
|
+
if (!suffix.test(name2) || !allowed.has(name2))
|
|
4862
|
+
throw new Error("service is not declared in loader allowlist");
|
|
4863
|
+
const own2 = targets.get(name2);
|
|
4864
|
+
if (own2)
|
|
4865
|
+
return own2;
|
|
4866
|
+
const specifier = `@crvouga/mockingbird-service-${name2}/server`;
|
|
4867
|
+
let location;
|
|
4868
|
+
try {
|
|
4869
|
+
location = require2.resolve(specifier);
|
|
4870
|
+
} catch {
|
|
4871
|
+
throw new Error(`cannot load service "${name2}": install @crvouga/mockingbird-service-${name2} in the consumer project; its /server export is required`);
|
|
4872
|
+
}
|
|
4873
|
+
const mod = await import(pathToFileURL(location).href);
|
|
4874
|
+
if (!mod.serveTarget || mod.serveTarget.name !== name2 || ("protocol" in mod.serveTarget ? typeof mod.serveTarget.start !== "function" : typeof mod.serveTarget.create !== "function"))
|
|
4875
|
+
throw new Error(`${specifier} exports no matching serveTarget`);
|
|
4876
|
+
return mod.serveTarget;
|
|
4877
|
+
};
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4880
|
+
// ../../adapters/node/dist/fleet-tools.js
|
|
4881
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
4882
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
4883
|
+
import { resolve as resolve3 } from "node:path";
|
|
4745
4884
|
|
|
4746
4885
|
// ../../adapters/node/dist/fleet-client.js
|
|
4747
4886
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
@@ -4755,6 +4894,14 @@ var FleetClientError = class extends Error {
|
|
|
4755
4894
|
this.details = details;
|
|
4756
4895
|
}
|
|
4757
4896
|
};
|
|
4897
|
+
var FleetClientResponseError = class extends FleetClientError {
|
|
4898
|
+
code;
|
|
4899
|
+
constructor(code, status, origin) {
|
|
4900
|
+
super(status, { code, body: "omitted", ...origin ? { origin } : {} });
|
|
4901
|
+
this.code = code;
|
|
4902
|
+
this.name = "FleetClientResponseError";
|
|
4903
|
+
}
|
|
4904
|
+
};
|
|
4758
4905
|
var FleetClient = class {
|
|
4759
4906
|
base;
|
|
4760
4907
|
options;
|
|
@@ -4767,7 +4914,14 @@ var FleetClient = class {
|
|
|
4767
4914
|
if (url.username || url.password)
|
|
4768
4915
|
throw new Error("fleet client URL must not contain credentials");
|
|
4769
4916
|
url.searchParams.set("namespace", options2.namespace ?? this.options.namespace ?? "default");
|
|
4917
|
+
const limit = options2.maxResponseBytes ?? this.options.maxResponseBytes ?? 64 * 1024 * 1024;
|
|
4918
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
4919
|
+
throw new Error("invalid response byte limit");
|
|
4920
|
+
const deadline = AbortSignal.timeout(this.options.timeoutMs ?? 3e4);
|
|
4921
|
+
const signal = options2.signal ? AbortSignal.any([options2.signal, deadline]) : deadline;
|
|
4922
|
+
signal.throwIfAborted();
|
|
4770
4923
|
const response = await (this.options.fetch ?? fetch)(url, {
|
|
4924
|
+
redirect: "manual",
|
|
4771
4925
|
method: options2.method ?? (options2.body === void 0 ? "GET" : "POST"),
|
|
4772
4926
|
headers: {
|
|
4773
4927
|
"content-type": "application/json",
|
|
@@ -4775,11 +4929,71 @@ var FleetClient = class {
|
|
|
4775
4929
|
...options2.idempotencyKey ? { "idempotency-key": options2.idempotencyKey } : {}
|
|
4776
4930
|
},
|
|
4777
4931
|
...options2.body !== void 0 ? { body: JSON.stringify(options2.body) } : {},
|
|
4778
|
-
signal
|
|
4932
|
+
signal
|
|
4779
4933
|
});
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
throw new
|
|
4934
|
+
if (response.status >= 300 && response.status < 400) {
|
|
4935
|
+
await response.body?.cancel();
|
|
4936
|
+
throw new FleetClientResponseError("redirect", response.status, url.origin);
|
|
4937
|
+
}
|
|
4938
|
+
if (Number(response.headers.get("content-length")) > limit) {
|
|
4939
|
+
await response.body?.cancel();
|
|
4940
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4941
|
+
}
|
|
4942
|
+
const reader = response.body?.getReader();
|
|
4943
|
+
const chunks = [];
|
|
4944
|
+
let size = 0;
|
|
4945
|
+
const abort = () => {
|
|
4946
|
+
void reader?.cancel(signal.reason).catch(() => {
|
|
4947
|
+
});
|
|
4948
|
+
};
|
|
4949
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
4950
|
+
try {
|
|
4951
|
+
if (reader)
|
|
4952
|
+
while (true) {
|
|
4953
|
+
signal.throwIfAborted();
|
|
4954
|
+
const { done, value } = await reader.read();
|
|
4955
|
+
signal.throwIfAborted();
|
|
4956
|
+
if (done)
|
|
4957
|
+
break;
|
|
4958
|
+
size += value.byteLength;
|
|
4959
|
+
if (size > limit) {
|
|
4960
|
+
await reader.cancel();
|
|
4961
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4962
|
+
}
|
|
4963
|
+
chunks.push(value);
|
|
4964
|
+
}
|
|
4965
|
+
} finally {
|
|
4966
|
+
signal.removeEventListener("abort", abort);
|
|
4967
|
+
if (signal.aborted)
|
|
4968
|
+
await reader?.cancel(signal.reason).catch(() => {
|
|
4969
|
+
});
|
|
4970
|
+
reader?.releaseLock();
|
|
4971
|
+
}
|
|
4972
|
+
const bytes = new Uint8Array(size);
|
|
4973
|
+
let offset = 0;
|
|
4974
|
+
for (const chunk of chunks) {
|
|
4975
|
+
bytes.set(chunk, offset);
|
|
4976
|
+
offset += chunk.byteLength;
|
|
4977
|
+
}
|
|
4978
|
+
const text = new TextDecoder().decode(bytes);
|
|
4979
|
+
let data;
|
|
4980
|
+
try {
|
|
4981
|
+
data = text.length ? JSON.parse(text) : void 0;
|
|
4982
|
+
} catch {
|
|
4983
|
+
if (response.ok)
|
|
4984
|
+
throw new FleetClientResponseError("invalid_json", response.status);
|
|
4985
|
+
}
|
|
4986
|
+
if (!response.ok) {
|
|
4987
|
+
const error = data && typeof data === "object" ? data.error : void 0;
|
|
4988
|
+
const detail = { body: "omitted" };
|
|
4989
|
+
if (error && typeof error === "object")
|
|
4990
|
+
for (const key of ["type", "code"]) {
|
|
4991
|
+
const value = error[key];
|
|
4992
|
+
if (typeof value === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(value))
|
|
4993
|
+
detail[key] = value;
|
|
4994
|
+
}
|
|
4995
|
+
throw new FleetClientError(response.status, detail);
|
|
4996
|
+
}
|
|
4783
4997
|
return data;
|
|
4784
4998
|
}
|
|
4785
4999
|
discover() {
|
|
@@ -4845,17 +5059,52 @@ function renderConnections(manifest, privateManifest, namespace, mapping) {
|
|
|
4845
5059
|
const child = manifest.services[entry.service], secret = privateManifest.services[entry.service];
|
|
4846
5060
|
if (!child || !secret)
|
|
4847
5061
|
throw new Error(`missing service mapping ${entry.service}`);
|
|
5062
|
+
let endpoint;
|
|
4848
5063
|
if (child.protocol === "http") {
|
|
4849
5064
|
const template = child.namespaces.path;
|
|
4850
5065
|
if (typeof template !== "string")
|
|
4851
5066
|
throw new Error(`missing HTTP namespace mapping ${entry.service}`);
|
|
4852
|
-
|
|
5067
|
+
endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
|
|
4853
5068
|
} else {
|
|
4854
|
-
const
|
|
4855
|
-
if (!
|
|
5069
|
+
const selected = secret.namespaces?.[namespace];
|
|
5070
|
+
if (!selected)
|
|
4856
5071
|
throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
|
|
4857
|
-
|
|
5072
|
+
endpoint = selected;
|
|
5073
|
+
}
|
|
5074
|
+
const url = new URL(endpoint);
|
|
5075
|
+
const field = entry.field ?? "url";
|
|
5076
|
+
let value;
|
|
5077
|
+
switch (field) {
|
|
5078
|
+
case "url":
|
|
5079
|
+
value = endpoint;
|
|
5080
|
+
break;
|
|
5081
|
+
case "hostname":
|
|
5082
|
+
value = url.hostname.replace(/^\[|\]$/g, "");
|
|
5083
|
+
break;
|
|
5084
|
+
case "port":
|
|
5085
|
+
value = url.port;
|
|
5086
|
+
break;
|
|
5087
|
+
case "username":
|
|
5088
|
+
value = decodeURIComponent(url.username);
|
|
5089
|
+
break;
|
|
5090
|
+
case "password":
|
|
5091
|
+
value = decodeURIComponent(url.password);
|
|
5092
|
+
break;
|
|
5093
|
+
case "pathname":
|
|
5094
|
+
value = decodeURIComponent(url.pathname);
|
|
5095
|
+
break;
|
|
5096
|
+
case "database":
|
|
5097
|
+
value = decodeURIComponent(url.pathname.replace(/^\//, ""));
|
|
5098
|
+
break;
|
|
5099
|
+
default:
|
|
5100
|
+
throw new Error("unsupported connection field");
|
|
5101
|
+
}
|
|
5102
|
+
if (!value) {
|
|
5103
|
+
if (typeof entry.fallback !== "string")
|
|
5104
|
+
throw new Error(`missing connection component ${field}`);
|
|
5105
|
+
value = entry.fallback;
|
|
4858
5106
|
}
|
|
5107
|
+
result[variable] = value;
|
|
4859
5108
|
}
|
|
4860
5109
|
return result;
|
|
4861
5110
|
}
|
|
@@ -4879,7 +5128,7 @@ async function doctorFleet(config, options2, probes = []) {
|
|
|
4879
5128
|
const plan = [];
|
|
4880
5129
|
try {
|
|
4881
5130
|
const targets = await preflightFleet(config, options2);
|
|
4882
|
-
const require2 =
|
|
5131
|
+
const require2 = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
4883
5132
|
for (const [service, target] of targets) {
|
|
4884
5133
|
let version = "development";
|
|
4885
5134
|
try {
|
|
@@ -4934,7 +5183,7 @@ async function doctorFleet(config, options2, probes = []) {
|
|
|
4934
5183
|
};
|
|
4935
5184
|
}
|
|
4936
5185
|
async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3e4) {
|
|
4937
|
-
const archive =
|
|
5186
|
+
const archive = assertArchiveCompatibility(input, options2.archiveCompatibility);
|
|
4938
5187
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4939
5188
|
const isolated = {
|
|
4940
5189
|
...config,
|
|
@@ -4946,7 +5195,7 @@ async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3
|
|
|
4946
5195
|
};
|
|
4947
5196
|
let fleet;
|
|
4948
5197
|
try {
|
|
4949
|
-
fleet = await startFleet(isolated,
|
|
5198
|
+
fleet = await startFleet(isolated, options2);
|
|
4950
5199
|
const client = new FleetClient(fleet.manifest.adminBase, {
|
|
4951
5200
|
...config.adminKey ? { adminKey: config.adminKey } : {}
|
|
4952
5201
|
});
|
|
@@ -5173,6 +5422,16 @@ var COMMON_SERVE_OPTIONS = {
|
|
|
5173
5422
|
value: "<seed>",
|
|
5174
5423
|
description: "Seed for every random choice (env MOCKINGBIRD_SEED)"
|
|
5175
5424
|
},
|
|
5425
|
+
"id-base": {
|
|
5426
|
+
type: "string",
|
|
5427
|
+
value: "<n|boot>",
|
|
5428
|
+
description: "Start generated ids at this base so a restart does not reissue the last boot's ids; boot derives one from the clock (env MOCKINGBIRD_ID_BASE; default 0, the same ids every boot)"
|
|
5429
|
+
},
|
|
5430
|
+
settings: {
|
|
5431
|
+
type: "string",
|
|
5432
|
+
value: "<json|file>",
|
|
5433
|
+
description: "Service settings to boot with, as JSON or a JSON file; every namespace starts from them (env MOCKINGBIRD_SETTINGS; only for services that declare settings)"
|
|
5434
|
+
},
|
|
5176
5435
|
"admin-controls": {
|
|
5177
5436
|
type: "string",
|
|
5178
5437
|
value: "<json|file>",
|
|
@@ -5267,19 +5526,40 @@ var readJsonFile = async (path, label) => {
|
|
|
5267
5526
|
}
|
|
5268
5527
|
};
|
|
5269
5528
|
var isObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5529
|
+
var readJsonOption = async (source, label) => {
|
|
5530
|
+
const trimmed = source.trim();
|
|
5531
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
5532
|
+
try {
|
|
5533
|
+
return JSON.parse(trimmed);
|
|
5534
|
+
} catch {
|
|
5535
|
+
throw new Error(`${label}: not valid JSON`);
|
|
5536
|
+
}
|
|
5537
|
+
}
|
|
5538
|
+
return readJsonFile(source, label);
|
|
5539
|
+
};
|
|
5540
|
+
var resolveServeIdBase = (values, env = process.env) => {
|
|
5541
|
+
const source = asString(values["id-base"]) ?? env.MOCKINGBIRD_ID_BASE;
|
|
5542
|
+
if (source === void 0 || source.trim() === "")
|
|
5543
|
+
return void 0;
|
|
5544
|
+
normalizeIdBase(source.trim(), "--id-base");
|
|
5545
|
+
return source.trim();
|
|
5546
|
+
};
|
|
5547
|
+
var resolveServeSettings = async (target, values, env = process.env) => {
|
|
5548
|
+
const flag2 = asString(values.settings);
|
|
5549
|
+
const source = flag2 ?? env.MOCKINGBIRD_SETTINGS;
|
|
5550
|
+
if (source === void 0 || source.trim() === "")
|
|
5551
|
+
return void 0;
|
|
5552
|
+
const label = flag2 !== void 0 ? "--settings" : "MOCKINGBIRD_SETTINGS";
|
|
5553
|
+
const parsed = await readJsonOption(source, label);
|
|
5554
|
+
if (!isObject2(parsed))
|
|
5555
|
+
throw new Error(`${label}: expected a JSON object`);
|
|
5556
|
+
return checkSettings(target, parsed, label);
|
|
5557
|
+
};
|
|
5270
5558
|
var resolveServeControls = async (values, env = process.env, base) => {
|
|
5271
5559
|
const source = asString(values["admin-controls"]) ?? env.MOCKINGBIRD_ADMIN_CONTROLS;
|
|
5272
5560
|
let document = isObject2(base) ? { ...base } : {};
|
|
5273
5561
|
if (source !== void 0 && source.trim() !== "") {
|
|
5274
|
-
|
|
5275
|
-
if (source.trim().startsWith("{")) {
|
|
5276
|
-
try {
|
|
5277
|
-
parsed = JSON.parse(source);
|
|
5278
|
-
} catch {
|
|
5279
|
-
throw new Error("--admin-controls: not valid JSON");
|
|
5280
|
-
}
|
|
5281
|
-
} else
|
|
5282
|
-
parsed = await readJsonFile(source, "--admin-controls");
|
|
5562
|
+
const parsed = source.trim().startsWith("{") ? await readJsonOption(source, "--admin-controls") : await readJsonFile(source, "--admin-controls");
|
|
5283
5563
|
if (!isObject2(parsed))
|
|
5284
5564
|
throw new Error("--admin-controls: expected a JSON object");
|
|
5285
5565
|
document = { ...document, ...parsed };
|
|
@@ -5321,26 +5601,7 @@ var resolveServeControls = async (values, env = process.env, base) => {
|
|
|
5321
5601
|
normalizeBootControls(document, "adminControls");
|
|
5322
5602
|
return document;
|
|
5323
5603
|
};
|
|
5324
|
-
var loadTarget =
|
|
5325
|
-
if (name2 === own2.name)
|
|
5326
|
-
return own2;
|
|
5327
|
-
const specifier = `@crvouga/mockingbird-service-${name2}/server`;
|
|
5328
|
-
try {
|
|
5329
|
-
let mod;
|
|
5330
|
-
try {
|
|
5331
|
-
mod = await import(specifier);
|
|
5332
|
-
} catch {
|
|
5333
|
-
const fromProject = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
5334
|
-
mod = await import(pathToFileURL(fromProject.resolve(specifier)).href);
|
|
5335
|
-
}
|
|
5336
|
-
if (!mod.serveTarget)
|
|
5337
|
-
throw new Error(`${specifier} exports no serveTarget`);
|
|
5338
|
-
return mod.serveTarget;
|
|
5339
|
-
} catch (error) {
|
|
5340
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
5341
|
-
throw new Error(`cannot load service "${name2}": ${reason}. Install @crvouga/mockingbird-service-${name2}.`);
|
|
5342
|
-
}
|
|
5343
|
-
};
|
|
5604
|
+
var loadTarget = (name2, own2) => createInstalledServiceLoader({ projectRoot: process.cwd(), services: [name2], targets: [own2] })(name2);
|
|
5344
5605
|
var start = async (target, values, config) => {
|
|
5345
5606
|
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
5346
5607
|
const runtime = await target.create(values, {
|
|
@@ -5348,8 +5609,11 @@ var start = async (target, values, config) => {
|
|
|
5348
5609
|
adminKey: config.adminKey,
|
|
5349
5610
|
seed: config.seed,
|
|
5350
5611
|
onLog: formatLog(config.log),
|
|
5612
|
+
...config.settings !== void 0 ? { settings: config.settings } : {},
|
|
5351
5613
|
...config.adminControls !== void 0 ? { adminControls: config.adminControls } : {}
|
|
5352
5614
|
});
|
|
5615
|
+
if (config.idBase !== void 0)
|
|
5616
|
+
runtime.setIdBase?.(config.idBase);
|
|
5353
5617
|
const listening = await listen(runtime, { port: config.port, host: config.host });
|
|
5354
5618
|
target.listening?.(listening);
|
|
5355
5619
|
console.log(`${target.name} emulator listening on ${listening.url}`);
|
|
@@ -5395,6 +5659,11 @@ var serveCommand = (target) => ({
|
|
|
5395
5659
|
const adminControls = await resolveServeControls(values, process.env, config.adminControls);
|
|
5396
5660
|
if (adminControls !== void 0)
|
|
5397
5661
|
config.adminControls = adminControls;
|
|
5662
|
+
if (values.settings !== void 0)
|
|
5663
|
+
throw new Error("--settings serves a single service; give each service its own `settings` in the config");
|
|
5664
|
+
const idBase = config.idBase ?? resolveServeIdBase(values);
|
|
5665
|
+
if (idBase !== void 0)
|
|
5666
|
+
config.idBase = idBase;
|
|
5398
5667
|
const fleet = await startFleet(config, {
|
|
5399
5668
|
load: (name2) => loadTarget(name2, target),
|
|
5400
5669
|
onLog: formatLog(config.log ?? log2),
|
|
@@ -5424,8 +5693,12 @@ var serveCommand = (target) => ({
|
|
|
5424
5693
|
let listening;
|
|
5425
5694
|
try {
|
|
5426
5695
|
const adminControls = await resolveServeControls(values);
|
|
5696
|
+
const idBase = resolveServeIdBase(values);
|
|
5697
|
+
const settings = await resolveServeSettings(target, values);
|
|
5427
5698
|
listening = await start(target, values, {
|
|
5428
5699
|
...adminControls !== void 0 ? { adminControls } : {},
|
|
5700
|
+
...idBase !== void 0 ? { idBase } : {},
|
|
5701
|
+
...settings !== void 0 ? { settings } : {},
|
|
5429
5702
|
adminPrefix: resolveAdminPrefix(asString(values["admin-prefix"]) ?? process.env.MOCKINGBIRD_ADMIN_PREFIX),
|
|
5430
5703
|
port: port === void 0 ? target.defaultPort : Number.parseInt(port, 10),
|
|
5431
5704
|
host: asString(values.host) ?? "127.0.0.1",
|
|
@@ -5786,9 +6059,9 @@ function stemEnglish(input) {
|
|
|
5786
6059
|
return false;
|
|
5787
6060
|
})();
|
|
5788
6061
|
if (!step1bDone) {
|
|
5789
|
-
for (const
|
|
5790
|
-
if (w.endsWith(
|
|
5791
|
-
const stem = w.slice(0, -
|
|
6062
|
+
for (const suffix2 of ["ingly", "edly", "ing", "ed"]) {
|
|
6063
|
+
if (w.endsWith(suffix2)) {
|
|
6064
|
+
const stem = w.slice(0, -suffix2.length);
|
|
5792
6065
|
if ([...stem].some(isVowel)) {
|
|
5793
6066
|
w = stem;
|
|
5794
6067
|
if (w.endsWith("at") || w.endsWith("bl") || w.endsWith("iz")) w += "e";
|
|
@@ -5826,9 +6099,9 @@ function stemEnglish(input) {
|
|
|
5826
6099
|
["alli", "al"],
|
|
5827
6100
|
["bli", "ble"]
|
|
5828
6101
|
];
|
|
5829
|
-
for (const [
|
|
5830
|
-
if (w.endsWith(
|
|
5831
|
-
if (w.length -
|
|
6102
|
+
for (const [suffix2, repl] of step2) {
|
|
6103
|
+
if (w.endsWith(suffix2)) {
|
|
6104
|
+
if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
|
|
5832
6105
|
break;
|
|
5833
6106
|
}
|
|
5834
6107
|
}
|
|
@@ -5847,9 +6120,9 @@ function stemEnglish(input) {
|
|
|
5847
6120
|
["ness", ""],
|
|
5848
6121
|
["ful", ""]
|
|
5849
6122
|
];
|
|
5850
|
-
for (const [
|
|
5851
|
-
if (w.endsWith(
|
|
5852
|
-
if (w.length -
|
|
6123
|
+
for (const [suffix2, repl] of step3) {
|
|
6124
|
+
if (w.endsWith(suffix2)) {
|
|
6125
|
+
if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
|
|
5853
6126
|
break;
|
|
5854
6127
|
}
|
|
5855
6128
|
}
|
|
@@ -5875,9 +6148,9 @@ function stemEnglish(input) {
|
|
|
5875
6148
|
"er",
|
|
5876
6149
|
"ic"
|
|
5877
6150
|
];
|
|
5878
|
-
for (const
|
|
5879
|
-
if (w.endsWith(
|
|
5880
|
-
if (w.length -
|
|
6151
|
+
for (const suffix2 of step4) {
|
|
6152
|
+
if (w.endsWith(suffix2)) {
|
|
6153
|
+
if (w.length - suffix2.length >= r2) w = w.slice(0, -suffix2.length);
|
|
5881
6154
|
break;
|
|
5882
6155
|
}
|
|
5883
6156
|
}
|
|
@@ -8085,6 +8358,12 @@ var invalidName = () => {
|
|
|
8085
8358
|
throw pgError("syntax", "invalid name syntax", "42602");
|
|
8086
8359
|
};
|
|
8087
8360
|
function parseNamespaceInput(text) {
|
|
8361
|
+
const parsed = parseRelationInput(text);
|
|
8362
|
+
if ("oid" in parsed) return parsed;
|
|
8363
|
+
if (parsed.parts.length !== 1) invalidName();
|
|
8364
|
+
return { name: parsed.parts[0] };
|
|
8365
|
+
}
|
|
8366
|
+
function parseRelationInput(text) {
|
|
8088
8367
|
if (text === "-") return { oid: 0 };
|
|
8089
8368
|
if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
|
|
8090
8369
|
const names = [];
|
|
@@ -8120,8 +8399,8 @@ function parseNamespaceInput(text) {
|
|
|
8120
8399
|
skipSpace();
|
|
8121
8400
|
if (at === text.length) invalidName();
|
|
8122
8401
|
}
|
|
8123
|
-
if (names.length
|
|
8124
|
-
return {
|
|
8402
|
+
if (names.length === 0 || names.length > 3) invalidName();
|
|
8403
|
+
return { parts: names };
|
|
8125
8404
|
}
|
|
8126
8405
|
function namespaceText(oid, name2) {
|
|
8127
8406
|
if (oid === 0) return "-";
|
|
@@ -8194,6 +8473,7 @@ var TYPE_ALIASES = {
|
|
|
8194
8473
|
regtype: "regtype",
|
|
8195
8474
|
regproc: "regproc",
|
|
8196
8475
|
regnamespace: "regnamespace",
|
|
8476
|
+
xid: "xid",
|
|
8197
8477
|
oid: "oid",
|
|
8198
8478
|
void: "void",
|
|
8199
8479
|
record: "record",
|
|
@@ -8270,6 +8550,7 @@ var TYPE_OIDS = {
|
|
|
8270
8550
|
regproc: 24,
|
|
8271
8551
|
text: 25,
|
|
8272
8552
|
oid: 26,
|
|
8553
|
+
xid: 28,
|
|
8273
8554
|
json: 114,
|
|
8274
8555
|
float4: 700,
|
|
8275
8556
|
float8: 701,
|
|
@@ -8589,6 +8870,7 @@ function recordText(rec, ctx) {
|
|
|
8589
8870
|
return `(${parts.join(",")})`;
|
|
8590
8871
|
}
|
|
8591
8872
|
function datumText(t, v, ctx) {
|
|
8873
|
+
if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
|
|
8592
8874
|
if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
|
|
8593
8875
|
if (v === null) throw pgError("internal", "datumText called with null");
|
|
8594
8876
|
if (isArrayType(t)) return arrayText(v, ctx);
|
|
@@ -8599,6 +8881,7 @@ function datumText(t, v, ctx) {
|
|
|
8599
8881
|
case "int2":
|
|
8600
8882
|
case "int4":
|
|
8601
8883
|
case "oid":
|
|
8884
|
+
case "xid":
|
|
8602
8885
|
return String(v);
|
|
8603
8886
|
case "int8":
|
|
8604
8887
|
return String(v);
|
|
@@ -8663,6 +8946,12 @@ function datumText(t, v, ctx) {
|
|
|
8663
8946
|
}
|
|
8664
8947
|
var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
|
|
8665
8948
|
function datumFromText(t, text, ctx) {
|
|
8949
|
+
if (t === "regclass") {
|
|
8950
|
+
const parsed = parseRelationInput(text);
|
|
8951
|
+
if ("oid" in parsed) return parsed.oid;
|
|
8952
|
+
if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
|
|
8953
|
+
return ctx.relationOid(parsed.parts);
|
|
8954
|
+
}
|
|
8666
8955
|
if (t === "regnamespace") {
|
|
8667
8956
|
const parsed = parseNamespaceInput(text);
|
|
8668
8957
|
if ("oid" in parsed) return parsed.oid;
|
|
@@ -8684,6 +8973,7 @@ function datumFromText(t, text, ctx) {
|
|
|
8684
8973
|
case "int8":
|
|
8685
8974
|
return parseIntegerText(text, t);
|
|
8686
8975
|
case "oid":
|
|
8976
|
+
case "xid":
|
|
8687
8977
|
return parseOidText(text);
|
|
8688
8978
|
case "float4":
|
|
8689
8979
|
return Math.fround(parseFloatText(text, "float4"));
|
|
@@ -8840,6 +9130,8 @@ var TableData = class _TableData {
|
|
|
8840
9130
|
schema;
|
|
8841
9131
|
columns;
|
|
8842
9132
|
rows;
|
|
9133
|
+
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
9134
|
+
slabXmins = null;
|
|
8843
9135
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
8844
9136
|
slab = null;
|
|
8845
9137
|
constraints;
|
|
@@ -8882,6 +9174,11 @@ var TableData = class _TableData {
|
|
|
8882
9174
|
materializeSlab() {
|
|
8883
9175
|
if (!this.slab) return;
|
|
8884
9176
|
this.rows = this.slab.materialize();
|
|
9177
|
+
if (this.slabXmins)
|
|
9178
|
+
this.rows.forEach((row, index) => {
|
|
9179
|
+
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
9180
|
+
});
|
|
9181
|
+
this.slabXmins = null;
|
|
8885
9182
|
this.slab = null;
|
|
8886
9183
|
this.indexStores = null;
|
|
8887
9184
|
}
|
|
@@ -8915,6 +9212,10 @@ var TableData = class _TableData {
|
|
|
8915
9212
|
} else {
|
|
8916
9213
|
t.rows = this.rows.map((r) => r.slice());
|
|
8917
9214
|
}
|
|
9215
|
+
t.rows.forEach((row, index) => {
|
|
9216
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
|
|
9217
|
+
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
9218
|
+
});
|
|
8918
9219
|
t.unlogged = this.unlogged;
|
|
8919
9220
|
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
8920
9221
|
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
@@ -9000,6 +9301,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
9000
9301
|
clock;
|
|
9001
9302
|
changes = 0;
|
|
9002
9303
|
oidCounter = 16384;
|
|
9304
|
+
/** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
|
|
9305
|
+
xidCounter = 3;
|
|
9306
|
+
transactionXid = null;
|
|
9307
|
+
allocateXid() {
|
|
9308
|
+
if (this.xidCounter > 4294967295)
|
|
9309
|
+
throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
|
|
9310
|
+
return this.xidCounter++;
|
|
9311
|
+
}
|
|
9003
9312
|
inTransaction = false;
|
|
9004
9313
|
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
9005
9314
|
pendingTriggers = [];
|
|
@@ -9213,6 +9522,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9213
9522
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
9214
9523
|
s.tableStats = new Map(this.tableStats);
|
|
9215
9524
|
s.oidCounter = this.oidCounter;
|
|
9525
|
+
s.xidCounter = this.xidCounter;
|
|
9526
|
+
s.transactionXid = this.transactionXid;
|
|
9216
9527
|
for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
|
|
9217
9528
|
return s;
|
|
9218
9529
|
}
|
|
@@ -9232,6 +9543,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9232
9543
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
9233
9544
|
s.tableStats = new Map(this.tableStats);
|
|
9234
9545
|
s.oidCounter = this.oidCounter;
|
|
9546
|
+
s.xidCounter = this.xidCounter;
|
|
9547
|
+
s.transactionXid = this.transactionXid;
|
|
9235
9548
|
for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
|
|
9236
9549
|
return s;
|
|
9237
9550
|
}
|
|
@@ -9307,6 +9620,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9307
9620
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
9308
9621
|
this.tableStats = other.tableStats;
|
|
9309
9622
|
this.oidCounter = other.oidCounter;
|
|
9623
|
+
this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
|
|
9624
|
+
this.transactionXid = other.transactionXid;
|
|
9310
9625
|
}
|
|
9311
9626
|
/** @internal Snapshot codec access to the oid allocator. */
|
|
9312
9627
|
snapshotOidCounter() {
|
|
@@ -9386,6 +9701,11 @@ function validateZone(zone) {
|
|
|
9386
9701
|
// src/expressions/context.ts
|
|
9387
9702
|
var EngineCtx = class {
|
|
9388
9703
|
state;
|
|
9704
|
+
writeXid = null;
|
|
9705
|
+
rowVersionXid() {
|
|
9706
|
+
if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
|
|
9707
|
+
return this.writeXid ??= this.state.allocateXid();
|
|
9708
|
+
}
|
|
9389
9709
|
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
9390
9710
|
txNow;
|
|
9391
9711
|
/** statement timestamp */
|
|
@@ -9400,6 +9720,23 @@ var EngineCtx = class {
|
|
|
9400
9720
|
timezone() {
|
|
9401
9721
|
return this.state.getSetting("timezone") ?? "UTC";
|
|
9402
9722
|
}
|
|
9723
|
+
relationOid(parts) {
|
|
9724
|
+
const target = this.state.resolveRelationSchema(parts);
|
|
9725
|
+
const schema = target ? this.state.schemas.get(target.schema) : void 0;
|
|
9726
|
+
const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
|
|
9727
|
+
if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
|
|
9728
|
+
return relation.oid;
|
|
9729
|
+
}
|
|
9730
|
+
relationName(oid) {
|
|
9731
|
+
for (const schema of this.state.schemas.values()) {
|
|
9732
|
+
for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
|
|
9733
|
+
if (relation.oid !== oid) continue;
|
|
9734
|
+
const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
|
|
9735
|
+
return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
|
|
9736
|
+
}
|
|
9737
|
+
}
|
|
9738
|
+
return null;
|
|
9739
|
+
}
|
|
9403
9740
|
namespaceOid(name2) {
|
|
9404
9741
|
const oid = builtinNamespaceOid(name2) ?? this.state.schemas.get(name2)?.oid;
|
|
9405
9742
|
if (oid === void 0) throw pgError("undefined_object", `schema "${name2}" does not exist`, "3F000");
|
|
@@ -9700,7 +10037,7 @@ function castTo(env, value, target, opts = {}) {
|
|
|
9700
10037
|
return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
|
|
9701
10038
|
}
|
|
9702
10039
|
if (from === "oid" && target === "regnamespace") return tv(target, v);
|
|
9703
|
-
if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
|
|
10040
|
+
if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
|
|
9704
10041
|
return tv(target, target === "int8" ? BigInt(v) : v);
|
|
9705
10042
|
}
|
|
9706
10043
|
if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
|
|
@@ -10401,6 +10738,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
|
|
|
10401
10738
|
case "int2":
|
|
10402
10739
|
case "int4":
|
|
10403
10740
|
case "oid":
|
|
10741
|
+
case "regclass":
|
|
10742
|
+
case "xid":
|
|
10404
10743
|
case "regnamespace":
|
|
10405
10744
|
case "date":
|
|
10406
10745
|
return expectNumber(a, t) - expectNumber(b, t);
|
|
@@ -10520,6 +10859,8 @@ function datumKey(t, v) {
|
|
|
10520
10859
|
case "int2":
|
|
10521
10860
|
case "int4":
|
|
10522
10861
|
case "oid":
|
|
10862
|
+
case "regclass":
|
|
10863
|
+
case "xid":
|
|
10523
10864
|
case "date":
|
|
10524
10865
|
return `i${v}`;
|
|
10525
10866
|
case "float4":
|
|
@@ -11403,8 +11744,8 @@ function toCharTimestamp(ctx, localMicros, fmt, tzOffsetSec) {
|
|
|
11403
11744
|
else if (tryPat("TH") || tryPat("th")) {
|
|
11404
11745
|
const prev = /(\d+)$/.exec(out);
|
|
11405
11746
|
const n = prev ? Number.parseInt(prev[1], 10) : 0;
|
|
11406
|
-
const
|
|
11407
|
-
out += rest.startsWith("TH") ?
|
|
11747
|
+
const suffix2 = ordinalSuffix(n);
|
|
11748
|
+
out += rest.startsWith("TH") ? suffix2.toUpperCase() : suffix2;
|
|
11408
11749
|
} else {
|
|
11409
11750
|
out += fmt[i];
|
|
11410
11751
|
i++;
|
|
@@ -12623,7 +12964,7 @@ function claimConstraintIndexName(schema, constraint, explicit, reserved = /* @_
|
|
|
12623
12964
|
if (used(constraint.name)) {
|
|
12624
12965
|
if (explicit) throw pgError("duplicate_table", `relation "${constraint.name}" already exists`, "42P07");
|
|
12625
12966
|
const base = constraint.name;
|
|
12626
|
-
for (let
|
|
12967
|
+
for (let suffix2 = 1; used(constraint.name); suffix2++) constraint.name = `${base}${suffix2}`;
|
|
12627
12968
|
}
|
|
12628
12969
|
reserved.add(constraint.name);
|
|
12629
12970
|
}
|
|
@@ -13428,7 +13769,7 @@ function setDatabaseCatalogContext(state, context) {
|
|
|
13428
13769
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
13429
13770
|
function findSequenceForCall(ctx, name2) {
|
|
13430
13771
|
const parts = parseQualifiedName(name2);
|
|
13431
|
-
const seq = ctx.state.findSequence(parts);
|
|
13772
|
+
const seq = /^\d+$/.test(name2) ? [...ctx.state.schemas.values()].flatMap((schema) => [...schema.sequences.values()]).find((sequence) => sequence.oid === Number(name2)) : ctx.state.findSequence(parts);
|
|
13432
13773
|
if (!seq) {
|
|
13433
13774
|
throw pgError("undefined_table", `relation "${name2}" does not exist`, "42P01");
|
|
13434
13775
|
}
|
|
@@ -13652,14 +13993,16 @@ function getMiscFunctions() {
|
|
|
13652
13993
|
"pg_get_serial_sequence",
|
|
13653
13994
|
strict("text", (ctx, args2) => {
|
|
13654
13995
|
const tableName2 = argText(ctx, args2[0]);
|
|
13655
|
-
const column = argText(ctx, args2[1])
|
|
13996
|
+
const column = argText(ctx, args2[1]);
|
|
13656
13997
|
const table = ctx.state.findTable(parseQualifiedName(tableName2));
|
|
13657
13998
|
if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
|
|
13658
13999
|
const col = table.columns.find((c) => c.name === column);
|
|
13659
14000
|
if (!col)
|
|
13660
14001
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
13661
|
-
|
|
13662
|
-
|
|
14002
|
+
const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
|
|
14003
|
+
(candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
|
|
14004
|
+
);
|
|
14005
|
+
return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
|
|
13663
14006
|
})
|
|
13664
14007
|
);
|
|
13665
14008
|
m.set("format_type", (ctx, args2) => {
|
|
@@ -15177,7 +15520,7 @@ function evalTrgmWordSimilar(ctx, left, right) {
|
|
|
15177
15520
|
const score = wordSimilarity(a.v, b.v);
|
|
15178
15521
|
return tv("bool", score >= WORD_SIMILARITY_THRESHOLD);
|
|
15179
15522
|
}
|
|
15180
|
-
function assertGinTrgmIndex(state, table, stmt) {
|
|
15523
|
+
function assertGinTrgmIndex(state, table, stmt, expressionType) {
|
|
15181
15524
|
const trgmCols = stmt.columns.filter((col2) => isGinTrgmOpclass(col2.opclass));
|
|
15182
15525
|
if (trgmCols.length === 0) return;
|
|
15183
15526
|
if (trgmCols.length !== stmt.columns.length || stmt.columns.length !== 1) {
|
|
@@ -15197,11 +15540,7 @@ function assertGinTrgmIndex(state, table, stmt) {
|
|
|
15197
15540
|
if (stmt.unique) {
|
|
15198
15541
|
throw pgError("feature_not_supported", `access method "gin" does not support unique indexes`, "0A000");
|
|
15199
15542
|
}
|
|
15200
|
-
|
|
15201
|
-
throw unsupported("expression gin_trgm_ops");
|
|
15202
|
-
}
|
|
15203
|
-
const index = table.columnIndex(col.expr.parts[0]);
|
|
15204
|
-
const typeId = table.columns[index].type.id;
|
|
15543
|
+
const typeId = col.expr.type === "colref" && col.expr.parts.length === 1 ? table.columns[table.columnIndex(col.expr.parts[0])].type.id : expressionType(col.expr);
|
|
15205
15544
|
if (!GIN_TRGM_TYPES.has(typeId)) {
|
|
15206
15545
|
throw pgError(
|
|
15207
15546
|
"datatype_mismatch",
|
|
@@ -18603,7 +18942,7 @@ var RowScope = class {
|
|
|
18603
18942
|
let count2 = 0;
|
|
18604
18943
|
for (let i = 0; i < this.columns.length; i++) {
|
|
18605
18944
|
const c = this.columns[i];
|
|
18606
|
-
if (c.name === name3 && !c.hidden) {
|
|
18945
|
+
if (c.name === name3 && (!c.hidden || c.system)) {
|
|
18607
18946
|
count2++;
|
|
18608
18947
|
if (count2 > 1) {
|
|
18609
18948
|
throw pgError("ambiguous_column", `column reference "${name3}" is ambiguous`);
|
|
@@ -18641,7 +18980,7 @@ var RowScope = class {
|
|
|
18641
18980
|
const names = [];
|
|
18642
18981
|
for (let i = 0; i < this.columns.length; i++) {
|
|
18643
18982
|
const c = this.columns[i];
|
|
18644
|
-
if (c.table === rangeVar) {
|
|
18983
|
+
if (c.table === rangeVar && !c.system) {
|
|
18645
18984
|
types.push(c.type);
|
|
18646
18985
|
values.push(this.row[i] ?? null);
|
|
18647
18986
|
names.push(c.name);
|
|
@@ -18839,6 +19178,17 @@ function tableScope(table, row) {
|
|
|
18839
19178
|
const cols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: table.name }));
|
|
18840
19179
|
return new RowScope(cols, row, null, /* @__PURE__ */ new Set([table.name]));
|
|
18841
19180
|
}
|
|
19181
|
+
function expressionTypeOf(env, table, expr) {
|
|
19182
|
+
const scope = makeEvalScope(
|
|
19183
|
+
env,
|
|
19184
|
+
tableScope(
|
|
19185
|
+
table,
|
|
19186
|
+
table.columns.map(() => null)
|
|
19187
|
+
)
|
|
19188
|
+
);
|
|
19189
|
+
const v = evalExpr(env.ctx, scope, expr);
|
|
19190
|
+
return v.t === "unknown" ? "text" : v.t;
|
|
19191
|
+
}
|
|
18842
19192
|
function checkNotNull(env, table, row) {
|
|
18843
19193
|
void env;
|
|
18844
19194
|
for (let i = 0; i < table.columns.length; i++) {
|
|
@@ -19084,7 +19434,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
19084
19434
|
if (!table) return null;
|
|
19085
19435
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
19086
19436
|
table.materializeSlab();
|
|
19087
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
19437
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
19088
19438
|
}
|
|
19089
19439
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
19090
19440
|
const parts = [];
|
|
@@ -21574,6 +21924,7 @@ var Parser = class {
|
|
|
21574
21924
|
let sqlBody = null;
|
|
21575
21925
|
let volatility = null;
|
|
21576
21926
|
let strict2 = false;
|
|
21927
|
+
const settings = {};
|
|
21577
21928
|
for (; ; ) {
|
|
21578
21929
|
if (this.eatKw("language")) {
|
|
21579
21930
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -21631,8 +21982,23 @@ var Parser = class {
|
|
|
21631
21982
|
continue;
|
|
21632
21983
|
}
|
|
21633
21984
|
if (this.eatKw("set")) {
|
|
21634
|
-
this.ident(true);
|
|
21635
|
-
if (this.
|
|
21985
|
+
const key = this.ident(true).toLowerCase();
|
|
21986
|
+
if (this.eatKw("from")) {
|
|
21987
|
+
this.expectKw("current");
|
|
21988
|
+
settings[key] = "__from_current__";
|
|
21989
|
+
} else {
|
|
21990
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
21991
|
+
const values = [];
|
|
21992
|
+
do {
|
|
21993
|
+
const value = this.next();
|
|
21994
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
21995
|
+
this.errorAt(value, "expected setting value");
|
|
21996
|
+
values.push(
|
|
21997
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
21998
|
+
);
|
|
21999
|
+
} while (this.eatPunct(","));
|
|
22000
|
+
settings[key] = values.join(", ");
|
|
22001
|
+
}
|
|
21636
22002
|
continue;
|
|
21637
22003
|
}
|
|
21638
22004
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -21712,7 +22078,8 @@ var Parser = class {
|
|
|
21712
22078
|
body,
|
|
21713
22079
|
sqlBody,
|
|
21714
22080
|
volatility,
|
|
21715
|
-
strict: strict2
|
|
22081
|
+
strict: strict2,
|
|
22082
|
+
settings
|
|
21716
22083
|
};
|
|
21717
22084
|
}
|
|
21718
22085
|
parseCreateTrigger(orReplace, constraint) {
|
|
@@ -21744,7 +22111,6 @@ var Parser = class {
|
|
|
21744
22111
|
} while (this.eatKw("or"));
|
|
21745
22112
|
this.expectKw("on");
|
|
21746
22113
|
const table = this.qualifiedName();
|
|
21747
|
-
if (this.eatKw("referencing")) throw unsupported("trigger transition tables");
|
|
21748
22114
|
let deferrable = false;
|
|
21749
22115
|
let initiallyDeferred = false;
|
|
21750
22116
|
if (this.eatKw("not")) this.expectKw("deferrable");
|
|
@@ -21757,6 +22123,23 @@ var Parser = class {
|
|
|
21757
22123
|
this.errorAt(this.peek(), "only constraint triggers can be deferred");
|
|
21758
22124
|
if (initiallyDeferred && !deferrable)
|
|
21759
22125
|
this.errorAt(this.peek(), "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
|
|
22126
|
+
const transitions = [];
|
|
22127
|
+
if (!constraint && this.eatKw("referencing")) {
|
|
22128
|
+
do {
|
|
22129
|
+
const isNew = this.eatKw("new");
|
|
22130
|
+
if (!isNew) this.expectKw("old");
|
|
22131
|
+
if (this.eatKw("row")) {
|
|
22132
|
+
throw pgError(
|
|
22133
|
+
"feature_not_supported",
|
|
22134
|
+
"ROW variable naming in the REFERENCING clause is not supported",
|
|
22135
|
+
"0A000"
|
|
22136
|
+
);
|
|
22137
|
+
}
|
|
22138
|
+
this.expectKw("table");
|
|
22139
|
+
this.eatKw("as");
|
|
22140
|
+
transitions.push({ isNew, name: this.ident() });
|
|
22141
|
+
} while (this.atKw("new") || this.atKw("old"));
|
|
22142
|
+
}
|
|
21760
22143
|
let forEachRow = false;
|
|
21761
22144
|
if (this.eatKw("for")) {
|
|
21762
22145
|
this.eatKw("each");
|
|
@@ -21794,7 +22177,8 @@ var Parser = class {
|
|
|
21794
22177
|
forEachRow,
|
|
21795
22178
|
when,
|
|
21796
22179
|
funcName,
|
|
21797
|
-
funcArgs
|
|
22180
|
+
funcArgs,
|
|
22181
|
+
...transitions.length > 0 ? { transitions } : {}
|
|
21798
22182
|
};
|
|
21799
22183
|
}
|
|
21800
22184
|
// --- ALTER --------------------------------------------------------------------
|
|
@@ -21821,8 +22205,8 @@ var Parser = class {
|
|
|
21821
22205
|
type: "alter_sequence",
|
|
21822
22206
|
name: name2,
|
|
21823
22207
|
ifExists,
|
|
21824
|
-
options: {
|
|
21825
|
-
|
|
22208
|
+
options: {},
|
|
22209
|
+
renameTo: to
|
|
21826
22210
|
};
|
|
21827
22211
|
}
|
|
21828
22212
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -24398,7 +24782,20 @@ function runFunctionBody(env, fn, args2) {
|
|
|
24398
24782
|
}
|
|
24399
24783
|
return last;
|
|
24400
24784
|
}
|
|
24785
|
+
function withFunctionSettings(env, fn, run) {
|
|
24786
|
+
const state = env.ctx.state;
|
|
24787
|
+
const saved = new Map(state.localSettings);
|
|
24788
|
+
for (const [name2, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name2, value);
|
|
24789
|
+
try {
|
|
24790
|
+
return run();
|
|
24791
|
+
} finally {
|
|
24792
|
+
state.localSettings = saved;
|
|
24793
|
+
}
|
|
24794
|
+
}
|
|
24401
24795
|
function callSqlFunctionScalar(env, fn, args2) {
|
|
24796
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args2));
|
|
24797
|
+
}
|
|
24798
|
+
function callSqlFunctionScalarBody(env, fn, args2) {
|
|
24402
24799
|
const retT = fn.returns ?? "text";
|
|
24403
24800
|
if (fn.language === "plpgsql") {
|
|
24404
24801
|
return callPlpgsqlScalar(env, fn, args2);
|
|
@@ -24428,6 +24825,9 @@ function callSqlFunctionScalar(env, fn, args2) {
|
|
|
24428
24825
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
24429
24826
|
}
|
|
24430
24827
|
function callSqlFunctionSet(env, fn, args2) {
|
|
24828
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args2));
|
|
24829
|
+
}
|
|
24830
|
+
function callSqlFunctionSetBody(env, fn, args2) {
|
|
24431
24831
|
if (fn.language === "plpgsql") {
|
|
24432
24832
|
return callPlpgsqlSet(env, fn, args2);
|
|
24433
24833
|
}
|
|
@@ -24582,15 +24982,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
24582
24982
|
return rel3;
|
|
24583
24983
|
}
|
|
24584
24984
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
24585
|
-
|
|
24985
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
24986
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
24586
24987
|
throw pgError(
|
|
24587
24988
|
"invalid_column_reference",
|
|
24588
|
-
`table "${what}" has ${
|
|
24989
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
24589
24990
|
"42P10"
|
|
24590
24991
|
);
|
|
24591
24992
|
}
|
|
24592
24993
|
const columns = rel3.columns.map((c, i) => ({
|
|
24593
|
-
|
|
24994
|
+
...c,
|
|
24995
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
24594
24996
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
24595
24997
|
table: label
|
|
24596
24998
|
}));
|
|
@@ -24611,8 +25013,11 @@ function materializeItem(env, item, scope) {
|
|
|
24611
25013
|
if (table) {
|
|
24612
25014
|
table.materializeSlab();
|
|
24613
25015
|
const rel3 = {
|
|
24614
|
-
columns:
|
|
24615
|
-
|
|
25016
|
+
columns: [
|
|
25017
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
25018
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
25019
|
+
],
|
|
25020
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
24616
25021
|
};
|
|
24617
25022
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
24618
25023
|
}
|
|
@@ -25242,7 +25647,7 @@ function resolveColIdx(columns, parts) {
|
|
|
25242
25647
|
let found = -1;
|
|
25243
25648
|
for (let i = 0; i < columns.length; i++) {
|
|
25244
25649
|
const c = columns[i];
|
|
25245
|
-
if (!c.hidden && c.name === name3) {
|
|
25650
|
+
if ((!c.hidden || c.system) && c.name === name3) {
|
|
25246
25651
|
if (found !== -1) return null;
|
|
25247
25652
|
found = i;
|
|
25248
25653
|
}
|
|
@@ -25826,7 +26231,7 @@ function expandTargets(core, columns) {
|
|
|
25826
26231
|
let any = false;
|
|
25827
26232
|
for (let i = 0; i < columns.length; i++) {
|
|
25828
26233
|
const c = columns[i];
|
|
25829
|
-
if (c.table === label) {
|
|
26234
|
+
if (c.table === label && !c.system) {
|
|
25830
26235
|
any = true;
|
|
25831
26236
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
25832
26237
|
}
|
|
@@ -26319,6 +26724,29 @@ function fireRowTriggers(env, table, timing, event, oldRow, newRow) {
|
|
|
26319
26724
|
}
|
|
26320
26725
|
return { row };
|
|
26321
26726
|
}
|
|
26727
|
+
function transitionRelation(table, name2, rows) {
|
|
26728
|
+
return {
|
|
26729
|
+
columns: table.columns.map((c) => ({ name: c.name, type: c.type.id, table: name2 })),
|
|
26730
|
+
rows
|
|
26731
|
+
};
|
|
26732
|
+
}
|
|
26733
|
+
function fireStatementTriggers(env, table, timing, event, transitions) {
|
|
26734
|
+
const fired = table.triggers.filter((t) => !t.forEachRow && t.timing === timing && matches(t, event)).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
26735
|
+
for (const t of fired) {
|
|
26736
|
+
if (!executor) throw unsupported(`trigger "${t.name}" execution`);
|
|
26737
|
+
const ctes = /* @__PURE__ */ new Map();
|
|
26738
|
+
if (t.oldTable !== void 0)
|
|
26739
|
+
ctes.set(t.oldTable, transitionRelation(table, t.oldTable, transitions?.oldRows ?? []));
|
|
26740
|
+
if (t.newTable !== void 0)
|
|
26741
|
+
ctes.set(t.newTable, transitionRelation(table, t.newTable, transitions?.newRows ?? []));
|
|
26742
|
+
const changes = env.ctx.state.changes;
|
|
26743
|
+
try {
|
|
26744
|
+
executor({ ctx: env.ctx, params: null, ctes, outer: null }, table, t, event, null, null);
|
|
26745
|
+
} finally {
|
|
26746
|
+
env.ctx.state.changes = changes;
|
|
26747
|
+
}
|
|
26748
|
+
}
|
|
26749
|
+
}
|
|
26322
26750
|
var keyOf = (schema, name2) => JSON.stringify([schema, name2]);
|
|
26323
26751
|
function flushConstraintTriggers(state, all = false) {
|
|
26324
26752
|
const env = { ctx: new EngineCtx(state), params: null, ctes: /* @__PURE__ */ new Map(), outer: null };
|
|
@@ -26431,6 +26859,7 @@ var TransactionManager = class {
|
|
|
26431
26859
|
this.base = null;
|
|
26432
26860
|
this.savepoints = [];
|
|
26433
26861
|
this.state.inTransaction = false;
|
|
26862
|
+
this.state.transactionXid = null;
|
|
26434
26863
|
this.state.localSettings.clear();
|
|
26435
26864
|
this.state.pendingTriggers = [];
|
|
26436
26865
|
this.state.constraintModes.clear();
|
|
@@ -26443,6 +26872,7 @@ var TransactionManager = class {
|
|
|
26443
26872
|
this.base = null;
|
|
26444
26873
|
this.savepoints = [];
|
|
26445
26874
|
this.state.inTransaction = false;
|
|
26875
|
+
this.state.transactionXid = null;
|
|
26446
26876
|
this.state.localSettings.clear();
|
|
26447
26877
|
this.state.pendingTriggers = [];
|
|
26448
26878
|
this.state.constraintModes.clear();
|
|
@@ -26477,6 +26907,7 @@ var TransactionManager = class {
|
|
|
26477
26907
|
this.base = null;
|
|
26478
26908
|
this.savepoints = [];
|
|
26479
26909
|
this.state.inTransaction = false;
|
|
26910
|
+
this.state.transactionXid = null;
|
|
26480
26911
|
this.freezeDepth = 0;
|
|
26481
26912
|
}
|
|
26482
26913
|
};
|
|
@@ -26680,6 +27111,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
26680
27111
|
const updated = existing.slice();
|
|
26681
27112
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
26682
27113
|
computeGeneratedColumns(env, table, updated);
|
|
27114
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
26683
27115
|
rows[existingIdx] = updated;
|
|
26684
27116
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
26685
27117
|
checkNotNull(env, table, updated);
|
|
@@ -26698,7 +27130,13 @@ function executeInsert(env0, stmt) {
|
|
|
26698
27130
|
const sourceRows = insertSourceRows(env, stmt, colIdxs);
|
|
26699
27131
|
const insertedRows = [];
|
|
26700
27132
|
let insertedCount = 0;
|
|
27133
|
+
const addedRows = [];
|
|
27134
|
+
const conflictOldRows = [];
|
|
27135
|
+
const conflictNewRows = [];
|
|
27136
|
+
const updatesOnConflict = stmt.onConflict !== null && stmt.onConflict.action !== "nothing";
|
|
26701
27137
|
return withStatementRollback(env, () => {
|
|
27138
|
+
fireStatementTriggers(env, table, "before", "insert");
|
|
27139
|
+
if (updatesOnConflict) fireStatementTriggers(env, table, "before", "update");
|
|
26702
27140
|
for (const srcRow of sourceRows) {
|
|
26703
27141
|
const row = table.columns.map(() => null);
|
|
26704
27142
|
const provided = /* @__PURE__ */ new Set();
|
|
@@ -26744,6 +27182,7 @@ function executeInsert(env0, stmt) {
|
|
|
26744
27182
|
}
|
|
26745
27183
|
if (conflictIdx !== null && conflictWhereOk) {
|
|
26746
27184
|
if (stmt.onConflict.action === "nothing") continue;
|
|
27185
|
+
const replaced = rows[conflictIdx];
|
|
26747
27186
|
const did = applyOnConflictUpdate(
|
|
26748
27187
|
env,
|
|
26749
27188
|
table,
|
|
@@ -26756,6 +27195,8 @@ function executeInsert(env0, stmt) {
|
|
|
26756
27195
|
if (did) {
|
|
26757
27196
|
insertedCount++;
|
|
26758
27197
|
insertedRows.push(rows[conflictIdx]);
|
|
27198
|
+
conflictOldRows.push(replaced);
|
|
27199
|
+
conflictNewRows.push(rows[conflictIdx]);
|
|
26759
27200
|
fireRowTriggers(env, table, "after", "update", null, rows[conflictIdx]);
|
|
26760
27201
|
}
|
|
26761
27202
|
continue;
|
|
@@ -26765,12 +27206,18 @@ function executeInsert(env0, stmt) {
|
|
|
26765
27206
|
checkChecks(env, table, newRow);
|
|
26766
27207
|
checkUnique(env, table, newRow, rows.length);
|
|
26767
27208
|
checkForeignKeys(env, table, newRow);
|
|
27209
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26768
27210
|
rows.push(newRow);
|
|
26769
27211
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
26770
27212
|
insertedCount++;
|
|
26771
27213
|
insertedRows.push(newRow);
|
|
27214
|
+
addedRows.push(newRow);
|
|
26772
27215
|
fireRowTriggers(env, table, "after", "insert", null, newRow);
|
|
26773
27216
|
}
|
|
27217
|
+
fireStatementTriggers(env, table, "after", "insert", { oldRows: [], newRows: addedRows });
|
|
27218
|
+
if (updatesOnConflict) {
|
|
27219
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: conflictOldRows, newRows: conflictNewRows });
|
|
27220
|
+
}
|
|
26774
27221
|
env.ctx.state.changes = insertedCount;
|
|
26775
27222
|
if (stmt.returning) {
|
|
26776
27223
|
const res = evalReturning(env, table, label, stmt.returning, insertedRows, "INSERT");
|
|
@@ -26851,10 +27298,12 @@ function executeUpdate(env0, stmt) {
|
|
|
26851
27298
|
const env = applyWith(env0, stmt.with);
|
|
26852
27299
|
const table = requireTargetTable(env, stmt.table, "update");
|
|
26853
27300
|
const label = stmt.alias ?? table.name;
|
|
27301
|
+
fireStatementTriggers(env, table, "before", "update");
|
|
26854
27302
|
const fromSource = stmt.from.length > 0 ? buildFrom(env, stmt.from) : null;
|
|
26855
27303
|
const rows = table.mutableRows();
|
|
26856
27304
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
26857
27305
|
const updatedRows = [];
|
|
27306
|
+
const replacedRows = [];
|
|
26858
27307
|
let updateCount = 0;
|
|
26859
27308
|
for (let ri = 0; ri < rows.length; ri++) {
|
|
26860
27309
|
const oldRow = rows[ri];
|
|
@@ -26882,6 +27331,7 @@ function executeUpdate(env0, stmt) {
|
|
|
26882
27331
|
if (fired.row === null) continue;
|
|
26883
27332
|
const finalRow = fired.row;
|
|
26884
27333
|
computeGeneratedColumns(env, table, finalRow);
|
|
27334
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
26885
27335
|
rows[ri] = finalRow;
|
|
26886
27336
|
try {
|
|
26887
27337
|
checkNotNull(env, table, finalRow);
|
|
@@ -26896,8 +27346,10 @@ function executeUpdate(env0, stmt) {
|
|
|
26896
27346
|
handleReferencedUpdate(env, table, [oldRow], [finalRow]);
|
|
26897
27347
|
updateCount++;
|
|
26898
27348
|
updatedRows.push(finalRow);
|
|
27349
|
+
replacedRows.push(oldRow);
|
|
26899
27350
|
fireRowTriggers(env, table, "after", "update", oldRow, finalRow);
|
|
26900
27351
|
}
|
|
27352
|
+
fireStatementTriggers(env, table, "after", "update", { oldRows: replacedRows, newRows: updatedRows });
|
|
26901
27353
|
env.ctx.state.changes = updateCount;
|
|
26902
27354
|
if (stmt.returning) {
|
|
26903
27355
|
const res = evalReturning(env, table, label, stmt.returning, updatedRows, "UPDATE");
|
|
@@ -26909,6 +27361,7 @@ function executeDelete(env0, stmt) {
|
|
|
26909
27361
|
const env = applyWith(env0, stmt.with);
|
|
26910
27362
|
const table = requireTargetTable(env, stmt.table, "delete from");
|
|
26911
27363
|
const label = stmt.alias ?? table.name;
|
|
27364
|
+
fireStatementTriggers(env, table, "before", "delete");
|
|
26912
27365
|
const rows = table.mutableRows();
|
|
26913
27366
|
const usingSource = stmt.using.length > 0 ? buildFrom(env, stmt.using) : null;
|
|
26914
27367
|
const targetCols = table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label }));
|
|
@@ -26946,6 +27399,7 @@ function executeDelete(env0, stmt) {
|
|
|
26946
27399
|
fireRowTriggers(env, table, "after", "delete", row, null);
|
|
26947
27400
|
}
|
|
26948
27401
|
if (deletedRows.length > 0) rebuildTableIndexes(env, table);
|
|
27402
|
+
fireStatementTriggers(env, table, "after", "delete", { oldRows: deletedRows, newRows: [] });
|
|
26949
27403
|
env.ctx.state.changes = deletedRows.length;
|
|
26950
27404
|
if (stmt.returning) {
|
|
26951
27405
|
const res = evalReturning(env, table, label, stmt.returning, deletedRows, "DELETE");
|
|
@@ -27001,6 +27455,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27001
27455
|
for (const c of con.columns) {
|
|
27002
27456
|
newRow[child.columnIndex(c)] = null;
|
|
27003
27457
|
}
|
|
27458
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27004
27459
|
childRows[i] = newRow;
|
|
27005
27460
|
checkNotNull(env, child, newRow);
|
|
27006
27461
|
checkChecks(env, child, newRow);
|
|
@@ -27014,6 +27469,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27014
27469
|
const ci = child.columnIndex(c);
|
|
27015
27470
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
27016
27471
|
}
|
|
27472
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27017
27473
|
childRows[i] = newRow;
|
|
27018
27474
|
checkNotNull(env, child, newRow);
|
|
27019
27475
|
checkChecks(env, child, newRow);
|
|
@@ -27051,6 +27507,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
27051
27507
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
27052
27508
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
27053
27509
|
}
|
|
27510
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27054
27511
|
childRows[i] = newRow;
|
|
27055
27512
|
checkChecks(env, child, newRow);
|
|
27056
27513
|
}
|
|
@@ -27060,6 +27517,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
27060
27517
|
for (const i of idxs) {
|
|
27061
27518
|
const newRow = childRows[i].slice();
|
|
27062
27519
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
27520
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27063
27521
|
childRows[i] = newRow;
|
|
27064
27522
|
checkNotNull(env, child, newRow);
|
|
27065
27523
|
}
|
|
@@ -27072,6 +27530,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
27072
27530
|
const ci = child.columnIndex(c);
|
|
27073
27531
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
27074
27532
|
}
|
|
27533
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27075
27534
|
childRows[i] = newRow;
|
|
27076
27535
|
checkForeignKeys(env, child, newRow);
|
|
27077
27536
|
}
|
|
@@ -29083,7 +29542,7 @@ function pgTrigger(ctx) {
|
|
|
29083
29542
|
let oid = 4e4;
|
|
29084
29543
|
for (const t of allTables(ctx.state)) {
|
|
29085
29544
|
for (const tr of t.triggers) {
|
|
29086
|
-
rows.push([oid++, tr.name, t.oid, !tr.forEachRow]);
|
|
29545
|
+
rows.push([oid++, tr.name, t.oid, !tr.forEachRow, tr.oldTable ?? null, tr.newTable ?? null]);
|
|
29087
29546
|
}
|
|
29088
29547
|
}
|
|
29089
29548
|
return rel2(
|
|
@@ -29091,7 +29550,9 @@ function pgTrigger(ctx) {
|
|
|
29091
29550
|
["oid", "oid"],
|
|
29092
29551
|
["tgname", "name"],
|
|
29093
29552
|
["tgrelid", "oid"],
|
|
29094
|
-
["tgisinternal", "bool"]
|
|
29553
|
+
["tgisinternal", "bool"],
|
|
29554
|
+
["tgoldtable", "name"],
|
|
29555
|
+
["tgnewtable", "name"]
|
|
29095
29556
|
],
|
|
29096
29557
|
rows,
|
|
29097
29558
|
"pg_trigger"
|
|
@@ -30119,13 +30580,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
30119
30580
|
schema.sequences.set(name2, seq);
|
|
30120
30581
|
return commandResult("CREATE SEQUENCE", 0);
|
|
30121
30582
|
}
|
|
30583
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
30584
|
+
const state = env.ctx.state;
|
|
30585
|
+
const matches2 = (value) => {
|
|
30586
|
+
try {
|
|
30587
|
+
const input = parseRelationInput(value);
|
|
30588
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
30589
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
30590
|
+
} catch {
|
|
30591
|
+
return false;
|
|
30592
|
+
}
|
|
30593
|
+
};
|
|
30594
|
+
const rewrite = (value) => {
|
|
30595
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
30596
|
+
if (value === null || typeof value !== "object") return value;
|
|
30597
|
+
const node = value;
|
|
30598
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
30599
|
+
const rewriteLiteral = (literal2) => {
|
|
30600
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
|
|
30601
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
30602
|
+
}
|
|
30603
|
+
return literal2;
|
|
30604
|
+
};
|
|
30605
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
30606
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
30607
|
+
if (node.type === "cast" && node.target && typeof node.target === "object" && "parts" in node.target && Array.isArray(node.target.parts) && node.target.parts.at(-1) === "regclass")
|
|
30608
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
30609
|
+
return updated;
|
|
30610
|
+
};
|
|
30611
|
+
for (const schema of state.schemas.values()) {
|
|
30612
|
+
for (const table of [...schema.tables.values()]) {
|
|
30613
|
+
const writable = state.ensureWritableTable(table);
|
|
30614
|
+
for (const column of writable.columns) {
|
|
30615
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
30616
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
30617
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
30618
|
+
}
|
|
30619
|
+
}
|
|
30620
|
+
}
|
|
30621
|
+
}
|
|
30122
30622
|
function executeAlterSequence(env, stmt) {
|
|
30123
30623
|
const state = env.ctx.state;
|
|
30124
|
-
const
|
|
30125
|
-
if (!
|
|
30624
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
30625
|
+
if (!foundSequence) {
|
|
30126
30626
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
30127
30627
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
30128
30628
|
}
|
|
30629
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
30630
|
+
if (stmt.renameTo) {
|
|
30631
|
+
const schema = state.getSchema(seq.schema);
|
|
30632
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
30633
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
30634
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
30635
|
+
schema.sequences.delete(seq.name);
|
|
30636
|
+
seq.name = stmt.renameTo;
|
|
30637
|
+
schema.sequences.set(seq.name, seq);
|
|
30638
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
30639
|
+
}
|
|
30129
30640
|
const o = stmt.options;
|
|
30130
30641
|
if (o.logged !== void 0) {
|
|
30131
30642
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -30183,7 +30694,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
30183
30694
|
col.defaultExpr = {
|
|
30184
30695
|
type: "func",
|
|
30185
30696
|
name: ["nextval"],
|
|
30186
|
-
args: [{ type: "string_lit", value:
|
|
30697
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
30187
30698
|
};
|
|
30188
30699
|
}
|
|
30189
30700
|
for (const c of def.constraints) {
|
|
@@ -30436,7 +30947,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
30436
30947
|
const table = new TableData(schema.name, name2, columns, state.nextOid(), stmt.temp);
|
|
30437
30948
|
table.unlogged = stmt.unlogged === true;
|
|
30438
30949
|
if (stmt.withData) {
|
|
30439
|
-
for (const row of rel3.rows)
|
|
30950
|
+
for (const row of rel3.rows) {
|
|
30951
|
+
const stored = row.slice();
|
|
30952
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
30953
|
+
table.mutableRows().push(stored);
|
|
30954
|
+
}
|
|
30440
30955
|
}
|
|
30441
30956
|
schema.tables.set(name2, table);
|
|
30442
30957
|
const count = stmt.withData ? table.rowCount() : 0;
|
|
@@ -30464,7 +30979,7 @@ function executeCreateIndex(env, stmt) {
|
|
|
30464
30979
|
}
|
|
30465
30980
|
}
|
|
30466
30981
|
}
|
|
30467
|
-
assertGinTrgmIndex(state, table, stmt);
|
|
30982
|
+
assertGinTrgmIndex(state, table, stmt, (expr) => expressionTypeOf(env, table, expr));
|
|
30468
30983
|
const method = stmt.using ?? "btree";
|
|
30469
30984
|
if (!ACCESS_METHODS.has(method) || method === "heap") {
|
|
30470
30985
|
throw pgError("undefined_object", `access method "${method}" does not exist`, "42704");
|
|
@@ -30705,6 +31220,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
30705
31220
|
language: lang,
|
|
30706
31221
|
body,
|
|
30707
31222
|
rawBody: stmt.body,
|
|
31223
|
+
settings: Object.fromEntries(
|
|
31224
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
31225
|
+
key,
|
|
31226
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
31227
|
+
])
|
|
31228
|
+
),
|
|
30708
31229
|
strict: stmt.strict,
|
|
30709
31230
|
oid: state.nextOid()
|
|
30710
31231
|
};
|
|
@@ -30713,6 +31234,50 @@ function executeCreateFunction(env, stmt) {
|
|
|
30713
31234
|
schema.functions.set(name2, existing);
|
|
30714
31235
|
return commandResult("CREATE FUNCTION", 0);
|
|
30715
31236
|
}
|
|
31237
|
+
function validateTransitionTables(stmt) {
|
|
31238
|
+
const transitions = stmt.transitions ?? [];
|
|
31239
|
+
if (transitions.length === 0) return {};
|
|
31240
|
+
const invalid = (message2) => pgError("invalid_table_definition", message2, "42P17");
|
|
31241
|
+
const unsupportedClause = (message2) => pgError("feature_not_supported", message2, "0A000");
|
|
31242
|
+
if (stmt.timing !== "after") throw invalid("transition table name can only be specified for an AFTER trigger");
|
|
31243
|
+
if (stmt.events.some((e) => e.event === "truncate")) {
|
|
31244
|
+
throw unsupportedClause("TRUNCATE triggers with transition tables are not supported");
|
|
31245
|
+
}
|
|
31246
|
+
if (stmt.events.some((e) => e.columns !== null)) {
|
|
31247
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with column lists");
|
|
31248
|
+
}
|
|
31249
|
+
if (stmt.events.length > 1) {
|
|
31250
|
+
throw unsupportedClause("transition tables cannot be specified for triggers with more than one event");
|
|
31251
|
+
}
|
|
31252
|
+
const event = stmt.events[0].event;
|
|
31253
|
+
let oldTable;
|
|
31254
|
+
let newTable;
|
|
31255
|
+
for (const transition of transitions) {
|
|
31256
|
+
if (transition.isNew) {
|
|
31257
|
+
if (event !== "insert" && event !== "update") {
|
|
31258
|
+
throw invalid("NEW TABLE can only be specified for an INSERT or UPDATE trigger");
|
|
31259
|
+
}
|
|
31260
|
+
if (newTable !== void 0) throw invalid("NEW TABLE cannot be specified multiple times");
|
|
31261
|
+
newTable = transition.name;
|
|
31262
|
+
} else {
|
|
31263
|
+
if (event !== "delete" && event !== "update") {
|
|
31264
|
+
throw invalid("OLD TABLE can only be specified for a DELETE or UPDATE trigger");
|
|
31265
|
+
}
|
|
31266
|
+
if (oldTable !== void 0) throw invalid("OLD TABLE cannot be specified multiple times");
|
|
31267
|
+
oldTable = transition.name;
|
|
31268
|
+
}
|
|
31269
|
+
}
|
|
31270
|
+
if (oldTable !== void 0 && oldTable === newTable) {
|
|
31271
|
+
throw invalid("OLD TABLE name and NEW TABLE name cannot be the same");
|
|
31272
|
+
}
|
|
31273
|
+
if (stmt.forEachRow) {
|
|
31274
|
+
throw pgError("unsupported", "transition tables on FOR EACH ROW triggers are not supported", "0A000");
|
|
31275
|
+
}
|
|
31276
|
+
return {
|
|
31277
|
+
...oldTable !== void 0 ? { oldTable } : {},
|
|
31278
|
+
...newTable !== void 0 ? { newTable } : {}
|
|
31279
|
+
};
|
|
31280
|
+
}
|
|
30716
31281
|
function executeCreateTrigger(env, stmt) {
|
|
30717
31282
|
if (stmt.constraint && (stmt.timing !== "after" || !stmt.forEachRow))
|
|
30718
31283
|
throw pgError("syntax", "constraint triggers must be AFTER ROW triggers", "42601");
|
|
@@ -30722,6 +31287,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
30722
31287
|
throw pgError("undefined_table", `relation "${stmt.table.join(".")}" does not exist`, "42P01");
|
|
30723
31288
|
}
|
|
30724
31289
|
const table = state.ensureWritableTable(found);
|
|
31290
|
+
const transitionTables = validateTransitionTables(stmt);
|
|
30725
31291
|
const fnSchema = stmt.funcName.length >= 2 ? stmt.funcName[stmt.funcName.length - 2] : null;
|
|
30726
31292
|
const fnName = stmt.funcName[stmt.funcName.length - 1];
|
|
30727
31293
|
const fns = state.findFunctions(stmt.funcName);
|
|
@@ -30740,6 +31306,7 @@ function executeCreateTrigger(env, stmt) {
|
|
|
30740
31306
|
timing: stmt.timing,
|
|
30741
31307
|
events: stmt.events,
|
|
30742
31308
|
forEachRow: stmt.forEachRow,
|
|
31309
|
+
...transitionTables,
|
|
30743
31310
|
when: stmt.when,
|
|
30744
31311
|
funcSchema: fnSchema ?? fns[0].schema,
|
|
30745
31312
|
funcName: fnName,
|
|
@@ -30889,6 +31456,7 @@ function executeAlterTable(env, stmt) {
|
|
|
30889
31456
|
}
|
|
30890
31457
|
const next = row.slice();
|
|
30891
31458
|
next[idx] = nv;
|
|
31459
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
30892
31460
|
rows[i] = next;
|
|
30893
31461
|
}
|
|
30894
31462
|
col.type = resolved.column;
|
|
@@ -30990,6 +31558,11 @@ function executeAlterTable(env, stmt) {
|
|
|
30990
31558
|
);
|
|
30991
31559
|
}
|
|
30992
31560
|
table.columns[idx].name = action.to;
|
|
31561
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
31562
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
31563
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
31564
|
+
}
|
|
31565
|
+
}
|
|
30993
31566
|
for (const con of table.constraints) {
|
|
30994
31567
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
30995
31568
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -31026,6 +31599,11 @@ function executeAlterTable(env, stmt) {
|
|
|
31026
31599
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
31027
31600
|
}
|
|
31028
31601
|
const oldName = table.name;
|
|
31602
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
31603
|
+
if (seq.ownedBy?.table === oldName) {
|
|
31604
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
31605
|
+
}
|
|
31606
|
+
}
|
|
31029
31607
|
schema.tables.delete(table.name);
|
|
31030
31608
|
table.name = action.to;
|
|
31031
31609
|
schema.tables.set(action.to, table);
|
|
@@ -32899,6 +33477,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
32899
33477
|
writeBjv(
|
|
32900
33478
|
w,
|
|
32901
33479
|
{
|
|
33480
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
32902
33481
|
name: table.name,
|
|
32903
33482
|
schema: table.schema,
|
|
32904
33483
|
columns: table.columns,
|
|
@@ -32996,8 +33575,14 @@ function decodeInner(snapshot, prng, clock) {
|
|
|
32996
33575
|
table.constraints = meta.constraints;
|
|
32997
33576
|
table.triggers = meta.triggers;
|
|
32998
33577
|
table.unlogged = meta.unlogged === true;
|
|
33578
|
+
table.slabXmins = meta.xmins ?? null;
|
|
33579
|
+
state.xidCounter = Math.max(
|
|
33580
|
+
state.xidCounter,
|
|
33581
|
+
(meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
|
|
33582
|
+
);
|
|
32999
33583
|
if (meta.stats) state.tableStats.set(table.oid, meta.stats);
|
|
33000
33584
|
const rowCount = readVarintU32(r);
|
|
33585
|
+
if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
|
|
33001
33586
|
const slabColumns = [];
|
|
33002
33587
|
for (let c = 0; c < meta.columns.length; c++)
|
|
33003
33588
|
slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
|
|
@@ -33441,6 +34026,8 @@ function validateTableMetaBjv(value) {
|
|
|
33441
34026
|
if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
33442
34027
|
if (!Array.isArray(value.columns)) throw snapshotError();
|
|
33443
34028
|
for (const col of value.columns) validateColumnMeta(col);
|
|
34029
|
+
if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
|
|
34030
|
+
throw snapshotError();
|
|
33444
34031
|
}
|
|
33445
34032
|
function validateViewMetaBjv(value) {
|
|
33446
34033
|
if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
@@ -33534,6 +34121,7 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
33534
34121
|
pool.forceId(table.name);
|
|
33535
34122
|
pool.forceId(table.schema);
|
|
33536
34123
|
forceBjvStrings(pool, {
|
|
34124
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
33537
34125
|
name: table.name,
|
|
33538
34126
|
schema: table.schema,
|
|
33539
34127
|
columns: table.columns,
|
|
@@ -35164,7 +35752,7 @@ var Connection = class {
|
|
|
35164
35752
|
if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
|
|
35165
35753
|
switch (stmt.action) {
|
|
35166
35754
|
case "begin":
|
|
35167
|
-
this.transaction ??= { statements: [], savepoints: [] };
|
|
35755
|
+
this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
|
|
35168
35756
|
return command("BEGIN");
|
|
35169
35757
|
case "commit": {
|
|
35170
35758
|
const transaction = this.transaction;
|
|
@@ -35173,6 +35761,7 @@ var Connection = class {
|
|
|
35173
35761
|
this.inSession(
|
|
35174
35762
|
this.database,
|
|
35175
35763
|
() => this.database.transaction(() => {
|
|
35764
|
+
this.database.state.transactionXid = transaction.xid;
|
|
35176
35765
|
for (const logged of transaction.statements) this.replay(this.database, logged);
|
|
35177
35766
|
})
|
|
35178
35767
|
);
|
|
@@ -35223,6 +35812,7 @@ var Connection = class {
|
|
|
35223
35812
|
workspace.state.settings = new Map(this.settings);
|
|
35224
35813
|
workspace.state.settingDefaults = this.settingDefaults;
|
|
35225
35814
|
workspace.transactions.begin();
|
|
35815
|
+
workspace.state.transactionXid = this.transaction?.xid ?? null;
|
|
35226
35816
|
for (const logged of this.transaction?.statements ?? []) {
|
|
35227
35817
|
this.replay(workspace, logged);
|
|
35228
35818
|
}
|