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    #[cfg(not(miri))] // ffi call
649    use crate::{IntoSql, dsl::sql};
650    use serde_json::{Value, json};
651    use sql_types::{Json, Jsonb};
652
653    // Helper function to create the correct JsonbHeader based on the payload size
654    pub(super) fn create_jsonb_header(
655        element_type: u8,
656        payload_size: usize,
657    ) -> Result<Vec<u8>, Box<dyn core::error::Error + Send + Sync>> {
658        let mut buffer = Vec::new();
659        jsonb::write_jsonb_header(&mut buffer, element_type, payload_size)?;
660        Ok(buffer)
661    }
662
663    fn value_with_payload(element_type: u8, payload: &[u8]) -> Vec<u8> {
664        let mut buffer = create_jsonb_header(element_type, payload.len()).unwrap();
665        buffer.extend_from_slice(payload);
666        buffer
667    }
668
669    #[diesel_test_helper::test]
670    fn regression_a_constant_reads_its_declared_size() {
671        let blobs: Vec<Vec<u8>> = vec![
672            value_with_payload(JSONB_NULL, &[0x0D, 0x00, 0xF3]), // null, inline size 3
673            value_with_payload(JSONB_TRUE, b"1.5"),              // true, inline size 3
674            value_with_payload(JSONB_NULL, &[0x00]),             // null, inline size 1
675            value_with_payload(JSONB_TRUE, &[0x08]),             // true, inline size 1
676            value_with_payload(JSONB_FALSE, &[0xFF]),            // false, inline size 1
677            // not buildable with create_jsonb_header because the writer takes the narrowest size spelling
678            vec![0xC0, 0x00], // null, two byte header
679            vec![0xC1, 0x00], // true, two byte header
680            {
681                // array holding a two byte true
682                let mut blob = create_jsonb_header(JSONB_ARRAY, 2).unwrap();
683                blob.extend_from_slice(&[0xC1, 0x00]);
684                blob
685            },
686            {
687                // object holding one
688                let mut blob = create_jsonb_header(JSONB_OBJECT, 4).unwrap();
689                blob.extend(create_jsonb_header(JSONB_TEXT, 1).unwrap());
690                blob.extend_from_slice(b"a");
691                blob.extend_from_slice(&[0xC1, 0x00]);
692                blob
693            },
694        ];
695        for blob in blobs {
696            let blob: &[u8] = &blob;
697            assert!(
698                read_jsonb_value(blob).is_err(),
699                "{blob:02X?} decoded to {:?}",
700                read_jsonb_value(blob).map(|value| value.0)
701            );
702        }
703
704        // the one byte spelling sqlite writes
705        let mut blob = create_jsonb_header(JSONB_ARRAY, 2).unwrap();
706        blob.extend(create_jsonb_header(JSONB_TRUE, 0).unwrap());
707        blob.extend(create_jsonb_header(JSONB_NULL, 0).unwrap());
708        assert_eq!(read_jsonb_value(&blob).unwrap().0, json!([true, null]));
709    }
710
711    #[diesel_test_helper::test]
712    #[cfg(not(miri))] // ffi call
713    fn regression_json_text_float_survives_a_round_trip() {
714        let conn = &mut connection();
715        for float in [
716            8.829872855928286e-308f64,
717            -0.20221894534048165,
718            1.7383394626966921e-307,
719            6.178787134922198e305,
720        ] {
721            let value = json!(float);
722            let text = diesel::select(sql::<sql_types::Text>("").bind::<sql_types::Json, _>(value))
723                .get_result::<String>(conn)
724                .unwrap();
725            let back = diesel::select(sql::<sql_types::Json>("").bind::<sql_types::Text, _>(text))
726                .get_result::<Value>(conn)
727                .unwrap();
728            assert_eq!(back.as_f64().map(f64::to_bits), Some(float.to_bits()));
729        }
730    }
731
732    #[diesel_test_helper::test]
733    #[cfg(not(miri))] // ffi call
734    fn regression_float_keeps_its_bits_through_the_writers_text() {
735        let conn = &mut connection();
736        let mut assert_roundtrip = |value: Value| {
737            let expected = value.as_f64().unwrap();
738            let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value))
739                .get_result::<Vec<u8>>(conn)
740                .unwrap();
741            let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob))
742                .get_result::<Value>(conn)
743                .unwrap();
744            assert_eq!(
745                back.as_f64().unwrap().to_bits(),
746                expected.to_bits(),
747                "{expected:?} came back as {back}"
748            );
749        };
750
751        // parsed from text, so `serde_json` chose the double
752        assert_roundtrip(serde_json::from_str("-922333372720360.5975808").unwrap());
753
754        for f in [
755            // these drift without `float_roundtrip`
756            -0.20221894534048165,
757            6.178787134922198e305,
758            -5.276099561814224e214,
759            3.587959730897931e-246,
760            9.136353238902674e-45,
761            2.4261860608815182e-160,
762            -2.5496151068102186e-175,
763            5.0513463356317975e-231,
764            // exact already, must stay exact
765            0.1,
766            1e-7,
767            5e-324,
768            -0.0,
769            f64::MAX,
770            f64::MIN_POSITIVE,
771        ] {
772            assert_roundtrip(json!(f));
773        }
774    }
775
776    #[diesel_test_helper::test]
777    fn regression_every_float_text_reads_back_as_the_same_double() {
778        let mut drifted = Vec::new();
779        let mut check = |bits: u64| {
780            let f = f64::from_bits(bits);
781            if !f.is_finite() {
782                return;
783            }
784            let mut buffer = Vec::new();
785            write_jsonb_number(&json!(f), &mut buffer).unwrap();
786            let back = read_jsonb_value(&buffer).unwrap().0;
787            if back.as_f64().map(f64::to_bits) != Some(bits) {
788                drifted.push(alloc::format!("{bits:#018x} {f:?} -> {back}"));
789            }
790        };
791
792        for exponent in [0, 1, 2, 512, 1021, 1022, 1023, 1024, 1075, 2045, 2046] {
793            for mantissa in [0, 1, 2, 1 << 26, 1 << 51, (1 << 52) - 2, (1 << 52) - 1] {
794                for sign in [0, 1u64 << 63] {
795                    check(sign | (exponent << 52) | mantissa);
796                }
797            }
798        }
799
800        // the doubles either side of the text-parsed witness
801        let witness = serde_json::from_str::<Value>("-922333372720360.5975808")
802            .unwrap()
803            .as_f64()
804            .unwrap()
805            .to_bits();
806        for bits in witness - 2..=witness + 2 {
807            check(bits);
808        }
809
810        // deterministic bit-pattern sweep
811        let mut state: u64 = 0x2545F4914F6CDD1D;
812        for _ in 0..256 {
813            state ^= state << 13;
814            state ^= state >> 7;
815            state ^= state << 17;
816            check(state);
817        }
818
819        assert!(
820            drifted.is_empty(),
821            "{} floats drifted, first {:?}",
822            drifted.len(),
823            &drifted[..drifted.len().min(4)]
824        );
825    }
826
827    #[diesel_test_helper::test]
828    #[cfg(not(miri))] // ffi call
829    fn every_jsonb_number_is_written_valid_and_round_trips() {
830        let conn = &mut connection();
831
832        // `1 << 63` is `i64::MAX + 1`, `1e21` is where Rust switches to exponent
833        // notation, and an exponent without a fraction digit carries no `.`.
834        let numbers = [
835            (json!(0), JSONB_INT),
836            (json!(1), JSONB_INT),
837            (json!(-1), JSONB_INT),
838            (json!(-5), JSONB_INT),
839            (json!(u64::from(u32::MAX)), JSONB_INT),
840            (json!(i64::MAX), JSONB_INT),
841            (json!(i64::MIN), JSONB_INT),
842            (json!(1u64 << 63), JSONB_INT),
843            (json!(u64::MAX), JSONB_INT),
844            (json!(3.0), JSONB_FLOAT),
845            (json!(-0.0), JSONB_FLOAT),
846            (json!(-2.5), JSONB_FLOAT),
847            (json!(1e-7), JSONB_FLOAT),
848            (json!(1e300), JSONB_FLOAT),
849            (json!(-1e300), JSONB_FLOAT),
850            (json!(1.5e300), JSONB_FLOAT),
851            (json!(1e21), JSONB_FLOAT),
852            (json!(f64::MIN), JSONB_FLOAT),
853            (json!(f64::MAX), JSONB_FLOAT),
854            (json!(f64::MIN_POSITIVE), JSONB_FLOAT),
855        ];
856
857        for (value, element_type) in numbers {
858            let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value.clone()))
859                .get_result::<Vec<u8>>(conn)
860                .unwrap();
861            assert_eq!(
862                blob[0] & 0x0F,
863                element_type,
864                "{value} was written with the wrong element type: {blob:02X?}"
865            );
866            let valid = diesel::select(json_valid_with_flags::<sql_types::Binary, _, _>(
867                blob.as_slice(),
868                JsonValidFlag::JsonbStrict,
869            ))
870            .get_result::<bool>(conn)
871            .unwrap();
872            assert!(
873                valid,
874                "sqlite rejects the blob written for {value}: {blob:02X?}"
875            );
876            let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob.clone()))
877                .get_result::<Value>(conn)
878                .unwrap_or_else(|error| panic!("{value} does not read back: {error}"));
879            assert_eq!(back, value, "{blob:02X?}");
880        }
881    }
882
883    // asserts a written blob is well formed to sqlite and reads back unchanged
884    #[cfg(not(miri))] // ffi call
885    fn jsonb_survives(conn: &mut crate::SqliteConnection, value: &Value) -> Result<(), String> {
886        let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value.clone()))
887            .get_result::<Vec<u8>>(conn)
888            .unwrap();
889        let valid = diesel::select(json_valid_with_flags::<sql_types::Binary, _, _>(
890            blob.as_slice(),
891            JsonValidFlag::JsonbStrict,
892        ))
893        .get_result::<bool>(conn)
894        .unwrap();
895        let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob.clone()))
896            .get_result::<Value>(conn);
897        if !valid {
898            return Err(alloc::format!(
899                "sqlite calls {value} malformed as {blob:02X?}"
900            ));
901        }
902        match back {
903            Ok(ref back) if back == value => Ok(()),
904            Ok(back) => Err(alloc::format!("{value} came back as {back}")),
905            Err(e) => Err(alloc::format!("{value} came back as {e}")),
906        }
907    }
908
909    #[diesel_test_helper::test]
910    #[cfg(not(miri))] // ffi call
911    fn regression_string_needing_an_escape_is_written_valid() {
912        let conn = &mut connection();
913        for value in [
914            json!(r#"a"b"#),
915            json!(r#"a\b"#),
916            json!(r#"a"\b"#),
917            json!(r#"""#),
918            json!(r#"\"#),
919            json!(r#"\""#),
920            json!(r#""leading"#),
921            json!(r#"trailing""#),
922            json!(r#"aaaaaaaaaaaa"bbbbbbbbbbbb"#),
923            json!({ "k": r#"a"b"# }),
924            json!([r#"a\b"#]),
925            json!({ r#"a"b"#: 1 }),
926            json!(""),
927            json!("abc"),
928            json!("a\nb"),
929            json!("a\"\nb"),
930        ] {
931            jsonb_survives(conn, &value).unwrap_or_else(|e| panic!("{e}"));
932        }
933    }
934
935    #[diesel_test_helper::test]
936    fn test_write_jsonb_number_classifies_by_integer_text() {
937        // `serde_json` writes an exponent with a sign, so the payload is `1e+300`.
938        for (value, element_type, payload) in [
939            (json!(0), JSONB_INT, "0"),
940            (json!(-1), JSONB_INT, "-1"),
941            (json!(i64::MIN), JSONB_INT, "-9223372036854775808"),
942            (json!(u64::MAX), JSONB_INT, "18446744073709551615"),
943            (json!(3.0), JSONB_FLOAT, "3.0"),
944            (json!(-0.0), JSONB_FLOAT, "-0.0"),
945            (json!(-2.5), JSONB_FLOAT, "-2.5"),
946            (json!(1e-7), JSONB_FLOAT, "1e-7"),
947            (json!(1e300), JSONB_FLOAT, "1e+300"),
948        ] {
949            let mut buffer = Vec::new();
950            write_jsonb_value(&value, &mut buffer).unwrap();
951
952            let mut expected = create_jsonb_header(element_type, payload.len()).unwrap();
953            expected.extend_from_slice(payload.as_bytes());
954
955            assert_eq!(buffer, expected, "{value} was not written as {payload}");
956        }
957    }
958
959    #[diesel_test_helper::test]
960    #[cfg(not(miri))] // ffi call
961    fn numbers_nested_in_containers_are_written_valid() {
962        let conn = &mut connection();
963        let value = json!({"a": -1, "b": [-2, -2.5, 1e-7, 0, u64::MAX], "c": {"d": i64::MIN}});
964
965        let blob = diesel::select(sql::<sql_types::Binary>("").bind::<Jsonb, _>(value.clone()))
966            .get_result::<Vec<u8>>(conn)
967            .unwrap();
968        let valid = diesel::select(
969            sql::<sql_types::Integer>("json_valid(")
970                .bind::<sql_types::Binary, _>(blob.clone())
971                .sql(", 8)"),
972        )
973        .get_result::<i32>(conn)
974        .unwrap();
975        assert_eq!(valid, 1, "sqlite rejects {blob:02X?}");
976
977        let back = diesel::select(sql::<Jsonb>("").bind::<sql_types::Binary, _>(blob))
978            .get_result::<Value>(conn)
979            .unwrap();
980        assert_eq!(back, value);
981    }
982
983    #[diesel_test_helper::test]
984    fn test_read_jsonb_int_decodes_the_whole_representable_range() {
985        for (payload, expected) in [
986            (&b"0"[..], json!(0)),
987            (&b"1"[..], json!(1)),
988            (&b"-1"[..], json!(-1)),
989            // sqlite stores `-0` as an integer and `json_extract` reads it as one
990            (&b"-0"[..], json!(0)),
991            (&b"9223372036854775807"[..], json!(i64::MAX)),
992            (&b"-9223372036854775808"[..], json!(i64::MIN)),
993            (&b"9223372036854775808"[..], json!(1u64 << 63)),
994            (&b"18446744073709551615"[..], json!(u64::MAX)),
995        ] {
996            let mut data = create_jsonb_header(JSONB_INT, payload.len()).unwrap();
997            data.extend_from_slice(payload);
998
999            let payload = core::str::from_utf8(payload).unwrap();
1000            assert_eq!(
1001                read_jsonb_value(&data).unwrap().0,
1002                expected,
1003                "{payload} did not decode to itself"
1004            );
1005        }
1006    }
1007
1008    #[diesel_test_helper::test]
1009    #[cfg(not(miri))] // ffi call
1010    fn regression_every_char_is_written_valid() {
1011        let conn = &mut connection();
1012        let mut offenders = Vec::new();
1013        // batch scalars into arrays so one query covers a chunk, then walk only a failing chunk
1014        let mut chunk = Vec::new();
1015        for code in 0u32..=0x10FFFF {
1016            if let Some(c) = char::from_u32(code) {
1017                let mut s = alloc::string::String::from('a');
1018                s.push(c);
1019                s.push('b');
1020                chunk.push(json!(s));
1021            }
1022            if chunk.len() < 2048 && code != 0x10FFFF {
1023                continue;
1024            }
1025            let batch = Value::Array(core::mem::take(&mut chunk));
1026            if let Err(batch_error) = jsonb_survives(conn, &batch) {
1027                let Value::Array(values) = batch else {
1028                    unreachable!()
1029                };
1030                let known = offenders.len();
1031                for value in values {
1032                    if let Err(e) = jsonb_survives(conn, &value) {
1033                        offenders.push(e);
1034                    }
1035                }
1036                // a batch no element explains means the array header itself is wrong, so keep it
1037                if offenders.len() == known {
1038                    offenders.push(batch_error);
1039                }
1040            }
1041        }
1042        assert!(
1043            offenders.is_empty(),
1044            "{} values broke the blob, first {:?}",
1045            offenders.len(),
1046            &offenders[..offenders.len().min(4)]
1047        );
1048    }
1049
1050    #[diesel_test_helper::test]
1051    fn test_read_jsonb_int_rejects_non_integer_payloads() {
1052        for payload in [
1053            // fractions and exponents belong to a FLOAT element
1054            &b"1.5"[..],
1055            &b"1e5"[..],
1056            // parses as neither an integer nor a finite float
1057            &b"1e999"[..],
1058            // not canonical JSON integer text
1059            &b"+1"[..],
1060            &b"01"[..],
1061            &b""[..],
1062            &b"-"[..],
1063            &b"0x10"[..],
1064            &b"nan"[..],
1065            &b"Infinity"[..],
1066        ] {
1067            let mut data = create_jsonb_header(JSONB_INT, payload.len()).unwrap();
1068            data.extend_from_slice(payload);
1069
1070            let payload = core::str::from_utf8(payload).unwrap();
1071            assert!(
1072                read_jsonb_value(&data).is_err(),
1073                "{payload} is not a JSONB integer"
1074            );
1075        }
1076    }
1077
1078    #[diesel_test_helper::test]
1079    fn test_read_jsonb_int_decodes_a_wide_integer_exactly_or_not_at_all() {
1080        // `Number::from_u128` succeeds only when `serde_json` can hold the value
1081        // exactly, which depends on its `arbitrary_precision` feature, and any
1082        // dependency can enable that.
1083        for payload in [
1084            &b"18446744073709551616"[..],
1085            &b"123456789012345678901234567890"[..],
1086        ] {
1087            let mut data = create_jsonb_header(JSONB_INT, payload.len()).unwrap();
1088            data.extend_from_slice(payload);
1089
1090            let payload = core::str::from_utf8(payload).unwrap();
1091            let exact = serde_json::Number::from_u128(payload.parse().unwrap()).map(Value::Number);
1092            let decoded = read_jsonb_value(&data);
1093
1094            match exact {
1095                Some(expected) => assert_eq!(
1096                    decoded.unwrap().0,
1097                    expected,
1098                    "{payload} is representable and must decode"
1099                ),
1100                None => assert!(decoded.is_err(), "{payload} would decode rounded"),
1101            }
1102        }
1103    }
1104
1105    #[diesel_test_helper::test]
1106    fn test_read_jsonb_int_above_i64_max_inside_containers() {
1107        let mut element = create_jsonb_header(JSONB_INT, 20).unwrap();
1108        element.extend_from_slice(b"18446744073709551615");
1109
1110        let mut array = create_jsonb_header(JSONB_ARRAY, element.len()).unwrap();
1111        array.extend_from_slice(&element);
1112        assert_eq!(read_jsonb_value(&array).unwrap().0, json!([u64::MAX]));
1113
1114        let mut key = create_jsonb_header(JSONB_TEXT, 1).unwrap();
1115        key.extend_from_slice(b"a");
1116        let mut object = create_jsonb_header(JSONB_OBJECT, key.len() + element.len()).unwrap();
1117        object.extend_from_slice(&key);
1118        object.extend_from_slice(&element);
1119        assert_eq!(read_jsonb_value(&object).unwrap().0, json!({"a": u64::MAX}));
1120    }
1121
1122    #[diesel_test_helper::test]
1123    #[cfg(not(miri))] // ffi call
1124    fn regression_unsigned_above_i64_reads_a_blob_sqlite_wrote() {
1125        let conn = &mut connection();
1126
1127        let back = diesel::select(sql::<Jsonb>("jsonb('18446744073709551615')"))
1128            .get_result::<Value>(conn)
1129            .unwrap();
1130
1131        assert_eq!(back, json!(u64::MAX));
1132    }
1133
1134    #[diesel_test_helper::test]
1135    #[cfg(not(miri))] // ffi call
1136    fn regression_negative_zero_reads_a_blob_sqlite_wrote() {
1137        let conn = &mut connection();
1138
1139        let back = diesel::select(sql::<Jsonb>("jsonb('-0')"))
1140            .get_result::<Value>(conn)
1141            .unwrap();
1142
1143        assert_eq!(back, json!(0));
1144    }
1145
1146    #[diesel_test_helper::test]
1147    #[cfg(not(miri))] // ffi call
1148    fn json_to_sql() {
1149        let conn = &mut connection();
1150        let res = diesel::select(json!(true).into_sql::<Json>().eq(&sql("json('true')")))
1151            .get_result::<bool>(conn)
1152            .unwrap();
1153        assert!(res);
1154    }
1155
1156    #[diesel_test_helper::test]
1157    fn test_read_jsonb_null() {
1158        let data = vec![JSONB_NULL];
1159        let result = read_jsonb_value(&data).unwrap().0;
1160        assert_eq!(result, Value::Null);
1161    }
1162
1163    #[diesel_test_helper::test]
1164    fn test_read_jsonb_true() {
1165        let data = vec![JSONB_TRUE];
1166        let result = read_jsonb_value(&data).unwrap().0;
1167        assert_eq!(result, Value::Bool(true));
1168    }
1169
1170    #[diesel_test_helper::test]
1171    fn test_read_jsonb_false() {
1172        let data = vec![JSONB_FALSE];
1173        let result = read_jsonb_value(&data).unwrap().0;
1174        assert_eq!(result, Value::Bool(false));
1175    }
1176
1177    #[diesel_test_helper::test]
1178    fn test_read_jsonb_int() {
1179        // JSONB_INT with payload "1"
1180        let mut data = Vec::new();
1181        data.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap());
1182        data.push(b'1'); // Add the payload (integer "1")
1183
1184        let result = read_jsonb_value(&data).unwrap().0;
1185        assert_eq!(result, json!(1));
1186    }
1187
1188    #[diesel_test_helper::test]
1189    fn test_read_jsonb_float() {
1190        // JSONB_FLOAT with payload "1.5"
1191        let mut data = Vec::new();
1192        data.extend(create_jsonb_header(JSONB_FLOAT, 0x03).unwrap());
1193        data.extend_from_slice(b"1.5"); // Add the payload (float "1.5")
1194
1195        let result = read_jsonb_value(&data).unwrap().0;
1196        assert_eq!(result, json!(1.5));
1197    }
1198
1199    #[diesel_test_helper::test]
1200    fn test_read_jsonb_text() {
1201        // JSONB_TEXT with payload "foo"
1202        let mut data = Vec::new();
1203        data.extend(create_jsonb_header(JSONB_TEXT, 0x03).unwrap());
1204        data.extend_from_slice(b"foo"); // Add the payload (text "foo")
1205
1206        let result = read_jsonb_value(&data).unwrap().0;
1207        assert_eq!(result, json!("foo"));
1208    }
1209
1210    #[diesel_test_helper::test]
1211    fn test_read_jsonb_textraw() {
1212        // JSONB_TEXTRAW with payload "foo"
1213        let mut data = Vec::new();
1214        data.extend(create_jsonb_header(JSONB_TEXTRAW, 0x03).unwrap());
1215        data.extend_from_slice(b"foo");
1216
1217        let result = read_jsonb_value(&data).unwrap().0;
1218        assert_eq!(result, json!("foo"));
1219    }
1220
1221    #[diesel_test_helper::test]
1222    fn test_read_jsonb_object_with_textraw_key() {
1223        // JSONB_OBJECT with a TEXTRAW key and value
1224        let mut data = Vec::new();
1225        data.extend(create_jsonb_header(JSONB_OBJECT, 0x06).unwrap());
1226        data.extend(create_jsonb_header(JSONB_TEXTRAW, 0x01).unwrap());
1227        data.extend_from_slice(b"a");
1228        data.extend(create_jsonb_header(JSONB_TEXTRAW, 0x03).unwrap());
1229        data.extend_from_slice(b"bar");
1230
1231        let result = read_jsonb_value(&data).unwrap().0;
1232        assert_eq!(result, json!({"a": "bar"}));
1233    }
1234
1235    #[diesel_test_helper::test]
1236    fn test_read_jsonb_array() {
1237        // JSONB_ARRAY with two elements: 1 and true
1238        let mut data = Vec::new();
1239        data.extend(create_jsonb_header(JSONB_ARRAY, 0x03).unwrap()); // Array header
1240
1241        // Element 1: integer "1"
1242        data.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap());
1243        data.push(b'1');
1244
1245        // Element 2: true
1246        data.extend(create_jsonb_header(JSONB_TRUE, 0x00).unwrap());
1247
1248        let result = read_jsonb_value(&data).unwrap().0;
1249        assert_eq!(result, json!([1, true]));
1250    }
1251
1252    #[diesel_test_helper::test]
1253    fn test_read_jsonb_object() {
1254        // JSONB_OBJECT with one key-value pair: "key": 42
1255        let mut data = Vec::new();
1256        data.extend(create_jsonb_header(JSONB_OBJECT, 0x07).unwrap()); // Object header
1257
1258        // Key: "key"
1259        data.extend(create_jsonb_header(JSONB_TEXT, 0x03).unwrap());
1260        data.extend_from_slice(b"key"); // Add the key payload
1261
1262        // Value: 42 (integer)
1263        data.extend(create_jsonb_header(JSONB_INT, 0x02).unwrap());
1264        data.extend_from_slice(b"42"); // Add the integer payload
1265
1266        let result = read_jsonb_value(&data).unwrap().0;
1267        assert_eq!(result, json!({"key": 42}));
1268    }
1269
1270    #[diesel_test_helper::test]
1271    fn test_read_jsonb_nested_object() {
1272        let mut data = Vec::new();
1273
1274        data.extend(create_jsonb_header(JSONB_OBJECT, 42).unwrap());
1275
1276        data.extend(create_jsonb_header(JSONB_TEXT, 9).unwrap());
1277        data.extend_from_slice(b"outer_key");
1278
1279        data.extend(create_jsonb_header(JSONB_OBJECT, 13).unwrap());
1280
1281        data.extend(create_jsonb_header(JSONB_TEXT, 9).unwrap());
1282        data.extend_from_slice(b"inner_key");
1283
1284        data.extend(create_jsonb_header(JSONB_INT, 2).unwrap());
1285        data.extend_from_slice(b"42");
1286
1287        data.extend(create_jsonb_header(JSONB_TEXT, 14).unwrap());
1288        data.extend_from_slice(b"additional_key");
1289
1290        data.extend(create_jsonb_header(JSONB_TRUE, 0).unwrap());
1291
1292        let result = read_jsonb_value(&data).unwrap().0;
1293        assert_eq!(
1294            result,
1295            json!({
1296                "additional_key": true,
1297                "outer_key": {
1298                    "inner_key": 42
1299                },
1300            })
1301        );
1302    }
1303
1304    #[diesel_test_helper::test]
1305    fn test_write_jsonb_null() {
1306        let value = serde_json::Value::Null;
1307        let mut buffer = Vec::new();
1308        write_jsonb_value(&value, &mut buffer).unwrap();
1309        assert_eq!(buffer, vec![JSONB_NULL]);
1310    }
1311
1312    #[diesel_test_helper::test]
1313    fn test_write_jsonb_true() {
1314        let value = serde_json::Value::Bool(true);
1315        let mut buffer = Vec::new();
1316        write_jsonb_value(&value, &mut buffer).unwrap();
1317        assert_eq!(buffer, vec![JSONB_TRUE]);
1318    }
1319
1320    #[diesel_test_helper::test]
1321    fn test_write_jsonb_false() {
1322        let value = serde_json::Value::Bool(false);
1323        let mut buffer = Vec::new();
1324        write_jsonb_value(&value, &mut buffer).unwrap();
1325        assert_eq!(buffer, vec![JSONB_FALSE]);
1326    }
1327
1328    #[diesel_test_helper::test]
1329    fn test_write_jsonb_int() {
1330        let value = serde_json::Value::Number(serde_json::Number::from(1));
1331        let mut buffer = Vec::new();
1332        write_jsonb_value(&value, &mut buffer).unwrap();
1333
1334        let mut expected_buffer = Vec::new();
1335        expected_buffer.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap());
1336        expected_buffer.push(b'1'); // Payload: integer "1"
1337
1338        assert_eq!(buffer, expected_buffer);
1339    }
1340
1341    #[diesel_test_helper::test]
1342    fn test_write_jsonb_float() {
1343        let value = serde_json::Value::Number(serde_json::Number::from_f64(1.5).unwrap());
1344        let mut buffer = Vec::new();
1345        write_jsonb_value(&value, &mut buffer).unwrap();
1346
1347        let mut expected_buffer = Vec::new();
1348        expected_buffer.extend(create_jsonb_header(JSONB_FLOAT, 0x03).unwrap());
1349        expected_buffer.extend_from_slice(b"1.5"); // Payload: float "1.5"
1350
1351        assert_eq!(buffer, expected_buffer);
1352    }
1353
1354    #[diesel_test_helper::test]
1355    fn test_write_jsonb_text() {
1356        let mut buffer = Vec::new();
1357        let input_string = "hello";
1358        write_jsonb_string(input_string, &mut buffer).unwrap();
1359
1360        let mut expected_buffer = Vec::new();
1361        expected_buffer.extend(create_jsonb_header(JSONB_TEXT, 0x05).unwrap());
1362        expected_buffer.extend_from_slice(b"hello");
1363
1364        assert_eq!(buffer, expected_buffer);
1365    }
1366
1367    #[diesel_test_helper::test]
1368    fn test_write_jsonb_textj() {
1369        let mut buffer = Vec::new();
1370        let input_string = "hello\nworld"; // Contains a newline, requires escaping
1371        write_jsonb_string(input_string, &mut buffer).unwrap();
1372
1373        let mut expected_buffer = Vec::new();
1374        expected_buffer.extend(create_jsonb_header(JSONB_TEXTJ, 12).unwrap());
1375        expected_buffer.extend_from_slice(b"hello\\nworld");
1376
1377        assert_eq!(buffer, expected_buffer);
1378    }
1379
1380    #[diesel_test_helper::test]
1381    fn test_write_jsonb_textj_quote_and_backslash() {
1382        let mut buffer = Vec::new();
1383        let input_string = r#"a"b\c"#;
1384        write_jsonb_string(input_string, &mut buffer).unwrap();
1385
1386        let mut expected_buffer = Vec::new();
1387        expected_buffer.extend(create_jsonb_header(JSONB_TEXTJ, 7).unwrap());
1388        expected_buffer.extend_from_slice(br#"a\"b\\c"#);
1389
1390        assert_eq!(buffer, expected_buffer);
1391    }
1392
1393    #[diesel_test_helper::test]
1394    fn test_write_jsonb_text_keeps_high_control_free_text() {
1395        // U+007F is a control character json never escapes, so it stays plain TEXT
1396        let mut buffer = Vec::new();
1397        write_jsonb_string("a\u{7f}b", &mut buffer).unwrap();
1398
1399        let mut expected_buffer = Vec::new();
1400        expected_buffer.extend(create_jsonb_header(JSONB_TEXT, 3).unwrap());
1401        expected_buffer.extend_from_slice("a\u{7f}b".as_bytes());
1402
1403        assert_eq!(buffer, expected_buffer);
1404    }
1405
1406    #[diesel_test_helper::test]
1407    fn test_write_jsonb_array() {
1408        let value = json!([1, true]);
1409        let mut buffer = Vec::new();
1410        write_jsonb_value(&value, &mut buffer).unwrap();
1411
1412        let mut expected_buffer = Vec::new();
1413        expected_buffer.extend(create_jsonb_header(JSONB_ARRAY, 0x03).unwrap()); // Array header
1414        expected_buffer.extend(create_jsonb_header(JSONB_INT, 0x01).unwrap()); // Integer header
1415        expected_buffer.push(b'1'); // Integer payload "1"
1416        expected_buffer.extend(create_jsonb_header(JSONB_TRUE, 0x00).unwrap()); // Boolean header for "true"
1417
1418        assert_eq!(buffer, expected_buffer);
1419    }
1420
1421    #[diesel_test_helper::test]
1422    fn test_write_jsonb_object() {
1423        let value = json!({"key": 42});
1424        let mut buffer = Vec::new();
1425        write_jsonb_value(&value, &mut buffer).unwrap();
1426
1427        let mut expected = Vec::new();
1428        expected.extend(create_jsonb_header(JSONB_OBJECT, 7).unwrap());
1429        expected.extend(create_jsonb_header(JSONB_TEXT, 3).unwrap());
1430        expected.extend_from_slice(b"key");
1431        expected.extend(create_jsonb_header(JSONB_INT, 2).unwrap());
1432        expected.extend_from_slice(b"42");
1433
1434        assert_eq!(buffer, expected,);
1435    }
1436
1437    #[diesel_test_helper::test]
1438    #[cfg(not(miri))] // ffi call
1439    fn jsonb_to_sql_bool() {
1440        let conn = &mut connection();
1441        let res = diesel::select(json!(true).into_sql::<Jsonb>().eq(&sql("jsonb('true')")))
1442            .get_result::<bool>(conn)
1443            .unwrap();
1444        assert!(res);
1445    }
1446
1447    #[diesel_test_helper::test]
1448    #[cfg(not(miri))] // ffi call
1449    fn jsonb_to_sql_null() {
1450        let conn = &mut connection();
1451        let res = diesel::select(json!(null).into_sql::<Jsonb>().eq(&sql("jsonb('null')")))
1452            .get_result::<bool>(conn)
1453            .unwrap();
1454        assert!(res);
1455    }
1456
1457    #[diesel_test_helper::test]
1458    #[cfg(not(miri))] // ffi call
1459    fn jsonb_to_sql_integer() {
1460        let conn = &mut connection();
1461        let res = diesel::select(json!(42).into_sql::<Jsonb>().eq(&sql("jsonb('42')")))
1462            .get_result::<bool>(conn)
1463            .unwrap();
1464        assert!(res);
1465    }
1466
1467    #[diesel_test_helper::test]
1468    #[cfg(not(miri))] // ffi call
1469    fn jsonb_to_sql_float() {
1470        let conn = &mut connection();
1471        let res = diesel::select(json!(42.23).into_sql::<Jsonb>().eq(&sql("jsonb('42.23')")))
1472            .get_result::<bool>(conn)
1473            .unwrap();
1474        assert!(res);
1475    }
1476
1477    #[diesel_test_helper::test]
1478    #[cfg(not(miri))] // ffi call
1479    fn jsonb_to_sql_text() {
1480        let conn = &mut connection();
1481
1482        // Test for TEXT (simple string)
1483        let res = diesel::select(
1484            json!("hello")
1485                .into_sql::<Jsonb>()
1486                .eq(&sql(r#"jsonb('"hello"')"#)),
1487        )
1488        .get_result::<bool>(conn)
1489        .unwrap();
1490
1491        assert!(res);
1492    }
1493
1494    #[diesel_test_helper::test]
1495    #[cfg(not(miri))] // ffi call
1496    fn jsonb_to_sql_textj() {
1497        let conn = &mut connection();
1498
1499        // Test for TEXTJ (JSON-escaped string, e.g., containing \n or \uXXXX)
1500        let res = diesel::select(
1501            json!("hello\nworld")
1502                .into_sql::<Jsonb>()
1503                .eq(&sql(r#"jsonb('"hello\nworld"')"#)), // The string is JSON-escaped
1504        )
1505        .get_result::<bool>(conn)
1506        .unwrap();
1507
1508        assert!(res);
1509    }
1510
1511    #[diesel_test_helper::test]
1512    #[cfg(not(miri))] // ffi call
1513    fn jsonb_to_sql_textj_quote_and_backslash() {
1514        let conn = &mut connection();
1515
1516        // a quote and a backslash are the other two characters sqlite writes as TEXTJ
1517        let res = diesel::select(
1518            json!(r#"a"b\c"#)
1519                .into_sql::<Jsonb>()
1520                .eq(&sql(r#"jsonb('"a\"b\\c"')"#)),
1521        )
1522        .get_result::<bool>(conn)
1523        .unwrap();
1524
1525        assert!(res);
1526    }
1527
1528    #[diesel_test_helper::test]
1529    #[cfg(not(miri))] // ffi call
1530    fn jsonb_to_sql_array() {
1531        let conn = &mut connection();
1532        let res = diesel::select(
1533            json!([1, true, "foo"])
1534                .into_sql::<Jsonb>()
1535                .eq(&sql(r#"jsonb('[1, true, "foo"]')"#)),
1536        )
1537        .get_result::<bool>(conn)
1538        .unwrap();
1539        assert!(res);
1540    }
1541
1542    #[diesel_test_helper::test]
1543    #[cfg(not(miri))] // ffi call
1544    fn jsonb_to_sql_object() {
1545        let conn = &mut connection();
1546        let res = diesel::select(
1547            json!({"key": "value"})
1548                .into_sql::<Jsonb>()
1549                .eq(&sql(r#"jsonb('{"key": "value"}')"#)),
1550        )
1551        .get_result::<bool>(conn)
1552        .unwrap();
1553        assert!(res);
1554    }
1555
1556    #[diesel_test_helper::test]
1557    #[cfg(not(miri))] // ffi call
1558    fn jsonb_to_sql_object_in_object() {
1559        let conn = &mut connection();
1560        let json_value = json!({
1561            "outer_key": {
1562                "additional_key": true,
1563                "inner_key": {
1564                    "nested_key": 42
1565                },
1566            }
1567        });
1568
1569        let res = diesel::select(json_value.into_sql::<Jsonb>().eq(&sql(
1570            r#"jsonb('{"outer_key": {"additional_key": true, "inner_key": {"nested_key": 42}}}')"#,
1571        )))
1572        .get_result::<bool>(conn)
1573        .unwrap();
1574        assert!(res);
1575    }
1576
1577    #[diesel_test_helper::test]
1578    #[cfg(not(miri))] // ffi call
1579    fn jsonb_to_sql_array_in_object() {
1580        let conn = &mut connection();
1581        let json_value = json!({
1582            "is_valid": false,
1583            "key": [1, 2, 3],
1584        });
1585        let res = diesel::select(
1586            json_value
1587                .into_sql::<Jsonb>()
1588                .eq(&sql(r#"jsonb('{"is_valid": false, "key": [1, 2, 3]}')"#)),
1589        )
1590        .get_result::<bool>(conn)
1591        .unwrap();
1592        assert!(res);
1593    }
1594
1595    #[diesel_test_helper::test]
1596    #[cfg(not(miri))] // ffi call
1597    fn jsonb_to_sql_object_in_array() {
1598        let conn = &mut connection();
1599        let json_value = json!([
1600            {
1601                "nested_key": "nested_value"
1602            },
1603            {
1604                "int_value": 99
1605            }
1606        ]);
1607        let res = diesel::select(json_value.into_sql::<Jsonb>().eq(&sql(
1608            r#"jsonb('[{"nested_key": "nested_value"}, {"int_value": 99}]')"#,
1609        )))
1610        .get_result::<bool>(conn)
1611        .unwrap();
1612        assert!(res);
1613    }
1614
1615    #[diesel_test_helper::test]
1616    #[cfg(not(miri))] // ffi call
1617    fn jsonb_from_sql_null() {
1618        let conn = &mut connection();
1619        let res = diesel::select(sql::<Jsonb>("jsonb('null')"))
1620            .get_result::<serde_json::Value>(conn)
1621            .unwrap();
1622        assert_eq!(res, serde_json::json!(null));
1623    }
1624
1625    #[diesel_test_helper::test]
1626    #[cfg(not(miri))] // ffi call
1627    fn jsonb_from_sql_true() {
1628        let conn = &mut connection();
1629        let res = diesel::select(sql::<Jsonb>("jsonb('true')"))
1630            .get_result::<serde_json::Value>(conn)
1631            .unwrap();
1632        assert_eq!(res, serde_json::json!(true));
1633    }
1634
1635    #[diesel_test_helper::test]
1636    #[cfg(not(miri))] // ffi call
1637    fn jsonb_from_sql_false() {
1638        let conn = &mut connection();
1639        let res = diesel::select(sql::<Jsonb>("jsonb('false')"))
1640            .get_result::<serde_json::Value>(conn)
1641            .unwrap();
1642        assert_eq!(res, serde_json::json!(false));
1643    }
1644
1645    #[diesel_test_helper::test]
1646    #[cfg(not(miri))] // ffi call
1647    fn jsonb_from_sql_int() {
1648        let conn = &mut connection();
1649        let res = diesel::select(sql::<Jsonb>("jsonb('42')"))
1650            .get_result::<serde_json::Value>(conn)
1651            .unwrap();
1652        assert_eq!(res, serde_json::json!(42));
1653    }
1654
1655    #[diesel_test_helper::test]
1656    #[cfg(not(miri))] // ffi call
1657    fn jsonb_from_sql_float() {
1658        let conn = &mut connection();
1659        let res = diesel::select(sql::<Jsonb>("jsonb('42.23')"))
1660            .get_result::<serde_json::Value>(conn)
1661            .unwrap();
1662        assert_eq!(res, serde_json::json!(42.23));
1663    }
1664
1665    #[diesel_test_helper::test]
1666    #[cfg(not(miri))] // ffi call
1667    fn jsonb_from_sql_object() {
1668        let conn = &mut connection();
1669        let res = diesel::select(sql::<Jsonb>(r#"jsonb('{"key": "value"}')"#))
1670            .get_result::<serde_json::Value>(conn)
1671            .unwrap();
1672        assert_eq!(res, serde_json::json!({"key": "value"}));
1673    }
1674
1675    #[diesel_test_helper::test]
1676    #[cfg(not(miri))] // ffi call
1677    fn jsonb_from_sql_array() {
1678        let conn = &mut connection();
1679        let res = diesel::select(sql::<Jsonb>("jsonb('[1, 2, 3]')"))
1680            .get_result::<serde_json::Value>(conn)
1681            .unwrap();
1682        assert_eq!(res, serde_json::json!([1, 2, 3]));
1683    }
1684
1685    #[diesel_test_helper::test]
1686    #[cfg(not(miri))] // ffi call
1687    fn jsonb_from_sql_nested_objects() {
1688        let conn = &mut connection();
1689        let res = diesel::select(sql::<Jsonb>(r#"jsonb('{"outer": {"inner": 42}}')"#))
1690            .get_result::<serde_json::Value>(conn)
1691            .unwrap();
1692        assert_eq!(res, serde_json::json!({"outer": {"inner": 42}}));
1693    }
1694
1695    #[diesel_test_helper::test]
1696    #[cfg(not(miri))] // ffi call
1697    fn jsonb_from_sql_nested_arrays() {
1698        let conn = &mut connection();
1699        let res = diesel::select(sql::<Jsonb>("jsonb('[[1, 2], [3, 4]]')"))
1700            .get_result::<serde_json::Value>(conn)
1701            .unwrap();
1702        assert_eq!(res, serde_json::json!([[1, 2], [3, 4]]));
1703    }
1704
1705    #[diesel_test_helper::test]
1706    #[cfg(not(miri))] // ffi call
1707    fn jsonb_from_sql_nested_arrays_in_objects() {
1708        let conn = &mut connection();
1709        let res = diesel::select(sql::<Jsonb>(r#"jsonb('{"array": [1, 2, 3]}')"#))
1710            .get_result::<serde_json::Value>(conn)
1711            .unwrap();
1712        assert_eq!(res, serde_json::json!({"array": [1, 2, 3]}));
1713    }
1714
1715    #[diesel_test_helper::test]
1716    #[cfg(not(miri))] // ffi call
1717    fn jsonb_from_sql_nested_objects_in_arrays() {
1718        let conn = &mut connection();
1719        let res = diesel::select(sql::<Jsonb>(
1720            r#"jsonb('[{"key1": "value1"}, {"key2": "value2"}]')"#,
1721        ))
1722        .get_result::<serde_json::Value>(conn)
1723        .unwrap();
1724        assert_eq!(
1725            res,
1726            serde_json::json!([{"key1": "value1"}, {"key2": "value2"}])
1727        );
1728    }
1729
1730    #[diesel_test_helper::test]
1731    #[cfg(not(miri))] // ffi call
1732    fn jsonb_from_sql_text() {
1733        let conn = &mut connection();
1734        let res = diesel::select(sql::<Jsonb>(r#"jsonb('"hello"')"#))
1735            .get_result::<serde_json::Value>(conn)
1736            .unwrap();
1737        assert_eq!(res, serde_json::json!("hello"));
1738    }
1739
1740    #[diesel_test_helper::test]
1741    #[cfg(not(miri))] // ffi call
1742    fn jsonb_from_sql_textj() {
1743        let conn = &mut connection();
1744        let res = diesel::select(sql::<Jsonb>(r#"jsonb('"hello\nworld"')"#))
1745            .get_result::<serde_json::Value>(conn)
1746            .unwrap();
1747        assert_eq!(res, serde_json::json!("hello\nworld"));
1748    }
1749
1750    #[diesel_test_helper::test]
1751    #[cfg(not(miri))] // ffi call
1752    fn bad_json_from_sql() {
1753        let conn = &mut connection();
1754        let res = diesel::select(json!(true).into_sql::<Json>().eq(&sql("json('boom')")))
1755            .get_result::<bool>(conn);
1756        assert_eq!(res.unwrap_err().to_string(), "malformed JSON");
1757    }
1758
1759    #[diesel_test_helper::test]
1760    #[cfg(not(miri))] // ffi call
1761    fn bad_jsonb_from_sql() {
1762        let conn = &mut connection();
1763        let res = diesel::select(json!(true).into_sql::<Jsonb>().eq(&sql("jsonb('boom')")))
1764            .get_result::<bool>(conn);
1765        assert_eq!(res.unwrap_err().to_string(), "malformed JSON");
1766    }
1767
1768    #[diesel_test_helper::test]
1769    fn no_json_from_sql() {
1770        let uuid: Result<serde_json::Value, _> = FromSql::<Json, Sqlite>::from_nullable_sql(None);
1771        assert_eq!(
1772            uuid.unwrap_err().to_string(),
1773            "Unexpected null for non-null column"
1774        );
1775    }
1776
1777    #[diesel_test_helper::test]
1778    fn no_jsonb_from_sql() {
1779        let uuid: Result<serde_json::Value, _> = FromSql::<Jsonb, Sqlite>::from_nullable_sql(None);
1780        assert_eq!(
1781            uuid.unwrap_err().to_string(),
1782            "Unexpected null for non-null column"
1783        );
1784    }
1785
1786    #[cfg(all(
1787        not(miri),
1788        not(all(target_family = "wasm", target_os = "unknown")),
1789        unix
1790    ))]
1791    const RECURSION_DEPTH: usize = 2000;
1792
1793    #[cfg(all(
1794        not(miri),
1795        any(windows, all(target_family = "wasm", target_os = "unknown"))
1796    ))]
1797    const RECURSION_DEPTH: usize = 1000;
1798
1799    #[cfg(any(
1800        miri,
1801        all(
1802            not(unix),
1803            not(windows),
1804            not(all(target_family = "wasm", target_os = "unknown"))
1805        )
1806    ))]
1807    const RECURSION_DEPTH: usize = 10;
1808
1809    #[diesel_test_helper::test]
1810    fn guard_against_stackoverflow_array() {
1811        let mut value = serde_json::Value::Number(42.into());
1812        for i in 0..RECURSION_DEPTH {
1813            value = serde_json::Value::Array(vec![value, serde_json::Value::Number(i.into())]);
1814        }
1815        // We compare the encoded buffer for both values here
1816        // as serde_json otherwise runs into stackoverflows itself
1817        let mut expected_buffer = Vec::new();
1818        write_jsonb_value(&value, &mut expected_buffer).unwrap();
1819        let res = read_jsonb_value(&expected_buffer).unwrap().0;
1820
1821        let mut buffer = Vec::new();
1822        write_jsonb_value(&res, &mut buffer).unwrap();
1823        assert_eq!(expected_buffer, buffer);
1824    }
1825
1826    #[diesel_test_helper::test]
1827    fn guard_against_stackoverflow_object() {
1828        let mut value = serde_json::Value::Number(42.into());
1829        for i in 0..RECURSION_DEPTH {
1830            let mut map = serde_json::Map::new();
1831            map.insert(format!("key_{i}"), value);
1832            value = serde_json::Value::Object(map);
1833        }
1834
1835        // We compare the encoded buffer for both values here
1836        // as serde_json otherwise runs into stackoverflows itself
1837        let mut expected_buffer = Vec::new();
1838        write_jsonb_value(&value, &mut expected_buffer).unwrap();
1839
1840        let res = read_jsonb_value(&expected_buffer).unwrap().0;
1841
1842        let mut buffer = Vec::new();
1843        write_jsonb_value(&res, &mut buffer).unwrap();
1844        assert_eq!(expected_buffer, buffer);
1845    }
1846
1847    #[diesel_test_helper::test]
1848    fn guard_against_stackoverflow_mixed() {
1849        let mut value = serde_json::Value::Number(42.into());
1850        for i in 0_usize..2000 {
1851            if i.is_multiple_of(2) {
1852                let mut map = serde_json::Map::new();
1853                map.insert(format!("key_{i}"), value);
1854                value = serde_json::Value::Object(map);
1855            } else {
1856                value = serde_json::Value::Array(vec![value]);
1857            }
1858        }
1859        // We compare the encoded buffer for both values here
1860        // as serde_json otherwise runs into stackoverflows itself
1861        let mut expected_buffer = Vec::new();
1862        write_jsonb_value(&value, &mut expected_buffer).unwrap();
1863        let res = read_jsonb_value(&expected_buffer).unwrap().0;
1864        let mut buffer = Vec::new();
1865        write_jsonb_value(&res, &mut buffer).unwrap();
1866        assert_eq!(expected_buffer, buffer);
1867    }
1868
1869    #[diesel_test_helper::test]
1870    #[cfg(not(miri))] // ffi call
1871    fn dangling_bytes_result_in_error() {
1872        let mut value = Vec::<u8>::new();
1873        value.extend(create_jsonb_header(JSONB_INT, 1).unwrap());
1874        value.push(b'1');
1875        value.push(42);
1876        assert_eq!(value.len(), 3);
1877        let conn = &mut connection();
1878        let res = diesel::select(
1879            crate::dsl::sql::<sql_types::Jsonb>("jsonb(?)").bind::<sql_types::Binary, _>(value),
1880        )
1881        .get_result::<serde_json::Value>(conn);
1882        assert!(res.is_err(), "{:?}", res.unwrap());
1883    }
1884
1885    #[diesel_test_helper::test]
1886    fn object_key_without_value_results_in_error() {
1887        let mut value = Vec::new();
1888        value.extend(create_jsonb_header(JSONB_OBJECT, 2).unwrap());
1889        value.extend(create_jsonb_header(JSONB_TEXT, 1).unwrap());
1890        value.push(b'a');
1891        let res = read_jsonb_value(&value);
1892        assert!(res.is_err(), "{:?}", res.unwrap());
1893    }
1894
1895    #[diesel_test_helper::test]
1896    fn check_invalid_size_header() {
1897        // 9-byte JSONB blob: first byte 0xFB (size_hint nibble = 0x0F),
1898        // bytes 1..9 = 0xFF -> encoded payload length = u64::MAX.
1899        let res = read_jsonb_value(&[0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
1900        assert!(res.is_err());
1901    }
1902
1903    #[diesel_test_helper::test]
1904    fn nested_container_cannot_cross_parent_boundary() {
1905        let res = read_jsonb_value(&[0x3B, 0x1B, 0x1B, JSONB_NULL]);
1906        assert!(res.is_err(), "{:?}", res.unwrap());
1907    }
1908
1909    #[diesel_test_helper::test]
1910    fn check_signed_integer() {
1911        let mut buf = Vec::new();
1912        write_jsonb_value(&json!(-42), &mut buf).unwrap();
1913        let mut expected = create_jsonb_header(JSONB_INT, 3).unwrap();
1914        expected.extend(b"-42");
1915        assert_eq!(buf, expected);
1916    }
1917}