@crvouga/mockingbird-service-postgres 3.6.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -1
- package/COMPATIBILITY.md +31 -0
- package/README.md +5 -0
- package/dist/admin.js +216 -26
- package/dist/admin.js.map +3 -3
- package/dist/api/schema-report.d.ts +32 -0
- package/dist/ast/nodes.d.ts +2 -0
- package/dist/executor/relation.d.ts +1 -0
- package/dist/expressions/context.d.ts +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +405 -27
- package/dist/index.js.map +4 -4
- package/dist/server.js +229 -27
- package/dist/server.js.map +3 -3
- package/dist/storage/database-state.d.ts +7 -0
- package/dist/types/regnamespace.d.ts +5 -0
- package/dist/types/value.d.ts +2 -0
- package/dist/unstable.js +388 -198
- package/dist/unstable.js.map +4 -4
- package/dist/wire/cli.js +457 -82
- package/dist/wire/cli.js.map +4 -4
- package/dist/wire/index.js +229 -27
- package/dist/wire/index.js.map +3 -3
- package/package.json +1 -1
package/dist/wire/cli.js
CHANGED
|
@@ -744,9 +744,6 @@ function ownedTransport(policy) {
|
|
|
744
744
|
|
|
745
745
|
// ../../adapters/node/dist/cli.js
|
|
746
746
|
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
747
|
import { parseArgs } from "node:util";
|
|
751
748
|
|
|
752
749
|
// ../../adapters/node/dist/fleet.js
|
|
@@ -760,6 +757,31 @@ import { createHash as createHash3, randomBytes, randomUUID as randomUUID3 } fro
|
|
|
760
757
|
|
|
761
758
|
// ../../adapters/node/dist/fleet-archive.js
|
|
762
759
|
import { createHash } from "node:crypto";
|
|
760
|
+
function validateCompatibilityTags(tags) {
|
|
761
|
+
if (!tags || typeof tags !== "object" || Array.isArray(tags))
|
|
762
|
+
throw new Error("invalid archive compatibility tags");
|
|
763
|
+
const entries = Object.entries(tags);
|
|
764
|
+
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)))
|
|
765
|
+
throw new Error("invalid archive compatibility tags");
|
|
766
|
+
}
|
|
767
|
+
function assertCompatibilityTags(tags, policy) {
|
|
768
|
+
if (tags !== void 0)
|
|
769
|
+
validateCompatibilityTags(tags);
|
|
770
|
+
if (!policy)
|
|
771
|
+
return;
|
|
772
|
+
validateCompatibilityTags(policy.tags);
|
|
773
|
+
if (policy.missing !== void 0 && !["allow", "reject"].includes(policy.missing))
|
|
774
|
+
throw new Error("invalid missing compatibility policy");
|
|
775
|
+
if (tags === void 0 && policy.missing === "allow")
|
|
776
|
+
return;
|
|
777
|
+
if (canonical(tags) !== canonical(policy.tags))
|
|
778
|
+
throw new Error("application archive compatibility mismatch");
|
|
779
|
+
}
|
|
780
|
+
function assertArchiveCompatibility(input, policy) {
|
|
781
|
+
const archive = validateArchive(input);
|
|
782
|
+
assertCompatibilityTags(archive.compatibility, policy);
|
|
783
|
+
return archive;
|
|
784
|
+
}
|
|
763
785
|
var canonical = (value) => {
|
|
764
786
|
if (Array.isArray(value))
|
|
765
787
|
return `[${value.map(canonical).join(",")}]`;
|
|
@@ -779,6 +801,8 @@ function validateArchive(value) {
|
|
|
779
801
|
const { sha256: sha2563, ...content } = doc;
|
|
780
802
|
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
803
|
throw new Error("unsupported or corrupt fleet archive");
|
|
804
|
+
if (doc.compatibility !== void 0)
|
|
805
|
+
validateCompatibilityTags(doc.compatibility);
|
|
782
806
|
for (const [namespace, entry] of Object.entries(doc.namespaces)) {
|
|
783
807
|
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
808
|
throw new Error("invalid archive namespace");
|
|
@@ -794,6 +818,7 @@ function inspectArchive(input) {
|
|
|
794
818
|
format: archive.format,
|
|
795
819
|
createdAt: archive.createdAt,
|
|
796
820
|
sha256: archive.sha256,
|
|
821
|
+
...archive.compatibility ? { compatibility: archive.compatibility } : {},
|
|
797
822
|
namespaces: Object.fromEntries(Object.entries(archive.namespaces).map(([name2, ns]) => [
|
|
798
823
|
name2,
|
|
799
824
|
{
|
|
@@ -1436,11 +1461,28 @@ var ingressSupport = {
|
|
|
1436
1461
|
streaming: true,
|
|
1437
1462
|
signing: "vendor request signing is not used; webhook signatures remain payload based"
|
|
1438
1463
|
},
|
|
1464
|
+
cognito: {
|
|
1465
|
+
publicOrigin: true,
|
|
1466
|
+
pathPrefix: true,
|
|
1467
|
+
namespaces: "path-or-header",
|
|
1468
|
+
streaming: true,
|
|
1469
|
+
signing: "JWT issuer and JWKS use the configured public namespace; SigV4 verification is not modelled"
|
|
1470
|
+
},
|
|
1471
|
+
medplum: {
|
|
1472
|
+
publicOrigin: true,
|
|
1473
|
+
pathPrefix: true,
|
|
1474
|
+
namespaces: "path-or-header",
|
|
1475
|
+
streaming: true,
|
|
1476
|
+
signing: "FHIR, OAuth and storage URLs use the configured public namespace"
|
|
1477
|
+
},
|
|
1439
1478
|
other: {
|
|
1440
1479
|
publicOrigin: false,
|
|
1441
1480
|
reason: "host/path-sensitive signing and hosted URL rewriting are not certified; use a direct endpoint"
|
|
1442
1481
|
}
|
|
1443
1482
|
};
|
|
1483
|
+
function supportsPublicIngress(service) {
|
|
1484
|
+
return service === "stripe" || service === "cognito" || service === "medplum";
|
|
1485
|
+
}
|
|
1444
1486
|
function advertisedHttpBase(entry) {
|
|
1445
1487
|
if (entry.publicPath !== void 0 && !entry.publicOrigin)
|
|
1446
1488
|
throw new Error("publicPath requires publicOrigin");
|
|
@@ -1979,7 +2021,7 @@ data: ${JSON.stringify(data)}
|
|
|
1979
2021
|
{
|
|
1980
2022
|
protocol: c.protocol,
|
|
1981
2023
|
coverage: c.coverage,
|
|
1982
|
-
ingress: c.targetName
|
|
2024
|
+
ingress: supportsPublicIngress(c.targetName ?? "") ? ingressSupport[c.targetName] : ingressSupport.other,
|
|
1983
2025
|
target: c.targetName,
|
|
1984
2026
|
outboundPolicy: c.outboundPolicy ?? "unsupported",
|
|
1985
2027
|
version: 1,
|
|
@@ -3063,11 +3105,12 @@ data: ${JSON.stringify(data)}
|
|
|
3063
3105
|
format: "mockingbird.fleet/v1",
|
|
3064
3106
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3065
3107
|
sourceId: this.ctx.id,
|
|
3108
|
+
...this.ctx.options.archiveCompatibility ? { compatibility: structuredClone(this.ctx.options.archiveCompatibility.tags) } : {},
|
|
3066
3109
|
namespaces: contents
|
|
3067
3110
|
});
|
|
3068
3111
|
}
|
|
3069
3112
|
async restoreArchive(input, selectedNamespace) {
|
|
3070
|
-
const archive =
|
|
3113
|
+
const archive = assertArchiveCompatibility(input, this.ctx.options.archiveCompatibility);
|
|
3071
3114
|
const entries = Object.entries(archive.namespaces).filter(([ns]) => selectedNamespace === void 0 || ns === selectedNamespace);
|
|
3072
3115
|
if (!entries.length)
|
|
3073
3116
|
throw new Error("selected namespace absent from archive");
|
|
@@ -3651,7 +3694,7 @@ async function preflightFleet(config, options2) {
|
|
|
3651
3694
|
if (entry.target !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.target))
|
|
3652
3695
|
throw new Error("target must name a supported service suffix");
|
|
3653
3696
|
const service = entry.target ?? name2;
|
|
3654
|
-
if (advertisedHttpBase(entry) && service
|
|
3697
|
+
if (advertisedHttpBase(entry) && !supportsPublicIngress(service))
|
|
3655
3698
|
throw new Error(`public ingress unsupported for ${service}; use a direct endpoint to preserve signed targets`);
|
|
3656
3699
|
const target = await options2.load(service);
|
|
3657
3700
|
const protocol = "protocol" in target ? target.protocol : "http";
|
|
@@ -3702,7 +3745,7 @@ async function preflightFleet(config, options2) {
|
|
|
3702
3745
|
break;
|
|
3703
3746
|
}
|
|
3704
3747
|
}
|
|
3705
|
-
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.
|
|
3748
|
+
targets.set(name2, { ...target, packageVersion: packageVersion ?? "3.7.0" });
|
|
3706
3749
|
} catch (error) {
|
|
3707
3750
|
throw new Error(`service ${name2}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
3708
3751
|
}
|
|
@@ -3746,6 +3789,11 @@ async function preflightFleet(config, options2) {
|
|
|
3746
3789
|
return ordered;
|
|
3747
3790
|
}
|
|
3748
3791
|
function validateFleetPolicies(options2) {
|
|
3792
|
+
if (options2.archiveCompatibility) {
|
|
3793
|
+
validateCompatibilityTags(options2.archiveCompatibility.tags);
|
|
3794
|
+
if (options2.archiveCompatibility.missing !== void 0 && !["allow", "reject"].includes(options2.archiveCompatibility.missing))
|
|
3795
|
+
throw new Error("archiveCompatibility.missing must be allow or reject");
|
|
3796
|
+
}
|
|
3749
3797
|
if (options2.journal && !options2.repository)
|
|
3750
3798
|
throw new Error("durable operation journal requires an archive repository");
|
|
3751
3799
|
if (options2.cors) {
|
|
@@ -4738,10 +4786,44 @@ async function startFleet(config, options2) {
|
|
|
4738
4786
|
}
|
|
4739
4787
|
}
|
|
4740
4788
|
|
|
4741
|
-
// ../../adapters/node/dist/fleet-
|
|
4742
|
-
import { readFile as readFile4 } from "node:fs/promises";
|
|
4789
|
+
// ../../adapters/node/dist/fleet-loader.js
|
|
4743
4790
|
import { createRequire as createRequire2 } from "node:module";
|
|
4744
4791
|
import { resolve as resolve2 } from "node:path";
|
|
4792
|
+
import { pathToFileURL } from "node:url";
|
|
4793
|
+
var suffix = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
4794
|
+
function createInstalledServiceLoader(options2) {
|
|
4795
|
+
if (!options2.projectRoot)
|
|
4796
|
+
throw new Error("consumer projectRoot required");
|
|
4797
|
+
const allowed = new Set(options2.services);
|
|
4798
|
+
for (const name2 of allowed)
|
|
4799
|
+
if (!suffix.test(name2))
|
|
4800
|
+
throw new Error("invalid service suffix");
|
|
4801
|
+
const require2 = createRequire2(resolve2(options2.projectRoot, "package.json"));
|
|
4802
|
+
const targets = new Map((options2.targets ?? []).map((target) => [target.name, target]));
|
|
4803
|
+
return async (name2) => {
|
|
4804
|
+
if (!suffix.test(name2) || !allowed.has(name2))
|
|
4805
|
+
throw new Error("service is not declared in loader allowlist");
|
|
4806
|
+
const own2 = targets.get(name2);
|
|
4807
|
+
if (own2)
|
|
4808
|
+
return own2;
|
|
4809
|
+
const specifier = `@crvouga/mockingbird-service-${name2}/server`;
|
|
4810
|
+
let location;
|
|
4811
|
+
try {
|
|
4812
|
+
location = require2.resolve(specifier);
|
|
4813
|
+
} catch {
|
|
4814
|
+
throw new Error(`cannot load service "${name2}": install @crvouga/mockingbird-service-${name2} in the consumer project; its /server export is required`);
|
|
4815
|
+
}
|
|
4816
|
+
const mod = await import(pathToFileURL(location).href);
|
|
4817
|
+
if (!mod.serveTarget || mod.serveTarget.name !== name2 || ("protocol" in mod.serveTarget ? typeof mod.serveTarget.start !== "function" : typeof mod.serveTarget.create !== "function"))
|
|
4818
|
+
throw new Error(`${specifier} exports no matching serveTarget`);
|
|
4819
|
+
return mod.serveTarget;
|
|
4820
|
+
};
|
|
4821
|
+
}
|
|
4822
|
+
|
|
4823
|
+
// ../../adapters/node/dist/fleet-tools.js
|
|
4824
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
4825
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
4826
|
+
import { resolve as resolve3 } from "node:path";
|
|
4745
4827
|
|
|
4746
4828
|
// ../../adapters/node/dist/fleet-client.js
|
|
4747
4829
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
@@ -4755,6 +4837,14 @@ var FleetClientError = class extends Error {
|
|
|
4755
4837
|
this.details = details;
|
|
4756
4838
|
}
|
|
4757
4839
|
};
|
|
4840
|
+
var FleetClientResponseError = class extends FleetClientError {
|
|
4841
|
+
code;
|
|
4842
|
+
constructor(code, status, origin) {
|
|
4843
|
+
super(status, { code, body: "omitted", ...origin ? { origin } : {} });
|
|
4844
|
+
this.code = code;
|
|
4845
|
+
this.name = "FleetClientResponseError";
|
|
4846
|
+
}
|
|
4847
|
+
};
|
|
4758
4848
|
var FleetClient = class {
|
|
4759
4849
|
base;
|
|
4760
4850
|
options;
|
|
@@ -4767,7 +4857,14 @@ var FleetClient = class {
|
|
|
4767
4857
|
if (url.username || url.password)
|
|
4768
4858
|
throw new Error("fleet client URL must not contain credentials");
|
|
4769
4859
|
url.searchParams.set("namespace", options2.namespace ?? this.options.namespace ?? "default");
|
|
4860
|
+
const limit = options2.maxResponseBytes ?? this.options.maxResponseBytes ?? 64 * 1024 * 1024;
|
|
4861
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
4862
|
+
throw new Error("invalid response byte limit");
|
|
4863
|
+
const deadline = AbortSignal.timeout(this.options.timeoutMs ?? 3e4);
|
|
4864
|
+
const signal = options2.signal ? AbortSignal.any([options2.signal, deadline]) : deadline;
|
|
4865
|
+
signal.throwIfAborted();
|
|
4770
4866
|
const response = await (this.options.fetch ?? fetch)(url, {
|
|
4867
|
+
redirect: "manual",
|
|
4771
4868
|
method: options2.method ?? (options2.body === void 0 ? "GET" : "POST"),
|
|
4772
4869
|
headers: {
|
|
4773
4870
|
"content-type": "application/json",
|
|
@@ -4775,11 +4872,71 @@ var FleetClient = class {
|
|
|
4775
4872
|
...options2.idempotencyKey ? { "idempotency-key": options2.idempotencyKey } : {}
|
|
4776
4873
|
},
|
|
4777
4874
|
...options2.body !== void 0 ? { body: JSON.stringify(options2.body) } : {},
|
|
4778
|
-
signal
|
|
4875
|
+
signal
|
|
4779
4876
|
});
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
throw new
|
|
4877
|
+
if (response.status >= 300 && response.status < 400) {
|
|
4878
|
+
await response.body?.cancel();
|
|
4879
|
+
throw new FleetClientResponseError("redirect", response.status, url.origin);
|
|
4880
|
+
}
|
|
4881
|
+
if (Number(response.headers.get("content-length")) > limit) {
|
|
4882
|
+
await response.body?.cancel();
|
|
4883
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4884
|
+
}
|
|
4885
|
+
const reader = response.body?.getReader();
|
|
4886
|
+
const chunks = [];
|
|
4887
|
+
let size = 0;
|
|
4888
|
+
const abort = () => {
|
|
4889
|
+
void reader?.cancel(signal.reason).catch(() => {
|
|
4890
|
+
});
|
|
4891
|
+
};
|
|
4892
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
4893
|
+
try {
|
|
4894
|
+
if (reader)
|
|
4895
|
+
while (true) {
|
|
4896
|
+
signal.throwIfAborted();
|
|
4897
|
+
const { done, value } = await reader.read();
|
|
4898
|
+
signal.throwIfAborted();
|
|
4899
|
+
if (done)
|
|
4900
|
+
break;
|
|
4901
|
+
size += value.byteLength;
|
|
4902
|
+
if (size > limit) {
|
|
4903
|
+
await reader.cancel();
|
|
4904
|
+
throw new FleetClientResponseError("response_too_large", response.status);
|
|
4905
|
+
}
|
|
4906
|
+
chunks.push(value);
|
|
4907
|
+
}
|
|
4908
|
+
} finally {
|
|
4909
|
+
signal.removeEventListener("abort", abort);
|
|
4910
|
+
if (signal.aborted)
|
|
4911
|
+
await reader?.cancel(signal.reason).catch(() => {
|
|
4912
|
+
});
|
|
4913
|
+
reader?.releaseLock();
|
|
4914
|
+
}
|
|
4915
|
+
const bytes = new Uint8Array(size);
|
|
4916
|
+
let offset = 0;
|
|
4917
|
+
for (const chunk of chunks) {
|
|
4918
|
+
bytes.set(chunk, offset);
|
|
4919
|
+
offset += chunk.byteLength;
|
|
4920
|
+
}
|
|
4921
|
+
const text = new TextDecoder().decode(bytes);
|
|
4922
|
+
let data;
|
|
4923
|
+
try {
|
|
4924
|
+
data = text.length ? JSON.parse(text) : void 0;
|
|
4925
|
+
} catch {
|
|
4926
|
+
if (response.ok)
|
|
4927
|
+
throw new FleetClientResponseError("invalid_json", response.status);
|
|
4928
|
+
}
|
|
4929
|
+
if (!response.ok) {
|
|
4930
|
+
const error = data && typeof data === "object" ? data.error : void 0;
|
|
4931
|
+
const detail = { body: "omitted" };
|
|
4932
|
+
if (error && typeof error === "object")
|
|
4933
|
+
for (const key of ["type", "code"]) {
|
|
4934
|
+
const value = error[key];
|
|
4935
|
+
if (typeof value === "string" && /^[A-Za-z0-9_.-]{1,128}$/.test(value))
|
|
4936
|
+
detail[key] = value;
|
|
4937
|
+
}
|
|
4938
|
+
throw new FleetClientError(response.status, detail);
|
|
4939
|
+
}
|
|
4783
4940
|
return data;
|
|
4784
4941
|
}
|
|
4785
4942
|
discover() {
|
|
@@ -4845,17 +5002,52 @@ function renderConnections(manifest, privateManifest, namespace, mapping) {
|
|
|
4845
5002
|
const child = manifest.services[entry.service], secret = privateManifest.services[entry.service];
|
|
4846
5003
|
if (!child || !secret)
|
|
4847
5004
|
throw new Error(`missing service mapping ${entry.service}`);
|
|
5005
|
+
let endpoint;
|
|
4848
5006
|
if (child.protocol === "http") {
|
|
4849
5007
|
const template = child.namespaces.path;
|
|
4850
5008
|
if (typeof template !== "string")
|
|
4851
5009
|
throw new Error(`missing HTTP namespace mapping ${entry.service}`);
|
|
4852
|
-
|
|
5010
|
+
endpoint = new URL(template.replace("{name}", encodeURIComponent(namespace)), secret.url).href;
|
|
4853
5011
|
} else {
|
|
4854
|
-
const
|
|
4855
|
-
if (!
|
|
5012
|
+
const selected = secret.namespaces?.[namespace];
|
|
5013
|
+
if (!selected)
|
|
4856
5014
|
throw new Error(`missing namespace mapping ${namespace}/${entry.service}`);
|
|
4857
|
-
|
|
5015
|
+
endpoint = selected;
|
|
4858
5016
|
}
|
|
5017
|
+
const url = new URL(endpoint);
|
|
5018
|
+
const field = entry.field ?? "url";
|
|
5019
|
+
let value;
|
|
5020
|
+
switch (field) {
|
|
5021
|
+
case "url":
|
|
5022
|
+
value = endpoint;
|
|
5023
|
+
break;
|
|
5024
|
+
case "hostname":
|
|
5025
|
+
value = url.hostname.replace(/^\[|\]$/g, "");
|
|
5026
|
+
break;
|
|
5027
|
+
case "port":
|
|
5028
|
+
value = url.port;
|
|
5029
|
+
break;
|
|
5030
|
+
case "username":
|
|
5031
|
+
value = decodeURIComponent(url.username);
|
|
5032
|
+
break;
|
|
5033
|
+
case "password":
|
|
5034
|
+
value = decodeURIComponent(url.password);
|
|
5035
|
+
break;
|
|
5036
|
+
case "pathname":
|
|
5037
|
+
value = decodeURIComponent(url.pathname);
|
|
5038
|
+
break;
|
|
5039
|
+
case "database":
|
|
5040
|
+
value = decodeURIComponent(url.pathname.replace(/^\//, ""));
|
|
5041
|
+
break;
|
|
5042
|
+
default:
|
|
5043
|
+
throw new Error("unsupported connection field");
|
|
5044
|
+
}
|
|
5045
|
+
if (!value) {
|
|
5046
|
+
if (typeof entry.fallback !== "string")
|
|
5047
|
+
throw new Error(`missing connection component ${field}`);
|
|
5048
|
+
value = entry.fallback;
|
|
5049
|
+
}
|
|
5050
|
+
result[variable] = value;
|
|
4859
5051
|
}
|
|
4860
5052
|
return result;
|
|
4861
5053
|
}
|
|
@@ -4879,7 +5071,7 @@ async function doctorFleet(config, options2, probes = []) {
|
|
|
4879
5071
|
const plan = [];
|
|
4880
5072
|
try {
|
|
4881
5073
|
const targets = await preflightFleet(config, options2);
|
|
4882
|
-
const require2 =
|
|
5074
|
+
const require2 = createRequire3(resolve3(process.cwd(), "package.json"));
|
|
4883
5075
|
for (const [service, target] of targets) {
|
|
4884
5076
|
let version = "development";
|
|
4885
5077
|
try {
|
|
@@ -4934,7 +5126,7 @@ async function doctorFleet(config, options2, probes = []) {
|
|
|
4934
5126
|
};
|
|
4935
5127
|
}
|
|
4936
5128
|
async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3e4) {
|
|
4937
|
-
const archive =
|
|
5129
|
+
const archive = assertArchiveCompatibility(input, options2.archiveCompatibility);
|
|
4938
5130
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4939
5131
|
const isolated = {
|
|
4940
5132
|
...config,
|
|
@@ -4946,7 +5138,7 @@ async function rehearseFleet(config, options2, input, probes = [], timeoutMs = 3
|
|
|
4946
5138
|
};
|
|
4947
5139
|
let fleet;
|
|
4948
5140
|
try {
|
|
4949
|
-
fleet = await startFleet(isolated,
|
|
5141
|
+
fleet = await startFleet(isolated, options2);
|
|
4950
5142
|
const client = new FleetClient(fleet.manifest.adminBase, {
|
|
4951
5143
|
...config.adminKey ? { adminKey: config.adminKey } : {}
|
|
4952
5144
|
});
|
|
@@ -5321,26 +5513,7 @@ var resolveServeControls = async (values, env = process.env, base) => {
|
|
|
5321
5513
|
normalizeBootControls(document, "adminControls");
|
|
5322
5514
|
return document;
|
|
5323
5515
|
};
|
|
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
|
-
};
|
|
5516
|
+
var loadTarget = (name2, own2) => createInstalledServiceLoader({ projectRoot: process.cwd(), services: [name2], targets: [own2] })(name2);
|
|
5344
5517
|
var start = async (target, values, config) => {
|
|
5345
5518
|
const adminPrefix = resolveAdminPrefix(config.adminPrefix);
|
|
5346
5519
|
const runtime = await target.create(values, {
|
|
@@ -5786,9 +5959,9 @@ function stemEnglish(input) {
|
|
|
5786
5959
|
return false;
|
|
5787
5960
|
})();
|
|
5788
5961
|
if (!step1bDone) {
|
|
5789
|
-
for (const
|
|
5790
|
-
if (w.endsWith(
|
|
5791
|
-
const stem = w.slice(0, -
|
|
5962
|
+
for (const suffix2 of ["ingly", "edly", "ing", "ed"]) {
|
|
5963
|
+
if (w.endsWith(suffix2)) {
|
|
5964
|
+
const stem = w.slice(0, -suffix2.length);
|
|
5792
5965
|
if ([...stem].some(isVowel)) {
|
|
5793
5966
|
w = stem;
|
|
5794
5967
|
if (w.endsWith("at") || w.endsWith("bl") || w.endsWith("iz")) w += "e";
|
|
@@ -5826,9 +5999,9 @@ function stemEnglish(input) {
|
|
|
5826
5999
|
["alli", "al"],
|
|
5827
6000
|
["bli", "ble"]
|
|
5828
6001
|
];
|
|
5829
|
-
for (const [
|
|
5830
|
-
if (w.endsWith(
|
|
5831
|
-
if (w.length -
|
|
6002
|
+
for (const [suffix2, repl] of step2) {
|
|
6003
|
+
if (w.endsWith(suffix2)) {
|
|
6004
|
+
if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
|
|
5832
6005
|
break;
|
|
5833
6006
|
}
|
|
5834
6007
|
}
|
|
@@ -5847,9 +6020,9 @@ function stemEnglish(input) {
|
|
|
5847
6020
|
["ness", ""],
|
|
5848
6021
|
["ful", ""]
|
|
5849
6022
|
];
|
|
5850
|
-
for (const [
|
|
5851
|
-
if (w.endsWith(
|
|
5852
|
-
if (w.length -
|
|
6023
|
+
for (const [suffix2, repl] of step3) {
|
|
6024
|
+
if (w.endsWith(suffix2)) {
|
|
6025
|
+
if (w.length - suffix2.length >= r1) w = w.slice(0, -suffix2.length) + repl;
|
|
5853
6026
|
break;
|
|
5854
6027
|
}
|
|
5855
6028
|
}
|
|
@@ -5875,9 +6048,9 @@ function stemEnglish(input) {
|
|
|
5875
6048
|
"er",
|
|
5876
6049
|
"ic"
|
|
5877
6050
|
];
|
|
5878
|
-
for (const
|
|
5879
|
-
if (w.endsWith(
|
|
5880
|
-
if (w.length -
|
|
6051
|
+
for (const suffix2 of step4) {
|
|
6052
|
+
if (w.endsWith(suffix2)) {
|
|
6053
|
+
if (w.length - suffix2.length >= r2) w = w.slice(0, -suffix2.length);
|
|
5881
6054
|
break;
|
|
5882
6055
|
}
|
|
5883
6056
|
}
|
|
@@ -8085,6 +8258,12 @@ var invalidName = () => {
|
|
|
8085
8258
|
throw pgError("syntax", "invalid name syntax", "42602");
|
|
8086
8259
|
};
|
|
8087
8260
|
function parseNamespaceInput(text) {
|
|
8261
|
+
const parsed = parseRelationInput(text);
|
|
8262
|
+
if ("oid" in parsed) return parsed;
|
|
8263
|
+
if (parsed.parts.length !== 1) invalidName();
|
|
8264
|
+
return { name: parsed.parts[0] };
|
|
8265
|
+
}
|
|
8266
|
+
function parseRelationInput(text) {
|
|
8088
8267
|
if (text === "-") return { oid: 0 };
|
|
8089
8268
|
if (/^\d+$/.test(text)) return { oid: parseOidText(text) };
|
|
8090
8269
|
const names = [];
|
|
@@ -8120,8 +8299,8 @@ function parseNamespaceInput(text) {
|
|
|
8120
8299
|
skipSpace();
|
|
8121
8300
|
if (at === text.length) invalidName();
|
|
8122
8301
|
}
|
|
8123
|
-
if (names.length
|
|
8124
|
-
return {
|
|
8302
|
+
if (names.length === 0 || names.length > 3) invalidName();
|
|
8303
|
+
return { parts: names };
|
|
8125
8304
|
}
|
|
8126
8305
|
function namespaceText(oid, name2) {
|
|
8127
8306
|
if (oid === 0) return "-";
|
|
@@ -8194,6 +8373,7 @@ var TYPE_ALIASES = {
|
|
|
8194
8373
|
regtype: "regtype",
|
|
8195
8374
|
regproc: "regproc",
|
|
8196
8375
|
regnamespace: "regnamespace",
|
|
8376
|
+
xid: "xid",
|
|
8197
8377
|
oid: "oid",
|
|
8198
8378
|
void: "void",
|
|
8199
8379
|
record: "record",
|
|
@@ -8270,6 +8450,7 @@ var TYPE_OIDS = {
|
|
|
8270
8450
|
regproc: 24,
|
|
8271
8451
|
text: 25,
|
|
8272
8452
|
oid: 26,
|
|
8453
|
+
xid: 28,
|
|
8273
8454
|
json: 114,
|
|
8274
8455
|
float4: 700,
|
|
8275
8456
|
float8: 701,
|
|
@@ -8589,6 +8770,7 @@ function recordText(rec, ctx) {
|
|
|
8589
8770
|
return `(${parts.join(",")})`;
|
|
8590
8771
|
}
|
|
8591
8772
|
function datumText(t, v, ctx) {
|
|
8773
|
+
if (t === "regclass") return v === 0 ? "-" : ctx.relationName?.(v) ?? String(v);
|
|
8592
8774
|
if (t === "regnamespace") return namespaceText(v, ctx.namespaceName?.(v));
|
|
8593
8775
|
if (v === null) throw pgError("internal", "datumText called with null");
|
|
8594
8776
|
if (isArrayType(t)) return arrayText(v, ctx);
|
|
@@ -8599,6 +8781,7 @@ function datumText(t, v, ctx) {
|
|
|
8599
8781
|
case "int2":
|
|
8600
8782
|
case "int4":
|
|
8601
8783
|
case "oid":
|
|
8784
|
+
case "xid":
|
|
8602
8785
|
return String(v);
|
|
8603
8786
|
case "int8":
|
|
8604
8787
|
return String(v);
|
|
@@ -8663,6 +8846,12 @@ function datumText(t, v, ctx) {
|
|
|
8663
8846
|
}
|
|
8664
8847
|
var UTC_INPUT = { zoneOffsetForNaive: () => 0 };
|
|
8665
8848
|
function datumFromText(t, text, ctx) {
|
|
8849
|
+
if (t === "regclass") {
|
|
8850
|
+
const parsed = parseRelationInput(text);
|
|
8851
|
+
if ("oid" in parsed) return parsed.oid;
|
|
8852
|
+
if (!ctx.relationOid) throw unsupported("regclass input without a catalog");
|
|
8853
|
+
return ctx.relationOid(parsed.parts);
|
|
8854
|
+
}
|
|
8666
8855
|
if (t === "regnamespace") {
|
|
8667
8856
|
const parsed = parseNamespaceInput(text);
|
|
8668
8857
|
if ("oid" in parsed) return parsed.oid;
|
|
@@ -8684,6 +8873,7 @@ function datumFromText(t, text, ctx) {
|
|
|
8684
8873
|
case "int8":
|
|
8685
8874
|
return parseIntegerText(text, t);
|
|
8686
8875
|
case "oid":
|
|
8876
|
+
case "xid":
|
|
8687
8877
|
return parseOidText(text);
|
|
8688
8878
|
case "float4":
|
|
8689
8879
|
return Math.fround(parseFloatText(text, "float4"));
|
|
@@ -8840,6 +9030,8 @@ var TableData = class _TableData {
|
|
|
8840
9030
|
schema;
|
|
8841
9031
|
columns;
|
|
8842
9032
|
rows;
|
|
9033
|
+
rowXmins = /* @__PURE__ */ new WeakMap();
|
|
9034
|
+
slabXmins = null;
|
|
8843
9035
|
/** Frozen columnar storage after snapshot hydrate; `rows` stays empty until materialized. */
|
|
8844
9036
|
slab = null;
|
|
8845
9037
|
constraints;
|
|
@@ -8882,6 +9074,11 @@ var TableData = class _TableData {
|
|
|
8882
9074
|
materializeSlab() {
|
|
8883
9075
|
if (!this.slab) return;
|
|
8884
9076
|
this.rows = this.slab.materialize();
|
|
9077
|
+
if (this.slabXmins)
|
|
9078
|
+
this.rows.forEach((row, index) => {
|
|
9079
|
+
this.rowXmins.set(row, this.slabXmins[index] ?? 2);
|
|
9080
|
+
});
|
|
9081
|
+
this.slabXmins = null;
|
|
8885
9082
|
this.slab = null;
|
|
8886
9083
|
this.indexStores = null;
|
|
8887
9084
|
}
|
|
@@ -8915,6 +9112,10 @@ var TableData = class _TableData {
|
|
|
8915
9112
|
} else {
|
|
8916
9113
|
t.rows = this.rows.map((r) => r.slice());
|
|
8917
9114
|
}
|
|
9115
|
+
t.rows.forEach((row, index) => {
|
|
9116
|
+
const xmin = this.slabXmins?.[index] ?? this.rowXmins.get(this.rows[index]);
|
|
9117
|
+
if (xmin !== void 0) t.rowXmins.set(row, xmin);
|
|
9118
|
+
});
|
|
8918
9119
|
t.unlogged = this.unlogged;
|
|
8919
9120
|
t.constraints = this.constraints.map((c) => ({ ...c }));
|
|
8920
9121
|
t.triggers = this.triggers.map((tr) => ({ ...tr }));
|
|
@@ -9000,6 +9201,14 @@ var DatabaseState = class _DatabaseState {
|
|
|
9000
9201
|
clock;
|
|
9001
9202
|
changes = 0;
|
|
9002
9203
|
oidCounter = 16384;
|
|
9204
|
+
/** Local monotonic xid allocator; 2 denotes a row from a legacy snapshot without metadata. */
|
|
9205
|
+
xidCounter = 3;
|
|
9206
|
+
transactionXid = null;
|
|
9207
|
+
allocateXid() {
|
|
9208
|
+
if (this.xidCounter > 4294967295)
|
|
9209
|
+
throw pgError("program_limit_exceeded", "transaction ID space exhausted; xid wraparound is not modeled", "54000");
|
|
9210
|
+
return this.xidCounter++;
|
|
9211
|
+
}
|
|
9003
9212
|
inTransaction = false;
|
|
9004
9213
|
/** Transaction-only events: included in rollback clones, never in exported snapshots. */
|
|
9005
9214
|
pendingTriggers = [];
|
|
@@ -9213,6 +9422,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9213
9422
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
9214
9423
|
s.tableStats = new Map(this.tableStats);
|
|
9215
9424
|
s.oidCounter = this.oidCounter;
|
|
9425
|
+
s.xidCounter = this.xidCounter;
|
|
9426
|
+
s.transactionXid = this.transactionXid;
|
|
9216
9427
|
for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
|
|
9217
9428
|
return s;
|
|
9218
9429
|
}
|
|
@@ -9232,6 +9443,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9232
9443
|
s.sequenceCurrval = new Map(this.sequenceCurrval);
|
|
9233
9444
|
s.tableStats = new Map(this.tableStats);
|
|
9234
9445
|
s.oidCounter = this.oidCounter;
|
|
9446
|
+
s.xidCounter = this.xidCounter;
|
|
9447
|
+
s.transactionXid = this.transactionXid;
|
|
9235
9448
|
for (const [name2, overloads] of this.systemFunctions) s.systemFunctions.set(name2, overloads.slice());
|
|
9236
9449
|
return s;
|
|
9237
9450
|
}
|
|
@@ -9307,6 +9520,8 @@ var DatabaseState = class _DatabaseState {
|
|
|
9307
9520
|
this.sequenceCurrval = other.sequenceCurrval;
|
|
9308
9521
|
this.tableStats = other.tableStats;
|
|
9309
9522
|
this.oidCounter = other.oidCounter;
|
|
9523
|
+
this.xidCounter = Math.max(this.xidCounter, other.xidCounter);
|
|
9524
|
+
this.transactionXid = other.transactionXid;
|
|
9310
9525
|
}
|
|
9311
9526
|
/** @internal Snapshot codec access to the oid allocator. */
|
|
9312
9527
|
snapshotOidCounter() {
|
|
@@ -9386,6 +9601,11 @@ function validateZone(zone) {
|
|
|
9386
9601
|
// src/expressions/context.ts
|
|
9387
9602
|
var EngineCtx = class {
|
|
9388
9603
|
state;
|
|
9604
|
+
writeXid = null;
|
|
9605
|
+
rowVersionXid() {
|
|
9606
|
+
if (this.state.inTransaction) return this.state.transactionXid ??= this.state.allocateXid();
|
|
9607
|
+
return this.writeXid ??= this.state.allocateXid();
|
|
9608
|
+
}
|
|
9389
9609
|
/** transaction timestamp (now(), current_timestamp) — UTC micros since PG epoch */
|
|
9390
9610
|
txNow;
|
|
9391
9611
|
/** statement timestamp */
|
|
@@ -9400,6 +9620,23 @@ var EngineCtx = class {
|
|
|
9400
9620
|
timezone() {
|
|
9401
9621
|
return this.state.getSetting("timezone") ?? "UTC";
|
|
9402
9622
|
}
|
|
9623
|
+
relationOid(parts) {
|
|
9624
|
+
const target = this.state.resolveRelationSchema(parts);
|
|
9625
|
+
const schema = target ? this.state.schemas.get(target.schema) : void 0;
|
|
9626
|
+
const relation = target ? schema?.sequences.get(target.name) ?? schema?.tables.get(target.name) ?? schema?.views.get(target.name) : void 0;
|
|
9627
|
+
if (!relation) throw pgError("undefined_table", `relation "${parts.join(".")}" does not exist`, "42P01");
|
|
9628
|
+
return relation.oid;
|
|
9629
|
+
}
|
|
9630
|
+
relationName(oid) {
|
|
9631
|
+
for (const schema of this.state.schemas.values()) {
|
|
9632
|
+
for (const relation of [...schema.tables.values(), ...schema.sequences.values(), ...schema.views.values()]) {
|
|
9633
|
+
if (relation.oid !== oid) continue;
|
|
9634
|
+
const visible = this.state.resolveRelationSchema([relation.name])?.schema === schema.name;
|
|
9635
|
+
return (visible ? [relation.name] : [schema.name, relation.name]).map(quoteIdentifier).join(".");
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9638
|
+
return null;
|
|
9639
|
+
}
|
|
9403
9640
|
namespaceOid(name2) {
|
|
9404
9641
|
const oid = builtinNamespaceOid(name2) ?? this.state.schemas.get(name2)?.oid;
|
|
9405
9642
|
if (oid === void 0) throw pgError("undefined_object", `schema "${name2}" does not exist`, "3F000");
|
|
@@ -9700,7 +9937,7 @@ function castTo(env, value, target, opts = {}) {
|
|
|
9700
9937
|
return tv(target, makeArray(toElem, items, arr.dims.slice(), arr.lbs.slice()));
|
|
9701
9938
|
}
|
|
9702
9939
|
if (from === "oid" && target === "regnamespace") return tv(target, v);
|
|
9703
|
-
if (from === "regnamespace" && (target === "oid" || target === "int4" || target === "int8")) {
|
|
9940
|
+
if ((from === "regnamespace" || from === "regclass") && (target === "oid" || target === "int4" || target === "int8")) {
|
|
9704
9941
|
return tv(target, target === "int8" ? BigInt(v) : v);
|
|
9705
9942
|
}
|
|
9706
9943
|
if ((from === "int4" || from === "int8" || from === "int2") && (target === "oid" || target === "regnamespace")) {
|
|
@@ -10401,6 +10638,8 @@ function datumCompare(t, a, b, ctx = DEFAULT_COMPARE_CTX) {
|
|
|
10401
10638
|
case "int2":
|
|
10402
10639
|
case "int4":
|
|
10403
10640
|
case "oid":
|
|
10641
|
+
case "regclass":
|
|
10642
|
+
case "xid":
|
|
10404
10643
|
case "regnamespace":
|
|
10405
10644
|
case "date":
|
|
10406
10645
|
return expectNumber(a, t) - expectNumber(b, t);
|
|
@@ -10520,6 +10759,8 @@ function datumKey(t, v) {
|
|
|
10520
10759
|
case "int2":
|
|
10521
10760
|
case "int4":
|
|
10522
10761
|
case "oid":
|
|
10762
|
+
case "regclass":
|
|
10763
|
+
case "xid":
|
|
10523
10764
|
case "date":
|
|
10524
10765
|
return `i${v}`;
|
|
10525
10766
|
case "float4":
|
|
@@ -11403,8 +11644,8 @@ function toCharTimestamp(ctx, localMicros, fmt, tzOffsetSec) {
|
|
|
11403
11644
|
else if (tryPat("TH") || tryPat("th")) {
|
|
11404
11645
|
const prev = /(\d+)$/.exec(out);
|
|
11405
11646
|
const n = prev ? Number.parseInt(prev[1], 10) : 0;
|
|
11406
|
-
const
|
|
11407
|
-
out += rest.startsWith("TH") ?
|
|
11647
|
+
const suffix2 = ordinalSuffix(n);
|
|
11648
|
+
out += rest.startsWith("TH") ? suffix2.toUpperCase() : suffix2;
|
|
11408
11649
|
} else {
|
|
11409
11650
|
out += fmt[i];
|
|
11410
11651
|
i++;
|
|
@@ -12623,7 +12864,7 @@ function claimConstraintIndexName(schema, constraint, explicit, reserved = /* @_
|
|
|
12623
12864
|
if (used(constraint.name)) {
|
|
12624
12865
|
if (explicit) throw pgError("duplicate_table", `relation "${constraint.name}" already exists`, "42P07");
|
|
12625
12866
|
const base = constraint.name;
|
|
12626
|
-
for (let
|
|
12867
|
+
for (let suffix2 = 1; used(constraint.name); suffix2++) constraint.name = `${base}${suffix2}`;
|
|
12627
12868
|
}
|
|
12628
12869
|
reserved.add(constraint.name);
|
|
12629
12870
|
}
|
|
@@ -13428,7 +13669,7 @@ function setDatabaseCatalogContext(state, context) {
|
|
|
13428
13669
|
var PG_VERSION_TEXT = "PostgreSQL 18.3 (postgres-mem) on TypeScript, in-memory engine";
|
|
13429
13670
|
function findSequenceForCall(ctx, name2) {
|
|
13430
13671
|
const parts = parseQualifiedName(name2);
|
|
13431
|
-
const seq = ctx.state.findSequence(parts);
|
|
13672
|
+
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
13673
|
if (!seq) {
|
|
13433
13674
|
throw pgError("undefined_table", `relation "${name2}" does not exist`, "42P01");
|
|
13434
13675
|
}
|
|
@@ -13652,14 +13893,16 @@ function getMiscFunctions() {
|
|
|
13652
13893
|
"pg_get_serial_sequence",
|
|
13653
13894
|
strict("text", (ctx, args2) => {
|
|
13654
13895
|
const tableName2 = argText(ctx, args2[0]);
|
|
13655
|
-
const column = argText(ctx, args2[1])
|
|
13896
|
+
const column = argText(ctx, args2[1]);
|
|
13656
13897
|
const table = ctx.state.findTable(parseQualifiedName(tableName2));
|
|
13657
13898
|
if (!table) throw pgError("undefined_table", `relation "${tableName2}" does not exist`, "42P01");
|
|
13658
13899
|
const col = table.columns.find((c) => c.name === column);
|
|
13659
13900
|
if (!col)
|
|
13660
13901
|
throw pgError("undefined_column", `column "${column}" of relation "${table.name}" does not exist`, "42703");
|
|
13661
|
-
|
|
13662
|
-
|
|
13902
|
+
const seq = [...ctx.state.schemas.get(table.schema)?.sequences.values() ?? []].find(
|
|
13903
|
+
(candidate) => candidate.ownedBy?.table === table.name && candidate.ownedBy.column === column
|
|
13904
|
+
);
|
|
13905
|
+
return tv("text", seq ? [seq.schema, seq.name].map(quoteIdent).join(".") : null);
|
|
13663
13906
|
})
|
|
13664
13907
|
);
|
|
13665
13908
|
m.set("format_type", (ctx, args2) => {
|
|
@@ -18603,7 +18846,7 @@ var RowScope = class {
|
|
|
18603
18846
|
let count2 = 0;
|
|
18604
18847
|
for (let i = 0; i < this.columns.length; i++) {
|
|
18605
18848
|
const c = this.columns[i];
|
|
18606
|
-
if (c.name === name3 && !c.hidden) {
|
|
18849
|
+
if (c.name === name3 && (!c.hidden || c.system)) {
|
|
18607
18850
|
count2++;
|
|
18608
18851
|
if (count2 > 1) {
|
|
18609
18852
|
throw pgError("ambiguous_column", `column reference "${name3}" is ambiguous`);
|
|
@@ -18641,7 +18884,7 @@ var RowScope = class {
|
|
|
18641
18884
|
const names = [];
|
|
18642
18885
|
for (let i = 0; i < this.columns.length; i++) {
|
|
18643
18886
|
const c = this.columns[i];
|
|
18644
|
-
if (c.table === rangeVar) {
|
|
18887
|
+
if (c.table === rangeVar && !c.system) {
|
|
18645
18888
|
types.push(c.type);
|
|
18646
18889
|
values.push(this.row[i] ?? null);
|
|
18647
18890
|
names.push(c.name);
|
|
@@ -19084,7 +19327,7 @@ function tryIndexedFromItem(env, item, where) {
|
|
|
19084
19327
|
if (!table) return null;
|
|
19085
19328
|
const alias = item.alias ?? item.name[item.name.length - 1];
|
|
19086
19329
|
table.materializeSlab();
|
|
19087
|
-
return tryIndexedTableRows(env, table, alias, where);
|
|
19330
|
+
return tryIndexedTableRows(env, table, alias, where)?.map((row) => [...row, table.rowXmins.get(row) ?? 2]) ?? null;
|
|
19088
19331
|
}
|
|
19089
19332
|
function joinKeyFromRow(row, colIdxs, srcTypes, unifiedTypes, ctx) {
|
|
19090
19333
|
const parts = [];
|
|
@@ -21574,6 +21817,7 @@ var Parser = class {
|
|
|
21574
21817
|
let sqlBody = null;
|
|
21575
21818
|
let volatility = null;
|
|
21576
21819
|
let strict2 = false;
|
|
21820
|
+
const settings = {};
|
|
21577
21821
|
for (; ; ) {
|
|
21578
21822
|
if (this.eatKw("language")) {
|
|
21579
21823
|
language = this.peek().type === "string" ? this.next().value : this.ident(true);
|
|
@@ -21631,8 +21875,23 @@ var Parser = class {
|
|
|
21631
21875
|
continue;
|
|
21632
21876
|
}
|
|
21633
21877
|
if (this.eatKw("set")) {
|
|
21634
|
-
this.ident(true);
|
|
21635
|
-
if (this.
|
|
21878
|
+
const key = this.ident(true).toLowerCase();
|
|
21879
|
+
if (this.eatKw("from")) {
|
|
21880
|
+
this.expectKw("current");
|
|
21881
|
+
settings[key] = "__from_current__";
|
|
21882
|
+
} else {
|
|
21883
|
+
if (!this.eatOp("=")) this.expectKw("to");
|
|
21884
|
+
const values = [];
|
|
21885
|
+
do {
|
|
21886
|
+
const value = this.next();
|
|
21887
|
+
if (!["string", "ident", "quoted_ident", "number"].includes(value.type))
|
|
21888
|
+
this.errorAt(value, "expected setting value");
|
|
21889
|
+
values.push(
|
|
21890
|
+
key === "search_path" && /[^a-z0-9_]/.test(value.value) ? `"${value.value.replaceAll('"', '""')}"` : value.value
|
|
21891
|
+
);
|
|
21892
|
+
} while (this.eatPunct(","));
|
|
21893
|
+
settings[key] = values.join(", ");
|
|
21894
|
+
}
|
|
21636
21895
|
continue;
|
|
21637
21896
|
}
|
|
21638
21897
|
if (this.eatKw("window")) throw unsupported("window functions via CREATE FUNCTION");
|
|
@@ -21712,7 +21971,8 @@ var Parser = class {
|
|
|
21712
21971
|
body,
|
|
21713
21972
|
sqlBody,
|
|
21714
21973
|
volatility,
|
|
21715
|
-
strict: strict2
|
|
21974
|
+
strict: strict2,
|
|
21975
|
+
settings
|
|
21716
21976
|
};
|
|
21717
21977
|
}
|
|
21718
21978
|
parseCreateTrigger(orReplace, constraint) {
|
|
@@ -21821,8 +22081,8 @@ var Parser = class {
|
|
|
21821
22081
|
type: "alter_sequence",
|
|
21822
22082
|
name: name2,
|
|
21823
22083
|
ifExists,
|
|
21824
|
-
options: {
|
|
21825
|
-
|
|
22084
|
+
options: {},
|
|
22085
|
+
renameTo: to
|
|
21826
22086
|
};
|
|
21827
22087
|
}
|
|
21828
22088
|
if (this.atKw("set") && (this.atKw("logged", 1) || this.atKw("unlogged", 1))) {
|
|
@@ -24398,7 +24658,20 @@ function runFunctionBody(env, fn, args2) {
|
|
|
24398
24658
|
}
|
|
24399
24659
|
return last;
|
|
24400
24660
|
}
|
|
24661
|
+
function withFunctionSettings(env, fn, run) {
|
|
24662
|
+
const state = env.ctx.state;
|
|
24663
|
+
const saved = new Map(state.localSettings);
|
|
24664
|
+
for (const [name2, value] of Object.entries(fn.settings ?? {})) state.localSettings.set(name2, value);
|
|
24665
|
+
try {
|
|
24666
|
+
return run();
|
|
24667
|
+
} finally {
|
|
24668
|
+
state.localSettings = saved;
|
|
24669
|
+
}
|
|
24670
|
+
}
|
|
24401
24671
|
function callSqlFunctionScalar(env, fn, args2) {
|
|
24672
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionScalarBody(env, fn, args2));
|
|
24673
|
+
}
|
|
24674
|
+
function callSqlFunctionScalarBody(env, fn, args2) {
|
|
24402
24675
|
const retT = fn.returns ?? "text";
|
|
24403
24676
|
if (fn.language === "plpgsql") {
|
|
24404
24677
|
return callPlpgsqlScalar(env, fn, args2);
|
|
@@ -24428,6 +24701,9 @@ function callSqlFunctionScalar(env, fn, args2) {
|
|
|
24428
24701
|
return castTo(env.ctx, tv(rawT, raw), retT, {});
|
|
24429
24702
|
}
|
|
24430
24703
|
function callSqlFunctionSet(env, fn, args2) {
|
|
24704
|
+
return withFunctionSettings(env, fn, () => callSqlFunctionSetBody(env, fn, args2));
|
|
24705
|
+
}
|
|
24706
|
+
function callSqlFunctionSetBody(env, fn, args2) {
|
|
24431
24707
|
if (fn.language === "plpgsql") {
|
|
24432
24708
|
return callPlpgsqlSet(env, fn, args2);
|
|
24433
24709
|
}
|
|
@@ -24582,15 +24858,17 @@ function executeRecursiveCte(env, cte, query) {
|
|
|
24582
24858
|
return rel3;
|
|
24583
24859
|
}
|
|
24584
24860
|
function renameWithAliases(rel3, label, colAliases, what) {
|
|
24585
|
-
|
|
24861
|
+
const visibleWidth = rel3.columns.filter((column) => !column.system).length;
|
|
24862
|
+
if (colAliases && colAliases.length > visibleWidth) {
|
|
24586
24863
|
throw pgError(
|
|
24587
24864
|
"invalid_column_reference",
|
|
24588
|
-
`table "${what}" has ${
|
|
24865
|
+
`table "${what}" has ${visibleWidth} columns available but ${colAliases.length} columns specified`,
|
|
24589
24866
|
"42P10"
|
|
24590
24867
|
);
|
|
24591
24868
|
}
|
|
24592
24869
|
const columns = rel3.columns.map((c, i) => ({
|
|
24593
|
-
|
|
24870
|
+
...c,
|
|
24871
|
+
name: c.system ? c.name : colAliases?.[i] ?? c.name,
|
|
24594
24872
|
type: c.type === UNKNOWN ? "text" : c.type,
|
|
24595
24873
|
table: label
|
|
24596
24874
|
}));
|
|
@@ -24611,8 +24889,11 @@ function materializeItem(env, item, scope) {
|
|
|
24611
24889
|
if (table) {
|
|
24612
24890
|
table.materializeSlab();
|
|
24613
24891
|
const rel3 = {
|
|
24614
|
-
columns:
|
|
24615
|
-
|
|
24892
|
+
columns: [
|
|
24893
|
+
...table.columns.map((c) => ({ name: c.name, type: c.type.id, table: label })),
|
|
24894
|
+
{ name: "xmin", type: "xid", table: label, hidden: true, system: true }
|
|
24895
|
+
],
|
|
24896
|
+
rows: table.rows.map((row) => [...row, table.rowXmins.get(row) ?? 2])
|
|
24616
24897
|
};
|
|
24617
24898
|
return { rel: renameWithAliases(rel3, label, item.colAliases, label), rangeVars: /* @__PURE__ */ new Set([label]) };
|
|
24618
24899
|
}
|
|
@@ -25242,7 +25523,7 @@ function resolveColIdx(columns, parts) {
|
|
|
25242
25523
|
let found = -1;
|
|
25243
25524
|
for (let i = 0; i < columns.length; i++) {
|
|
25244
25525
|
const c = columns[i];
|
|
25245
|
-
if (!c.hidden && c.name === name3) {
|
|
25526
|
+
if ((!c.hidden || c.system) && c.name === name3) {
|
|
25246
25527
|
if (found !== -1) return null;
|
|
25247
25528
|
found = i;
|
|
25248
25529
|
}
|
|
@@ -25826,7 +26107,7 @@ function expandTargets(core, columns) {
|
|
|
25826
26107
|
let any = false;
|
|
25827
26108
|
for (let i = 0; i < columns.length; i++) {
|
|
25828
26109
|
const c = columns[i];
|
|
25829
|
-
if (c.table === label) {
|
|
26110
|
+
if (c.table === label && !c.system) {
|
|
25830
26111
|
any = true;
|
|
25831
26112
|
items.push({ name: c.name, kind: "col", colIdx: i, expr: null, hidden: false });
|
|
25832
26113
|
}
|
|
@@ -26431,6 +26712,7 @@ var TransactionManager = class {
|
|
|
26431
26712
|
this.base = null;
|
|
26432
26713
|
this.savepoints = [];
|
|
26433
26714
|
this.state.inTransaction = false;
|
|
26715
|
+
this.state.transactionXid = null;
|
|
26434
26716
|
this.state.localSettings.clear();
|
|
26435
26717
|
this.state.pendingTriggers = [];
|
|
26436
26718
|
this.state.constraintModes.clear();
|
|
@@ -26443,6 +26725,7 @@ var TransactionManager = class {
|
|
|
26443
26725
|
this.base = null;
|
|
26444
26726
|
this.savepoints = [];
|
|
26445
26727
|
this.state.inTransaction = false;
|
|
26728
|
+
this.state.transactionXid = null;
|
|
26446
26729
|
this.state.localSettings.clear();
|
|
26447
26730
|
this.state.pendingTriggers = [];
|
|
26448
26731
|
this.state.constraintModes.clear();
|
|
@@ -26477,6 +26760,7 @@ var TransactionManager = class {
|
|
|
26477
26760
|
this.base = null;
|
|
26478
26761
|
this.savepoints = [];
|
|
26479
26762
|
this.state.inTransaction = false;
|
|
26763
|
+
this.state.transactionXid = null;
|
|
26480
26764
|
this.freezeDepth = 0;
|
|
26481
26765
|
}
|
|
26482
26766
|
};
|
|
@@ -26680,6 +26964,7 @@ function applyOnConflictUpdate(env, table, label, existingIdx, newRow, sets, whe
|
|
|
26680
26964
|
const updated = existing.slice();
|
|
26681
26965
|
applyUpdateSets(env, table, sets, scope, updated);
|
|
26682
26966
|
computeGeneratedColumns(env, table, updated);
|
|
26967
|
+
table.rowXmins.set(updated, env.ctx.rowVersionXid());
|
|
26683
26968
|
rows[existingIdx] = updated;
|
|
26684
26969
|
indexUpdateRow(env, table, existingIdx, existing, updated);
|
|
26685
26970
|
checkNotNull(env, table, updated);
|
|
@@ -26765,6 +27050,7 @@ function executeInsert(env0, stmt) {
|
|
|
26765
27050
|
checkChecks(env, table, newRow);
|
|
26766
27051
|
checkUnique(env, table, newRow, rows.length);
|
|
26767
27052
|
checkForeignKeys(env, table, newRow);
|
|
27053
|
+
table.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
26768
27054
|
rows.push(newRow);
|
|
26769
27055
|
indexInsertRow(env, table, rows.length - 1, newRow);
|
|
26770
27056
|
insertedCount++;
|
|
@@ -26882,6 +27168,7 @@ function executeUpdate(env0, stmt) {
|
|
|
26882
27168
|
if (fired.row === null) continue;
|
|
26883
27169
|
const finalRow = fired.row;
|
|
26884
27170
|
computeGeneratedColumns(env, table, finalRow);
|
|
27171
|
+
table.rowXmins.set(finalRow, env.ctx.rowVersionXid());
|
|
26885
27172
|
rows[ri] = finalRow;
|
|
26886
27173
|
try {
|
|
26887
27174
|
checkNotNull(env, table, finalRow);
|
|
@@ -27001,6 +27288,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27001
27288
|
for (const c of con.columns) {
|
|
27002
27289
|
newRow[child.columnIndex(c)] = null;
|
|
27003
27290
|
}
|
|
27291
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27004
27292
|
childRows[i] = newRow;
|
|
27005
27293
|
checkNotNull(env, child, newRow);
|
|
27006
27294
|
checkChecks(env, child, newRow);
|
|
@@ -27014,6 +27302,7 @@ function handleReferencedDelete(env, table, row, depth) {
|
|
|
27014
27302
|
const ci = child.columnIndex(c);
|
|
27015
27303
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
27016
27304
|
}
|
|
27305
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27017
27306
|
childRows[i] = newRow;
|
|
27018
27307
|
checkNotNull(env, child, newRow);
|
|
27019
27308
|
checkChecks(env, child, newRow);
|
|
@@ -27051,6 +27340,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
27051
27340
|
const refIdx = table.columnIndex(con.refColumns[c]);
|
|
27052
27341
|
newRow[localIdx] = newRows[r][refIdx] ?? null;
|
|
27053
27342
|
}
|
|
27343
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27054
27344
|
childRows[i] = newRow;
|
|
27055
27345
|
checkChecks(env, child, newRow);
|
|
27056
27346
|
}
|
|
@@ -27060,6 +27350,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
27060
27350
|
for (const i of idxs) {
|
|
27061
27351
|
const newRow = childRows[i].slice();
|
|
27062
27352
|
for (const c of con.columns) newRow[child.columnIndex(c)] = null;
|
|
27353
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27063
27354
|
childRows[i] = newRow;
|
|
27064
27355
|
checkNotNull(env, child, newRow);
|
|
27065
27356
|
}
|
|
@@ -27072,6 +27363,7 @@ function handleReferencedUpdate(env, table, oldRows, newRows) {
|
|
|
27072
27363
|
const ci = child.columnIndex(c);
|
|
27073
27364
|
newRow[ci] = columnDefault(env, child, child.columns[ci]);
|
|
27074
27365
|
}
|
|
27366
|
+
child.rowXmins.set(newRow, env.ctx.rowVersionXid());
|
|
27075
27367
|
childRows[i] = newRow;
|
|
27076
27368
|
checkForeignKeys(env, child, newRow);
|
|
27077
27369
|
}
|
|
@@ -30119,13 +30411,63 @@ function executeCreateSequence(env, stmt) {
|
|
|
30119
30411
|
schema.sequences.set(name2, seq);
|
|
30120
30412
|
return commandResult("CREATE SEQUENCE", 0);
|
|
30121
30413
|
}
|
|
30414
|
+
function renameSequenceReferences(env, seq, newName) {
|
|
30415
|
+
const state = env.ctx.state;
|
|
30416
|
+
const matches2 = (value) => {
|
|
30417
|
+
try {
|
|
30418
|
+
const input = parseRelationInput(value);
|
|
30419
|
+
if ("oid" in input) return input.oid === seq.oid;
|
|
30420
|
+
return state.findSequence(input.parts)?.oid === seq.oid;
|
|
30421
|
+
} catch {
|
|
30422
|
+
return false;
|
|
30423
|
+
}
|
|
30424
|
+
};
|
|
30425
|
+
const rewrite = (value) => {
|
|
30426
|
+
if (Array.isArray(value)) return value.map(rewrite);
|
|
30427
|
+
if (value === null || typeof value !== "object") return value;
|
|
30428
|
+
const node = value;
|
|
30429
|
+
const updated = Object.fromEntries(Object.entries(node).map(([key, child]) => [key, rewrite(child)]));
|
|
30430
|
+
const rewriteLiteral = (literal2) => {
|
|
30431
|
+
if (literal2 && typeof literal2 === "object" && "type" in literal2 && literal2.type === "string_lit" && "value" in literal2 && typeof literal2.value === "string" && matches2(literal2.value)) {
|
|
30432
|
+
return { ...literal2, value: [seq.schema, newName].map(quoteIdent).join(".") };
|
|
30433
|
+
}
|
|
30434
|
+
return literal2;
|
|
30435
|
+
};
|
|
30436
|
+
if (node.type === "func" && Array.isArray(node.name) && ["nextval", "currval", "setval"].includes(String(node.name.at(-1))) && Array.isArray(updated.args))
|
|
30437
|
+
updated.args[0] = rewriteLiteral(updated.args[0]);
|
|
30438
|
+
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")
|
|
30439
|
+
updated.expr = rewriteLiteral(updated.expr);
|
|
30440
|
+
return updated;
|
|
30441
|
+
};
|
|
30442
|
+
for (const schema of state.schemas.values()) {
|
|
30443
|
+
for (const table of [...schema.tables.values()]) {
|
|
30444
|
+
const writable = state.ensureWritableTable(table);
|
|
30445
|
+
for (const column of writable.columns) {
|
|
30446
|
+
if (column.defaultExpr) column.defaultExpr = rewrite(column.defaultExpr);
|
|
30447
|
+
if (column.identity?.sequence === `${seq.schema}.${seq.name}`)
|
|
30448
|
+
column.identity = { ...column.identity, sequence: `${seq.schema}.${newName}` };
|
|
30449
|
+
}
|
|
30450
|
+
}
|
|
30451
|
+
}
|
|
30452
|
+
}
|
|
30122
30453
|
function executeAlterSequence(env, stmt) {
|
|
30123
30454
|
const state = env.ctx.state;
|
|
30124
|
-
const
|
|
30125
|
-
if (!
|
|
30455
|
+
const foundSequence = state.findSequence(stmt.name);
|
|
30456
|
+
if (!foundSequence) {
|
|
30126
30457
|
if (stmt.ifExists) return commandResult("ALTER SEQUENCE", 0);
|
|
30127
30458
|
throw pgError("undefined_table", `relation "${stmt.name.join(".")}" does not exist`, "42P01");
|
|
30128
30459
|
}
|
|
30460
|
+
const seq = state.ensureWritableSequence(foundSequence);
|
|
30461
|
+
if (stmt.renameTo) {
|
|
30462
|
+
const schema = state.getSchema(seq.schema);
|
|
30463
|
+
if (schema.hasRelation(stmt.renameTo))
|
|
30464
|
+
throw pgError("duplicate_table", `relation "${stmt.renameTo}" already exists`, "42P07");
|
|
30465
|
+
renameSequenceReferences(env, seq, stmt.renameTo);
|
|
30466
|
+
schema.sequences.delete(seq.name);
|
|
30467
|
+
seq.name = stmt.renameTo;
|
|
30468
|
+
schema.sequences.set(seq.name, seq);
|
|
30469
|
+
return commandResult("ALTER SEQUENCE", 0);
|
|
30470
|
+
}
|
|
30129
30471
|
const o = stmt.options;
|
|
30130
30472
|
if (o.logged !== void 0) {
|
|
30131
30473
|
setSequenceLogged(state, seq, o.logged);
|
|
@@ -30183,7 +30525,7 @@ function buildColumn(env, schema, tableName2, def, out, taken) {
|
|
|
30183
30525
|
col.defaultExpr = {
|
|
30184
30526
|
type: "func",
|
|
30185
30527
|
name: ["nextval"],
|
|
30186
|
-
args: [{ type: "string_lit", value:
|
|
30528
|
+
args: [{ type: "string_lit", value: [schema.name, seqName].map(quoteIdent).join(".") }]
|
|
30187
30529
|
};
|
|
30188
30530
|
}
|
|
30189
30531
|
for (const c of def.constraints) {
|
|
@@ -30436,7 +30778,11 @@ function executeCreateTableAs(env, stmt) {
|
|
|
30436
30778
|
const table = new TableData(schema.name, name2, columns, state.nextOid(), stmt.temp);
|
|
30437
30779
|
table.unlogged = stmt.unlogged === true;
|
|
30438
30780
|
if (stmt.withData) {
|
|
30439
|
-
for (const row of rel3.rows)
|
|
30781
|
+
for (const row of rel3.rows) {
|
|
30782
|
+
const stored = row.slice();
|
|
30783
|
+
table.rowXmins.set(stored, env.ctx.rowVersionXid());
|
|
30784
|
+
table.mutableRows().push(stored);
|
|
30785
|
+
}
|
|
30440
30786
|
}
|
|
30441
30787
|
schema.tables.set(name2, table);
|
|
30442
30788
|
const count = stmt.withData ? table.rowCount() : 0;
|
|
@@ -30705,6 +31051,12 @@ function executeCreateFunction(env, stmt) {
|
|
|
30705
31051
|
language: lang,
|
|
30706
31052
|
body,
|
|
30707
31053
|
rawBody: stmt.body,
|
|
31054
|
+
settings: Object.fromEntries(
|
|
31055
|
+
Object.entries(stmt.settings ?? {}).map(([key, value]) => [
|
|
31056
|
+
key,
|
|
31057
|
+
value === "__from_current__" ? state.getSetting(key) ?? "" : value
|
|
31058
|
+
])
|
|
31059
|
+
),
|
|
30708
31060
|
strict: stmt.strict,
|
|
30709
31061
|
oid: state.nextOid()
|
|
30710
31062
|
};
|
|
@@ -30889,6 +31241,7 @@ function executeAlterTable(env, stmt) {
|
|
|
30889
31241
|
}
|
|
30890
31242
|
const next = row.slice();
|
|
30891
31243
|
next[idx] = nv;
|
|
31244
|
+
table.rowXmins.set(next, table.rowXmins.get(rows[i]) ?? 2);
|
|
30892
31245
|
rows[i] = next;
|
|
30893
31246
|
}
|
|
30894
31247
|
col.type = resolved.column;
|
|
@@ -30990,6 +31343,11 @@ function executeAlterTable(env, stmt) {
|
|
|
30990
31343
|
);
|
|
30991
31344
|
}
|
|
30992
31345
|
table.columns[idx].name = action.to;
|
|
31346
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
31347
|
+
if (seq.ownedBy?.table === table.name && seq.ownedBy.column === action.from) {
|
|
31348
|
+
state.ensureWritableSequence(seq).ownedBy = { table: table.name, column: action.to };
|
|
31349
|
+
}
|
|
31350
|
+
}
|
|
30993
31351
|
for (const con of table.constraints) {
|
|
30994
31352
|
if (con.kind === "primary_key" || con.kind === "unique" || con.kind === "foreign_key") {
|
|
30995
31353
|
con.columns = con.columns.map((c) => c === action.from ? action.to : c);
|
|
@@ -31026,6 +31384,11 @@ function executeAlterTable(env, stmt) {
|
|
|
31026
31384
|
throw pgError("duplicate_table", `relation "${action.to}" already exists`, "42P07");
|
|
31027
31385
|
}
|
|
31028
31386
|
const oldName = table.name;
|
|
31387
|
+
for (const seq of [...schema.sequences.values()]) {
|
|
31388
|
+
if (seq.ownedBy?.table === oldName) {
|
|
31389
|
+
state.ensureWritableSequence(seq).ownedBy = { ...seq.ownedBy, table: action.to };
|
|
31390
|
+
}
|
|
31391
|
+
}
|
|
31029
31392
|
schema.tables.delete(table.name);
|
|
31030
31393
|
table.name = action.to;
|
|
31031
31394
|
schema.tables.set(action.to, table);
|
|
@@ -32899,6 +33262,7 @@ function encodeDatabaseState(state, runtime) {
|
|
|
32899
33262
|
writeBjv(
|
|
32900
33263
|
w,
|
|
32901
33264
|
{
|
|
33265
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
32902
33266
|
name: table.name,
|
|
32903
33267
|
schema: table.schema,
|
|
32904
33268
|
columns: table.columns,
|
|
@@ -32996,8 +33360,14 @@ function decodeInner(snapshot, prng, clock) {
|
|
|
32996
33360
|
table.constraints = meta.constraints;
|
|
32997
33361
|
table.triggers = meta.triggers;
|
|
32998
33362
|
table.unlogged = meta.unlogged === true;
|
|
33363
|
+
table.slabXmins = meta.xmins ?? null;
|
|
33364
|
+
state.xidCounter = Math.max(
|
|
33365
|
+
state.xidCounter,
|
|
33366
|
+
(meta.xmins ?? []).reduce((max, xid) => Math.max(max, xid + 1), 3)
|
|
33367
|
+
);
|
|
32999
33368
|
if (meta.stats) state.tableStats.set(table.oid, meta.stats);
|
|
33000
33369
|
const rowCount = readVarintU32(r);
|
|
33370
|
+
if (meta.xmins && meta.xmins.length !== rowCount) throw snapshotError();
|
|
33001
33371
|
const slabColumns = [];
|
|
33002
33372
|
for (let c = 0; c < meta.columns.length; c++)
|
|
33003
33373
|
slabColumns.push(readPackedColumn(r, rowCount, intern, meta.columns[c].type.id));
|
|
@@ -33441,6 +33811,8 @@ function validateTableMetaBjv(value) {
|
|
|
33441
33811
|
if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
33442
33812
|
if (!Array.isArray(value.columns)) throw snapshotError();
|
|
33443
33813
|
for (const col of value.columns) validateColumnMeta(col);
|
|
33814
|
+
if (value.xmins !== void 0 && (!Array.isArray(value.xmins) || value.xmins.some((xid) => !Number.isInteger(xid) || xid < 2 || xid > 4294967295)))
|
|
33815
|
+
throw snapshotError();
|
|
33444
33816
|
}
|
|
33445
33817
|
function validateViewMetaBjv(value) {
|
|
33446
33818
|
if (!isRecord2(value) || typeof value.name !== "string" || typeof value.schema !== "string") throw snapshotError();
|
|
@@ -33534,6 +33906,7 @@ function forceSchemaIntern(pool, state, schemas) {
|
|
|
33534
33906
|
pool.forceId(table.name);
|
|
33535
33907
|
pool.forceId(table.schema);
|
|
33536
33908
|
forceBjvStrings(pool, {
|
|
33909
|
+
xmins: table.allRows().map((row) => table.rowXmins.get(row) ?? 2),
|
|
33537
33910
|
name: table.name,
|
|
33538
33911
|
schema: table.schema,
|
|
33539
33912
|
columns: table.columns,
|
|
@@ -35164,7 +35537,7 @@ var Connection = class {
|
|
|
35164
35537
|
if (stmt?.type !== "transaction") throw pgError2("syntax", "invalid transaction command", "42601");
|
|
35165
35538
|
switch (stmt.action) {
|
|
35166
35539
|
case "begin":
|
|
35167
|
-
this.transaction ??= { statements: [], savepoints: [] };
|
|
35540
|
+
this.transaction ??= { statements: [], savepoints: [], xid: this.database.state.allocateXid() };
|
|
35168
35541
|
return command("BEGIN");
|
|
35169
35542
|
case "commit": {
|
|
35170
35543
|
const transaction = this.transaction;
|
|
@@ -35173,6 +35546,7 @@ var Connection = class {
|
|
|
35173
35546
|
this.inSession(
|
|
35174
35547
|
this.database,
|
|
35175
35548
|
() => this.database.transaction(() => {
|
|
35549
|
+
this.database.state.transactionXid = transaction.xid;
|
|
35176
35550
|
for (const logged of transaction.statements) this.replay(this.database, logged);
|
|
35177
35551
|
})
|
|
35178
35552
|
);
|
|
@@ -35223,6 +35597,7 @@ var Connection = class {
|
|
|
35223
35597
|
workspace.state.settings = new Map(this.settings);
|
|
35224
35598
|
workspace.state.settingDefaults = this.settingDefaults;
|
|
35225
35599
|
workspace.transactions.begin();
|
|
35600
|
+
workspace.state.transactionXid = this.transaction?.xid ?? null;
|
|
35226
35601
|
for (const logged of this.transaction?.statements ?? []) {
|
|
35227
35602
|
this.replay(workspace, logged);
|
|
35228
35603
|
}
|