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/// ¶ms[..], 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}