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
//! Module containing implementations of the `Parameter` trait. use std::{convert::TryInto, ffi::c_void}; use odbc_sys::CDataType; use crate::{ handles::{CData, Input}, DataType, }; /// Extend the input trait with the guarantee, that the bound parameter buffer contains at least one /// element. pub unsafe trait Parameter: Input {} /// Annotates an instance of an inner type with an SQL Data type in order to indicate how it should /// be bound as a parameter to an SQL Statement. /// /// # Example /// /// ```no_run /// use odbc_api::{Environment, parameter::WithDataType, DataType}; /// /// let env = unsafe { /// Environment::new()? /// }; /// /// let mut conn = env.connect("YourDatabase", "SA", "<YourStrong@Passw0rd>")?; /// // Bind year as VARCHAR(4) rather than integer. /// let year = WithDataType{ /// value: 1980, /// data_type: DataType::Varchar {length: 4} /// }; /// if let Some(cursor) = conn.execute("SELECT year, name FROM Birthdays WHERE year > ?;", year)? { /// // Use cursor to process query results. /// } /// # Ok::<(), odbc_api::Error>(()) /// ``` pub struct WithDataType<T> { pub value: T, pub data_type: DataType, } unsafe impl<T> CData for WithDataType<T> where T: CData, { fn cdata_type(&self) -> CDataType { self.value.cdata_type() } fn indicator_ptr(&self) -> *const isize { self.value.indicator_ptr() } fn value_ptr(&self) -> *const c_void { self.value.value_ptr() } fn buffer_length(&self) -> isize { self.value.buffer_length() } } unsafe impl<T> Input for WithDataType<T> where T: Input, { fn data_type(&self) -> DataType { self.data_type } } unsafe impl<T> Parameter for WithDataType<T> where T: Parameter {} /// Binds a byte array as a VarChar input parameter. /// /// While a byte array can provide us with a pointer to the start of the array and the length of the /// array itself, it can not provide us with a pointer to the length of the buffer. So to bind /// strings which are not zero terminated we need to store the length in a separate value. /// /// This type is created if `into_parameter` of the `IntoParameter` trait is called on a `&str`. /// /// # Example /// /// ```no_run /// use odbc_api::{Environment, IntoParameter}; /// /// let env = unsafe { /// Environment::new()? /// }; /// /// let mut conn = env.connect("YourDatabase", "SA", "<YourStrong@Passw0rd>")?; /// if let Some(cursor) = conn.execute( /// "SELECT year FROM Birthdays WHERE name=?;", /// "Bernd".into_parameter())? /// { /// // Use cursor to process query results. /// }; /// # Ok::<(), odbc_api::Error>(()) /// ``` pub struct VarChar<'a> { bytes: &'a [u8], /// Will be set to value.len() by constructor. length: isize, } impl<'a> VarChar<'a> { pub fn new(value: &'a [u8]) -> Self { VarChar { bytes: value, length: value.len().try_into().unwrap(), } } } unsafe impl CData for VarChar<'_> { fn cdata_type(&self) -> CDataType { CDataType::Char } fn indicator_ptr(&self) -> *const isize { &self.length } fn value_ptr(&self) -> *const c_void { self.bytes.as_ptr() as *const c_void } fn buffer_length(&self) -> isize { 0 } } unsafe impl Input for VarChar<'_> { fn data_type(&self) -> DataType { DataType::Varchar { length: self.bytes.len(), } } } unsafe impl Parameter for VarChar<'_> {}