odbc_api/
parameter_collection.rs

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