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