sqlx_exasol_impl/arguments/
mod.rs

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