odbc_api/
parameter_collection.rs

1use crate::{handles::Statement, parameter::InputParameter, Error};
2
3mod tuple;
4
5pub use tuple::ParameterTupleElement;
6
7/// A collection of input parameters. They can be bound to a statement using a shared reference.
8///
9/// # Safety
10///
11/// Must only bind pointers to statement which are valid for the lifetime of the collection. The
12/// parameter set size returned must not be larger than the range of valid values behind these
13/// pointers.
14pub unsafe trait InputParameterCollection {
15    /// Number of values per parameter in the collection. This can be different from the maximum
16    /// batch size a buffer may be able to hold. Returning `0` will cause the the query not to be
17    /// executed.
18    fn parameter_set_size(&self) -> usize;
19
20    /// # Safety
21    ///
22    /// On execution a statement may want to read/write to the bound paramaters. It is the callers
23    /// responsibility that by then the buffers are either unbound from the statement or still
24    /// valid.
25    unsafe fn bind_input_parameters_to(&self, stmt: &mut impl Statement) -> Result<(), Error>;
26}
27
28unsafe impl<T> ParameterCollectionRef for &T
29where
30    T: InputParameterCollection + ?Sized,
31{
32    fn parameter_set_size(&self) -> usize {
33        (**self).parameter_set_size()
34    }
35
36    unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error> {
37        self.bind_input_parameters_to(stmt)
38    }
39}
40
41unsafe impl<T> InputParameterCollection for T
42where
43    T: InputParameter + ?Sized,
44{
45    fn parameter_set_size(&self) -> usize {
46        1
47    }
48
49    unsafe fn bind_input_parameters_to(&self, stmt: &mut impl Statement) -> Result<(), Error> {
50        self.assert_completness();
51        stmt.bind_input_parameter(1, self).into_result(stmt)
52    }
53}
54
55unsafe impl<T> InputParameterCollection for [T]
56where
57    T: InputParameter,
58{
59    fn parameter_set_size(&self) -> usize {
60        1
61    }
62
63    unsafe fn bind_input_parameters_to(&self, stmt: &mut impl Statement) -> Result<(), Error> {
64        for (index, parameter) in self.iter().enumerate() {
65            parameter.assert_completness();
66            stmt.bind_input_parameter(index as u16 + 1, parameter)
67                .into_result(stmt)?;
68        }
69        Ok(())
70    }
71}
72
73/// SQL Parameters used to execute a query.
74///
75/// ODBC allows to place question marks (`?`) in the statement text as placeholders. For each such
76/// placeholder a parameter needs to be bound to the statement before executing it.
77///
78/// # Examples
79///
80/// This trait is implemented by single parameters.
81///
82/// ```no_run
83/// use odbc_api::{Environment, ConnectionOptions};
84///
85/// let env = Environment::new()?;
86///
87/// let mut conn = env.connect(
88///     "YourDatabase", "SA", "My@Test@Password1",
89///     ConnectionOptions::default()
90/// )?;
91/// let year = 1980;
92/// let timeout = None;
93/// let maybe_cursor = conn.execute(
94///     "SELECT year, name FROM Birthdays WHERE year > ?;",
95///     &year,
96///     timeout,
97/// )?;
98/// if let Some(cursor) = maybe_cursor {
99///     // Use cursor to process query results.
100/// }
101/// # Ok::<(), odbc_api::Error>(())
102/// ```
103///
104/// Tuples of `Parameter`s implement this trait, too.
105///
106/// ```no_run
107/// use odbc_api::{Environment, ConnectionOptions};
108///
109/// let env = Environment::new()?;
110///
111/// let mut conn = env.connect(
112///     "YourDatabase", "SA", "My@Test@Password1",
113///     ConnectionOptions::default()
114/// )?;
115/// let too_old = 1980;
116/// let too_young = 2000;
117/// let timeout = None;
118/// if let Some(cursor) = conn.execute(
119///     "SELECT year, name FROM Birthdays WHERE ? < year < ?;",
120///     (&too_old, &too_young),
121///     timeout,
122/// )? {
123///     // Use cursor to congratulate only persons in the right age group...
124/// }
125/// # Ok::<(), odbc_api::Error>(())
126/// ```
127///
128/// And so do array slices of `Parameter`s.
129///
130/// ```no_run
131/// use odbc_api::{Environment, ConnectionOptions};
132///
133/// let env = Environment::new()?;
134///
135/// let mut conn = env.connect(
136///     "YourDatabase",
137///     "SA",
138///     "My@Test@Password1",
139///     ConnectionOptions::default()
140/// )?;
141/// let params = [1980, 2000];
142/// let timeout = None;
143/// if let Some(cursor) = conn.execute(
144///     "SELECT year, name FROM Birthdays WHERE ? < year < ?;",
145///     &params[..], timeout)?
146/// {
147///     // Use cursor to process query results.
148/// }
149/// # Ok::<(), odbc_api::Error>(())
150/// ```
151///
152/// # Safety
153///
154/// Instances of this type are passed by value, so this type can be implemented by both constant and
155/// mutable references. Implementers should take care that the values bound by `bind_parameters_to`
156/// to the statement live at least for the Duration of `self`. The most straight forward way of
157/// achieving this is of course, to bind members.
158pub unsafe trait ParameterCollectionRef {
159    /// Number of values per parameter in the collection. This can be different from the maximum
160    /// batch size a buffer may be able to hold. Returning `0` will cause the the query not to be
161    /// executed.
162    fn parameter_set_size(&self) -> usize;
163
164    /// # Safety
165    ///
166    /// On execution a statement may want to read/write to the bound paramaters. It is the callers
167    /// responsibility that by then the buffers are either unbound from the statement or still
168    /// valild.
169    unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error>;
170}
171
172unsafe impl<T> ParameterCollectionRef for &mut T
173where
174    T: ParameterCollection,
175{
176    fn parameter_set_size(&self) -> usize {
177        (**self).parameter_set_size()
178    }
179
180    unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error> {
181        (**self).bind_parameters_to(stmt)
182    }
183}
184
185/// Implementers of this trait can be bound to a statement through a
186/// [`self::ParameterCollectionRef`].
187///
188/// # Safety
189///
190/// Parameters bound to the statement must remain valid for the lifetime of the instance.
191pub unsafe trait ParameterCollection {
192    /// Number of values per parameter in the collection. This can be different from the maximum
193    /// batch size a buffer may be able to hold. Returning `0` will cause the the query not to be
194    /// executed.
195    fn parameter_set_size(&self) -> usize;
196
197    /// Bind the parameters to a statement
198    ///
199    /// # Safety
200    ///
201    /// Since the parameter is now bound to `stmt` callers must take care that it is ensured that
202    /// the parameter remains valid while it is used. If the parameter is bound as an output
203    /// parameter it must also be ensured that it is exclusively referenced by statement.
204    unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error>;
205}
206
207unsafe impl<T> ParameterCollection for T
208where
209    T: InputParameterCollection + ?Sized,
210{
211    fn parameter_set_size(&self) -> usize {
212        (*self).parameter_set_size()
213    }
214
215    unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error> {
216        self.bind_input_parameters_to(stmt)
217    }
218}