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