Skip to main content

diesel/sqlite/types/
json.rs

1//! Support for JSON and JSONB values under SQLite.
2
3use crate::deserialize::{self, FromSql};
4use crate::serialize::{self, IsNull, Output, ToSql};
5use crate::sql_types;
6use crate::sqlite::{Sqlite, SqliteValue};
7use alloc::boxed::Box;
8use alloc::string::{String, ToString};
9use alloc::vec::Vec;
10
11#[cfg(all(feature = "__sqlite-shared", feature = "serde_json"))]
12impl FromSql<sql_types::Json, Sqlite> for serde_json::Value {
13    fn from_sql(mut value: SqliteValue<'_, '_, '_>) -> deserialize::Result<Self> {
14        serde_json::from_str(value.read_text()).map_err(|_| "Invalid Json".into())
15    }
16}
17
18#[cfg(all(feature = "__sqlite-shared", feature = "serde_json"))]
19impl ToSql<sql_types::Json, Sqlite> for serde_json::Value {
20    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
21        out.set_value(serde_json::to_string(self)?);
22        Ok(IsNull::No)
23    }
24}
25
26#[cfg(all(feature = "__sqlite-shared", feature = "serde_json"))]
27impl FromSql<sql_types::Jsonb, Sqlite> for serde_json::Value {
28    fn from_sql(mut value: SqliteValue<'_, '_, '_>) -> deserialize::Result<Self> {
29        use self::jsonb::*;
30
31        let bytes = value.read_blob();
32
33        if bytes.is_empty() {
34            return Err("Empty blob cannot be decoded as JSONB".into());
35        }
36
37        // Read the JSONB value from the byte stream
38        let (jsonb, size) = read_jsonb_value(bytes)?;
39        if size == bytes.len() {
40            Ok(jsonb)
41        } else {
42            Err("Payload contained more bytes than the encoded JSONB".into())
43        }
44    }
45}
46
47#[cfg(all(feature = "__sqlite-shared", feature = "serde_json"))]
48impl ToSql<sql_types::Jsonb, Sqlite> for serde_json::Value {
49    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
50        use self::jsonb::*;
51
52        // Create a buffer to hold the binary JSONB encoding
53        let mut buffer = Vec::new();
54
55        // Write the JSON value into the buffer in JSONB format
56        write_jsonb_value(self, &mut buffer)?;
57
58        // Set the serialized binary data to the output
59        out.set_value(buffer);
60
61        Ok(IsNull::No)
62    }
63}
64
65#[cfg(all(feature = "__sqlite-shared", feature = "serde_json"))]
66mod jsonb {
67    extern crate serde_json;
68
69    use core::error::Error;
70
71    use super::*;
72
73    pub(super) const JSONB_NULL: u8 = 0x00;
74    pub(super) const JSONB_TRUE: u8 = 0x01;
75    pub(super) const JSONB_FALSE: u8 = 0x02;
76    pub(super) const JSONB_INT: u8 = 0x03;
77    pub(super) const JSONB_INT5: u8 = 0x04;
78    pub(super) const JSONB_FLOAT: u8 = 0x05;
79    pub(super) const JSONB_FLOAT5: u8 = 0x06;
80    pub(super) const JSONB_TEXT: u8 = 0x07;
81    pub(super) const JSONB_TEXTJ: u8 = 0x08;
82    pub(super) const JSONB_TEXT5: u8 = 0x09;
83    pub(super) const JSONB_TEXTRAW: u8 = 0x0A;
84    pub(super) const JSONB_ARRAY: u8 = 0x0B;
85    pub(super) const JSONB_OBJECT: u8 = 0x0C;
86
87    #[derive(#[automatically_derived]
impl ::core::fmt::Debug for JsonbHeader {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f, "JsonbHeader",
            "element_type", &self.element_type, "payload_size",
            &self.payload_size, "header_size", &self.header_size,
            "total_size", &&self.total_size)
    }
}Debug)]
88    struct JsonbHeader {
89        element_type: u8,
90        payload_size: usize,
91        header_size: usize,
92        total_size: usize,
93    }
94
95    // Helper function to read a JSONB value from the byte stream
96    #[allow(unsafe_code)]
97    pub(super) fn read_jsonb_value(
98        bytes: &[u8],
99    ) -> deserialize::Result<(serde_json::Value, usize)> {
100        if bytes.is_empty() {
101            return Err("Empty JSONB data".into());
102        }
103        let (global_header, mut global_value) = read_header_and_value(bytes)?;
104
105        if global_value.is_array() || global_value.is_object() {
106            // we need to use pointers here, as the borrow checker does not understand
107            // that we only modify the last value in this stack. Given that we cannot
108            // invalidate any pointer that's up in the stack
109            let mut stack = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [(&mut global_value as *mut serde_json::Value,
                    global_header.payload_size)]))vec![(
110                &mut global_value as *mut serde_json::Value,
111                global_header.payload_size,
112            )];
113            let mut payload = &bytes[global_header.header_size..];
114            let mut total_read = 0;
115            // we must use a loop based decoding approach here instead of the much simpler recursive implementation
116            // as we otherwise run into stack overflows for deeply nested objects/arrays
117
118            while total_read < global_header.payload_size {
119                let Some((value, _size)) = stack.last().copied() else {
120                    break;
121                };
122                let value = unsafe {
123                    // SAFETY: The pointer was initialized before
124                    // We we cannot invalidate the underlying object
125                    &mut *value
126                };
127
128                if let serde_json::Value::Array(array) = value {
129                    let (header, value) = read_header_and_value(payload)?;
130
131                    array.push(value);
132                    let last_ref = array.last_mut().expect("Pushed above");
133                    let payload_size = if last_ref.is_object() || last_ref.is_array() {
134                        stack.push((last_ref as *mut _, total_read + header.total_size));
135                        header.header_size
136                    } else {
137                        header.total_size
138                    };
139                    total_read += payload_size;
140                    if payload.len() > payload_size {
141                        payload = &payload[payload_size..];
142                    } else {
143                        for (_, v) in stack {
144                            if v != total_read {
145                                return Err("Invalid size of payload declared".into());
146                            }
147                        }
148                        break;
149                    }
150                } else if let serde_json::Value::Object(object) = value {
151                    //       while total_read < payload_size {
152                    let (key_header, key) = read_header_and_value(payload)?;
153                    total_read += key_header.total_size;
154                    let serde_json::Value::String(key) = key else {
155                        return Err("Expected a string as object key".into());
156                    };
157                    if payload.len() > key_header.total_size {
158                        payload = &payload[key_header.total_size..];
159                    } else {
160                        return Err("No value found for object".into());
161                    }
162                    let (value_header, value) = read_header_and_value(payload)?;
163                    object.insert(key.clone(), value);
164                    let last_ref = object.get_mut(&key).expect("We inserted it above");
165                    let payload_size = if last_ref.is_object() || last_ref.is_array() {
166                        stack.push((last_ref as *mut _, total_read + value_header.total_size));
167                        value_header.header_size
168                    } else {
169                        value_header.total_size
170                    };
171                    total_read += payload_size;
172                    if payload.len() > payload_size {
173                        payload = &payload[payload_size..];
174                    } else {
175                        for (_, v) in stack {
176                            if v != total_read {
177                                return Err("Invalid size of payload declared".into());
178                            }
179                        }
180                        break;
181                    }
182                } else {
183                    ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
184                }
185
186                while let Some(v) = stack.last().map(|(_, v)| *v) {
187                    if v > total_read {
188                        break;
189                    } else if v == total_read {
190                        stack.pop();
191                    } else {
192                        return Err("Invalid size of payload declared".into());
193                    }
194                }
195            }
196        }
197        Ok((global_value, global_header.total_size))
198    }
199
200    // This function decodes the jsonb header
201    // and the value for non-composite values. For composite values like array and object
202    // we only decode the "value header" and leave decoding
203    // the actual child values to future calls
204    fn read_header_and_value(
205        bytes: &[u8],
206    ) -> deserialize::Result<(JsonbHeader, serde_json::Value)> {
207        let header = read_jsonb_value_header(bytes)?;
208        let payload_bytes = &bytes[header.header_size..header.total_size];
209        let value = match header.element_type {
210            // sqlite writes a constant as a bare one byte header and refuses any other spelling
211            JSONB_NULL | JSONB_TRUE | JSONB_FALSE if header.total_size != 1 => {
212                Err("Invalid JSONB data: a constant must be a single byte".into())
213            }
214            JSONB_NULL => Ok(serde_json::Value::Null),
215            JSONB_TRUE => Ok(serde_json::Value::Bool(true)),
216            JSONB_FALSE => Ok(serde_json::Value::Bool(false)),
217            JSONB_INT => read_jsonb_int(payload_bytes, header.payload_size),
218            JSONB_INT5 => Err("INT5 is not supported".into()),
219            JSONB_FLOAT => read_jsonb_float(payload_bytes, header.payload_size),
220            JSONB_FLOAT5 => Err("FLOAT5 is not supported".into()),
221            JSONB_TEXT => read_jsonb_text(payload_bytes, header.payload_size),
222            JSONB_TEXTJ => read_jsonb_textj(payload_bytes, header.payload_size),
223            JSONB_TEXTRAW => read_jsonb_text(payload_bytes, header.payload_size),
224            JSONB_TEXT5 => Err("TEXT5 is not supported".into()),
225            JSONB_ARRAY => Ok(serde_json::Value::Array(alloc::vec::Vec::new())),
226            JSONB_OBJECT => Ok(serde_json::Value::Object(serde_json::Map::new())),
227            _ => Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Unsupported or reserved JSONB type: {0}",
                header.element_type))
    })alloc::format!(
228                "Unsupported or reserved JSONB type: {}",
229                header.element_type
230            )
231            .into()),
232        }?;
233        Ok((header, value))
234    }
235
236    fn read_jsonb_value_header(bytes: &[u8]) -> deserialize::Result<JsonbHeader> {
237        let first_byte = bytes[0];
238        let element_type = first_byte & 0x0F;
239        let size_hint = (first_byte & 0xF0) >> 4;
240        let (payload_size, header_size): (usize, usize) = match size_hint {
241            0x00..=0x0B => (size_hint as usize, 1), // Payload size is directly in the upper nibble
242            0x0C => {
243                if bytes.len() < 2 {
244                    return Err("Invalid JSONB data: insufficient bytes for payload size".into());
245                }
246                (bytes[1] as usize, 2) // 1 additional byte for payload size
247            }
248            0x0D => {
249                if bytes.len() < 3 {
250                    return Err("Invalid JSONB data: insufficient bytes for payload size".into());
251                }
252                (u16::from_be_bytes([bytes[1], bytes[2]]) as usize, 3) // 2 additional bytes
253            }
254            0x0E => {
255                if bytes.len() < 5 {
256                    return Err("Invalid JSONB data: insufficient bytes for payload size".into());
257                }
258                (
259                    u32::from_be_bytes([bytes[1], bytes[2], bytes[3], bytes[4]]) as usize,
260                    5,
261                ) // 4 additional bytes
262            }
263            0x0F => {
264                if bytes.len() < 9 {
265                    return Err("Invalid JSONB data: insufficient bytes for payload size".into());
266                }
267                (
268                    usize::try_from(u64::from_be_bytes([
269                        bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
270                        bytes[8],
271                    ]))
272                    .map_err(Box::new)?,
273                    9,
274                ) // 8 additional bytes
275            }
276            _ => return Err("Invalid payload size hint".into()),
277        };
278        let total_size = header_size
279            .checked_add(payload_size)
280            .ok_or("The provided payload size overflows usize")?;
281        if bytes.len() < total_size {
282            return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Invalid JSONB data: insufficient bytes for value of type {0}, expected {1} bytes, got {2}",
                element_type, total_size, bytes.len()))
    })alloc::format!(
283                "Invalid JSONB data: insufficient bytes for value of type {}, expected {} bytes, got {}",
284                element_type,
285                total_size,
286                bytes.len()
287            )
288            .into());
289        }
290
291        Ok(JsonbHeader {
292            element_type,
293            payload_size,
294            header_size,
295            total_size,
296        })
297    }
298
299    // Read a JSON integer in canonical format (INT)
300    pub(super) fn read_jsonb_int(
301        bytes: &[u8],
302        payload_size: usize,
303    ) -> deserialize::Result<serde_json::Value> {
304        // Ensure the bytes are at least as large as the payload size
305        if bytes.len() < payload_size {
306            return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Expected payload of size {0}, but got {1}",
                payload_size, bytes.len()))
    })alloc::format!(
307                "Expected payload of size {}, but got {}",
308                payload_size,
309                bytes.len()
310            )
311            .into());
312        }
313
314        // Read only the number of bytes specified by the payload size
315        let int_str = core::str::from_utf8(bytes).map_err(|_| "Invalid ASCII in JSONB integer")?;
316        // An INT payload is integer text, so fractional and exponent forms are malformed.
317        // `serde_json` reports a non-finite `1e999` as neither float nor integer.
318        if int_str.contains(['.', 'e', 'E']) {
319            return Err("Failed to parse JSONB integer".into());
320        }
321        // `-0` is the one integer text `serde_json` turns into a float, and a signed
322        // zero only carries meaning for floats, so decode the integer it denotes.
323        if int_str == "-0" {
324            return Ok(serde_json::Value::Number(serde_json::Number::from(0)));
325        }
326        let int_value = serde_json::from_str(int_str)
327            .map_err(|_| "Failed to parse JSONB")
328            .and_then(|v: serde_json::Value| {
329                // Without `arbitrary_precision` an integer wider than 64 bits parses as
330                // a lossy float, which must not pass as the stored value.
331                (v.is_number() && !v.is_f64())
332                    .then_some(v)
333                    .ok_or("Failed to parse JSONB integer")
334            })?;
335
336        Ok(int_value)
337    }
338
339    // Read a JSON float in canonical format (FLOAT)
340    pub(super) fn read_jsonb_float(
341        bytes: &[u8],
342        payload_size: usize,
343    ) -> deserialize::Result<serde_json::Value> {
344        if bytes.len() < payload_size {
345            return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Expected payload of size {0}, but got {1}",
                payload_size, bytes.len()))
    })alloc::format!(
346                "Expected payload of size {}, but got {}",
347                payload_size,
348                bytes.len()
349            )
350            .into());
351        }
352
353        let float_str = core::str::from_utf8(bytes).map_err(|_| "Invalid UTF-8 in JSONB float")?;
354        let float_value = serde_json::from_str(float_str)
355            .map_err(|_| "Failed to parse JSONB")
356            .and_then(|v: serde_json::Value| {
357                v.is_f64()
358                    .then_some(v)
359                    .ok_or("Failed to parse JSONB number")
360            })?;
361
362        Ok(float_value)
363    }
364
365    // Read a JSON string
366    pub(super) fn read_jsonb_text(
367        bytes: &[u8],
368        payload_size: usize,
369    ) -> deserialize::Result<serde_json::Value> {
370        if bytes.len() < payload_size {
371            return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Expected payload of size {0}, but got {1}",
                payload_size, bytes.len()))
    })alloc::format!(
372                "Expected payload of size {}, but got {}",
373                payload_size,
374                bytes.len()
375            )
376            .into());
377        }
378
379        let text = core::str::from_utf8(bytes).map_err(|_| "Invalid UTF-8 in JSONB string")?;
380        Ok(serde_json::Value::String(text.to_string()))
381    }
382
383    pub(super) fn read_jsonb_textj(
384        bytes: &[u8],
385        payload_size: usize,
386    ) -> deserialize::Result<serde_json::Value> {
387        if bytes.len() < payload_size {
388            return Err(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Expected payload of size {0}, but got {1}",
                payload_size, bytes.len()))
    })alloc::format!(
389                "Expected payload of size {}, but got {}",
390                payload_size,
391                bytes.len()
392            )
393            .into());
394        }
395
396        let text = core::str::from_utf8(bytes).map_err(|_| "Invalid UTF-8 in JSONB string")?;
397
398        // Unescape JSON escape sequences (e.g., "\n", "\u0020")
399        let unescaped_text = serde_json::from_str(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\"{0}\"", text))
    })alloc::format!("\"{text}\""))
400            .map_err(|_| "Failed to parse JSON-escaped text in TEXTJ")?;
401
402        Ok(unescaped_text)
403    }
404
405    enum JsonValuePtr<'a> {
406        Value(&'a serde_json::Value),
407        Array {
408            values: &'a [serde_json::Value],
409            serialized_buffer: Vec<u8>,
410        },
411        Object {
412            object: &'a serde_json::value::Map<String, serde_json::Value>,
413            keys: Box<dyn Iterator<Item = &'a String> + 'a>,
414            serialized_buffer: Vec<u8>,
415        },
416    }
417
418    pub(super) fn write_jsonb_header(
419        buffer: &mut Vec<u8>,
420        element_type: u8,
421        payload_size: usize,
422    ) -> serialize::Result {
423        // Check if payload size exceeds the maximum allowed size
424        if payload_size > 2_147_483_647 {
425            return Err("Payload size exceeds the maximum allowed size of 2GB".into());
426        }
427
428        if payload_size <= 0x0B {
429            // Small payloads, 0 additional byte for size
430            buffer.push(
431                ((u8::try_from(payload_size).map_err(|e| e.to_string())?) << 4) | element_type,
432            );
433        } else if payload_size <= 0xFF {
434            // Medium payloads, 1 additional byte for size
435            buffer.extend_from_slice(&[
436                (0x0C << 4) | element_type,
437                u8::try_from(payload_size).map_err(|e| e.to_string())?,
438            ]);
439        } else if payload_size <= 0xFFFF {
440            // Larger payloads, 2 additional bytes for size
441            buffer.push((0x0D << 4) | element_type);
442            buffer.extend_from_slice(
443                &(u16::try_from(payload_size).map_err(|e| e.to_string())?).to_be_bytes(),
444            );
445        } else {
446            // Very large payloads, 4 additional bytes for size (up to 2 GiB)
447            buffer.push((0x0E << 4) | element_type);
448            buffer.extend_from_slice(
449                &(u32::try_from(payload_size).map_err(|e| e.to_string())?).to_be_bytes(),
450            );
451        };
452
453        Ok(IsNull::No)
454    }
455
456    fn place_composite_value(
457        buffer: &mut Vec<u8>,
458        stack: &mut [JsonValuePtr<'_>],
459        serialized_buffer: Vec<u8>,
460        tpe: u8,
461    ) -> serialize::Result {
462        let buffer = match stack.last_mut() {
463            None | Some(JsonValuePtr::Value(_)) => buffer,
464            Some(
465                JsonValuePtr::Array {
466                    serialized_buffer, ..
467                }
468                | JsonValuePtr::Object {
469                    serialized_buffer, ..
470                },
471            ) => serialized_buffer,
472        };
473        write_jsonb_header(buffer, tpe, serialized_buffer.len())?;
474        buffer.extend(serialized_buffer);
475
476        Ok(IsNull::No)
477    }
478
479    // Helper function to write a JSON value into a JSONB binary format
480    pub(super) fn write_jsonb_value(
481        value: &serde_json::Value,
482        buffer: &mut Vec<u8>,
483    ) -> serialize::Result {
484        let mut stack = ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [JsonValuePtr::Value(value)]))vec![JsonValuePtr::Value(value)];
485
486        while let Some(value) = stack.pop() {
487            let add_to_stack = match value {
488                JsonValuePtr::Value(value) => write_plain_jsonb_value(buffer, value)?,
489                JsonValuePtr::Array {
490                    values,
491                    mut serialized_buffer,
492                } => {
493                    if let Some((el, tail)) = values.split_first() {
494                        let ret = write_plain_jsonb_value(&mut serialized_buffer, el)?;
495                        stack.push(JsonValuePtr::Array {
496                            values: tail,
497                            serialized_buffer,
498                        });
499                        ret
500                    } else {
501                        place_composite_value(buffer, &mut stack, serialized_buffer, JSONB_ARRAY)?;
502                        None
503                    }
504                }
505                JsonValuePtr::Object {
506                    object,
507                    mut keys,
508                    mut serialized_buffer,
509                } => {
510                    if let Some(next_key) = keys.next() {
511                        let value = object
512                            .get(next_key)
513                            .ok_or_else(|| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("Missing value for object key: `{0}`",
                next_key))
    })format!("Missing value for object key: `{next_key}`"))?;
514                        write_jsonb_string(next_key, &mut serialized_buffer)?;
515                        let ret = write_plain_jsonb_value(&mut serialized_buffer, value)?;
516                        stack.push(JsonValuePtr::Object {
517                            object,
518                            keys,
519                            serialized_buffer,
520                        });
521                        ret
522                    } else {
523                        place_composite_value(buffer, &mut stack, serialized_buffer, JSONB_OBJECT)?;
524                        None
525                    }
526                }
527            };
528            if let Some(next) = add_to_stack {
529                stack.push(next);
530            }
531        }
532
533        Ok(IsNull::No)
534    }
535
536    fn write_plain_jsonb_value<'a>(
537        buffer: &mut Vec<u8>,
538        value: &'a serde_json::Value,
539    ) -> Result<Option<JsonValuePtr<'a>>, Box<dyn Error + Send + Sync>> {
540        let ret = if value.is_null() {
541            write_jsonb_null(buffer)?;
542            None
543        } else if value.is_boolean() {
544            write_jsonb_bool(value.as_bool().ok_or("Failed to read JSONB value")?, buffer)?;
545            None
546        } else if value.is_number() {
547            write_jsonb_number(value, buffer)?;
548            None
549        } else if value.is_string() {
550            write_jsonb_string(value.as_str().ok_or("Failed to read JSONB value")?, buffer)?;
551            None
552        } else if value.is_array() {
553            let array = value.as_array().ok_or("Failed to read JSONB value")?;
554            Some(JsonValuePtr::Array {
555                values: array,
556                serialized_buffer: Vec::new(),
557            })
558        } else if value.is_object() {
559            let object = value.as_object().ok_or("Failed to read JSONB value")?;
560            Some(JsonValuePtr::Object {
561                object,
562                keys: Box::new(object.keys()),
563                serialized_buffer: Vec::new(),
564            })
565        } else {
566            return Err("Unsupported JSONB value type".into());
567        };
568        Ok(ret)
569    }
570
571    // Write a JSON null
572    pub(super) fn write_jsonb_null(buffer: &mut Vec<u8>) -> serialize::Result {
573        write_jsonb_header(buffer, JSONB_NULL, 0x0)?;
574        Ok(IsNull::No)
575    }
576
577    // Write a JSON boolean
578    pub(super) fn write_jsonb_bool(b: bool, buffer: &mut Vec<u8>) -> serialize::Result {
579        // Use the constants for true and false
580        write_jsonb_header(buffer, if b { JSONB_TRUE } else { JSONB_FALSE }, 0x0)?;
581        Ok(IsNull::No)
582    }
583
584    // Write a JSON number (integers and floats)
585    pub(super) fn write_jsonb_number(
586        n: &serde_json::Value,
587        buffer: &mut Vec<u8>,
588    ) -> serialize::Result {
589        let n = n.to_string();
590        let tpe = if n
591            .char_indices()
592            .any(|(idx, c)| !(c.is_ascii_digit() || (idx == 0 && (c == '-' || c == '+'))))
593        {
594            JSONB_FLOAT
595        } else {
596            JSONB_INT
597        };
598        write_jsonb_header(buffer, tpe, n.len())?;
599
600        // Write the ASCII text representation of the integer/float as the payload
601        buffer.extend_from_slice(n.as_bytes());
602
603        Ok(IsNull::No)
604    }
605
606    pub(super) fn write_jsonb_string(s: &str, buffer: &mut Vec<u8>) -> serialize::Result {
607        // strings needing a json escape go down TEXTJ, matching what sqlite's own jsonb() writes
608        // the scan is over bytes because json escapes nothing above 0x1F, unlike char::is_control
609        if s.bytes().any(|b| b < 0x20 || b == b'"' || b == b'\\') {
610            write_jsonb_textj(s, buffer)
611        } else {
612            write_jsonb_header(buffer, JSONB_TEXT, s.len())?;
613            buffer.extend_from_slice(s.as_bytes());
614            Ok(IsNull::No)
615        }
616    }
617
618    pub(super) fn write_jsonb_textj(s: &str, buffer: &mut Vec<u8>) -> serialize::Result {
619        // &s passes a sized &str, required by the serde_json 0.8.0 to_string bound
620        let escaped_string =
621            serde_json::to_string(&s).map_err(|_| "Failed to serialize string for TEXTJ")?;
622
623        let escaped_string = &escaped_string[1..escaped_string.len() - 1];
624
625        write_jsonb_header(buffer, JSONB_TEXTJ, escaped_string.len())?;
626
627        buffer.extend_from_slice(escaped_string.as_bytes());
628
629        Ok(IsNull::No)
630    }
631}
632
633#[cfg(test)]
634#[cfg(all(feature = "__sqlite-shared", feature = "serde_json"))]
635mod tests {
636    use super::jsonb::*;
637    use super::*;
638    #[cfg(not(miri))] // ffi call
639    use crate::ExpressionMethods;
640    #[cfg(not(miri))] // ffi call
641    use crate::dsl::json_valid_with_flags;
642    #[cfg(not(miri))] // ffi call
643    use crate::query_dsl::RunQueryDsl;
644    #[cfg(not(miri))] // ffi call
645    use crate::sqlite::JsonValidFlag;
646    #[cfg(not(miri))] // ffi call
647    use crate::test_helpers::connection;
648    use crate::test_helpers::format_error;
649    #[cfg(not(miri))] // ffi call
650    use crate::{IntoSql, dsl::sql};
651    use serde_json::{Value, json};
652    use sql_types::{Json, Jsonb};
653
654    // Helper function to create the correct JsonbHeader based on the payload size
655    pub(super) fn create_jsonb_header(
656        element_type: u8,
657        payload_size: usize,
658    ) -> Result<Vec<u8>, Box<dyn core::error::Error + Send + Sync>> {
659        let mut buffer = Vec::new();
660        jsonb::write_jsonb_header(&mut buffer, element_type, payload_size)?;
661        Ok(buffer)
662    }
663
664    fn value_with_payload(element_type: u8, payload: &[u8]) -> Vec<u8> {
665        let mut buffer = create_jsonb_header(element_type, payload.len()).unwrap();
666        buffer.extend_from_slice(payload);
667        buffer
668    }
669
670    #[diesel_test_helper::test]
671    fn regression_a_constant_reads_its_declared_size() {
672        let blobs: Vec<Vec<u8>> = vec![
673            value_with_payload(JSONB_NULL, &[0x0D, 0x00, 0xF3]), // null, inline size 3
674            value_with_payload(JSONB_TRUE, b"1.5"),              // true, inline size 3
675            value_with_payload(JSONB_NULL, &[0x00]),             // null, inline size 1
676            value_with_payload(JSONB_TRUE, &[0x08]),             // true, inline size 1
677            value_with_payload(JSONB_FALSE, &[0xFF]),            // false, inline size 1
678            // not buildable with create_jsonb_header because the writer takes the narrowest size spelling
679            vec![0xC0, 0x00], // null, two byte header
680            vec![0xC1, 0x00], // true, two byte header
681            {
682                // array holding a two byte true
683                let mut blob = create_jsonb_header(JSONB_ARRAY, 2).unwrap();
684                blob.extend_from_slice(&[0xC1, 0x00]);
685                blob
686            },
687            {
688                // object holding one
689                let mut blob = create_jsonb_header(JSONB_OBJECT, 4).unwrap();
690                blob.extend(create_jsonb_header(JSONB_TEXT, 1).unwrap());
691                blob.extend_from_slice(b"a");
692                blob.extend_from_slice(&[0xC1, 0x00]);
693                blob
694            },
695        ];
696        for blob in blobs {
697            let blob: &[u8] = &blob;
698            assert!(
699                read_jsonb_value(blob).is_err(),
700                "{blob:02X?} decoded to {:?}",
701                read_jsonb_value(blob).map(|value| value.0)
702            );
703        }
704
705        // the one byte spelling sqlite writes
706        let mut blob = create_jsonb_header(JSONB_ARRAY, 2).unwrap();
707        blob.extend(create_jsonb_header(JSONB_TRUE, 0).unwrap());
708        blob.extend(create_jsonb_header(JSONB_NULL, 0).unwrap());
709        assert_eq!(read_jsonb_value(&blob).unwrap().0, json!([true, null]));
710    }
711
712    #[diesel_test_helper::test]
713    #[cfg(not(miri))] // ffi call
714    fn regression_json_text_float_survives_a_round_trip() {
715        let conn = &mut connection();
716        for float in [
717            8.829872855928286e-308f64,
718            -0.20221894534048165,
719            1.7383394626966921e-307,
720            6.178787134922198e305,
721        ] {
722            let value = json!(float);
723            let text = diesel::select(sql::<sql_types::Text>("").bind::<sql_types::Json, _>(value))
724                .get_result::<String>(conn)
725                .unwrap();
726            let back = diesel::select(sql::<sql_types::Json>("").bind::<sql_types::Text, _>(text))
727                .get_result::<Value>(conn)
728                .unwrap();
729            assert_eq!(back.as_f64().map(f64::to_bits), Some(float.to_bits()));
730        }
731    }
732
733    #[diesel_test_helper::test]
734    #[cfg(not(miri))] // ffi call
735    fn regression_float_keeps_its_bits_through_the_writers_text() {
736        let conn = &mut connection();
737        let mut assert_roundtrip = |value: Value| {
738            let expected = value.as_f64().unwrap();
739            let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value))
740                .get_result::<Vec<u8>>(conn)
741                .unwrap();
742            let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob))
743                .get_result::<Value>(conn)
744                .unwrap();
745            assert_eq!(
746                back.as_f64().unwrap().to_bits(),
747                expected.to_bits(),
748                "{expected:?} came back as {back}"
749            );
750        };
751
752        // parsed from text, so `serde_json` chose the double
753        assert_roundtrip(serde_json::from_str("-922333372720360.5975808").unwrap());
754
755        for f in [
756            // these drift without `float_roundtrip`
757            -0.20221894534048165,
758            6.178787134922198e305,
759            -5.276099561814224e214,
760            3.587959730897931e-246,
761            9.136353238902674e-45,
762            2.4261860608815182e-160,
763            -2.5496151068102186e-175,
764            5.0513463356317975e-231,
765            // exact already, must stay exact
766            0.1,
767            1e-7,
768            5e-324,
769            -0.0,
770            f64::MAX,
771            f64::MIN_POSITIVE,
772        ] {
773            assert_roundtrip(json!(f));
774        }
775    }
776
777    #[diesel_test_helper::test]
778    fn regression_every_float_text_reads_back_as_the_same_double() {
779        let mut drifted = Vec::new();
780        let mut check = |bits: u64| {
781            let f = f64::from_bits(bits);
782            if !f.is_finite() {
783                return;
784            }
785            let mut buffer = Vec::new();
786            write_jsonb_number(&json!(f), &mut buffer).unwrap();
787            let back = read_jsonb_value(&buffer).unwrap().0;
788            if back.as_f64().map(f64::to_bits) != Some(bits) {
789                drifted.push(alloc::format!("{bits:#018x} {f:?} -> {back}"));
790            }
791        };
792
793        for exponent in [0, 1, 2, 512, 1021, 1022, 1023, 1024, 1075, 2045, 2046] {
794            for mantissa in [0, 1, 2, 1 << 26, 1 << 51, (1 << 52) - 2, (1 << 52) - 1] {
795                for sign in [0, 1u64 << 63] {
796                    check(sign | (exponent << 52) | mantissa);
797                }
798            }
799        }
800
801        // the doubles either side of the text-parsed witness
802        let witness = serde_json::from_str::<Value>("-922333372720360.5975808")
803            .unwrap()
804            .as_f64()
805            .unwrap()
806            .to_bits();
807        for bits in witness - 2..=witness + 2 {
808            check(bits);
809        }
810
811        // deterministic bit-pattern sweep
812        let mut state: u64 = 0x2545F4914F6CDD1D;
813        for _ in 0..256 {
814            state ^= state << 13;
815            state ^= state >> 7;
816            state ^= state << 17;
817            check(state);
818        }
819
820        assert!(
821            drifted.is_empty(),
822            "{} floats drifted, first {:?}",
823            drifted.len(),
824            &drifted[..drifted.len().min(4)]
825        );
826    }
827
828    #[diesel_test_helper::test]
829    #[cfg(not(miri))] // ffi call
830    fn every_jsonb_number_is_written_valid_and_round_trips() {
831        let conn = &mut connection();
832
833        // `1 << 63` is `i64::MAX + 1`, `1e21` is where Rust switches to exponent
834        // notation, and an exponent without a fraction digit carries no `.`.
835        let numbers = [
836            (json!(0), JSONB_INT),
837            (json!(1), JSONB_INT),
838            (json!(-1), JSONB_INT),
839            (json!(-5), JSONB_INT),
840            (json!(u64::from(u32::MAX)), JSONB_INT),
841            (json!(i64::MAX), JSONB_INT),
842            (json!(i64::MIN), JSONB_INT),
843            (json!(1u64 << 63), JSONB_INT),
844            (json!(u64::MAX), JSONB_INT),
845            (json!(3.0), JSONB_FLOAT),
846            (json!(-0.0), JSONB_FLOAT),
847            (json!(-2.5), JSONB_FLOAT),
848            (json!(1e-7), JSONB_FLOAT),
849            (json!(1e300), JSONB_FLOAT),
850            (json!(-1e300), JSONB_FLOAT),
851            (json!(1.5e300), JSONB_FLOAT),
852            (json!(1e21), JSONB_FLOAT),
853            (json!(f64::MIN), JSONB_FLOAT),
854            (json!(f64::MAX), JSONB_FLOAT),
855            (json!(f64::MIN_POSITIVE), JSONB_FLOAT),
856        ];
857
858        for (value, element_type) in numbers {
859            let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value.clone()))
860                .get_result::<Vec<u8>>(conn)
861                .unwrap();
862            assert_eq!(
863                blob[0] & 0x0F,
864                element_type,
865                "{value} was written with the wrong element type: {blob:02X?}"
866            );
867            let valid = diesel::select(json_valid_with_flags::<sql_types::Binary, _, _>(
868                blob.as_slice(),
869                JsonValidFlag::JsonbStrict,
870            ))
871            .get_result::<bool>(conn)
872            .unwrap();
873            assert!(
874                valid,
875                "sqlite rejects the blob written for {value}: {blob:02X?}"
876            );
877            let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob.clone()))
878                .get_result::<Value>(conn)
879                .unwrap_or_else(|error| panic!("{value} does not read back: {error}"));
880            assert_eq!(back, value, "{blob:02X?}");
881        }
882    }
883
884    // asserts a written blob is well formed to sqlite and reads back unchanged
885    #[cfg(not(miri))] // ffi call
886    fn jsonb_survives(conn: &mut crate::SqliteConnection, value: &Value) -> Result<(), String> {
887        let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value.clone()))
888            .get_result::<Vec<u8>>(conn)
889            .unwrap();
890        let valid = diesel::select(json_valid_with_flags::<sql_types::Binary, _, _>(
891            blob.as_slice(),
892            JsonValidFlag::JsonbStrict,
893        ))
894        .get_result::<bool>(conn)
895        .unwrap();
896        let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob.clone()))
897            .get_result::<Value>(conn);
898        if !valid {
899            return Err(alloc::format!(
900                "sqlite calls {value} malformed as {blob:02X?}"
901            ));
902        }
903        match back {
904            Ok(ref back) if back == value => Ok(()),
905            Ok(back) => Err(alloc::format!("{value} came back as {back}")),
906            Err(e) => Err(alloc::format!("{value} came back as {e}")),
907        }
908    }
909
910    #[diesel_test_helper::test]
911    #[cfg(not(miri))] // ffi call
912    fn regression_string_needing_an_escape_is_written_valid() {
913        let conn = &mut connection();
914        for value in [
915            json!(r#"a"b"#),
916            json!(r#"a\b"#),
917            json!(r#"a"\b"#),
918            json!(r#"""#),
919            json!(r#"\"#),
920            json!(r#"\""#),
921            json!(r#""leading"#),
922            json!(r#"trailing""#),
923            json!(r#"aaaaaaaaaaaa"bbbbbbbbbbbb"#),
924            json!({ "k": r#"a"b"# }),
925            json!([r#"a\b"#]),
926            json!({ r#"a"b"#: 1 }),
927            json!(""),
928            json!("abc"),
929            json!("a\nb"),
930            json!("a\"\nb"),
931        ] {
932            jsonb_survives(conn, &value).unwrap_or_else(|e| panic!("{e}"));
933        }
934    }
935
936    #[diesel_test_helper::test]
937    fn test_write_jsonb_number_classifies_by_integer_text() {
938        // `serde_json` writes an exponent with a sign, so the payload is `1e+300`.
939        for (value, element_type, payload) in [
940            (json!(0), JSONB_INT, "0"),
941            (json!(-1), JSONB_INT, "-1"),
942            (json!(i64::MIN), JSONB_INT, "-9223372036854775808"),
943            (json!(u64::MAX), JSONB_INT, "18446744073709551615"),
944            (json!(3.0), JSONB_FLOAT, "3.0"),
945            (json!(-0.0), JSONB_FLOAT, "-0.0"),
946            (json!(-2.5), JSONB_FLOAT, "-2.5"),
947            (json!(1e-7), JSONB_FLOAT, "1e-7"),
948            (json!(1e300), JSONB_FLOAT, "1e+300"),
949        ] {
950            let mut buffer = Vec::new();
951            write_jsonb_value(&value, &mut buffer).unwrap();
952
953            let mut expected = create_jsonb_header(element_type, payload.len()).unwrap();
954            expected.extend_from_slice(payload.as_bytes());
955
956            assert_eq!(buffer, expected, "{value} was not written as {payload}");
957        }
958    }
959
960    #[diesel_test_helper::test]
961    #[cfg(not(miri))] // ffi call
962    fn numbers_nested_in_containers_are_written_valid() {
963        let conn = &mut connection();
964        let value = json!({"a": -1, "b": [-2, -2.5, 1e-7, 0, u64::MAX], "c": {"d": i64::MIN}});
965
966        let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value.clone()))
967            .get_result::<Vec<u8>>(conn)
968            .unwrap();
969        let valid = diesel::select(
970            sql::<sql_types::Integer>("json_valid(")
971                .bind::<sql_types::Binary, _>(blob.clone())
972                .sql(", 8)"),
973        )
974        .get_result::<i32>(conn)
975        .unwrap();
976        assert_eq!(valid, 1, "sqlite rejects {blob:02X?}");
977
978        let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob))
979            .get_result::<Value>(conn)
980            .unwrap();
981        assert_eq!(back, value);
982    }
983
984    #[diesel_test_helper::test]
985    fn test_read_jsonb_int_decodes_the_whole_representable_range() {
986        for (payload, expected) in [
987            (&b"0"[..], json!(0)),
988            (&b"1"[..], json!(1)),
989            (&b"-1"[..], json!(-1)),
990            // sqlite stores `-0` as an integer and `json_extract` reads it as one
991            (&b"-0"[..], json!(0)),
992            (&b"9223372036854775807"[..], json!(i64::MAX)),
993            (&b"-9223372036854775808"[..], json!(i64::MIN)),
994            (&b"9223372036854775808"[..], json!(1u64 << 63)),
995            (&b"18446744073709551615"[..], json!(u64::MAX)),
996        ] {
997            let mut data = create_jsonb_header(JSONB_INT, payload.len()).unwrap();
998            data.extend_from_slice(payload);
999
1000            let payload = core::str::from_utf8(payload).unwrap();
1001            assert_eq!(
1002                read_jsonb_value(&data).unwrap().0,
1003                expected,
1004                "{payload} did not decode to itself"
1005            );
1006        }
1007    }
1008
1009    #[diesel_test_helper::test]
1010    #[cfg(not(miri))] // ffi call
1011    fn regression_every_char_is_written_valid() {
1012        let conn = &mut connection();
1013        let mut offenders = Vec::new();
1014        // batch scalars into arrays so one query covers a chunk, then walk only a failing chunk
1015        let mut chunk = Vec::new();
1016        for code in 0u32..=0x10FFFF {
1017            if let Some(c) = char::from_u32(code) {
1018                let mut s = alloc::string::String::from('a');
1019                s.push(c);
1020                s.push('b');
1021                chunk.push(json!(s));
1022            }
1023            if chunk.len() < 2048 && code != 0x10FFFF {
1024                continue;
1025            }
1026            let batch = Value::Array(core::mem::take(&mut chunk));
1027            if let Err(batch_error) = jsonb_survives(conn, &batch) {
1028                let Value::Array(values) = batch else {
1029                    unreachable!()
1030                };
1031                let known = offenders.len();
1032                for value in values {
1033                    if let Err(e) = jsonb_survives(conn, &value) {
1034                        offenders.push(e);
1035                    }
1036                }
1037                // a batch no element explains means the array header itself is wrong, so keep it
1038                if offenders.len() == known {
1039                    offenders.push(batch_error);
1040                }
1041            }
1042        }
1043        assert!(
1044            offenders.is_empty(),
1045            "{} values broke the blob, first {:?}",
1046            offenders.len(),
1047            &offenders[..offenders.len().min(4)]
1048        );
1049    }
1050
1051    #[diesel_test_helper::test]
1052    fn test_read_jsonb_int_rejects_non_integer_payloads() {
1053        for payload in [
1054            // fractions and exponents belong to a FLOAT element
1055            &b"1.5"[..],
1056            &b"1e5"[..],
1057            // parses as neither an integer nor a finite float
1058            &b"1e999"[..],
1059            // not canonical JSON integer text
1060            &b"+1"[..],
1061            &b"01"[..],
1062            &b""[..],
1063            &b"-"[..],
1064            &b"0x10"[..],
1065            &b"nan"[..],
1066            &b"Infinity"[..],
1067        ] {
1068            let mut data = create_jsonb_header(JSONB_INT, payload.len()).unwrap();
1069            data.extend_from_slice(payload);
1070
1071            let payload = core::str::from_utf8(payload).unwrap();
1072            assert!(
1073                read_jsonb_value(&data).is_err(),
1074                "{payload} is not a JSONB integer"
1075            );
1076        }
1077    }
1078
1079    #[diesel_test_helper::test]
1080    fn test_read_jsonb_int_decodes_a_wide_integer_exactly_or_not_at_all() {
1081        // `Number::from_u128` succeeds only when `serde_json` can hold the value
1082        // exactly, which depends on its `arbitrary_precision` feature, and any
1083        // dependency can enable that.
1084        for payload in [
1085            &b"18446744073709551616"[..],
1086            &b"123456789012345678901234567890"[..],
1087        ] {
1088            let mut data = create_jsonb_header(JSONB_INT, payload.len()).unwrap();
1089            data.extend_from_slice(payload);
1090
1091            let payload = core::str::from_utf8(payload).unwrap();
1092            let exact = serde_json::Number::from_u128(payload.parse().unwrap()).map(Value::Number);
1093            let decoded = read_jsonb_value(&data);
1094
1095            match exact {
1096                Some(expected) => assert_eq!(
1097                    decoded.unwrap().0,
1098                    expected,
1099                    "{payload} is representable and must decode"
1100                ),
1101                None => assert!(decoded.is_err(), "{payload} would decode rounded"),
1102            }
1103        }
1104    }
1105
1106    #[diesel_test_helper::test]
1107    fn test_read_jsonb_int_above_i64_max_inside_containers() {
1108        let mut element = create_jsonb_header(JSONB_INT, 20).unwrap();
1109        element.extend_from_slice(b"18446744073709551615");
1110
1111        let mut array = create_jsonb_header(JSONB_ARRAY, element.len()).unwrap();
1112        array.extend_from_slice(&element);
1113        assert_eq!(read_jsonb_value(&array).unwrap().0, json!([u64::MAX]));
1114
1115        let mut key = create_jsonb_header(JSONB_TEXT, 1).unwrap();
1116        key.extend_from_slice(b"a");
1117        let mut object = create_jsonb_header(JSONB_OBJECT, key.len() + element.len()).unwrap();
1118        object.extend_from_slice(&key);
1119        object.extend_from_slice(&element);
1120        assert_eq!(read_jsonb_value(&object).unwrap().0, json!({"a": u64::MAX}));
1121    }
1122
1123    #[diesel_test_helper::test]
1124    #[cfg(not(miri))] // ffi call
1125    fn regression_unsigned_above_i64_reads_a_blob_sqlite_wrote() {
1126        let conn = &mut connection();
1127
1128        let back = diesel::select(sql::<Jsonb>("jsonb('18446744073709551615')"))
1129            .get_result::<Value>(conn)
1130            .unwrap();
1131
1132        assert_eq!(back, json!(u64::MAX));
1133    }
1134
1135    #[diesel_test_helper::test]
1136    #[cfg(not(miri))] // ffi call
1137    fn regression_negative_zero_reads_a_blob_sqlite_wrote() {
1138        let conn = &mut connection();
1139
1140        let back = diesel::select(sql::<Jsonb>("jsonb('-0')"))
1141            .get_result::<Value>(conn)
1142            .unwrap();
1143
1144        assert_eq!(back, json!(0));
1145    }
1146
1147    #[diesel_test_helper::test]
1148    #[cfg(not(miri))] // ffi call
1149    fn json_to_sql() {
1150        let conn = &mut connection();
1151        let res = diesel::select(json!(true).into_sql::<Json>().eq(&sql("json('true')")))
1152            .get_result::<bool>(conn)
1153            .unwrap();
1154        assert!(res);
1155    }
1156
1157    #[diesel_test_helper::test]
1158    fn test_read_jsonb_null() {
1159        let data = vec![JSONB_NULL];
1160        let result = read_jsonb_value(&data).unwrap().0;
1161        assert_eq!(result, Value::Null);
1162    }
1163
1164    #[diesel_test_helper::test]
1165    fn test_read_jsonb_true() {
1166        let data = vec![JSONB_TRUE];
1167        let result = read_jsonb_value(&data).unwrap().0;
1168        assert_eq!(result, Value::Bool(true));
1169    }
1170
1171    #[diesel_test_helper::test]
1172    fn test_read_jsonb_false() {
1173        let data = vec![JSONB_FALSE];
1174        let result = read_jsonb_value(&data).unwrap().0;
1175        assert_eq!(result, Value::Bool(false));
1176    }
1177
1178    #[diesel_test_helper::test]
1179    fn test_read_jsonb_int() {
1180        // JSONB_INT with payload "1"
1181        let mut data = Vec::new();
1182        data.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap());
1183        data.push(b'1'); // Add the payload (integer "1")
1184
1185        let result = read_jsonb_value(&data).unwrap().0;
1186        assert_eq!(result, json!(1));
1187    }
1188
1189    #[diesel_test_helper::test]
1190    fn test_read_jsonb_float() {
1191        // JSONB_FLOAT with payload "1.5"
1192        let mut data = Vec::new();
1193        data.extend(create_jsonb_header(JSONB_FLOAT, 0x03).unwrap());
1194        data.extend_from_slice(b"1.5"); // Add the payload (float "1.5")
1195
1196        let result = read_jsonb_value(&data).unwrap().0;
1197        assert_eq!(result, json!(1.5));
1198    }
1199
1200    #[diesel_test_helper::test]
1201    fn test_read_jsonb_text() {
1202        // JSONB_TEXT with payload "foo"
1203        let mut data = Vec::new();
1204        data.extend(create_jsonb_header(JSONB_TEXT, 0x03).unwrap());
1205        data.extend_from_slice(b"foo"); // Add the payload (text "foo")
1206
1207        let result = read_jsonb_value(&data).unwrap().0;
1208        assert_eq!(result, json!("foo"));
1209    }
1210
1211    #[diesel_test_helper::test]
1212    fn test_read_jsonb_textraw() {
1213        // JSONB_TEXTRAW with payload "foo"
1214        let mut data = Vec::new();
1215        data.extend(create_jsonb_header(JSONB_TEXTRAW, 0x03).unwrap());
1216        data.extend_from_slice(b"foo");
1217
1218        let result = read_jsonb_value(&data).unwrap().0;
1219        assert_eq!(result, json!("foo"));
1220    }
1221
1222    #[diesel_test_helper::test]
1223    fn test_read_jsonb_object_with_textraw_key() {
1224        // JSONB_OBJECT with a TEXTRAW key and value
1225        let mut data = Vec::new();
1226        data.extend(create_jsonb_header(JSONB_OBJECT, 0x06).unwrap());
1227        data.extend(create_jsonb_header(JSONB_TEXTRAW, 0x01).unwrap());
1228        data.extend_from_slice(b"a");
1229        data.extend(create_jsonb_header(JSONB_TEXTRAW, 0x03).unwrap());
1230        data.extend_from_slice(b"bar");
1231
1232        let result = read_jsonb_value(&data).unwrap().0;
1233        assert_eq!(result, json!({"a": "bar"}));
1234    }
1235
1236    #[diesel_test_helper::test]
1237    fn test_read_jsonb_array() {
1238        // JSONB_ARRAY with two elements: 1 and true
1239        let mut data = Vec::new();
1240        data.extend(create_jsonb_header(JSONB_ARRAY, 0x03).unwrap()); // Array header
1241
1242        // Element 1: integer "1"
1243        data.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap());
1244        data.push(b'1');
1245
1246        // Element 2: true
1247        data.extend(create_jsonb_header(JSONB_TRUE, 0x00).unwrap());
1248
1249        let result = read_jsonb_value(&data).unwrap().0;
1250        assert_eq!(result, json!([1, true]));
1251    }
1252
1253    #[diesel_test_helper::test]
1254    fn test_read_jsonb_object() {
1255        // JSONB_OBJECT with one key-value pair: "key": 42
1256        let mut data = Vec::new();
1257        data.extend(create_jsonb_header(JSONB_OBJECT, 0x07).unwrap()); // Object header
1258
1259        // Key: "key"
1260        data.extend(create_jsonb_header(JSONB_TEXT, 0x03).unwrap());
1261        data.extend_from_slice(b"key"); // Add the key payload
1262
1263        // Value: 42 (integer)
1264        data.extend(create_jsonb_header(JSONB_INT, 0x02).unwrap());
1265        data.extend_from_slice(b"42"); // Add the integer payload
1266
1267        let result = read_jsonb_value(&data).unwrap().0;
1268        assert_eq!(result, json!({"key": 42}));
1269    }
1270
1271    #[diesel_test_helper::test]
1272    fn test_read_jsonb_nested_object() {
1273        let mut data = Vec::new();
1274
1275        data.extend(create_jsonb_header(JSONB_OBJECT, 42).unwrap());
1276
1277        data.extend(create_jsonb_header(JSONB_TEXT, 9).unwrap());
1278        data.extend_from_slice(b"outer_key");
1279
1280        data.extend(create_jsonb_header(JSONB_OBJECT, 13).unwrap());
1281
1282        data.extend(create_jsonb_header(JSONB_TEXT, 9).unwrap());
1283        data.extend_from_slice(b"inner_key");
1284
1285        data.extend(create_jsonb_header(JSONB_INT, 2).unwrap());
1286        data.extend_from_slice(b"42");
1287
1288        data.extend(create_jsonb_header(JSONB_TEXT, 14).unwrap());
1289        data.extend_from_slice(b"additional_key");
1290
1291        data.extend(create_jsonb_header(JSONB_TRUE, 0).unwrap());
1292
1293        let result = read_jsonb_value(&data).unwrap().0;
1294        assert_eq!(
1295            result,
1296            json!({
1297                "additional_key": true,
1298                "outer_key": {
1299                    "inner_key": 42
1300                },
1301            })
1302        );
1303    }
1304
1305    #[diesel_test_helper::test]
1306    fn test_write_jsonb_null() {
1307        let value = serde_json::Value::Null;
1308        let mut buffer = Vec::new();
1309        write_jsonb_value(&value, &mut buffer).unwrap();
1310        assert_eq!(buffer, vec![JSONB_NULL]);
1311    }
1312
1313    #[diesel_test_helper::test]
1314    fn test_write_jsonb_true() {
1315        let value = serde_json::Value::Bool(true);
1316        let mut buffer = Vec::new();
1317        write_jsonb_value(&value, &mut buffer).unwrap();
1318        assert_eq!(buffer, vec![JSONB_TRUE]);
1319    }
1320
1321    #[diesel_test_helper::test]
1322    fn test_write_jsonb_false() {
1323        let value = serde_json::Value::Bool(false);
1324        let mut buffer = Vec::new();
1325        write_jsonb_value(&value, &mut buffer).unwrap();
1326        assert_eq!(buffer, vec![JSONB_FALSE]);
1327    }
1328
1329    #[diesel_test_helper::test]
1330    fn test_write_jsonb_int() {
1331        let value = serde_json::Value::Number(serde_json::Number::from(1));
1332        let mut buffer = Vec::new();
1333        write_jsonb_value(&value, &mut buffer).unwrap();
1334
1335        let mut expected_buffer = Vec::new();
1336        expected_buffer.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap());
1337        expected_buffer.push(b'1'); // Payload: integer "1"
1338
1339        assert_eq!(buffer, expected_buffer);
1340    }
1341
1342    #[diesel_test_helper::test]
1343    fn test_write_jsonb_float() {
1344        let value = serde_json::Value::Number(serde_json::Number::from_f64(1.5).unwrap());
1345        let mut buffer = Vec::new();
1346        write_jsonb_value(&value, &mut buffer).unwrap();
1347
1348        let mut expected_buffer = Vec::new();
1349        expected_buffer.extend(create_jsonb_header(JSONB_FLOAT, 0x03).unwrap());
1350        expected_buffer.extend_from_slice(b"1.5"); // Payload: float "1.5"
1351
1352        assert_eq!(buffer, expected_buffer);
1353    }
1354
1355    #[diesel_test_helper::test]
1356    fn test_write_jsonb_text() {
1357        let mut buffer = Vec::new();
1358        let input_string = "hello";
1359        write_jsonb_string(input_string, &mut buffer).unwrap();
1360
1361        let mut expected_buffer = Vec::new();
1362        expected_buffer.extend(create_jsonb_header(JSONB_TEXT, 0x05).unwrap());
1363        expected_buffer.extend_from_slice(b"hello");
1364
1365        assert_eq!(buffer, expected_buffer);
1366    }
1367
1368    #[diesel_test_helper::test]
1369    fn test_write_jsonb_textj() {
1370        let mut buffer = Vec::new();
1371        let input_string = "hello\nworld"; // Contains a newline, requires escaping
1372        write_jsonb_string(input_string, &mut buffer).unwrap();
1373
1374        let mut expected_buffer = Vec::new();
1375        expected_buffer.extend(create_jsonb_header(JSONB_TEXTJ, 12).unwrap());
1376        expected_buffer.extend_from_slice(b"hello\\nworld");
1377
1378        assert_eq!(buffer, expected_buffer);
1379    }
1380
1381    #[diesel_test_helper::test]
1382    fn test_write_jsonb_textj_quote_and_backslash() {
1383        let mut buffer = Vec::new();
1384        let input_string = r#"a"b\c"#;
1385        write_jsonb_string(input_string, &mut buffer).unwrap();
1386
1387        let mut expected_buffer = Vec::new();
1388        expected_buffer.extend(create_jsonb_header(JSONB_TEXTJ, 7).unwrap());
1389        expected_buffer.extend_from_slice(br#"a\"b\\c"#);
1390
1391        assert_eq!(buffer, expected_buffer);
1392    }
1393
1394    #[diesel_test_helper::test]
1395    fn test_write_jsonb_text_keeps_high_control_free_text() {
1396        // U+007F is a control character json never escapes, so it stays plain TEXT
1397        let mut buffer = Vec::new();
1398        write_jsonb_string("a\u{7f}b", &mut buffer).unwrap();
1399
1400        let mut expected_buffer = Vec::new();
1401        expected_buffer.extend(create_jsonb_header(JSONB_TEXT, 3).unwrap());
1402        expected_buffer.extend_from_slice("a\u{7f}b".as_bytes());
1403
1404        assert_eq!(buffer, expected_buffer);
1405    }
1406
1407    #[diesel_test_helper::test]
1408    fn test_write_jsonb_array() {
1409        let value = json!([1, true]);
1410        let mut buffer = Vec::new();
1411        write_jsonb_value(&value, &mut buffer).unwrap();
1412
1413        let mut expected_buffer = Vec::new();
1414        expected_buffer.extend(create_jsonb_header(JSONB_ARRAY, 0x03).unwrap()); // Array header
1415        expected_buffer.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap()); // Integer header
1416        expected_buffer.push(b'1'); // Integer payload "1"
1417        expected_buffer.extend(create_jsonb_header(JSONB_TRUE, 0x00).unwrap()); // Boolean header for "true"
1418
1419        assert_eq!(buffer, expected_buffer);
1420    }
1421
1422    #[diesel_test_helper::test]
1423    fn test_write_jsonb_object() {
1424        let value = json!({"key": 42});
1425        let mut buffer = Vec::new();
1426        write_jsonb_value(&value, &mut buffer).unwrap();
1427
1428        let mut expected = Vec::new();
1429        expected.extend(create_jsonb_header(JSONB_OBJECT, 7).unwrap());
1430        expected.extend(create_jsonb_header(JSONB_TEXT, 3).unwrap());
1431        expected.extend_from_slice(b"key");
1432        expected.extend(create_jsonb_header(JSONB_INT, 2).unwrap());
1433        expected.extend_from_slice(b"42");
1434
1435        assert_eq!(buffer, expected,);
1436    }
1437
1438    #[diesel_test_helper::test]
1439    #[cfg(not(miri))] // ffi call
1440    fn jsonb_to_sql_bool() {
1441        let conn = &mut connection();
1442        let res = diesel::select(json!(true).into_sql::<Jsonb>().eq(&sql("jsonb('true')")))
1443            .get_result::<bool>(conn)
1444            .unwrap();
1445        assert!(res);
1446    }
1447
1448    #[diesel_test_helper::test]
1449    #[cfg(not(miri))] // ffi call
1450    fn jsonb_to_sql_null() {
1451        let conn = &mut connection();
1452        let res = diesel::select(json!(null).into_sql::<Jsonb>().eq(&sql("jsonb('null')")))
1453            .get_result::<bool>(conn)
1454            .unwrap();
1455        assert!(res);
1456    }
1457
1458    #[diesel_test_helper::test]
1459    #[cfg(not(miri))] // ffi call
1460    fn jsonb_to_sql_integer() {
1461        let conn = &mut connection();
1462        let res = diesel::select(json!(42).into_sql::<Jsonb>().eq(&sql("jsonb('42')")))
1463            .get_result::<bool>(conn)
1464            .unwrap();
1465        assert!(res);
1466    }
1467
1468    #[diesel_test_helper::test]
1469    #[cfg(not(miri))] // ffi call
1470    fn jsonb_to_sql_float() {
1471        let conn = &mut connection();
1472        let res = diesel::select(json!(42.23).into_sql::<Jsonb>().eq(&sql("jsonb('42.23')")))
1473            .get_result::<bool>(conn)
1474            .unwrap();
1475        assert!(res);
1476    }
1477
1478    #[diesel_test_helper::test]
1479    #[cfg(not(miri))] // ffi call
1480    fn jsonb_to_sql_text() {
1481        let conn = &mut connection();
1482
1483        // Test for TEXT (simple string)
1484        let res = diesel::select(
1485            json!("hello")
1486                .into_sql::<Jsonb>()
1487                .eq(&sql(r#"jsonb('"hello"')"#)),
1488        )
1489        .get_result::<bool>(conn)
1490        .unwrap();
1491
1492        assert!(res);
1493    }
1494
1495    #[diesel_test_helper::test]
1496    #[cfg(not(miri))] // ffi call
1497    fn jsonb_to_sql_textj() {
1498        let conn = &mut connection();
1499
1500        // Test for TEXTJ (JSON-escaped string, e.g., containing \n or \uXXXX)
1501        let res = diesel::select(
1502            json!("hello\nworld")
1503                .into_sql::<Jsonb>()
1504                .eq(&sql(r#"jsonb('"hello\nworld"')"#)), // The string is JSON-escaped
1505        )
1506        .get_result::<bool>(conn)
1507        .unwrap();
1508
1509        assert!(res);
1510    }
1511
1512    #[diesel_test_helper::test]
1513    #[cfg(not(miri))] // ffi call
1514    fn jsonb_to_sql_textj_quote_and_backslash() {
1515        let conn = &mut connection();
1516
1517        // a quote and a backslash are the other two characters sqlite writes as TEXTJ
1518        let res = diesel::select(
1519            json!(r#"a"b\c"#)
1520                .into_sql::<Jsonb>()
1521                .eq(&sql(r#"jsonb('"a\"b\\c"')"#)),
1522        )
1523        .get_result::<bool>(conn)
1524        .unwrap();
1525
1526        assert!(res);
1527    }
1528
1529    #[diesel_test_helper::test]
1530    #[cfg(not(miri))] // ffi call
1531    fn jsonb_to_sql_array() {
1532        let conn = &mut connection();
1533        let res = diesel::select(
1534            json!([1, true, "foo"])
1535                .into_sql::<Jsonb>()
1536                .eq(&sql(r#"jsonb('[1, true, "foo"]')"#)),
1537        )
1538        .get_result::<bool>(conn)
1539        .unwrap();
1540        assert!(res);
1541    }
1542
1543    #[diesel_test_helper::test]
1544    #[cfg(not(miri))] // ffi call
1545    fn jsonb_to_sql_object() {
1546        let conn = &mut connection();
1547        let res = diesel::select(
1548            json!({"key": "value"})
1549                .into_sql::<Jsonb>()
1550                .eq(&sql(r#"jsonb('{"key": "value"}')"#)),
1551        )
1552        .get_result::<bool>(conn)
1553        .unwrap();
1554        assert!(res);
1555    }
1556
1557    #[diesel_test_helper::test]
1558    #[cfg(not(miri))] // ffi call
1559    fn jsonb_to_sql_object_in_object() {
1560        let conn = &mut connection();
1561        let json_value = json!({
1562            "outer_key": {
1563                "additional_key": true,
1564                "inner_key": {
1565                    "nested_key": 42
1566                },
1567            }
1568        });
1569
1570        let res = diesel::select(json_value.into_sql::<Jsonb>().eq(&sql(
1571            r#"jsonb('{"outer_key": {"additional_key": true, "inner_key": {"nested_key": 42}}}')"#,
1572        )))
1573        .get_result::<bool>(conn)
1574        .unwrap();
1575        assert!(res);
1576    }
1577
1578    #[diesel_test_helper::test]
1579    #[cfg(not(miri))] // ffi call
1580    fn jsonb_to_sql_array_in_object() {
1581        let conn = &mut connection();
1582        let json_value = json!({
1583            "is_valid": false,
1584            "key": [1, 2, 3],
1585        });
1586        let res = diesel::select(
1587            json_value
1588                .into_sql::<Jsonb>()
1589                .eq(&sql(r#"jsonb('{"is_valid": false, "key": [1, 2, 3]}')"#)),
1590        )
1591        .get_result::<bool>(conn)
1592        .unwrap();
1593        assert!(res);
1594    }
1595
1596    #[diesel_test_helper::test]
1597    #[cfg(not(miri))] // ffi call
1598    fn jsonb_to_sql_object_in_array() {
1599        let conn = &mut connection();
1600        let json_value = json!([
1601            {
1602                "nested_key": "nested_value"
1603            },
1604            {
1605                "int_value": 99
1606            }
1607        ]);
1608        let res = diesel::select(json_value.into_sql::<Jsonb>().eq(&sql(
1609            r#"jsonb('[{"nested_key": "nested_value"}, {"int_value": 99}]')"#,
1610        )))
1611        .get_result::<bool>(conn)
1612        .unwrap();
1613        assert!(res);
1614    }
1615
1616    #[diesel_test_helper::test]
1617    #[cfg(not(miri))] // ffi call
1618    fn jsonb_from_sql_null() {
1619        let conn = &mut connection();
1620        let res = diesel::select(sql::<Jsonb>("jsonb('null')"))
1621            .get_result::<serde_json::Value>(conn)
1622            .unwrap();
1623        assert_eq!(res, serde_json::json!(null));
1624    }
1625
1626    #[diesel_test_helper::test]
1627    #[cfg(not(miri))] // ffi call
1628    fn jsonb_from_sql_true() {
1629        let conn = &mut connection();
1630        let res = diesel::select(sql::<Jsonb>("jsonb('true')"))
1631            .get_result::<serde_json::Value>(conn)
1632            .unwrap();
1633        assert_eq!(res, serde_json::json!(true));
1634    }
1635
1636    #[diesel_test_helper::test]
1637    #[cfg(not(miri))] // ffi call
1638    fn jsonb_from_sql_false() {
1639        let conn = &mut connection();
1640        let res = diesel::select(sql::<Jsonb>("jsonb('false')"))
1641            .get_result::<serde_json::Value>(conn)
1642            .unwrap();
1643        assert_eq!(res, serde_json::json!(false));
1644    }
1645
1646    #[diesel_test_helper::test]
1647    #[cfg(not(miri))] // ffi call
1648    fn jsonb_from_sql_int() {
1649        let conn = &mut connection();
1650        let res = diesel::select(sql::<Jsonb>("jsonb('42')"))
1651            .get_result::<serde_json::Value>(conn)
1652            .unwrap();
1653        assert_eq!(res, serde_json::json!(42));
1654    }
1655
1656    #[diesel_test_helper::test]
1657    #[cfg(not(miri))] // ffi call
1658    fn jsonb_from_sql_float() {
1659        let conn = &mut connection();
1660        let res = diesel::select(sql::<Jsonb>("jsonb('42.23')"))
1661            .get_result::<serde_json::Value>(conn)
1662            .unwrap();
1663        assert_eq!(res, serde_json::json!(42.23));
1664    }
1665
1666    #[diesel_test_helper::test]
1667    #[cfg(not(miri))] // ffi call
1668    fn jsonb_from_sql_object() {
1669        let conn = &mut connection();
1670        let res = diesel::select(sql::<Jsonb>(r#"jsonb('{"key": "value"}')"#))
1671            .get_result::<serde_json::Value>(conn)
1672            .unwrap();
1673        assert_eq!(res, serde_json::json!({"key": "value"}));
1674    }
1675
1676    #[diesel_test_helper::test]
1677    #[cfg(not(miri))] // ffi call
1678    fn jsonb_from_sql_array() {
1679        let conn = &mut connection();
1680        let res = diesel::select(sql::<Jsonb>("jsonb('[1, 2, 3]')"))
1681            .get_result::<serde_json::Value>(conn)
1682            .unwrap();
1683        assert_eq!(res, serde_json::json!([1, 2, 3]));
1684    }
1685
1686    #[diesel_test_helper::test]
1687    #[cfg(not(miri))] // ffi call
1688    fn jsonb_from_sql_nested_objects() {
1689        let conn = &mut connection();
1690        let res = diesel::select(sql::<Jsonb>(r#"jsonb('{"outer": {"inner": 42}}')"#))
1691            .get_result::<serde_json::Value>(conn)
1692            .unwrap();
1693        assert_eq!(res, serde_json::json!({"outer": {"inner": 42}}));
1694    }
1695
1696    #[diesel_test_helper::test]
1697    #[cfg(not(miri))] // ffi call
1698    fn jsonb_from_sql_nested_arrays() {
1699        let conn = &mut connection();
1700        let res = diesel::select(sql::<Jsonb>("jsonb('[[1, 2], [3, 4]]')"))
1701            .get_result::<serde_json::Value>(conn)
1702            .unwrap();
1703        assert_eq!(res, serde_json::json!([[1, 2], [3, 4]]));
1704    }
1705
1706    #[diesel_test_helper::test]
1707    #[cfg(not(miri))] // ffi call
1708    fn jsonb_from_sql_nested_arrays_in_objects() {
1709        let conn = &mut connection();
1710        let res = diesel::select(sql::<Jsonb>(r#"jsonb('{"array": [1, 2, 3]}')"#))
1711            .get_result::<serde_json::Value>(conn)
1712            .unwrap();
1713        assert_eq!(res, serde_json::json!({"array": [1, 2, 3]}));
1714    }
1715
1716    #[diesel_test_helper::test]
1717    #[cfg(not(miri))] // ffi call
1718    fn jsonb_from_sql_nested_objects_in_arrays() {
1719        let conn = &mut connection();
1720        let res = diesel::select(sql::<Jsonb>(
1721            r#"jsonb('[{"key1": "value1"}, {"key2": "value2"}]')"#,
1722        ))
1723        .get_result::<serde_json::Value>(conn)
1724        .unwrap();
1725        assert_eq!(
1726            res,
1727            serde_json::json!([{"key1": "value1"}, {"key2": "value2"}])
1728        );
1729    }
1730
1731    #[diesel_test_helper::test]
1732    #[cfg(not(miri))] // ffi call
1733    fn jsonb_from_sql_text() {
1734        let conn = &mut connection();
1735        let res = diesel::select(sql::<Jsonb>(r#"jsonb('"hello"')"#))
1736            .get_result::<serde_json::Value>(conn)
1737            .unwrap();
1738        assert_eq!(res, serde_json::json!("hello"));
1739    }
1740
1741    #[diesel_test_helper::test]
1742    #[cfg(not(miri))] // ffi call
1743    fn jsonb_from_sql_textj() {
1744        let conn = &mut connection();
1745        let res = diesel::select(sql::<Jsonb>(r#"jsonb('"hello\nworld"')"#))
1746            .get_result::<serde_json::Value>(conn)
1747            .unwrap();
1748        assert_eq!(res, serde_json::json!("hello\nworld"));
1749    }
1750
1751    #[diesel_test_helper::test]
1752    #[cfg(not(miri))] // ffi call
1753    fn bad_json_from_sql() {
1754        let conn = &mut connection();
1755        let res = diesel::select(json!(true).into_sql::<Json>().eq(&sql("json('boom')")))
1756            .get_result::<bool>(conn);
1757        assert_eq!(format_error(&res.unwrap_err()), "malformed JSON");
1758    }
1759
1760    #[diesel_test_helper::test]
1761    #[cfg(not(miri))] // ffi call
1762    fn bad_jsonb_from_sql() {
1763        let conn = &mut connection();
1764        let res = diesel::select(json!(true).into_sql::<Jsonb>().eq(&sql("jsonb('boom')")))
1765            .get_result::<bool>(conn);
1766        assert_eq!(format_error(&res.unwrap_err()), "malformed JSON");
1767    }
1768
1769    #[diesel_test_helper::test]
1770    fn no_json_from_sql() {
1771        let uuid: Result<serde_json::Value, _> = FromSql::<Json, Sqlite>::from_nullable_sql(None);
1772        assert_eq!(
1773            format_error(&*uuid.unwrap_err()),
1774            "Unexpected null for non-null column"
1775        );
1776    }
1777
1778    #[diesel_test_helper::test]
1779    fn no_jsonb_from_sql() {
1780        let uuid: Result<serde_json::Value, _> = FromSql::<Jsonb, Sqlite>::from_nullable_sql(None);
1781        assert_eq!(
1782            format_error(&*uuid.unwrap_err()),
1783            "Unexpected null for non-null column"
1784        );
1785    }
1786
1787    #[cfg(all(
1788        not(miri),
1789        not(all(target_family = "wasm", target_os = "unknown")),
1790        unix
1791    ))]
1792    const RECURSION_DEPTH: usize = 2000;
1793
1794    #[cfg(all(
1795        not(miri),
1796        any(windows, all(target_family = "wasm", target_os = "unknown"))
1797    ))]
1798    const RECURSION_DEPTH: usize = 1000;
1799
1800    #[cfg(any(
1801        miri,
1802        all(
1803            not(unix),
1804            not(windows),
1805            not(all(target_family = "wasm", target_os = "unknown"))
1806        )
1807    ))]
1808    const RECURSION_DEPTH: usize = 10;
1809
1810    #[diesel_test_helper::test]
1811    fn guard_against_stackoverflow_array() {
1812        let mut value = serde_json::Value::Number(42.into());
1813        for i in 0..RECURSION_DEPTH {
1814            value = serde_json::Value::Array(vec![value, serde_json::Value::Number(i.into())]);
1815        }
1816        // We compare the encoded buffer for both values here
1817        // as serde_json otherwise runs into stackoverflows itself
1818        let mut expected_buffer = Vec::new();
1819        write_jsonb_value(&value, &mut expected_buffer).unwrap();
1820        let res = read_jsonb_value(&expected_buffer).unwrap().0;
1821
1822        let mut buffer = Vec::new();
1823        write_jsonb_value(&res, &mut buffer).unwrap();
1824        assert_eq!(expected_buffer, buffer);
1825    }
1826
1827    #[diesel_test_helper::test]
1828    fn guard_against_stackoverflow_object() {
1829        let mut value = serde_json::Value::Number(42.into());
1830        for i in 0..RECURSION_DEPTH {
1831            let mut map = serde_json::Map::new();
1832            map.insert(format!("key_{i}"), value);
1833            value = serde_json::Value::Object(map);
1834        }
1835
1836        // We compare the encoded buffer for both values here
1837        // as serde_json otherwise runs into stackoverflows itself
1838        let mut expected_buffer = Vec::new();
1839        write_jsonb_value(&value, &mut expected_buffer).unwrap();
1840
1841        let res = read_jsonb_value(&expected_buffer).unwrap().0;
1842
1843        let mut buffer = Vec::new();
1844        write_jsonb_value(&res, &mut buffer).unwrap();
1845        assert_eq!(expected_buffer, buffer);
1846    }
1847
1848    #[diesel_test_helper::test]
1849    fn guard_against_stackoverflow_mixed() {
1850        // otherwise miri is too slow
1851        #[cfg(not(miri))]
1852        const SIZE: usize = 2000;
1853        #[cfg(miri)]
1854        const SIZE: usize = 20;
1855
1856        let mut value = serde_json::Value::Number(42.into());
1857        for i in 0_usize..SIZE {
1858            if i.is_multiple_of(2) {
1859                let mut map = serde_json::Map::new();
1860                map.insert(format!("key_{i}"), value);
1861                value = serde_json::Value::Object(map);
1862            } else {
1863                value = serde_json::Value::Array(vec![value]);
1864            }
1865        }
1866        // We compare the encoded buffer for both values here
1867        // as serde_json otherwise runs into stackoverflows itself
1868        let mut expected_buffer = Vec::new();
1869        write_jsonb_value(&value, &mut expected_buffer).unwrap();
1870        let res = read_jsonb_value(&expected_buffer).unwrap().0;
1871        let mut buffer = Vec::new();
1872        write_jsonb_value(&res, &mut buffer).unwrap();
1873        assert_eq!(expected_buffer, buffer);
1874    }
1875
1876    #[diesel_test_helper::test]
1877    #[cfg(not(miri))] // ffi call
1878    fn dangling_bytes_result_in_error() {
1879        let mut value = Vec::<u8>::new();
1880        value.extend(create_jsonb_header(JSONB_INT, 1).unwrap());
1881        value.push(b'1');
1882        value.push(42);
1883        assert_eq!(value.len(), 3);
1884        let conn = &mut connection();
1885        let res = diesel::select(
1886            crate::dsl::sql::<sql_types::Jsonb>("jsonb(?)").bind::<sql_types::Binary, _>(value),
1887        )
1888        .get_result::<serde_json::Value>(conn);
1889        assert!(res.is_err(), "{:?}", res.unwrap());
1890    }
1891
1892    #[diesel_test_helper::test]
1893    fn object_key_without_value_results_in_error() {
1894        let mut value = Vec::new();
1895        value.extend(create_jsonb_header(JSONB_OBJECT, 2).unwrap());
1896        value.extend(create_jsonb_header(JSONB_TEXT, 1).unwrap());
1897        value.push(b'a');
1898        let res = read_jsonb_value(&value);
1899        assert!(res.is_err(), "{:?}", res.unwrap());
1900    }
1901
1902    #[diesel_test_helper::test]
1903    fn check_invalid_size_header() {
1904        // 9-byte JSONB blob: first byte 0xFB (size_hint nibble = 0x0F),
1905        // bytes 1..9 = 0xFF -> encoded payload length = u64::MAX.
1906        let res = read_jsonb_value(&[0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
1907        assert!(res.is_err());
1908    }
1909
1910    #[diesel_test_helper::test]
1911    fn nested_container_cannot_cross_parent_boundary() {
1912        let res = read_jsonb_value(&[0x3B, 0x1B, 0x1B, JSONB_NULL]);
1913        assert!(res.is_err(), "{:?}", res.unwrap());
1914    }
1915
1916    #[diesel_test_helper::test]
1917    fn check_signed_integer() {
1918        let mut buf = Vec::new();
1919        write_jsonb_value(&json!(-42), &mut buf).unwrap();
1920        let mut expected = create_jsonb_header(JSONB_INT, 3).unwrap();
1921        expected.extend(b"-42");
1922        assert_eq!(buf, expected);
1923    }
1924}