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