1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
//! [`sqlx`](https://docs.rs/sqlx) `Type` / `Encode` / `Decode` bindings.
//!
//! ## Shape
//!
//! One impl trio per type, generic over `DB: Database`, delegating to the
//! standard-library type the driver already supports — `[u8]` and `&[u8]` for
//! the byte types, `str` and `&str` for the UTF-8 ones. Every backend that
//! supports those comes along for free; PostgreSQL, MySQL and SQLite all do.
//! This mirrors `sqlx-core`'s own `bstr` integration.
//!
//! The four types bound are [`shared::Bytes`](crate::shared::Bytes),
//! [`compact::Bytes`](crate::compact::Bytes),
//! [`shared::Utf8Bytes`](crate::shared::Utf8Bytes) and
//! [`compact::Utf8Bytes`](crate::compact::Utf8Bytes).
//!
//! ## PostgreSQL: the byte types need a prepared query
//!
//! Decoding borrows from the row, and `sqlx-postgres` refuses to lend `BYTEA`
//! out as a `&[u8]` in a simple (unprepared) query — there the value arrives
//! as `\x`-prefixed hex text, so the row holds no bytes to borrow. The error
//! reads *"unsupported decode to `&[u8]` of BYTEA in a simple query; use a
//! prepared query or decode to `Vec<u8>`"*.
//!
//! A statement is prepared whenever it carries an argument list, which
//! `query`, `query_as` and the `query!` macros always do, even with nothing
//! bound. The simple protocol is reached only by executing a statement that
//! has no argument list at all: `raw_sql`, or a SQL string handed straight to
//! an `Executor` method. Where one of those has to read bytes, decode the
//! column as a `Vec<u8>` and convert — at the cost of the allocation this
//! binding otherwise avoids:
//!
//! ```text
//! let raw: Vec<u8> = row.try_get("payload")?;
//! let payload = smol_bytes::shared::Bytes::from(raw);
//! ```
//!
//! Nothing else is restricted: PostgreSQL lends `&str` out under either
//! protocol, so the UTF-8 types are unaffected, and MySQL and SQLite lend both
//! unconditionally.
//!
//! ## SQLite: a decoded value is marked borrowed
//!
//! `SqliteValueRef::blob_borrowed` and `text_borrowed` record on the value
//! handle that its buffer was lent out, because SQLite may invalidate that
//! pointer when the same value is read as another type. The one consequence is
//! that `sqlite3_value_int64` and `sqlite3_value_double` on **that same
//! handle** then report `BorrowedBlobError`: decoding a value as bytes or text
//! and *then* as a number is what breaks. Decoding a row is unaffected — each
//! column arrives as its own handle and is decoded once.
//!
//! ## The capped types are not bound
//!
//! [`Buffer`](crate::Buffer) and [`Utf8Buffer`](crate::Utf8Buffer) hold their
//! contents inline and are capped at [`INLINE_CAP`](crate::INLINE_CAP) bytes;
//! their `TryFrom` conversions refuse anything longer. A database column
//! carries data of unbounded length that the program does not choose, so
//! decoding one into a capped type turns an ordinary long row into a runtime
//! failure on data nobody picked — and a `Decode` cannot even warn about it
//! ahead of time, because `Type::compatible` sees the SQL type and never the
//! value. The four types above accept any length. A caller that knows its
//! rows are short enough can convert after decoding, where the length bound is
//! its own to check and its own to report on.
//!
//! ## Why the delegate is a borrow
//!
//! The obvious ambition is for a `Decode` that takes an owned or shareable
//! buffer off the row rather than copying out of it. **No backend permits
//! that from third-party code**, checked against sqlx 0.9.0 rather than
//! assumed:
//!
//! - `PgValueRef` does hold a `&Bytes` pointing at the row buffer, but that
//! field is `pub(crate)`; the only public accessors are `as_bytes()` and
//! `as_str()`, both of which yield a borrow.
//! - `MySqlValueRef` is stricter still — even `as_bytes()` is `pub(crate)`,
//! so a foreign `Decode` impl has no way to reach the bytes except through
//! another `Decode` impl. `ValueRef::to_owned` does slice the row's `Bytes`
//! without copying, but it returns a `MySqlValue` whose payload is private.
//! - `SqliteValueRef` wraps a `sqlite3_value` owned by SQLite's C allocator.
//! There is no Rust-side buffer to share at all, `blob_owned()` is a
//! `to_vec()`, and the handle is deliberately `!Send + !Sync`.
//!
//! So exactly one copy out of the row is unavoidable for every type on every
//! backend, and delegating is the only shape available rather than merely the
//! convenient one. What that leaves to choose is *which* delegate, and the
//! borrowed one is never worse. `&[u8]` and `&str` hand over a view of the
//! row, and this crate then performs the one unavoidable copy directly into
//! its own representation. `Vec<u8>` and `String` perform that copy into an
//! allocation of their own first: above 62 bytes the allocation is handed on
//! and the two routes come out even, but at or below 62 bytes it is allocated,
//! copied out of, and freed — for a value that was always going to live
//! inline. That is the allocation this crate exists to avoid, and it is the
//! whole of what the delegate decides.
//!
//! There is no third shape that tries the borrow and falls back to the owned
//! delegate. `decode` consumes the `ValueRef` by value, and neither
//! `sqlx_core::value::ValueRef` nor `Database::ValueRef` is bound by `Copy` or
//! `Clone`, so a generic impl has nothing left to make a second attempt with.
//!
//! ## Copying, per type and direction
//!
//! | Type | `decode`, at or below 62 bytes | `decode`, above 62 bytes | `encode_by_ref` |
//! | --- | --- | --- | --- |
//! | [`shared::Bytes`](crate::shared::Bytes) / [`compact::Bytes`](crate::compact::Bytes) | one copy row → inline, **no allocation** | one copy row → a fresh reference-counted allocation | one copy into the argument buffer |
//! | [`shared::Utf8Bytes`](crate::shared::Utf8Bytes) / [`compact::Utf8Bytes`](crate::compact::Utf8Bytes) | the same, after the driver has validated UTF-8 | the same, after the driver has validated UTF-8 | one copy into the argument buffer |
//!
//! The two strategies do not differ here: both store a value inline when it
//! fits at the moment of construction, and they part company only later, over
//! whether an operation that shrinks a heap-backed value converts it back.
//!
//! ## `encode` versus `encode_by_ref`
//!
//! Only [`Encode::encode_by_ref`] is implemented; `encode` keeps its default,
//! deliberately. The consuming form's advantage is backend-specific and does
//! not survive a `DB`-generic impl: SQLite's `Encode for Vec<u8>` really does
//! move the vector into an `Arc` instead of cloning it, so routing through
//! `Vec<u8>` would let a uniquely-owned [`shared::Bytes`](crate::shared::Bytes)
//! reach the driver with no copy at all — but PostgreSQL and MySQL both write
//! straight into the argument buffer from a `&[u8]`, so the same routing would
//! *add* an allocation and a copy on two backends out of three. Encoding from
//! a borrow costs one copy everywhere and never more.
//!
//! Encoding from a borrow is possible at all only because sqlx 0.9 dropped
//! the lifetime parameter from `Database::ArgumentBuffer`; a higher-ranked
//! `for<'a> &'a [u8]: Encode<'a, DB>` bound then lets `encode_by_ref` pass a
//! slice borrowed from `&self`. `sqlx-core`'s own `bstr` integration cannot do
//! this and calls `to_vec()` first, paying an extra allocation and copy per
//! encode.
use ;
use crate::;
byte_type!;
byte_type!;
text_type!;
text_type!;