@coffre/db 0.14.4 → 0.15.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.
Files changed (218) hide show
  1. package/README.md +2 -1
  2. package/dist/change-records-_fKvahvs.js +55 -0
  3. package/dist/connect.d.ts +22 -10
  4. package/dist/connect.js +74 -12
  5. package/dist/database-CVteLhp1.d.ts +410 -0
  6. package/dist/{database-BadNeeN-.js → database-D55ENPX-.js} +46 -25
  7. package/dist/dialect.d.ts +4 -3
  8. package/dist/dialect.js +14 -5
  9. package/dist/grants.d.ts +4 -4
  10. package/dist/grants.js +4 -4
  11. package/dist/hyperdrive.d.ts +48 -23
  12. package/dist/hyperdrive.js +168 -91
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.js +1 -1
  15. package/dist/log-DaD7fyUq.d.ts +722 -0
  16. package/dist/log.d.ts +2 -596
  17. package/dist/log.js +224 -10
  18. package/dist/migrate.d.ts +43 -3
  19. package/dist/migrate.js +149 -29
  20. package/dist/migrations/postgres/0021_prune_vault_releases.sql +19 -0
  21. package/dist/migrations/postgres/0022_log_015.sql +672 -0
  22. package/dist/migrations/postgres/0023_change_path.sql +153 -0
  23. package/dist/migrations/postgres/0024_use_015.sql +556 -0
  24. package/dist/migrations/postgres/0025_app_change.sql +221 -0
  25. package/dist/migrations/postgres/0026_issue_lock.sql +106 -0
  26. package/dist/migrations/postgres/0027_retention.sql +118 -0
  27. package/dist/migrations/postgres/0028_use_stalls.sql +594 -0
  28. package/dist/migrations/postgres/0029_use_objects.sql +887 -0
  29. package/dist/migrations/postgres/0030_unarchive_restores.sql +259 -0
  30. package/dist/migrations/postgres/0031_app_read.sql +65 -0
  31. package/dist/migrations/postgres/0032_secrets_live_index.sql +4 -0
  32. package/dist/migrations/postgres/0033_use_generations.sql +582 -0
  33. package/dist/migrations/postgres/0034_vault_credentials.sql +153 -0
  34. package/dist/migrations/postgres/0035_first_days.sql +3 -0
  35. package/dist/migrations/postgres/0036_vault_issues.sql +91 -0
  36. package/dist/migrations/postgres/0037_vault_bindings.sql +271 -0
  37. package/dist/migrations/postgres/0040_binding_origin.sql +159 -0
  38. package/dist/migrations/postgres/0041_cutover.sql +132 -0
  39. package/dist/migrations/postgres/0042_sign_in_index.sql +7 -0
  40. package/dist/migrations/postgres/0043_issue_revoke_index.sql +4 -0
  41. package/dist/migrations/postgres/0044_use_by_name.sql +705 -0
  42. package/dist/migrations/postgres/0045_decide_first.sql +878 -0
  43. package/dist/migrations/postgres/0046_way_in_uses.sql +1149 -0
  44. package/dist/migrations/postgres/0047_cutover_finish.sql +268 -0
  45. package/dist/migrations/postgres/0048_use_batch.sql +59 -0
  46. package/dist/migrations/postgres/0049_reads.sql +171 -0
  47. package/dist/migrations/postgres/meta/0021_snapshot.json +3334 -0
  48. package/dist/migrations/postgres/meta/0022_snapshot.json +3831 -0
  49. package/dist/migrations/postgres/meta/0023_snapshot.json +3831 -0
  50. package/dist/migrations/postgres/meta/0024_snapshot.json +3831 -0
  51. package/dist/migrations/postgres/meta/0025_snapshot.json +3831 -0
  52. package/dist/migrations/postgres/meta/0026_snapshot.json +3831 -0
  53. package/dist/migrations/postgres/meta/0027_snapshot.json +3853 -0
  54. package/dist/migrations/postgres/meta/0028_snapshot.json +3853 -0
  55. package/dist/migrations/postgres/meta/0029_snapshot.json +3859 -0
  56. package/dist/migrations/postgres/meta/0030_snapshot.json +3859 -0
  57. package/dist/migrations/postgres/meta/0031_snapshot.json +3859 -0
  58. package/dist/migrations/postgres/meta/0032_snapshot.json +3875 -0
  59. package/dist/migrations/postgres/meta/0033_snapshot.json +3875 -0
  60. package/dist/migrations/postgres/meta/0034_snapshot.json +3875 -0
  61. package/dist/migrations/postgres/meta/0035_snapshot.json +3875 -0
  62. package/dist/migrations/postgres/meta/0036_snapshot.json +3875 -0
  63. package/dist/migrations/postgres/meta/0037_snapshot.json +3875 -0
  64. package/dist/migrations/postgres/meta/0038_snapshot.json +3881 -0
  65. package/dist/migrations/postgres/meta/0039_snapshot.json +3881 -0
  66. package/dist/migrations/postgres/meta/0040_snapshot.json +3931 -0
  67. package/dist/migrations/postgres/meta/0041_snapshot.json +3981 -0
  68. package/dist/migrations/postgres/meta/0042_snapshot.json +3981 -0
  69. package/dist/migrations/postgres/meta/0043_snapshot.json +3981 -0
  70. package/dist/migrations/postgres/meta/0044_snapshot.json +3991 -0
  71. package/dist/migrations/postgres/meta/0045_snapshot.json +3997 -0
  72. package/dist/migrations/postgres/meta/0046_snapshot.json +3997 -0
  73. package/dist/migrations/postgres/meta/0047_snapshot.json +4234 -0
  74. package/dist/migrations/postgres/meta/_journal.json +189 -0
  75. package/dist/migrations/sqlite/0018_log_015.sql +84 -0
  76. package/dist/migrations/sqlite/0019_retention.sql +2 -0
  77. package/dist/migrations/sqlite/0020_ended_references.sql +1 -0
  78. package/dist/migrations/sqlite/0021_secrets_live_index.sql +1 -0
  79. package/dist/migrations/sqlite/0022_binding_origin.sql +1 -0
  80. package/dist/migrations/sqlite/0023_sign_in_index.sql +2 -0
  81. package/dist/migrations/sqlite/0024_issue_revoke_index.sql +2 -0
  82. package/dist/migrations/sqlite/0025_way_in_uses.sql +42 -0
  83. package/dist/migrations/sqlite/0026_cutover_finish.sql +11 -0
  84. package/dist/migrations/sqlite/0027_reads.sql +38 -0
  85. package/dist/migrations/sqlite/meta/0018_snapshot.json +3529 -0
  86. package/dist/migrations/sqlite/meta/0019_snapshot.json +3538 -0
  87. package/dist/migrations/sqlite/meta/0020_snapshot.json +3545 -0
  88. package/dist/migrations/sqlite/meta/0021_snapshot.json +3553 -0
  89. package/dist/migrations/sqlite/meta/0022_snapshot.json +3560 -0
  90. package/dist/migrations/sqlite/meta/0023_snapshot.json +3579 -0
  91. package/dist/migrations/sqlite/meta/0024_snapshot.json +3598 -0
  92. package/dist/migrations/sqlite/meta/0025_snapshot.json +3609 -0
  93. package/dist/migrations/sqlite/meta/0026_snapshot.json +3616 -0
  94. package/dist/migrations/sqlite/meta/0027_snapshot.json +3834 -0
  95. package/dist/migrations/sqlite/meta/_journal.json +70 -0
  96. package/dist/platform-Y3gICK6n.d.ts +58 -0
  97. package/dist/portable.d.ts +2 -2
  98. package/dist/postgres-BI3xTnyw.js +1718 -0
  99. package/dist/postgres-platform-node.d.ts +14 -0
  100. package/dist/postgres-platform-node.js +21 -0
  101. package/dist/postgres-platform-workerd.d.ts +61 -0
  102. package/dist/postgres-platform-workerd.js +163 -0
  103. package/dist/{schema-z8GcN_Xu.d.ts → schema-DgoPqqsI.d.ts} +1329 -9
  104. package/dist/schema-sqlite.d.ts +1308 -8
  105. package/dist/schema-sqlite.js +156 -20
  106. package/dist/schema-version.d.ts +1 -1
  107. package/dist/schema-version.js +261 -2
  108. package/dist/schema.d.ts +2 -2
  109. package/dist/schema.js +229 -22
  110. package/package.json +13 -5
  111. package/src/active-subject.ts +9 -0
  112. package/src/change-records.ts +38 -0
  113. package/src/connect.ts +67 -13
  114. package/src/database.ts +67 -51
  115. package/src/dialect.ts +17 -8
  116. package/src/grants.ts +3 -3
  117. package/src/hyperdrive.ts +181 -104
  118. package/src/log.ts +244 -11
  119. package/src/migrate.ts +157 -30
  120. package/src/migrations/postgres/0021_prune_vault_releases.sql +19 -0
  121. package/src/migrations/postgres/0022_log_015.sql +672 -0
  122. package/src/migrations/postgres/0023_change_path.sql +153 -0
  123. package/src/migrations/postgres/0024_use_015.sql +556 -0
  124. package/src/migrations/postgres/0025_app_change.sql +221 -0
  125. package/src/migrations/postgres/0026_issue_lock.sql +106 -0
  126. package/src/migrations/postgres/0027_retention.sql +118 -0
  127. package/src/migrations/postgres/0028_use_stalls.sql +594 -0
  128. package/src/migrations/postgres/0029_use_objects.sql +887 -0
  129. package/src/migrations/postgres/0030_unarchive_restores.sql +259 -0
  130. package/src/migrations/postgres/0031_app_read.sql +65 -0
  131. package/src/migrations/postgres/0032_secrets_live_index.sql +4 -0
  132. package/src/migrations/postgres/0033_use_generations.sql +582 -0
  133. package/src/migrations/postgres/0034_vault_credentials.sql +153 -0
  134. package/src/migrations/postgres/0035_first_days.sql +3 -0
  135. package/src/migrations/postgres/0036_vault_issues.sql +91 -0
  136. package/src/migrations/postgres/0037_vault_bindings.sql +271 -0
  137. package/src/migrations/postgres/0040_binding_origin.sql +159 -0
  138. package/src/migrations/postgres/0041_cutover.sql +132 -0
  139. package/src/migrations/postgres/0042_sign_in_index.sql +7 -0
  140. package/src/migrations/postgres/0043_issue_revoke_index.sql +4 -0
  141. package/src/migrations/postgres/0044_use_by_name.sql +705 -0
  142. package/src/migrations/postgres/0045_decide_first.sql +878 -0
  143. package/src/migrations/postgres/0046_way_in_uses.sql +1149 -0
  144. package/src/migrations/postgres/0047_cutover_finish.sql +268 -0
  145. package/src/migrations/postgres/0048_use_batch.sql +59 -0
  146. package/src/migrations/postgres/0049_reads.sql +171 -0
  147. package/src/migrations/postgres/meta/0021_snapshot.json +3334 -0
  148. package/src/migrations/postgres/meta/0022_snapshot.json +3831 -0
  149. package/src/migrations/postgres/meta/0023_snapshot.json +3831 -0
  150. package/src/migrations/postgres/meta/0024_snapshot.json +3831 -0
  151. package/src/migrations/postgres/meta/0025_snapshot.json +3831 -0
  152. package/src/migrations/postgres/meta/0026_snapshot.json +3831 -0
  153. package/src/migrations/postgres/meta/0027_snapshot.json +3853 -0
  154. package/src/migrations/postgres/meta/0028_snapshot.json +3853 -0
  155. package/src/migrations/postgres/meta/0029_snapshot.json +3859 -0
  156. package/src/migrations/postgres/meta/0030_snapshot.json +3859 -0
  157. package/src/migrations/postgres/meta/0031_snapshot.json +3859 -0
  158. package/src/migrations/postgres/meta/0032_snapshot.json +3875 -0
  159. package/src/migrations/postgres/meta/0033_snapshot.json +3875 -0
  160. package/src/migrations/postgres/meta/0034_snapshot.json +3875 -0
  161. package/src/migrations/postgres/meta/0035_snapshot.json +3875 -0
  162. package/src/migrations/postgres/meta/0036_snapshot.json +3875 -0
  163. package/src/migrations/postgres/meta/0037_snapshot.json +3875 -0
  164. package/src/migrations/postgres/meta/0038_snapshot.json +3881 -0
  165. package/src/migrations/postgres/meta/0039_snapshot.json +3881 -0
  166. package/src/migrations/postgres/meta/0040_snapshot.json +3931 -0
  167. package/src/migrations/postgres/meta/0041_snapshot.json +3981 -0
  168. package/src/migrations/postgres/meta/0042_snapshot.json +3981 -0
  169. package/src/migrations/postgres/meta/0043_snapshot.json +3981 -0
  170. package/src/migrations/postgres/meta/0044_snapshot.json +3991 -0
  171. package/src/migrations/postgres/meta/0045_snapshot.json +3997 -0
  172. package/src/migrations/postgres/meta/0046_snapshot.json +3997 -0
  173. package/src/migrations/postgres/meta/0047_snapshot.json +4234 -0
  174. package/src/migrations/postgres/meta/_journal.json +189 -0
  175. package/src/migrations/sqlite/0018_log_015.sql +84 -0
  176. package/src/migrations/sqlite/0019_retention.sql +2 -0
  177. package/src/migrations/sqlite/0020_ended_references.sql +1 -0
  178. package/src/migrations/sqlite/0021_secrets_live_index.sql +1 -0
  179. package/src/migrations/sqlite/0022_binding_origin.sql +1 -0
  180. package/src/migrations/sqlite/0023_sign_in_index.sql +2 -0
  181. package/src/migrations/sqlite/0024_issue_revoke_index.sql +2 -0
  182. package/src/migrations/sqlite/0025_way_in_uses.sql +42 -0
  183. package/src/migrations/sqlite/0026_cutover_finish.sql +11 -0
  184. package/src/migrations/sqlite/0027_reads.sql +38 -0
  185. package/src/migrations/sqlite/meta/0018_snapshot.json +3529 -0
  186. package/src/migrations/sqlite/meta/0019_snapshot.json +3538 -0
  187. package/src/migrations/sqlite/meta/0020_snapshot.json +3545 -0
  188. package/src/migrations/sqlite/meta/0021_snapshot.json +3553 -0
  189. package/src/migrations/sqlite/meta/0022_snapshot.json +3560 -0
  190. package/src/migrations/sqlite/meta/0023_snapshot.json +3579 -0
  191. package/src/migrations/sqlite/meta/0024_snapshot.json +3598 -0
  192. package/src/migrations/sqlite/meta/0025_snapshot.json +3609 -0
  193. package/src/migrations/sqlite/meta/0026_snapshot.json +3616 -0
  194. package/src/migrations/sqlite/meta/0027_snapshot.json +3834 -0
  195. package/src/migrations/sqlite/meta/_journal.json +70 -0
  196. package/src/postgres-js/README.md +183 -0
  197. package/src/postgres-js/UNLICENSE +24 -0
  198. package/src/postgres-js/bytes.ts +89 -0
  199. package/src/postgres-js/connection.ts +882 -0
  200. package/src/postgres-js/errors.ts +84 -0
  201. package/src/postgres-js/index.ts +516 -0
  202. package/src/postgres-js/platform.node.ts +29 -0
  203. package/src/postgres-js/platform.ts +60 -0
  204. package/src/postgres-js/platform.workerd.ts +225 -0
  205. package/src/postgres-js/query.ts +123 -0
  206. package/src/postgres-js/queue.ts +42 -0
  207. package/src/postgres-js/result.ts +46 -0
  208. package/src/postgres-js/types.ts +52 -0
  209. package/src/postgres.ts +375 -26
  210. package/src/schema-version.ts +2 -2
  211. package/src/schema.sqlite.ts +200 -9
  212. package/src/schema.ts +294 -8
  213. package/src/verify-runtime.ts +18 -29
  214. package/LICENSE +0 -21
  215. package/dist/database-CFhTnnzM.d.ts +0 -73
  216. package/dist/postgres-Bmar8y0q.js +0 -29
  217. package/dist/relations-BfR3JjT1.js +0 -38
  218. package/src/relations.ts +0 -40
@@ -0,0 +1,594 @@
1
+ -- One hot principal's uses never queue on its own lock, and a new backend plans its statements before it takes the fence (T127, T131; docs/design/0.15-plan.md, "One hot principal, cold backends"; formal/HotPathOne.tla). use_credential as 0024 wrote it, but for the bulk cap's writes and the warm-up below. It replaces a function only 0.15's hot path calls, behind the switch.
2
+ --
3
+ -- The cap's row (T127, R44). In 0024 a use whose key's row was stale took its principal's lock exclusive, as one entering the set does, and read again: each use of one principal that saw a stale row waited for the one before it to commit. Now:
4
+ -- a key that enters the set (no row, or a row out of the window) takes the lock exclusive, counts the other keys and writes (PrincipalLocks), as before;
5
+ -- a key in the set whose row is from an earlier refresh period moves it on under the lock shared (RefreshLocks, RefreshShared): a key entering waits for every move numbered before it, and no move waits for another;
6
+ -- every write is the start of the use's refresh period, at - at % refresh (RefreshPeriods), and a move only raises the row: moves at once write the same period, or the greater stands, so the row ends where the replay's does whichever commits first. The first use to move a key to a period takes a lock of that key and period's own without waiting, and moves the row; the others take it shared, which waits for that one's end but never for each other, then read the row again, locking none, and leave it moved. (An UPDATE that waits on a row another is moving, and then finds it moved, keeps the row locked to its own commit, as an upsert does: each would queue the next.) If the first rolled back, the others elect another the same way, on the lock's next round;
7
+ -- the writes leave the statement every use runs: a call that took the principal's lock makes them in a statement of its own, after the one that read, in the same transaction and under the same locks. The uses that find their key fresh, nearly all, plan and run no write of the cap's row;
8
+ -- a key is fresh while its row is from the use's own period, for covers too (CoverFresh). A period starts less than a refresh before its use, the margin the set's bounds already have (BulkCapHolds; Use.lean, periodOf_lags);
9
+ -- refresh is at least 1 ms: a tenth of a window under 10 ms was 0;
10
+ -- another key counts against one entering a minute longer than before, over window + refresh + deadline + 60 s (AheadSlack): a use is decided up to the deadline after its `at`, and, its Worker's clock up to a minute ahead (the most 'ahead' lets by), up to a minute before it, so one stamped up to deadline + 60 s before another can be decided after it. With deadline alone, TLC let two keys out in one window (HotPathOneBulkSkew, with the clock run longer: 0024 has the hole too).
11
+ --
12
+ -- The cold plan (T131, R58). A new backend's first call planned its statement holding the fence shared (29 ms against 1.5 ms after), and a barrier queued behind it held every use up meanwhile. Now a session's first call runs each of the four statements once dry, before the fence: each reads and writes nothing (`WHERE NOT dry`, a one-time filter in the generic plan the hot login keeps) and takes no advisory lock (only, as any statement does, each table's AccessShare lock, to the commit), and its plan stays cached for the session. The session then says so in a setting of its own, coffre.use_planned, holding this migration's number, so that a function replaced again plans again; a rollback or RESET ALL (DISCARD ALL) clears it, and the next call plans again, as it must.
13
+ --> statement-breakpoint
14
+ CREATE OR REPLACE FUNCTION use_credential(
15
+ p_credential uuid, p_secret uuid, p_request bigint, p_at bigint, p_purpose smallint, p_place uuid, p_mac bytea, p_deadline bigint,
16
+ p_cover bigint DEFAULT NULL, p_cover_at bigint DEFAULT NULL, p_cover_request bigint DEFAULT NULL, p_known bigint DEFAULT NULL, p_known_mac bytea DEFAULT NULL,
17
+ p_cap_count integer DEFAULT NULL, p_cap_window bigint DEFAULT NULL
18
+ ) RETURNS json
19
+ LANGUAGE plpgsql SECURITY DEFINER SET search_path = pg_catalog, pg_temp SET bytea_output = 'hex' AS $$
20
+ DECLARE
21
+ r public.use_row;
22
+ -- The principal's lock held: exclusive (`locked`), to enter its key in the cap's set; shared (`moving`), to move it on.
23
+ locked boolean := false;
24
+ moving boolean := false;
25
+ probe boolean := p_known IS NULL OR p_cap_count IS NULL OR p_cap_window IS NULL;
26
+ -- A use through a place, or of a key with no value of its own (a reference), reads every input; the others, most
27
+ -- uses, the plain shape: no place, no source, none of their joins.
28
+ whole boolean := p_place IS NOT NULL;
29
+ -- The cached forms' refresh and period, from the cap the isolate passes; the probing forms work theirs out from the cap they read.
30
+ c_refresh bigint := greatest(1, least(60000, p_cap_window / 10));
31
+ c_period bigint := p_at - ((p_at % c_refresh) + c_refresh) % c_refresh;
32
+ -- Whether this session has yet to plan the four statements (T131), and the form the warm-up is at.
33
+ dry boolean := current_setting('coffre.use_planned', true) IS DISTINCT FROM '0028';
34
+ form integer := 0;
35
+ first_probe boolean;
36
+ first_whole boolean;
37
+ -- The period this call writes, if it writes the cap's row, and the lock that elects the one use that moves it.
38
+ b_refresh bigint;
39
+ b_period bigint;
40
+ b_lock bigint;
41
+ b_round integer := 0;
42
+ BEGIN
43
+ IF p_deadline IS NULL OR p_deadline > p_at + public.deadline_max() THEN r.state := 'late'; RETURN to_json(r); END IF;
44
+ -- Its Worker's clock ahead by over a minute (0022 says why): checked here at no cost, and again in the statement.
45
+ IF p_at > (extract(epoch FROM clock_timestamp()) * 1000)::bigint + 60000 THEN r.state := 'ahead'; RETURN to_json(r); END IF;
46
+ IF dry THEN
47
+ -- Each form first runs dry, outside the fence, so that its plan is made before this call holds the fence.
48
+ first_probe := probe;
49
+ first_whole := whole;
50
+ probe := true;
51
+ whole := false;
52
+ ELSE
53
+ PERFORM pg_advisory_xact_lock_shared(1668244070, 0);
54
+ END IF;
55
+ LOOP
56
+ IF probe AND NOT whole THEN
57
+ WITH i AS MATERIALIZED (
58
+ SELECT n.number AS newest, n.mac AS newest_mac, coalesce(n.number = p_known AND n.mac = p_known_mac, false) AS cached,
59
+ f.at_floor, (lpol.payload::jsonb #>> '{value,bulk,count}')::integer AS cap_count, (lpol.payload::jsonb #>> '{value,bulk,windowMs}')::bigint AS cap_window,
60
+ lpol.number AS lpol_number, lpol.seal AS p_last,
61
+ c.principal AS p, c.kind AS c_kind, c.scope AS c_scope, c.revoked_at IS NOT NULL AS c_revoked,
62
+ floor(extract(epoch FROM least(c.expires_at, c.not_after)) * 1000)::bigint AS c_expires, c.seal AS c_seal,
63
+ m.status AS m_status, m.owner AS m_owner, m.role AS m_role, m.scope AS m_scope, m.seal AS m_seal,
64
+ cfg.r_value, cfg.r_seal, cfg.p_value, cfg.p_seal,
65
+ s.project_id AS s_project, s.environment_id AS s_environment, s.current_version_id AS s_version, NULL::uuid AS s_source, s.seal AS s_seal,
66
+ NULL::uuid AS x_project, NULL::uuid AS x_environment, NULL::uuid AS x_version, NULL::uuid AS x_source, NULL::bytea AS x_seal,
67
+ sv.envelope_version, sv.ciphertext, sv.iv, sv.auth_tag, sv.wrapped_dek, sv.kek_provider, sv.kek_id, sv.kek_version, sv.sensitive, sv.plaintext IS NOT NULL AS v_plain,
68
+ NULL::uuid AS e1_id, NULL::uuid AS e1_project, NULL::text AS e1_slug, NULL::text AS e1_owner, NULL::uuid AS e1_parent, NULL::boolean AS e1_protected, NULL::boolean AS e1_archived, NULL::bytea AS e1_seal,
69
+ s.environment_id AS e2_id, e2.project_id AS e2_project, e2.slug AS e2_slug, e2.owner AS e2_owner, e2.parent_id AS e2_parent, e2.protected AS e2_protected, e2.archived_at IS NOT NULL AS e2_archived, e2.seal AS e2_seal,
70
+ NULL::uuid AS e3_id, NULL::uuid AS e3_project, NULL::text AS e3_slug, NULL::text AS e3_owner, NULL::uuid AS e3_parent, NULL::boolean AS e3_protected, NULL::boolean AS e3_archived, NULL::bytea AS e3_seal,
71
+ CASE WHEN e2.owner IS NOT NULL THEN e2.parent_id END AS e4_id, e4.project_id AS e4_project, e4.slug AS e4_slug, e4.owner AS e4_owner, e4.parent_id AS e4_parent, e4.protected AS e4_protected, e4.archived_at IS NOT NULL AS e4_archived, e4.seal AS e4_seal,
72
+ b.last AS bulk_last,
73
+ -- Each input's object key, computed once: a key in a probe's own condition is computed again for every row it reads (0022, decision 3).
74
+ public.log_object('credential', p_credential::text) AS k_credential,
75
+ public.log_object('principal', c.principal) AS k_member,
76
+ public.log_object('secret', p_secret::text) AS k_secret,
77
+ public.log_object('environment', s.environment_id::text) AS k_e2,
78
+ public.log_object('environment', (CASE WHEN e2.owner IS NOT NULL THEN e2.parent_id END)::text) AS k_e4
79
+ FROM (SELECT 1) one
80
+ LEFT JOIN LATERAL (SELECT x.number, x.mac FROM public.log_changes x ORDER BY x.number DESC LIMIT 1) n ON true
81
+ LEFT JOIN public.log_fence f ON f.only_row
82
+ -- The roles and the policy, both rows in one read of their one-page table.
83
+ LEFT JOIN LATERAL (
84
+ SELECT max(g.value) FILTER (WHERE g.name = 'roles') AS r_value, (array_agg(g.seal) FILTER (WHERE g.name = 'roles'))[1] AS r_seal,
85
+ max(g.value) FILTER (WHERE g.name = 'policy') AS p_value, (array_agg(g.seal) FILTER (WHERE g.name = 'policy'))[1] AS p_seal
86
+ FROM public.log_config g
87
+ ) cfg ON true
88
+ -- The cap as the policy's newest change says it (CapSealed): every policy change logs the whole policy as its `value`.
89
+ LEFT JOIN LATERAL (
90
+ SELECT x.number, x.seal, x.payload FROM public.log_changes x WHERE x.object = public.log_object('policy', 'instance') ORDER BY x.number DESC LIMIT 1
91
+ ) lpol ON true
92
+ LEFT JOIN public.credentials c ON c.id = p_credential
93
+ LEFT JOIN public.vault_members m ON m.principal = c.principal
94
+ -- An archived key is gone (`secret.delete`): no object.
95
+ LEFT JOIN public.secrets s ON s.id = p_secret AND s.archived_at IS NULL
96
+ -- The key's own version, its own environment, and that environment's parent when it is a personal config.
97
+ LEFT JOIN public.secret_versions sv ON sv.id = s.current_version_id
98
+ LEFT JOIN public.environments e2 ON e2.id = s.environment_id
99
+ LEFT JOIN public.environments e4 ON e4.id = e2.parent_id AND e2.owner IS NOT NULL
100
+ LEFT JOIN public.log_bulk b ON b.principal = c.principal AND b.secret = p_secret
101
+ WHERE NOT dry
102
+ ),
103
+ v AS MATERIALIZED (
104
+ SELECT i.*, cap.refresh, cap.period,
105
+ CASE WHEN i.s_project IS NOT NULL AND i.s_version IS NULL THEN 'whole'
106
+ WHEN i.at_floor IS NULL OR p_at < i.at_floor OR (extract(epoch FROM clock_timestamp()) * 1000)::bigint > p_deadline THEN 'late'
107
+ WHEN p_at > (extract(epoch FROM clock_timestamp()) * 1000)::bigint + 60000 THEN 'ahead'
108
+ WHEN i.cap_count IS NULL OR i.cap_window IS NULL THEN 'unconfigured'
109
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT coalesce(i.bulk_last > p_at - i.cap_window - cap.refresh, false) THEN 'lock'
110
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT moving AND i.bulk_last < cap.period THEN 'share' END AS state,
111
+ greatest(lc.number, lm.number, lr.number, i.lpol_number, ls.number, l2.number, l4.number) AS inputs,
112
+ lc.seal AS c_last, lm.seal AS m_last, (lm.payload::jsonb ->> 'old')::bigint AS m_old, lr.seal AS r_last, ls.seal AS s_last, NULL::bytea AS x_last,
113
+ NULL::bytea AS e1_last, l2.seal AS e2_last, NULL::bytea AS e3_last, l4.seal AS e4_last,
114
+ coalesce(i.bulk_last > p_at - i.cap_window - cap.refresh, false) AS is_in,
115
+ -- The other keys in the set, up to the cap: read only under the principal's lock, for a key not in it.
116
+ CASE WHEN locked AND i.p IS NOT NULL AND NOT coalesce(i.bulk_last > p_at - i.cap_window - cap.refresh, false) THEN (
117
+ SELECT count(*)::integer FROM (
118
+ SELECT 1 FROM public.log_bulk o
119
+ WHERE o.principal = i.p AND o.secret <> p_secret AND o.last > p_at - i.cap_window - cap.refresh - public.deadline_max() - 60000
120
+ LIMIT i.cap_count
121
+ ) z
122
+ ) ELSE 0 END AS n_others,
123
+ -- A repeat rides its cover only while every part of this holds: never on a key whose bulk row is missing (CoverFresh).
124
+ coalesce(p_cover IS NOT NULL AND i.bulk_last >= cap.period AND p_cover > coalesce(greatest(lc.number, lm.number, lr.number, i.lpol_number, ls.number, l2.number, l4.number), 0)
125
+ AND EXISTS (SELECT 1 FROM public.log_uses u WHERE u.at = p_cover_at AND u.request_id = p_cover_request AND u.number = p_cover
126
+ AND u.credential = p_credential AND u.secret = p_secret AND u.purpose = p_purpose AND u.place IS NOT DISTINCT FROM p_place), false) AS is_covered
127
+ FROM i
128
+ CROSS JOIN LATERAL (SELECT greatest(1, least(60000, i.cap_window / 10)) AS refresh) r0
129
+ CROSS JOIN LATERAL (SELECT r0.refresh, p_at - ((p_at % r0.refresh) + r0.refresh) % r0.refresh AS period) cap
130
+ -- Each input's newest change: one index-only probe each (log_changes_object_idx holds the seal), the principal's
131
+ -- with its payload, which names the 0.14 entry it accounts for.
132
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_credential ORDER BY x.number DESC LIMIT 1) lc ON true
133
+ LEFT JOIN LATERAL (SELECT x.number, x.seal, x.payload FROM public.log_changes x WHERE x.object = i.k_member ORDER BY x.number DESC LIMIT 1) lm ON i.k_member IS NOT NULL
134
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = public.log_object('roles', 'instance') ORDER BY x.number DESC LIMIT 1) lr ON true
135
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_secret ORDER BY x.number DESC LIMIT 1) ls ON true
136
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_e2 ORDER BY x.number DESC LIMIT 1) l2 ON i.k_e2 IS NOT NULL
137
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_e4 ORDER BY x.number DESC LIMIT 1) l4 ON i.k_e4 IS NOT NULL
138
+ ),
139
+ w AS (
140
+ INSERT INTO public.log_uses (number, at, request_id, credential, secret, purpose, mac, place)
141
+ SELECT nextval('public.log_number'), p_at, p_request, p_credential, p_secret, p_purpose, p_mac, p_place
142
+ FROM v WHERE v.state IS NULL AND NOT v.is_covered
143
+ RETURNING log_uses.number
144
+ )
145
+ SELECT v.state, (SELECT w.number FROM w), CASE WHEN v.state IS NULL AND v.is_covered THEN p_cover END, v.newest, v.newest_mac, v.inputs, true,
146
+ v.p, v.c_kind, v.c_scope, v.c_revoked, v.c_expires, v.c_seal, v.c_last,
147
+ v.m_status, v.m_owner, v.m_role, v.m_scope, v.m_seal, v.m_last, v.m_old,
148
+ (SELECT a.seq FROM public.audit_log a WHERE a.author = 'vault' AND a.subject_principal = v.p AND a.decision = 'allow'
149
+ AND a.action IN ('member.add', 'member.restore', 'member.owner', 'member.role', 'member.remove', 'access.grant', 'access.revoke') ORDER BY a.seq DESC LIMIT 1),
150
+ gr.g_project, gr.g_environment, gr.g_slug, gr.g_role, gr.g_expires,
151
+ v.r_value, v.r_seal, v.r_last,
152
+ v.p_value, v.p_seal, v.p_last, v.cap_count, v.cap_window,
153
+ v.s_project, v.s_environment, v.s_version, v.s_source, v.s_seal, v.s_last,
154
+ v.x_project, v.x_environment, v.x_version, v.x_source, v.x_seal, v.x_last,
155
+ v.envelope_version, v.ciphertext, v.iv, v.auth_tag, v.wrapped_dek, v.kek_provider, v.kek_id, v.kek_version, v.sensitive, v.v_plain,
156
+ v.e1_id, v.e1_project, v.e1_slug, v.e1_owner, v.e1_parent, v.e1_protected, v.e1_archived, v.e1_seal, v.e1_last,
157
+ v.e2_id, v.e2_project, v.e2_slug, v.e2_owner, v.e2_parent, v.e2_protected, v.e2_archived, v.e2_seal, v.e2_last,
158
+ v.e3_id, v.e3_project, v.e3_slug, v.e3_owner, v.e3_parent, v.e3_protected, v.e3_archived, v.e3_seal, v.e3_last,
159
+ v.e4_id, v.e4_project, v.e4_slug, v.e4_owner, v.e4_parent, v.e4_protected, v.e4_archived, v.e4_seal, v.e4_last,
160
+ v.is_in, v.n_others
161
+ INTO r
162
+ FROM v
163
+ -- The principal's grants as five lists, one entry per grant, lapsed ones included; an environment's grant with its project, which its row finds through `environments`.
164
+ LEFT JOIN LATERAL (
165
+ SELECT array_agg(coalesce(g.project_id, ge.project_id)) AS g_project, array_agg(g.environment_id) AS g_environment,
166
+ array_agg(g.environment_slug) AS g_slug, array_agg(g.role) AS g_role, array_agg(g.expires_at) AS g_expires
167
+ FROM public.vault_grants g LEFT JOIN public.environments ge ON ge.id = g.environment_id
168
+ WHERE g.principal = v.p
169
+ ) gr ON v.m_status IS NOT NULL;
170
+ ELSIF probe THEN
171
+ WITH i AS MATERIALIZED (
172
+ SELECT n.number AS newest, n.mac AS newest_mac, coalesce(n.number = p_known AND n.mac = p_known_mac, false) AS cached,
173
+ f.at_floor, (lpol.payload::jsonb #>> '{value,bulk,count}')::integer AS cap_count, (lpol.payload::jsonb #>> '{value,bulk,windowMs}')::bigint AS cap_window,
174
+ lpol.number AS lpol_number, lpol.seal AS p_last,
175
+ c.principal AS p, c.kind AS c_kind, c.scope AS c_scope, c.revoked_at IS NOT NULL AS c_revoked,
176
+ floor(extract(epoch FROM least(c.expires_at, c.not_after)) * 1000)::bigint AS c_expires, c.seal AS c_seal,
177
+ m.status AS m_status, m.owner AS m_owner, m.role AS m_role, m.scope AS m_scope, m.seal AS m_seal,
178
+ cfg.r_value, cfg.r_seal, cfg.p_value, cfg.p_seal,
179
+ s.project_id AS s_project, s.environment_id AS s_environment, s.current_version_id AS s_version, ref.source_secret_id AS s_source, s.seal AS s_seal,
180
+ src.project_id AS x_project, src.environment_id AS x_environment, src.current_version_id AS x_version, xref.source_secret_id AS x_source, src.seal AS x_seal,
181
+ sv.envelope_version, sv.ciphertext, sv.iv, sv.auth_tag, sv.wrapped_dek, sv.kek_provider, sv.kek_id, sv.kek_version, sv.sensitive, sv.plaintext IS NOT NULL AS v_plain,
182
+ ids.e1 AS e1_id, e1.project_id AS e1_project, e1.slug AS e1_slug, e1.owner AS e1_owner, e1.parent_id AS e1_parent, e1.protected AS e1_protected, e1.archived_at IS NOT NULL AS e1_archived, e1.seal AS e1_seal,
183
+ s.environment_id AS e2_id, e2.project_id AS e2_project, e2.slug AS e2_slug, e2.owner AS e2_owner, e2.parent_id AS e2_parent, e2.protected AS e2_protected, e2.archived_at IS NOT NULL AS e2_archived, e2.seal AS e2_seal,
184
+ ids.e3 AS e3_id, e3.project_id AS e3_project, e3.slug AS e3_slug, e3.owner AS e3_owner, e3.parent_id AS e3_parent, e3.protected AS e3_protected, e3.archived_at IS NOT NULL AS e3_archived, e3.seal AS e3_seal,
185
+ CASE WHEN ve.owner IS NOT NULL THEN ve.parent END AS e4_id, e4.project_id AS e4_project, e4.slug AS e4_slug, e4.owner AS e4_owner, e4.parent_id AS e4_parent, e4.protected AS e4_protected, e4.archived_at IS NOT NULL AS e4_archived, e4.seal AS e4_seal,
186
+ b.last AS bulk_last,
187
+ -- Each input's object key, computed once: a key in a probe's own condition is computed again for every row it reads (0022, decision 3).
188
+ public.log_object('credential', p_credential::text) AS k_credential,
189
+ public.log_object('principal', c.principal) AS k_member,
190
+ public.log_object('secret', p_secret::text) AS k_secret,
191
+ public.log_object('secret', ref.source_secret_id::text) AS k_source,
192
+ public.log_object('environment', ids.e1::text) AS k_e1,
193
+ public.log_object('environment', s.environment_id::text) AS k_e2,
194
+ public.log_object('environment', ids.e3::text) AS k_e3,
195
+ public.log_object('environment', (CASE WHEN ve.owner IS NOT NULL THEN ve.parent END)::text) AS k_e4
196
+ FROM (SELECT 1) one
197
+ LEFT JOIN LATERAL (SELECT x.number, x.mac FROM public.log_changes x ORDER BY x.number DESC LIMIT 1) n ON true
198
+ LEFT JOIN public.log_fence f ON f.only_row
199
+ -- The roles and the policy, both rows in one read of their one-page table.
200
+ LEFT JOIN LATERAL (
201
+ SELECT max(g.value) FILTER (WHERE g.name = 'roles') AS r_value, (array_agg(g.seal) FILTER (WHERE g.name = 'roles'))[1] AS r_seal,
202
+ max(g.value) FILTER (WHERE g.name = 'policy') AS p_value, (array_agg(g.seal) FILTER (WHERE g.name = 'policy'))[1] AS p_seal
203
+ FROM public.log_config g
204
+ ) cfg ON true
205
+ -- The cap as the policy's newest change says it (CapSealed): every policy change logs the whole policy as its `value`.
206
+ LEFT JOIN LATERAL (
207
+ SELECT x.number, x.seal, x.payload FROM public.log_changes x WHERE x.object = public.log_object('policy', 'instance') ORDER BY x.number DESC LIMIT 1
208
+ ) lpol ON true
209
+ LEFT JOIN public.credentials c ON c.id = p_credential
210
+ LEFT JOIN public.vault_members m ON m.principal = c.principal
211
+ -- An archived key is gone (`secret.delete`): no object.
212
+ LEFT JOIN public.secrets s ON s.id = p_secret AND s.archived_at IS NULL
213
+ -- A key with no version of its own is a reference while its newest reference row names a source.
214
+ LEFT JOIN LATERAL (
215
+ SELECT y.source_secret_id FROM public.secret_references y WHERE y.secret_id = s.id ORDER BY y.created_seq DESC LIMIT 1
216
+ ) ref ON s.current_version_id IS NULL
217
+ LEFT JOIN public.secrets src ON src.id = ref.source_secret_id AND src.archived_at IS NULL
218
+ LEFT JOIN LATERAL (
219
+ SELECT y.source_secret_id FROM public.secret_references y WHERE y.secret_id = src.id ORDER BY y.created_seq DESC LIMIT 1
220
+ ) xref ON src.current_version_id IS NULL
221
+ -- The value's version: the key's own, or its source's.
222
+ LEFT JOIN public.secret_versions sv ON sv.id = CASE WHEN ref.source_secret_id IS NULL THEN s.current_version_id ELSE src.current_version_id END
223
+ -- The environments `useEnvironments` names, each by the id the rows name, whether or not its row is there: e1 the
224
+ -- place read through, e2 the key's own, e3 its value's (a reference's source's) where that is another, and e4
225
+ -- the parent of its value's when that is a personal config.
226
+ LEFT JOIN LATERAL (
227
+ SELECT CASE WHEN p_place IS DISTINCT FROM s.environment_id THEN p_place END AS e1,
228
+ CASE WHEN src.environment_id IS DISTINCT FROM s.environment_id THEN src.environment_id END AS e3
229
+ ) ids ON true
230
+ LEFT JOIN public.environments e1 ON e1.id = ids.e1
231
+ LEFT JOIN public.environments e2 ON e2.id = s.environment_id
232
+ LEFT JOIN public.environments e3 ON e3.id = ids.e3
233
+ -- The value's environment's row: the key's own, unless it is a reference, whose source is elsewhere or gone.
234
+ LEFT JOIN LATERAL (
235
+ SELECT CASE WHEN ref.source_secret_id IS NULL OR (src.id IS NOT NULL AND ids.e3 IS NULL) THEN e2.owner ELSE e3.owner END AS owner,
236
+ CASE WHEN ref.source_secret_id IS NULL OR (src.id IS NOT NULL AND ids.e3 IS NULL) THEN e2.parent_id ELSE e3.parent_id END AS parent
237
+ ) ve ON true
238
+ LEFT JOIN public.environments e4 ON e4.id = ve.parent AND ve.owner IS NOT NULL
239
+ LEFT JOIN public.log_bulk b ON b.principal = c.principal AND b.secret = p_secret
240
+ WHERE NOT dry
241
+ ),
242
+ v AS MATERIALIZED (
243
+ SELECT i.*, cap.refresh, cap.period,
244
+ CASE WHEN i.at_floor IS NULL OR p_at < i.at_floor OR (extract(epoch FROM clock_timestamp()) * 1000)::bigint > p_deadline THEN 'late'
245
+ WHEN p_at > (extract(epoch FROM clock_timestamp()) * 1000)::bigint + 60000 THEN 'ahead'
246
+ WHEN i.cap_count IS NULL OR i.cap_window IS NULL THEN 'unconfigured'
247
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT coalesce(i.bulk_last > p_at - i.cap_window - cap.refresh, false) THEN 'lock'
248
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT moving AND i.bulk_last < cap.period THEN 'share' END AS state,
249
+ greatest(lc.number, lm.number, lr.number, i.lpol_number, ls.number, lx.number, l1.number, l2.number, l3.number, l4.number) AS inputs,
250
+ lc.seal AS c_last, lm.seal AS m_last, (lm.payload::jsonb ->> 'old')::bigint AS m_old, lr.seal AS r_last, ls.seal AS s_last, lx.seal AS x_last,
251
+ l1.seal AS e1_last, l2.seal AS e2_last, l3.seal AS e3_last, l4.seal AS e4_last,
252
+ coalesce(i.bulk_last > p_at - i.cap_window - cap.refresh, false) AS is_in,
253
+ -- The other keys in the set, up to the cap: read only under the principal's lock, for a key not in it.
254
+ CASE WHEN locked AND i.p IS NOT NULL AND NOT coalesce(i.bulk_last > p_at - i.cap_window - cap.refresh, false) THEN (
255
+ SELECT count(*)::integer FROM (
256
+ SELECT 1 FROM public.log_bulk o
257
+ WHERE o.principal = i.p AND o.secret <> p_secret AND o.last > p_at - i.cap_window - cap.refresh - public.deadline_max() - 60000
258
+ LIMIT i.cap_count
259
+ ) z
260
+ ) ELSE 0 END AS n_others,
261
+ -- A repeat rides its cover only while every part of this holds: never on a key whose bulk row is missing (CoverFresh).
262
+ coalesce(p_cover IS NOT NULL AND i.bulk_last >= cap.period AND p_cover > coalesce(greatest(lc.number, lm.number, lr.number, i.lpol_number, ls.number, lx.number, l1.number, l2.number, l3.number, l4.number), 0)
263
+ AND EXISTS (SELECT 1 FROM public.log_uses u WHERE u.at = p_cover_at AND u.request_id = p_cover_request AND u.number = p_cover
264
+ AND u.credential = p_credential AND u.secret = p_secret AND u.purpose = p_purpose AND u.place IS NOT DISTINCT FROM p_place), false) AS is_covered
265
+ FROM i
266
+ CROSS JOIN LATERAL (SELECT greatest(1, least(60000, i.cap_window / 10)) AS refresh) r0
267
+ CROSS JOIN LATERAL (SELECT r0.refresh, p_at - ((p_at % r0.refresh) + r0.refresh) % r0.refresh AS period) cap
268
+ -- Each input's newest change: one index-only probe each (log_changes_object_idx holds the seal), the principal's
269
+ -- with its payload, which names the 0.14 entry it accounts for.
270
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_credential ORDER BY x.number DESC LIMIT 1) lc ON true
271
+ LEFT JOIN LATERAL (SELECT x.number, x.seal, x.payload FROM public.log_changes x WHERE x.object = i.k_member ORDER BY x.number DESC LIMIT 1) lm ON i.k_member IS NOT NULL
272
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = public.log_object('roles', 'instance') ORDER BY x.number DESC LIMIT 1) lr ON true
273
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_secret ORDER BY x.number DESC LIMIT 1) ls ON true
274
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_source ORDER BY x.number DESC LIMIT 1) lx ON i.k_source IS NOT NULL
275
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_e1 ORDER BY x.number DESC LIMIT 1) l1 ON i.k_e1 IS NOT NULL
276
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_e2 ORDER BY x.number DESC LIMIT 1) l2 ON i.k_e2 IS NOT NULL
277
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_e3 ORDER BY x.number DESC LIMIT 1) l3 ON i.k_e3 IS NOT NULL
278
+ LEFT JOIN LATERAL (SELECT x.number, x.seal FROM public.log_changes x WHERE x.object = i.k_e4 ORDER BY x.number DESC LIMIT 1) l4 ON i.k_e4 IS NOT NULL
279
+ ),
280
+ w AS (
281
+ INSERT INTO public.log_uses (number, at, request_id, credential, secret, purpose, mac, place)
282
+ SELECT nextval('public.log_number'), p_at, p_request, p_credential, p_secret, p_purpose, p_mac, p_place
283
+ FROM v WHERE v.state IS NULL AND NOT v.is_covered
284
+ RETURNING log_uses.number
285
+ )
286
+ SELECT v.state, (SELECT w.number FROM w), CASE WHEN v.state IS NULL AND v.is_covered THEN p_cover END, v.newest, v.newest_mac, v.inputs, true,
287
+ v.p, v.c_kind, v.c_scope, v.c_revoked, v.c_expires, v.c_seal, v.c_last,
288
+ v.m_status, v.m_owner, v.m_role, v.m_scope, v.m_seal, v.m_last, v.m_old,
289
+ (SELECT a.seq FROM public.audit_log a WHERE a.author = 'vault' AND a.subject_principal = v.p AND a.decision = 'allow'
290
+ AND a.action IN ('member.add', 'member.restore', 'member.owner', 'member.role', 'member.remove', 'access.grant', 'access.revoke') ORDER BY a.seq DESC LIMIT 1),
291
+ gr.g_project, gr.g_environment, gr.g_slug, gr.g_role, gr.g_expires,
292
+ v.r_value, v.r_seal, v.r_last,
293
+ v.p_value, v.p_seal, v.p_last, v.cap_count, v.cap_window,
294
+ v.s_project, v.s_environment, v.s_version, v.s_source, v.s_seal, v.s_last,
295
+ v.x_project, v.x_environment, v.x_version, v.x_source, v.x_seal, v.x_last,
296
+ v.envelope_version, v.ciphertext, v.iv, v.auth_tag, v.wrapped_dek, v.kek_provider, v.kek_id, v.kek_version, v.sensitive, v.v_plain,
297
+ v.e1_id, v.e1_project, v.e1_slug, v.e1_owner, v.e1_parent, v.e1_protected, v.e1_archived, v.e1_seal, v.e1_last,
298
+ v.e2_id, v.e2_project, v.e2_slug, v.e2_owner, v.e2_parent, v.e2_protected, v.e2_archived, v.e2_seal, v.e2_last,
299
+ v.e3_id, v.e3_project, v.e3_slug, v.e3_owner, v.e3_parent, v.e3_protected, v.e3_archived, v.e3_seal, v.e3_last,
300
+ v.e4_id, v.e4_project, v.e4_slug, v.e4_owner, v.e4_parent, v.e4_protected, v.e4_archived, v.e4_seal, v.e4_last,
301
+ v.is_in, v.n_others
302
+ INTO r
303
+ FROM v
304
+ -- The principal's grants as five lists, one entry per grant, lapsed ones included; an environment's grant with its project, which its row finds through `environments`.
305
+ LEFT JOIN LATERAL (
306
+ SELECT array_agg(coalesce(g.project_id, ge.project_id)) AS g_project, array_agg(g.environment_id) AS g_environment,
307
+ array_agg(g.environment_slug) AS g_slug, array_agg(g.role) AS g_role, array_agg(g.expires_at) AS g_expires
308
+ FROM public.vault_grants g LEFT JOIN public.environments ge ON ge.id = g.environment_id
309
+ WHERE g.principal = v.p
310
+ ) gr ON v.m_status IS NOT NULL;
311
+ ELSIF NOT whole THEN
312
+ -- The isolate's seals, and its cap, read at the change it names: no probe, only whether a change came since
313
+ -- (then nothing is written: 'reprobe').
314
+ WITH i AS MATERIALIZED (
315
+ SELECT n.number AS newest, n.mac AS newest_mac, coalesce(n.number = p_known AND n.mac = p_known_mac, false) AS cached,
316
+ f.at_floor,
317
+ c.principal AS p, c.kind AS c_kind, c.scope AS c_scope, c.revoked_at IS NOT NULL AS c_revoked,
318
+ floor(extract(epoch FROM least(c.expires_at, c.not_after)) * 1000)::bigint AS c_expires, c.seal AS c_seal,
319
+ m.status AS m_status, m.owner AS m_owner, m.role AS m_role, m.scope AS m_scope, m.seal AS m_seal,
320
+ cfg.r_value, cfg.r_seal, cfg.p_value, cfg.p_seal,
321
+ s.project_id AS s_project, s.environment_id AS s_environment, s.current_version_id AS s_version, NULL::uuid AS s_source, s.seal AS s_seal,
322
+ NULL::uuid AS x_project, NULL::uuid AS x_environment, NULL::uuid AS x_version, NULL::uuid AS x_source, NULL::bytea AS x_seal,
323
+ sv.envelope_version, sv.ciphertext, sv.iv, sv.auth_tag, sv.wrapped_dek, sv.kek_provider, sv.kek_id, sv.kek_version, sv.sensitive, sv.plaintext IS NOT NULL AS v_plain,
324
+ NULL::uuid AS e1_id, NULL::uuid AS e1_project, NULL::text AS e1_slug, NULL::text AS e1_owner, NULL::uuid AS e1_parent, NULL::boolean AS e1_protected, NULL::boolean AS e1_archived, NULL::bytea AS e1_seal,
325
+ s.environment_id AS e2_id, e2.project_id AS e2_project, e2.slug AS e2_slug, e2.owner AS e2_owner, e2.parent_id AS e2_parent, e2.protected AS e2_protected, e2.archived_at IS NOT NULL AS e2_archived, e2.seal AS e2_seal,
326
+ NULL::uuid AS e3_id, NULL::uuid AS e3_project, NULL::text AS e3_slug, NULL::text AS e3_owner, NULL::uuid AS e3_parent, NULL::boolean AS e3_protected, NULL::boolean AS e3_archived, NULL::bytea AS e3_seal,
327
+ CASE WHEN e2.owner IS NOT NULL THEN e2.parent_id END AS e4_id, e4.project_id AS e4_project, e4.slug AS e4_slug, e4.owner AS e4_owner, e4.parent_id AS e4_parent, e4.protected AS e4_protected, e4.archived_at IS NOT NULL AS e4_archived, e4.seal AS e4_seal,
328
+ b.last AS bulk_last
329
+ FROM (SELECT 1) one
330
+ LEFT JOIN LATERAL (SELECT x.number, x.mac FROM public.log_changes x ORDER BY x.number DESC LIMIT 1) n ON true
331
+ LEFT JOIN public.log_fence f ON f.only_row
332
+ -- The roles and the policy, both rows in one read of their one-page table.
333
+ LEFT JOIN LATERAL (
334
+ SELECT max(g.value) FILTER (WHERE g.name = 'roles') AS r_value, (array_agg(g.seal) FILTER (WHERE g.name = 'roles'))[1] AS r_seal,
335
+ max(g.value) FILTER (WHERE g.name = 'policy') AS p_value, (array_agg(g.seal) FILTER (WHERE g.name = 'policy'))[1] AS p_seal
336
+ FROM public.log_config g
337
+ ) cfg ON true
338
+ LEFT JOIN public.credentials c ON c.id = p_credential
339
+ LEFT JOIN public.vault_members m ON m.principal = c.principal
340
+ -- An archived key is gone (`secret.delete`): no object.
341
+ LEFT JOIN public.secrets s ON s.id = p_secret AND s.archived_at IS NULL
342
+ -- The key's own version, its own environment, and that environment's parent when it is a personal config.
343
+ LEFT JOIN public.secret_versions sv ON sv.id = s.current_version_id
344
+ LEFT JOIN public.environments e2 ON e2.id = s.environment_id
345
+ LEFT JOIN public.environments e4 ON e4.id = e2.parent_id AND e2.owner IS NOT NULL
346
+ LEFT JOIN public.log_bulk b ON b.principal = c.principal AND b.secret = p_secret
347
+ WHERE NOT dry
348
+ ),
349
+ v AS MATERIALIZED (
350
+ SELECT i.*, c_refresh AS refresh, c_period AS period,
351
+ CASE WHEN NOT i.cached THEN 'reprobe'
352
+ WHEN i.s_project IS NOT NULL AND i.s_version IS NULL THEN 'whole'
353
+ WHEN i.at_floor IS NULL OR p_at < i.at_floor OR (extract(epoch FROM clock_timestamp()) * 1000)::bigint > p_deadline THEN 'late'
354
+ WHEN p_at > (extract(epoch FROM clock_timestamp()) * 1000)::bigint + 60000 THEN 'ahead'
355
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT coalesce(i.bulk_last > p_at - p_cap_window - c_refresh, false) THEN 'lock'
356
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT moving AND i.bulk_last < c_period THEN 'share' END AS state,
357
+ coalesce(i.bulk_last > p_at - p_cap_window - c_refresh, false) AS is_in,
358
+ -- The other keys in the set, up to the cap: read only under the principal's lock, for a key not in it.
359
+ CASE WHEN locked AND i.p IS NOT NULL AND NOT coalesce(i.bulk_last > p_at - p_cap_window - c_refresh, false) THEN (
360
+ SELECT count(*)::integer FROM (
361
+ SELECT 1 FROM public.log_bulk o
362
+ WHERE o.principal = i.p AND o.secret <> p_secret AND o.last > p_at - p_cap_window - c_refresh - public.deadline_max() - 60000
363
+ LIMIT p_cap_count
364
+ ) z
365
+ ) ELSE 0 END AS n_others,
366
+ -- A repeat rides its cover only while every part of this holds: never on a key whose bulk row is missing (CoverFresh).
367
+ coalesce(p_cover IS NOT NULL AND i.bulk_last >= c_period
368
+ AND EXISTS (SELECT 1 FROM public.log_uses u WHERE u.at = p_cover_at AND u.request_id = p_cover_request AND u.number = p_cover
369
+ AND u.credential = p_credential AND u.secret = p_secret AND u.purpose = p_purpose AND u.place IS NOT DISTINCT FROM p_place), false) AS is_covered
370
+ FROM i
371
+ ),
372
+ w AS (
373
+ INSERT INTO public.log_uses (number, at, request_id, credential, secret, purpose, mac, place)
374
+ SELECT nextval('public.log_number'), p_at, p_request, p_credential, p_secret, p_purpose, p_mac, p_place
375
+ -- The isolate held its cover to the cached seals' numbers when it read them.
376
+ FROM v WHERE v.state IS NULL AND NOT v.is_covered
377
+ RETURNING log_uses.number
378
+ )
379
+ SELECT v.state, (SELECT w.number FROM w), CASE WHEN v.state IS NULL AND v.is_covered THEN p_cover END, v.newest, v.newest_mac, NULL::bigint, false,
380
+ v.p, v.c_kind, v.c_scope, v.c_revoked, v.c_expires, v.c_seal, NULL::bytea,
381
+ v.m_status, v.m_owner, v.m_role, v.m_scope, v.m_seal, NULL::bytea, NULL::bigint,
382
+ (SELECT a.seq FROM public.audit_log a WHERE a.author = 'vault' AND a.subject_principal = v.p AND a.decision = 'allow'
383
+ AND a.action IN ('member.add', 'member.restore', 'member.owner', 'member.role', 'member.remove', 'access.grant', 'access.revoke') ORDER BY a.seq DESC LIMIT 1),
384
+ gr.g_project, gr.g_environment, gr.g_slug, gr.g_role, gr.g_expires,
385
+ v.r_value, v.r_seal, NULL::bytea,
386
+ v.p_value, v.p_seal, NULL::bytea, p_cap_count, p_cap_window,
387
+ v.s_project, v.s_environment, v.s_version, v.s_source, v.s_seal, NULL::bytea,
388
+ v.x_project, v.x_environment, v.x_version, v.x_source, v.x_seal, NULL::bytea,
389
+ v.envelope_version, v.ciphertext, v.iv, v.auth_tag, v.wrapped_dek, v.kek_provider, v.kek_id, v.kek_version, v.sensitive, v.v_plain,
390
+ v.e1_id, v.e1_project, v.e1_slug, v.e1_owner, v.e1_parent, v.e1_protected, v.e1_archived, v.e1_seal, NULL::bytea,
391
+ v.e2_id, v.e2_project, v.e2_slug, v.e2_owner, v.e2_parent, v.e2_protected, v.e2_archived, v.e2_seal, NULL::bytea,
392
+ v.e3_id, v.e3_project, v.e3_slug, v.e3_owner, v.e3_parent, v.e3_protected, v.e3_archived, v.e3_seal, NULL::bytea,
393
+ v.e4_id, v.e4_project, v.e4_slug, v.e4_owner, v.e4_parent, v.e4_protected, v.e4_archived, v.e4_seal, NULL::bytea,
394
+ v.is_in, v.n_others
395
+ INTO r
396
+ FROM v
397
+ -- The principal's grants as five lists, one entry per grant, lapsed ones included; an environment's grant with its project, which its row finds through `environments`.
398
+ LEFT JOIN LATERAL (
399
+ SELECT array_agg(coalesce(g.project_id, ge.project_id)) AS g_project, array_agg(g.environment_id) AS g_environment,
400
+ array_agg(g.environment_slug) AS g_slug, array_agg(g.role) AS g_role, array_agg(g.expires_at) AS g_expires
401
+ FROM public.vault_grants g LEFT JOIN public.environments ge ON ge.id = g.environment_id
402
+ WHERE g.principal = v.p
403
+ ) gr ON v.m_status IS NOT NULL;
404
+ ELSE
405
+ WITH i AS MATERIALIZED (
406
+ SELECT n.number AS newest, n.mac AS newest_mac, coalesce(n.number = p_known AND n.mac = p_known_mac, false) AS cached,
407
+ f.at_floor,
408
+ c.principal AS p, c.kind AS c_kind, c.scope AS c_scope, c.revoked_at IS NOT NULL AS c_revoked,
409
+ floor(extract(epoch FROM least(c.expires_at, c.not_after)) * 1000)::bigint AS c_expires, c.seal AS c_seal,
410
+ m.status AS m_status, m.owner AS m_owner, m.role AS m_role, m.scope AS m_scope, m.seal AS m_seal,
411
+ cfg.r_value, cfg.r_seal, cfg.p_value, cfg.p_seal,
412
+ s.project_id AS s_project, s.environment_id AS s_environment, s.current_version_id AS s_version, ref.source_secret_id AS s_source, s.seal AS s_seal,
413
+ src.project_id AS x_project, src.environment_id AS x_environment, src.current_version_id AS x_version, xref.source_secret_id AS x_source, src.seal AS x_seal,
414
+ sv.envelope_version, sv.ciphertext, sv.iv, sv.auth_tag, sv.wrapped_dek, sv.kek_provider, sv.kek_id, sv.kek_version, sv.sensitive, sv.plaintext IS NOT NULL AS v_plain,
415
+ ids.e1 AS e1_id, e1.project_id AS e1_project, e1.slug AS e1_slug, e1.owner AS e1_owner, e1.parent_id AS e1_parent, e1.protected AS e1_protected, e1.archived_at IS NOT NULL AS e1_archived, e1.seal AS e1_seal,
416
+ s.environment_id AS e2_id, e2.project_id AS e2_project, e2.slug AS e2_slug, e2.owner AS e2_owner, e2.parent_id AS e2_parent, e2.protected AS e2_protected, e2.archived_at IS NOT NULL AS e2_archived, e2.seal AS e2_seal,
417
+ ids.e3 AS e3_id, e3.project_id AS e3_project, e3.slug AS e3_slug, e3.owner AS e3_owner, e3.parent_id AS e3_parent, e3.protected AS e3_protected, e3.archived_at IS NOT NULL AS e3_archived, e3.seal AS e3_seal,
418
+ CASE WHEN ve.owner IS NOT NULL THEN ve.parent END AS e4_id, e4.project_id AS e4_project, e4.slug AS e4_slug, e4.owner AS e4_owner, e4.parent_id AS e4_parent, e4.protected AS e4_protected, e4.archived_at IS NOT NULL AS e4_archived, e4.seal AS e4_seal,
419
+ b.last AS bulk_last
420
+ FROM (SELECT 1) one
421
+ LEFT JOIN LATERAL (SELECT x.number, x.mac FROM public.log_changes x ORDER BY x.number DESC LIMIT 1) n ON true
422
+ LEFT JOIN public.log_fence f ON f.only_row
423
+ -- The roles and the policy, both rows in one read of their one-page table.
424
+ LEFT JOIN LATERAL (
425
+ SELECT max(g.value) FILTER (WHERE g.name = 'roles') AS r_value, (array_agg(g.seal) FILTER (WHERE g.name = 'roles'))[1] AS r_seal,
426
+ max(g.value) FILTER (WHERE g.name = 'policy') AS p_value, (array_agg(g.seal) FILTER (WHERE g.name = 'policy'))[1] AS p_seal
427
+ FROM public.log_config g
428
+ ) cfg ON true
429
+ LEFT JOIN public.credentials c ON c.id = p_credential
430
+ LEFT JOIN public.vault_members m ON m.principal = c.principal
431
+ -- An archived key is gone (`secret.delete`): no object.
432
+ LEFT JOIN public.secrets s ON s.id = p_secret AND s.archived_at IS NULL
433
+ -- A key with no version of its own is a reference while its newest reference row names a source.
434
+ LEFT JOIN LATERAL (
435
+ SELECT y.source_secret_id FROM public.secret_references y WHERE y.secret_id = s.id ORDER BY y.created_seq DESC LIMIT 1
436
+ ) ref ON s.current_version_id IS NULL
437
+ LEFT JOIN public.secrets src ON src.id = ref.source_secret_id AND src.archived_at IS NULL
438
+ LEFT JOIN LATERAL (
439
+ SELECT y.source_secret_id FROM public.secret_references y WHERE y.secret_id = src.id ORDER BY y.created_seq DESC LIMIT 1
440
+ ) xref ON src.current_version_id IS NULL
441
+ -- The value's version: the key's own, or its source's.
442
+ LEFT JOIN public.secret_versions sv ON sv.id = CASE WHEN ref.source_secret_id IS NULL THEN s.current_version_id ELSE src.current_version_id END
443
+ -- The environments `useEnvironments` names, each by the id the rows name, whether or not its row is there: e1 the
444
+ -- place read through, e2 the key's own, e3 its value's (a reference's source's) where that is another, and e4
445
+ -- the parent of its value's when that is a personal config.
446
+ LEFT JOIN LATERAL (
447
+ SELECT CASE WHEN p_place IS DISTINCT FROM s.environment_id THEN p_place END AS e1,
448
+ CASE WHEN src.environment_id IS DISTINCT FROM s.environment_id THEN src.environment_id END AS e3
449
+ ) ids ON true
450
+ LEFT JOIN public.environments e1 ON e1.id = ids.e1
451
+ LEFT JOIN public.environments e2 ON e2.id = s.environment_id
452
+ LEFT JOIN public.environments e3 ON e3.id = ids.e3
453
+ -- The value's environment's row: the key's own, unless it is a reference, whose source is elsewhere or gone.
454
+ LEFT JOIN LATERAL (
455
+ SELECT CASE WHEN ref.source_secret_id IS NULL OR (src.id IS NOT NULL AND ids.e3 IS NULL) THEN e2.owner ELSE e3.owner END AS owner,
456
+ CASE WHEN ref.source_secret_id IS NULL OR (src.id IS NOT NULL AND ids.e3 IS NULL) THEN e2.parent_id ELSE e3.parent_id END AS parent
457
+ ) ve ON true
458
+ LEFT JOIN public.environments e4 ON e4.id = ve.parent AND ve.owner IS NOT NULL
459
+ LEFT JOIN public.log_bulk b ON b.principal = c.principal AND b.secret = p_secret
460
+ WHERE NOT dry
461
+ ),
462
+ v AS MATERIALIZED (
463
+ SELECT i.*, c_refresh AS refresh, c_period AS period,
464
+ CASE WHEN NOT i.cached THEN 'reprobe'
465
+ WHEN i.at_floor IS NULL OR p_at < i.at_floor OR (extract(epoch FROM clock_timestamp()) * 1000)::bigint > p_deadline THEN 'late'
466
+ WHEN p_at > (extract(epoch FROM clock_timestamp()) * 1000)::bigint + 60000 THEN 'ahead'
467
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT coalesce(i.bulk_last > p_at - p_cap_window - c_refresh, false) THEN 'lock'
468
+ WHEN i.p IS NOT NULL AND NOT locked AND NOT moving AND i.bulk_last < c_period THEN 'share' END AS state,
469
+ coalesce(i.bulk_last > p_at - p_cap_window - c_refresh, false) AS is_in,
470
+ -- The other keys in the set, up to the cap: read only under the principal's lock, for a key not in it.
471
+ CASE WHEN locked AND i.p IS NOT NULL AND NOT coalesce(i.bulk_last > p_at - p_cap_window - c_refresh, false) THEN (
472
+ SELECT count(*)::integer FROM (
473
+ SELECT 1 FROM public.log_bulk o
474
+ WHERE o.principal = i.p AND o.secret <> p_secret AND o.last > p_at - p_cap_window - c_refresh - public.deadline_max() - 60000
475
+ LIMIT p_cap_count
476
+ ) z
477
+ ) ELSE 0 END AS n_others,
478
+ -- A repeat rides its cover only while every part of this holds: never on a key whose bulk row is missing (CoverFresh).
479
+ coalesce(p_cover IS NOT NULL AND i.bulk_last >= c_period
480
+ AND EXISTS (SELECT 1 FROM public.log_uses u WHERE u.at = p_cover_at AND u.request_id = p_cover_request AND u.number = p_cover
481
+ AND u.credential = p_credential AND u.secret = p_secret AND u.purpose = p_purpose AND u.place IS NOT DISTINCT FROM p_place), false) AS is_covered
482
+ FROM i
483
+ ),
484
+ w AS (
485
+ INSERT INTO public.log_uses (number, at, request_id, credential, secret, purpose, mac, place)
486
+ SELECT nextval('public.log_number'), p_at, p_request, p_credential, p_secret, p_purpose, p_mac, p_place
487
+ -- The isolate held its cover to the cached seals' numbers when it read them.
488
+ FROM v WHERE v.state IS NULL AND NOT v.is_covered
489
+ RETURNING log_uses.number
490
+ )
491
+ SELECT v.state, (SELECT w.number FROM w), CASE WHEN v.state IS NULL AND v.is_covered THEN p_cover END, v.newest, v.newest_mac, NULL::bigint, false,
492
+ v.p, v.c_kind, v.c_scope, v.c_revoked, v.c_expires, v.c_seal, NULL::bytea,
493
+ v.m_status, v.m_owner, v.m_role, v.m_scope, v.m_seal, NULL::bytea, NULL::bigint,
494
+ (SELECT a.seq FROM public.audit_log a WHERE a.author = 'vault' AND a.subject_principal = v.p AND a.decision = 'allow'
495
+ AND a.action IN ('member.add', 'member.restore', 'member.owner', 'member.role', 'member.remove', 'access.grant', 'access.revoke') ORDER BY a.seq DESC LIMIT 1),
496
+ gr.g_project, gr.g_environment, gr.g_slug, gr.g_role, gr.g_expires,
497
+ v.r_value, v.r_seal, NULL::bytea,
498
+ v.p_value, v.p_seal, NULL::bytea, p_cap_count, p_cap_window,
499
+ v.s_project, v.s_environment, v.s_version, v.s_source, v.s_seal, NULL::bytea,
500
+ v.x_project, v.x_environment, v.x_version, v.x_source, v.x_seal, NULL::bytea,
501
+ v.envelope_version, v.ciphertext, v.iv, v.auth_tag, v.wrapped_dek, v.kek_provider, v.kek_id, v.kek_version, v.sensitive, v.v_plain,
502
+ v.e1_id, v.e1_project, v.e1_slug, v.e1_owner, v.e1_parent, v.e1_protected, v.e1_archived, v.e1_seal, NULL::bytea,
503
+ v.e2_id, v.e2_project, v.e2_slug, v.e2_owner, v.e2_parent, v.e2_protected, v.e2_archived, v.e2_seal, NULL::bytea,
504
+ v.e3_id, v.e3_project, v.e3_slug, v.e3_owner, v.e3_parent, v.e3_protected, v.e3_archived, v.e3_seal, NULL::bytea,
505
+ v.e4_id, v.e4_project, v.e4_slug, v.e4_owner, v.e4_parent, v.e4_protected, v.e4_archived, v.e4_seal, NULL::bytea,
506
+ v.is_in, v.n_others
507
+ INTO r
508
+ FROM v
509
+ -- The principal's grants as five lists, one entry per grant, lapsed ones included; an environment's grant with its project, which its row finds through `environments`.
510
+ LEFT JOIN LATERAL (
511
+ SELECT array_agg(coalesce(g.project_id, ge.project_id)) AS g_project, array_agg(g.environment_id) AS g_environment,
512
+ array_agg(g.environment_slug) AS g_slug, array_agg(g.role) AS g_role, array_agg(g.expires_at) AS g_expires
513
+ FROM public.vault_grants g LEFT JOIN public.environments ge ON ge.id = g.environment_id
514
+ WHERE g.principal = v.p
515
+ ) gr ON v.m_status IS NOT NULL;
516
+ END IF;
517
+ IF dry THEN
518
+ -- The forms in turn: probing plain, probing whole, cached plain, cached whole; then the call itself, under the fence.
519
+ form := form + 1;
520
+ IF form < 4 THEN
521
+ probe := form < 2;
522
+ whole := form % 2 = 1;
523
+ CONTINUE;
524
+ END IF;
525
+ PERFORM set_config('coffre.use_planned', '0028', false);
526
+ dry := false;
527
+ probe := first_probe;
528
+ whole := first_whole;
529
+ PERFORM pg_advisory_xact_lock_shared(1668244070, 0);
530
+ CONTINUE;
531
+ END IF;
532
+ -- A use the statement took writes its entry or rides its cover, never neither.
533
+ IF r.state IS NULL AND r.number IS NULL AND r.covered IS NULL THEN
534
+ RAISE EXCEPTION 'a use wrote no entry and rode no cover' USING ERRCODE = 'XX000';
535
+ END IF;
536
+ IF r.state = 'reprobe' THEN probe := true; CONTINUE; END IF;
537
+ IF r.state = 'whole' THEN whole := true; CONTINUE; END IF;
538
+ EXIT WHEN r.state IS DISTINCT FROM 'lock' AND r.state IS DISTINCT FROM 'share';
539
+ -- Its key's bulk row is missing or out of the set: this use may enter it, so it takes its principal's lock exclusive
540
+ -- and reads again. Or the row is in the set, from an earlier period: this use may move it on, so it takes the lock
541
+ -- shared, beside the principal's other uses that move a key on, and reads again.
542
+ -- Holding it shared, a key never leaves the set (SharedStaysInSet) unless a row was put back under it: then the
543
+ -- call ends, refused as late, rather than ask for the lock exclusive while it holds it shared (two such would
544
+ -- deadlock).
545
+ IF r.state = 'lock' AND moving THEN
546
+ RAISE EXCEPTION 'its key left the cap''s set under the principal''s lock: a row put back' USING ERRCODE = '57014';
547
+ END IF;
548
+ IF r.state = 'lock' THEN
549
+ PERFORM pg_advisory_xact_lock(1668244066, hashtext(r.c_principal));
550
+ locked := true;
551
+ ELSE
552
+ PERFORM pg_advisory_xact_lock_shared(1668244066, hashtext(r.c_principal));
553
+ moving := true;
554
+ END IF;
555
+ END LOOP;
556
+ -- The cap's row, written only by a call that took the principal's lock, in a statement of its own after the one that
557
+ -- read, in the same transaction, under the same locks: the uses that read their key fresh, nearly all, run no write.
558
+ -- A key in the set moves on to this use's period, only ever up. A key entering the set, under the lock exclusive, is
559
+ -- made or moved on from a window past. Every request counts, whatever the Worker then decides but the cap (HotPathOneStaleBulk).
560
+ IF r.state IS NULL AND (locked OR moving) THEN
561
+ b_refresh := greatest(1, least(60000, r.cap_window / 10));
562
+ b_period := p_at - ((p_at % b_refresh) + b_refresh) % b_refresh;
563
+ IF r.in_set THEN
564
+ -- One use moves the key to this period: the one that takes a lock of the key and period's own without waiting.
565
+ -- The others take it shared, which waits only for that one's end, never for each other, and read the row again,
566
+ -- locking none: moved, they leave it. An UPDATE that waits on a row another is moving, then finds it moved,
567
+ -- keeps the row locked to its own commit, and queues the next. If the one moving it rolled back, the others
568
+ -- elect another the same way, on the lock's next round.
569
+ LOOP
570
+ b_lock := hashtextextended(r.c_principal || '/' || p_secret::text || '/' || b_period::text || '/' || b_round::text, 1668244066);
571
+ IF pg_try_advisory_xact_lock(b_lock) THEN
572
+ UPDATE public.log_bulk SET last = b_period WHERE principal = r.c_principal AND secret = p_secret AND last < b_period;
573
+ EXIT;
574
+ END IF;
575
+ PERFORM pg_advisory_xact_lock_shared(b_lock);
576
+ EXIT WHEN NOT EXISTS (SELECT 1 FROM public.log_bulk WHERE principal = r.c_principal AND secret = p_secret AND last < b_period);
577
+ b_round := b_round + 1;
578
+ END LOOP;
579
+ ELSIF r.others < r.cap_count THEN
580
+ INSERT INTO public.log_bulk (principal, secret, last) VALUES (r.c_principal, p_secret, b_period)
581
+ ON CONFLICT ON CONSTRAINT log_bulk_pkey DO UPDATE SET last = greatest(log_bulk.last, EXCLUDED.last);
582
+ END IF;
583
+ END IF;
584
+ -- The deadline holds in Postgres to the end: a call that ran past it rolls back and writes nothing. The hot login's lock_timeout and statement_timeout bound the waits.
585
+ IF r.state IS NULL AND (extract(epoch FROM clock_timestamp()) * 1000)::bigint > p_deadline THEN
586
+ RAISE EXCEPTION 'past its deadline' USING ERRCODE = '57014';
587
+ END IF;
588
+ RETURN to_json(r);
589
+ END
590
+ $$;
591
+ --> statement-breakpoint
592
+ REVOKE ALL ON FUNCTION use_credential(uuid, uuid, bigint, bigint, smallint, uuid, bytea, bigint, bigint, bigint, bigint, bigint, bytea, integer, bigint) FROM PUBLIC;
593
+ --> statement-breakpoint
594
+ GRANT EXECUTE ON FUNCTION use_credential(uuid, uuid, bigint, bigint, smallint, uuid, bytea, bigint, bigint, bigint, bigint, bigint, bytea, integer, bigint) TO coffre_vault;