@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
@@ -127,6 +127,76 @@
127
127
  "when": 1793017781451,
128
128
  "tag": "0017_vault_releases",
129
129
  "breakpoints": true
130
+ },
131
+ {
132
+ "idx": 18,
133
+ "version": "6",
134
+ "when": 1793068925491,
135
+ "tag": "0018_log_015",
136
+ "breakpoints": true
137
+ },
138
+ {
139
+ "idx": 19,
140
+ "version": "6",
141
+ "when": 1793120000000,
142
+ "tag": "0019_retention",
143
+ "breakpoints": true
144
+ },
145
+ {
146
+ "idx": 20,
147
+ "version": "6",
148
+ "when": 1793130000000,
149
+ "tag": "0020_ended_references",
150
+ "breakpoints": true
151
+ },
152
+ {
153
+ "idx": 21,
154
+ "version": "6",
155
+ "when": 1793180484098,
156
+ "tag": "0021_secrets_live_index",
157
+ "breakpoints": true
158
+ },
159
+ {
160
+ "idx": 22,
161
+ "version": "6",
162
+ "when": 1793247590011,
163
+ "tag": "0022_binding_origin",
164
+ "breakpoints": true
165
+ },
166
+ {
167
+ "idx": 23,
168
+ "version": "6",
169
+ "when": 1793268597317,
170
+ "tag": "0023_sign_in_index",
171
+ "breakpoints": true
172
+ },
173
+ {
174
+ "idx": 24,
175
+ "version": "6",
176
+ "when": 1793306933393,
177
+ "tag": "0024_issue_revoke_index",
178
+ "breakpoints": true
179
+ },
180
+ {
181
+ "idx": 25,
182
+ "version": "6",
183
+ "when": 1793352372923,
184
+ "tag": "0025_way_in_uses",
185
+ "breakpoints": true
186
+ },
187
+ {
188
+ "idx": 26,
189
+ "version": "6",
190
+ "when": 1793372630506,
191
+ "tag": "0026_cutover_finish",
192
+ "breakpoints": true
193
+ },
194
+ {
195
+ "idx": 27,
196
+ "version": "6",
197
+ "when": 1793445615378,
198
+ "tag": "0027_reads",
199
+ "breakpoints": true
130
200
  }
131
201
  ]
132
202
  }
@@ -0,0 +1,183 @@
1
+ # postgres.js, Coffre's copy
2
+
3
+ [postgres.js](https://github.com/porsager/postgres) 3.4.9 (npm tarball
4
+ `sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==`,
5
+ commit `e7dfa14519f363229ccc3ead7b1b2f2051937efb`), released under the
6
+ Unlicense (`UNLICENSE`), in TypeScript. Coffre owns this copy, and keeps of
7
+ it what coffre uses. One tree runs on Node and on workerd: what differs, the
8
+ socket, TLS, hashes and a timer, is behind `#postgres/platform` (`@coffre/db`'s
9
+ `package.json`), `platform.node.ts` or `platform.workerd.ts` (upstream's
10
+ `cf/polyfills.js`), which both satisfy `platform.ts`.
11
+
12
+ | File | What |
13
+ | --- | --- |
14
+ | `index.ts` | The pool: `unsafe`, `begin` and its savepoints, `reserve`, `end`; its options |
15
+ | `connection.ts` | One connection: TLS, startup, authentication (SCRAM-SHA-256, MD5, cleartext), the extended and simple protocols |
16
+ | `query.ts` | A statement: a promise, sent once awaited or `execute`d; `.values()` for its rows as arrays |
17
+ | `result.ts` | Its rows, with `count`, `command` and `state` (the backend's pid and secret) |
18
+ | `types.ts` | The built-in parsers and serializers (text, numbers, JSON, booleans, dates, bytea) |
19
+ | `errors.ts`, `bytes.ts`, `queue.ts` | `PostgresError` and the driver's own errors, the message writer, the pool's queues |
20
+
21
+ ## What is left out
22
+
23
+ What nothing in coffre reached: logical replication (`subscribe`), large
24
+ objects, COPY streams (a COPY a statement asks for fails, with an error that
25
+ says so), LISTEN/NOTIFY (a notification is dropped), cursors and `forEach`,
26
+ `fetch_types` and array types read from `pg_type` (`postgresClient` takes
27
+ Postgres's own as known), named prepared statements and their cache (every
28
+ statement is unnamed, as coffre sent them), `transform`, the tagged template
29
+ and its helpers (`sql\`…\``, `sql(rows)`, `sql.json`, `sql.typed`,
30
+ `sql.file`), two-phase commit (`prepare`), several hosts and
31
+ `target_session_attrs`, a statement's `cancel()`, and reading a URL and the
32
+ `PG*` environment: the driver takes an options object, every option given
33
+ or its default, and reads nothing from the environment (`postgresOptions`, in
34
+ `../postgres.ts`, reads the URL). A transaction's own statements, `begin`,
35
+ `savepoint`, `rollback` and `commit`, go as simple statements, where upstream
36
+ wrote them with its tagged template.
37
+
38
+ ## Changes from upstream
39
+
40
+ Ten, each marked `Coffre:` in the code:
41
+
42
+ - **One round trip per statement** (`typedByServer`, in `connection.ts`).
43
+ Upstream asks the server for an unnamed statement's parameter types (Parse,
44
+ Describe, Flush) and waits for them before it sends the values (Bind,
45
+ Execute, Sync), which doubles the round trips of every query with parameters
46
+ that Drizzle sends. Here the values go with the statement, as text the server
47
+ types, as node-postgres sends them, unless one is an object postgres.js has
48
+ no type for (an array is typed by its first element, so `[true]` is sent
49
+ as a boolean: `postgresClient` sends arrays as their text before the
50
+ driver sees them) (porsager/postgres#1225). `postgresClient`
51
+ (`packages/db/src/postgres.ts`) sends arrays, dates and objects as text, so none is.
52
+ - **A transaction's BEGIN goes with its first statement** (`begin`, in
53
+ `index.ts`; `toBuffer` and `CommandComplete`, in `connection.ts`), a round
54
+ trip less for every transaction. Upstream sent BEGIN alone and waited for
55
+ it. The two go under one Sync: as the extended protocol's Parse, Bind and
56
+ Execute ahead of the statement's, or, for a statement without parameters,
57
+ in one Query message (`begin;\n<statement>`). Either way, a BEGIN that
58
+ fails has Postgres skip the statement, which so never runs outside its
59
+ transaction; what waited behind it is not sent, nor anything the
60
+ transaction asks after, which fails `TRANSACTION_NOT_BEGUN`, and nothing
61
+ is rolled back. Nothing waits behind the BEGIN's statement for less: one
62
+ the client failed to write (a value it cannot send) takes its BEGIN with
63
+ it. A transaction that asks nothing sends nothing. It holds its
64
+ connection from the start, as `reserve()` does, and gives it back once
65
+ it has ended: upstream gave it back once Postgres said the connection
66
+ was idle, which it also says after a BEGIN that failed. Its end is
67
+ decided once its work has settled (`settle`): what the work left running
68
+ asks from then on is refused, unsent (`TRANSACTION_ENDED`), as is what it
69
+ asks once its connection closed (the close's error); the transaction
70
+ then waits for every statement it asked to answer, and ends with a
71
+ ROLLBACK if any failed, waited for or not, or if its work asked anything
72
+ once settled (`TRANSACTION_UNFINISHED`: it would commit only part of
73
+ it), else a COMMIT; and a COMMIT that Postgres answers with ROLLBACK (a
74
+ savepoint's statement that failed once its savepoint's work had
75
+ returned) fails it. A refused BEGIN's error names the BEGIN; a first
76
+ statement's error its position in the statement. Upstream sent
77
+ the COMMIT or ROLLBACK at once: a statement asked during it ran after it,
78
+ outside the transaction, in autocommit, kept even when the transaction
79
+ rolled back; and a statement that failed unwaited left a COMMIT, which
80
+ Postgres answers with ROLLBACK, not an error, and upstream took for
81
+ success. No ROLLBACK goes to a connection gone. A held
82
+ connection asked to end meanwhile, its `max_lifetime` say, closes once
83
+ given back (`release`, in `connection.ts`), and its socket draining
84
+ never gives it to the pool (`drain`), as upstream's could, mid-transaction. Through Hyperdrive, the
85
+ first statement reaches the pooler with its BEGIN, in one batch: the
86
+ pooler keeps the connection for the transaction from the ReadyForQuery
87
+ after it, which says so (`T`), and coffre's Hyperdrive configurations
88
+ cache nothing (`docs/deploy.md`), so that statement is never answered
89
+ from a cache. Both shapes reach the pooler: Parse, Bind and Execute under
90
+ one Sync, and one Query message of two statements. Both were checked on
91
+ a real Hyperdrive for 0.15: `select pg_backend_pid()` as a transaction's
92
+ first statement (with a parameter, and without, and after the vault's
93
+ `SET LOCAL`) and again later in it, the same backend and transaction
94
+ each time, over 11,000 transactions, 40 to 50 at once over 10 backends;
95
+ what rolled back or failed kept nothing. A change to how they go is
96
+ checked there again. Hyperdrive sends a client's Syncs on one at a
97
+ time, each once the one before has answered: what costs a round trip
98
+ there is a Sync, not a write, so `test/hyperdrive.test.ts` counts
99
+ both. A first statement described first (Parse, Describe, Flush,
100
+ then a wait) would reach Hyperdrive before any ReadyForQuery had pinned
101
+ the connection, a flow Cloudflare says hangs under its pooling; coffre
102
+ sends none (`postgresClient`), and none is supported there. This
103
+ replaces PR A's fix for a BEGIN queued behind `max_pipeline` statements,
104
+ which left `begin()` without its connection: a transaction now waits for
105
+ a connection of its own instead.
106
+ - **Statements in a group go under one Sync** (`group`, in `index.ts`;
107
+ `toBuffer`, `build` and `CommandComplete`, in `connection.ts`), a round
108
+ trip for them all through a pooler that sends a client's Syncs on one at
109
+ a time, as Hyperdrive does (`HyperdrivePool`'s `groupReads`, in
110
+ `../hyperdrive.ts`). Each is its own Parse, Describe, Bind and Execute,
111
+ its values sent with it; one Sync follows the last. The group is one
112
+ query to the connection: each statement's rows are its own result,
113
+ split at its CommandComplete, and the group answers once Postgres is
114
+ ready again, every result at once. Postgres runs them as one implicit
115
+ transaction, so if one fails it skips the rest, and the group fails with
116
+ that error, naming the statement. A group holds plain reads alone
117
+ (`select …`, `GROUP_NOT_READ` otherwise: a write grouped with a statement
118
+ that fails would be rolled back by an error not its own; a `select` that
119
+ writes through a function is not seen, and says so ahead of itself, as
120
+ `/* writes */ select …`, which no group takes), and is the
121
+ pool's alone: a transaction's statements each go under its own Sync, so
122
+ BEGIN and COMMIT mean what they did. Upstream has no such thing; its
123
+ pipelined statements each carry a Sync.
124
+ - **A connection closed while it opens fails its query** (`closed`, in
125
+ `connection.ts`), as node-postgres's "Connection terminated
126
+ unexpectedly" did. Upstream dialled again, at once and for ever (thousands
127
+ of dials a second), the query never answering; its retry was for the next
128
+ of several hosts, which coffre never names (`postgresOptions` refuses
129
+ them).
130
+ - **A query cut short by its connection's close leaves it** (`closed`, in
131
+ `connection.ts`). Upstream rejected the query but kept it as the
132
+ connection's, so `end()` waited for it to answer, for ever, unless another
133
+ query opened the connection again: a Worker call whose connection was cut
134
+ under a query, then closed (`HyperdrivePool.end`), hung until Cloudflare
135
+ cancelled it. Likewise an `end()` asked while the connection opened or
136
+ answered: the connection's close ends it. And what the cut query's answer
137
+ had left half read goes with it, its error, its row count, its results:
138
+ upstream kept them, so the next query on the connection, opened again,
139
+ failed with the dead one's error, and the one after answered its rows
140
+ after the dead one's count, holes first.
141
+ - **An ending client opens no connection again** (`onclose`, in
142
+ `index.ts`). Upstream opened a closed connection again for a query still
143
+ waiting for one, even once `end()` had been asked, and answered: that
144
+ connection outlived the client's end, which no other `end()` could close.
145
+ Those queries fail, `CONNECTION_ENDED`, as any asked after `end()` does,
146
+ and so does a `reserve()` (in `index.ts`); a connection reserved before
147
+ `end()` and released after it closes, which `end()` waits for, where
148
+ upstream gave it back to the pool.
149
+ - **A `reserve()` that opens its connection gets it** (`ReadyForQuery`, in
150
+ `connection.ts`; `hold`, in `index.ts`). Upstream handed it over after
151
+ `fetch_types`'s own query, so without `fetch_types`, as coffre opened
152
+ every client, a `reserve()` on a pool with no connection open waited for
153
+ ever. And upstream's reservation both waited in the pool's queue and
154
+ opened a connection, which gave itself to the queue's first: one taken
155
+ from the queue to open a connection again, after one closed, was no
156
+ longer there, and waited for ever, as a transaction waiting for the
157
+ connection its predecessor lost would have. A reservation now either
158
+ waits or opens a connection, which is given to it.
159
+ - **The pool takes the connection idle the shortest** (`Queue.pop`, in
160
+ `queue.ts` and `index.ts`), as pg-pool does. Upstream takes the one idle the
161
+ longest, so a steady load cycles every connection of the pool and each
162
+ backend's caches stay cold: Postgres spent ~8% more CPU per use at a pool of
163
+ 16 (`packages/db/test/pool.test.ts`).
164
+ - **An opening the client cannot finish fails its connection**
165
+ (`openingFailed`, `secure`, `connected`, `createSocket` and
166
+ `authenticate`, in `connection.ts`): its TLS (a key or certificate it
167
+ cannot read), its startup, its sign-in (a hash that throws, a server's SCRAM
168
+ message it cannot read, a method it has not: GSSAPI, SSPI, Kerberos), or a
169
+ `socket` factory that throws (which backs off as a refused connection does)
170
+ fails what waits for the connection and closes it, so that it opens again
171
+ for the next query. Upstream left the error unhandled, which ends a Node
172
+ process, or the connection opening until its `connect_timeout`, if any,
173
+ every query after it waiting. A step of the opening that finishes once its
174
+ socket has closed (on workerd, the server's answer to the SSLRequest and
175
+ the hashes are promises, which can settle after the close) writes nothing
176
+ and fails nothing: upstream went on with the connection opened again, or
177
+ failed on its null socket.
178
+ - **A statement the client cannot write fails alone** (`execute`, in
179
+ `connection.ts`): too many parameters, a value it cannot serialize.
180
+ Nothing of it is sent; on an idle connection, a lone Sync answers it, so
181
+ the connection goes on as after any answer. Upstream failed the statement
182
+ already answering instead, and left this one waiting, its transaction and
183
+ connection with it, for ever.
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
@@ -0,0 +1,89 @@
1
+ import { Buffer } from 'node:buffer';
2
+
3
+ /** The NUL that ends a string in the protocol. */
4
+ export const N = '\0';
5
+
6
+ const SIZE = 256;
7
+
8
+ /**
9
+ * The message being written: started with its type (`b.typed('Q')`), or
10
+ * none (`b.untyped()`, for the startup's and the SSLRequest's), then its
11
+ * fields, then `end()`, which writes its length and hands it over. One at a
12
+ * time, each written whole before the next starts.
13
+ */
14
+ class Writer {
15
+ #buffer = Buffer.allocUnsafe(SIZE);
16
+ /** Where the next field goes. */
17
+ i = 0;
18
+
19
+ /** A message of `type`, a letter: its length, written by `end()`, follows it. */
20
+ typed(type: string): this {
21
+ this.#buffer[0] = type.charCodeAt(0);
22
+ this.i = 5;
23
+ return this;
24
+ }
25
+
26
+ untyped(): this {
27
+ this.i = 0;
28
+ return this;
29
+ }
30
+
31
+ /** Skip `n` bytes, to be written later (`i32(x, at)`). */
32
+ inc(n: number): this {
33
+ this.i += n;
34
+ return this;
35
+ }
36
+
37
+ str(x: string): this {
38
+ const length = Buffer.byteLength(x);
39
+ this.#fit(length);
40
+ this.i += this.#buffer.write(x, this.i, length, 'utf8');
41
+ return this;
42
+ }
43
+
44
+ i16(x: number): this {
45
+ this.#fit(2);
46
+ this.#buffer.writeUInt16BE(x, this.i);
47
+ this.i += 2;
48
+ return this;
49
+ }
50
+
51
+ /** `x` next, or at `at`, a place skipped before. */
52
+ i32(x: number, at?: number): this {
53
+ if (at !== undefined) {
54
+ this.#buffer.writeUInt32BE(x, at);
55
+ return this;
56
+ }
57
+ this.#fit(4);
58
+ this.#buffer.writeUInt32BE(x, this.i);
59
+ this.i += 4;
60
+ return this;
61
+ }
62
+
63
+ /** `n` zero bytes. */
64
+ z(n: number): this {
65
+ this.#fit(n);
66
+ this.#buffer.fill(0, this.i, this.i + n);
67
+ this.i += n;
68
+ return this;
69
+ }
70
+
71
+ /** The message, its length written at `at`: 1 after a type, 0 for an untyped one. */
72
+ end(at = 1): Buffer {
73
+ this.#buffer.writeUInt32BE(this.i - at, at);
74
+ const out = this.#buffer.subarray(0, this.i);
75
+ this.i = 0;
76
+ this.#buffer = Buffer.allocUnsafe(SIZE);
77
+ return out;
78
+ }
79
+
80
+ #fit(n: number): void {
81
+ if (this.#buffer.length - this.i < n) {
82
+ const prev = this.#buffer;
83
+ this.#buffer = Buffer.allocUnsafe(prev.length + (prev.length >> 1) + n);
84
+ prev.copy(this.#buffer);
85
+ }
86
+ }
87
+ }
88
+
89
+ export const b = new Writer();