sqlx_exasol/
arguments.rs

1use serde::Serialize;
2use serde_json::Error as SerdeError;
3use sqlx_core::{arguments::Arguments, encode::Encode, error::BoxDynError, types::Type};
4
5use crate::{database::Exasol, error::ExaProtocolError, type_info::ExaTypeInfo};
6
7/// Implementor of [`Arguments`].
8#[derive(Debug, Default)]
9pub struct ExaArguments {
10    pub buf: ExaBuffer,
11    pub types: Vec<ExaTypeInfo>,
12}
13
14impl<'q> Arguments<'q> for ExaArguments {
15    type Database = Exasol;
16
17    fn reserve(&mut self, additional: usize, size: usize) {
18        self.types.reserve(additional);
19        self.buf.buffer.reserve(size);
20    }
21
22    fn add<T>(&mut self, value: T) -> Result<(), BoxDynError>
23    where
24        T: 'q + Encode<'q, Self::Database> + Type<Self::Database>,
25    {
26        let ty = value.produces().unwrap_or_else(T::type_info);
27
28        self.buf.start_seq();
29        let _ = value.encode(&mut self.buf)?;
30        self.buf.end_seq();
31        self.buf.add_separator();
32
33        self.buf.check_param_count()?;
34
35        self.types.push(ty);
36
37        Ok(())
38    }
39
40    fn len(&self) -> usize {
41        self.types.len()
42    }
43}
44
45/// Prepared statement parameters serialization buffer.
46#[derive(Debug)]
47pub struct ExaBuffer {
48    /// JSON buffer where we serialize data.
49    ///
50    /// Storing this as a [`String`] allows for zero cost serialization of the buffer in the
51    /// containing types.
52    pub(crate) buffer: String,
53    /// Counter for the number of parameters we are serializing for a column.
54    ///
55    /// While typically `1`, the columnar nature of Exasol allows us to pass parameter arrays for
56    /// multiple rows. However, we must ensure that all parameter columns have the same number
57    /// of rows.
58    pub(crate) col_params_counter: usize,
59    /// Storage for the first final value of `col_params_counter`.
60    ///
61    /// All subsequent columns are expected to have the same amount of rows.
62    pub(crate) first_col_params_num: Option<usize>,
63}
64
65impl ExaBuffer {
66    /// Serializes and appends a value to this buffer.
67    pub fn append<T>(&mut self, value: T) -> Result<(), SerdeError>
68    where
69        T: Serialize,
70    {
71        self.col_params_counter += 1;
72        // SAFETY: `serde_json` will only write valid UTF-8.
73        serde_json::to_writer(unsafe { self.buffer.as_mut_vec() }, &value)
74    }
75
76    /// Serializes and appends an iterator of values to this buffer.
77    pub fn append_iter<'q, I, T>(&mut self, iter: I) -> Result<(), BoxDynError>
78    where
79        I: IntoIterator<Item = T>,
80        T: 'q + Encode<'q, Exasol> + Type<Exasol>,
81    {
82        let mut iter = iter.into_iter();
83
84        if let Some(value) = iter.next() {
85            let _ = value.encode(self)?;
86        }
87
88        for value in iter {
89            self.add_separator();
90            let _ = value.encode(self)?;
91        }
92
93        Ok(())
94    }
95
96    /// Outputs the numbers of parameter sets in the buffer.
97    pub(crate) fn num_param_sets(&self) -> usize {
98        self.first_col_params_num.unwrap_or_default()
99    }
100
101    /// Ends the main sequence serialization and returns the JSON [`String`] buffer.
102    pub(crate) fn finish(mut self) -> String {
103        // Pop the last `,` separator automatically added when an element is encoded and appended.
104        self.buffer.pop();
105        self.end_seq();
106        self.buffer
107    }
108
109    /// Adds the sequence serialization start to the buffer.
110    fn start_seq(&mut self) {
111        self.buffer.push('[');
112    }
113
114    /// Adds the sequence serialization start to the buffer.
115    fn end_seq(&mut self) {
116        self.buffer.push(']');
117    }
118
119    /// Adds the sequence serialization separator to the buffer.
120    fn add_separator(&mut self) {
121        self.buffer.push(',');
122    }
123
124    /// Registers the number of rows we bound parameters for.
125    ///
126    /// The first time we add an argument, we store the number of rows we pass parameters for. This
127    /// is useful for when arrays of parameters get passed for each column.
128    ///
129    /// All subsequent calls will check that the number of rows is the same.
130    fn check_param_count(&mut self) -> Result<(), ExaProtocolError> {
131        let count = self.col_params_counter;
132
133        // We must reset the count in preparation for the next parameter.
134        self.col_params_counter = 0;
135
136        match self.first_col_params_num {
137            Some(n) if n == count => (),
138            Some(n) => Err(ExaProtocolError::ParameterLengthMismatch(count, n))?,
139            None => self.first_col_params_num = Some(count),
140        };
141
142        Ok(())
143    }
144}
145
146impl Default for ExaBuffer {
147    fn default() -> Self {
148        let mut buffer = Self {
149            buffer: String::with_capacity(1),
150            col_params_counter: 0,
151            first_col_params_num: None,
152        };
153
154        buffer.start_seq();
155        buffer
156    }
157}