odbc_api/parameter_collection.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
use crate::{handles::Statement, parameter::InputParameter, Error};
mod tuple;
pub use tuple::ParameterTupleElement;
/// A collection of input parameters. They can be bound to a statement using a shared reference.
///
/// # Safety
///
/// Must only bind pointers to statement which are valid for the lifetime of the collection. The
/// parameter set size returned must not be larger than the range of valid values behind these
/// pointers.
pub unsafe trait InputParameterCollection {
/// Number of values per parameter in the collection. This can be different from the maximum
/// batch size a buffer may be able to hold. Returning `0` will cause the the query not to be
/// executed.
fn parameter_set_size(&self) -> usize;
/// # Safety
///
/// On execution a statement may want to read/write to the bound paramaters. It is the callers
/// responsibility that by then the buffers are either unbound from the statement or still
/// valid.
unsafe fn bind_input_parameters_to(&self, stmt: &mut impl Statement) -> Result<(), Error>;
}
unsafe impl<T> ParameterCollectionRef for &T
where
T: InputParameterCollection + ?Sized,
{
fn parameter_set_size(&self) -> usize {
(**self).parameter_set_size()
}
unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error> {
self.bind_input_parameters_to(stmt)
}
}
unsafe impl<T> InputParameterCollection for T
where
T: InputParameter + ?Sized,
{
fn parameter_set_size(&self) -> usize {
1
}
unsafe fn bind_input_parameters_to(&self, stmt: &mut impl Statement) -> Result<(), Error> {
self.assert_completness();
stmt.bind_input_parameter(1, self).into_result(stmt)
}
}
unsafe impl<T> InputParameterCollection for [T]
where
T: InputParameter,
{
fn parameter_set_size(&self) -> usize {
1
}
unsafe fn bind_input_parameters_to(&self, stmt: &mut impl Statement) -> Result<(), Error> {
for (index, parameter) in self.iter().enumerate() {
parameter.assert_completness();
stmt.bind_input_parameter(index as u16 + 1, parameter)
.into_result(stmt)?;
}
Ok(())
}
}
/// SQL Parameters used to execute a query.
///
/// ODBC allows to place question marks (`?`) in the statement text as placeholders. For each such
/// placeholder a parameter needs to be bound to the statement before executing it.
///
/// # Examples
///
/// This trait is implemented by single parameters.
///
/// ```no_run
/// use odbc_api::{Environment, ConnectionOptions};
///
/// let env = Environment::new()?;
///
/// let mut conn = env.connect(
/// "YourDatabase", "SA", "My@Test@Password1",
/// ConnectionOptions::default()
/// )?;
/// let year = 1980;
/// if let Some(cursor) = conn.execute("SELECT year, name FROM Birthdays WHERE year > ?;", &year)? {
/// // Use cursor to process query results.
/// }
/// # Ok::<(), odbc_api::Error>(())
/// ```
///
/// Tuples of `Parameter`s implement this trait, too.
///
/// ```no_run
/// use odbc_api::{Environment, ConnectionOptions};
///
/// let env = Environment::new()?;
///
/// let mut conn = env.connect(
/// "YourDatabase", "SA", "My@Test@Password1",
/// ConnectionOptions::default()
/// )?;
/// let too_old = 1980;
/// let too_young = 2000;
/// if let Some(cursor) = conn.execute(
/// "SELECT year, name FROM Birthdays WHERE ? < year < ?;",
/// (&too_old, &too_young),
/// )? {
/// // Use cursor to congratulate only persons in the right age group...
/// }
/// # Ok::<(), odbc_api::Error>(())
/// ```
///
/// And so do array slices of `Parameter`s.
///
/// ```no_run
/// use odbc_api::{Environment, ConnectionOptions};
///
/// let env = Environment::new()?;
///
/// let mut conn = env.connect(
/// "YourDatabase",
/// "SA",
/// "My@Test@Password1",
/// ConnectionOptions::default()
/// )?;
/// let params = [1980, 2000];
/// if let Some(cursor) = conn.execute(
/// "SELECT year, name FROM Birthdays WHERE ? < year < ?;",
/// ¶ms[..])?
/// {
/// // Use cursor to process query results.
/// }
/// # Ok::<(), odbc_api::Error>(())
/// ```
///
/// # Safety
///
/// Instances of this type are passed by value, so this type can be implemented by both constant and
/// mutable references. Implementers should take care that the values bound by `bind_parameters_to`
/// to the statement live at least for the Duration of `self`. The most straight forward way of
/// achieving this is of course, to bind members.
pub unsafe trait ParameterCollectionRef {
/// Number of values per parameter in the collection. This can be different from the maximum
/// batch size a buffer may be able to hold. Returning `0` will cause the the query not to be
/// executed.
fn parameter_set_size(&self) -> usize;
/// # Safety
///
/// On execution a statement may want to read/write to the bound paramaters. It is the callers
/// responsibility that by then the buffers are either unbound from the statement or still
/// valild.
unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error>;
}
unsafe impl<T> ParameterCollectionRef for &mut T
where
T: ParameterCollection,
{
fn parameter_set_size(&self) -> usize {
(**self).parameter_set_size()
}
unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error> {
(**self).bind_parameters_to(stmt)
}
}
/// Implementers of this trait can be bound to a statement through a
/// [`self::ParameterCollectionRef`].
///
/// # Safety
///
/// Parameters bound to the statement must remain valid for the lifetime of the instance.
pub unsafe trait ParameterCollection {
/// Number of values per parameter in the collection. This can be different from the maximum
/// batch size a buffer may be able to hold. Returning `0` will cause the the query not to be
/// executed.
fn parameter_set_size(&self) -> usize;
/// Bind the parameters to a statement
///
/// # Safety
///
/// Since the parameter is now bound to `stmt` callers must take care that it is ensured that
/// the parameter remains valid while it is used. If the parameter is bound as an output
/// parameter it must also be ensured that it is exclusively referenced by statement.
unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error>;
}
unsafe impl<T> ParameterCollection for T
where
T: InputParameterCollection + ?Sized,
{
fn parameter_set_size(&self) -> usize {
(*self).parameter_set_size()
}
unsafe fn bind_parameters_to(&mut self, stmt: &mut impl Statement) -> Result<(), Error> {
self.bind_input_parameters_to(stmt)
}
}