odbc_api/parameter/varcell.rs
1use std::{
2 borrow::{Borrow, BorrowMut},
3 ffi::c_void,
4 marker::PhantomData,
5 mem::{size_of, size_of_val},
6 num::NonZeroUsize,
7 str::Utf8Error,
8};
9
10use odbc_sys::{CDataType, NULL_DATA};
11use widestring::{U16Str, U16String};
12
13use crate::{
14 buffers::{FetchRowMember, Indicator},
15 handles::{CData, CDataMut, HasDataType},
16 DataType, OutputParameter,
17};
18
19use super::CElement;
20
21/// A tag used to differentiate between different types of variadic buffers.
22///
23/// # Safety
24///
25/// * [`Self::TERMINATING_ZEROES`] is used to calculate buffer offsets. The number of terminating
26/// zeroes is expressed in `BufferElement`s.
27/// * [`Self::C_DATA_TYPE`] is used to bind parameters. Providing wrong values like e.g. a fixed length
28/// types, would cause even a correctly implemented odbc driver to access invalid memory.
29pub unsafe trait VarKind {
30 /// Either `u8` for binary and narrow text or `u16` for wide text. Wide text could also be
31 /// represented as `u8`, after all everything is bytes. This makes it difficult though to create
32 /// owned VarCell types from `u16` buffers.
33 type Element: Copy + Eq;
34 /// Zero for buffer element.
35 const ZERO: Self::Element;
36 /// Number of terminating zeroes required for this kind of variadic buffer.
37 const TERMINATING_ZEROES: usize;
38 const C_DATA_TYPE: CDataType;
39 /// Relational type used to bind the parameter. `buffer_length` is specified in elements rather
40 /// than bytes, if the two differ.
41 fn relational_type(buffer_length: usize) -> DataType;
42}
43
44/// Intended to be used as a generic argument for [`VarCell`] to declare that this buffer is used to
45/// hold narrow (as opposed to wide UTF-16) text.
46#[derive(Clone, Copy)]
47pub struct Text;
48
49unsafe impl VarKind for Text {
50 type Element = u8;
51 const ZERO: u8 = 0;
52 const TERMINATING_ZEROES: usize = 1;
53 const C_DATA_TYPE: CDataType = CDataType::Char;
54
55 fn relational_type(length: usize) -> DataType {
56 // Since we might use as an input buffer, we report the full buffer length in the type and
57 // do not deduct 1 for the terminating zero.
58 DataType::Varchar {
59 length: NonZeroUsize::new(length),
60 }
61 }
62}
63
64/// Intended to be used as a generic argument for [`VarCell`] to declare that this buffer is used to
65/// hold wide UTF-16 (as opposed to narrow ASCII or UTF-8) text. Use this to annotate `[u16]`
66/// buffers.
67#[derive(Clone, Copy)]
68pub struct WideText;
69
70unsafe impl VarKind for WideText {
71 type Element = u16;
72 const ZERO: u16 = 0;
73 const TERMINATING_ZEROES: usize = 1;
74 const C_DATA_TYPE: CDataType = CDataType::WChar;
75
76 fn relational_type(length: usize) -> DataType {
77 // Since we might use as an input buffer, we report the full buffer length in the type and
78 // do not deduct 1 for the terminating zero.
79 DataType::WVarchar {
80 length: NonZeroUsize::new(length),
81 }
82 }
83}
84
85/// Intended to be used as a generic argument for [`VarCell`] to declare that this buffer is used to
86/// hold raw binary input.
87#[derive(Clone, Copy)]
88pub struct Binary;
89
90unsafe impl VarKind for Binary {
91 type Element = u8;
92 const ZERO: u8 = 0;
93 const TERMINATING_ZEROES: usize = 0;
94 const C_DATA_TYPE: CDataType = CDataType::Binary;
95
96 fn relational_type(length: usize) -> DataType {
97 DataType::Varbinary {
98 length: NonZeroUsize::new(length),
99 }
100 }
101}
102
103/// Binds a byte array as Variadic sized character data. It can not be used for columnar bulk
104/// fetches, but if the buffer type is stack allocated it can be utilized in row wise bulk fetches.
105///
106/// Meaningful instantiations of this type are:
107///
108/// * [`self::VarCharSlice`] - immutable borrowed narrow character strings
109/// * [`self::VarCharSliceMut`] - mutable borrowed input / output narrow character strings
110/// * [`self::VarCharArray`] - stack allocated owned input / output narrow character strings
111/// * [`self::VarCharBox`] - heap allocated owned input /output narrow character strings
112/// * [`self::VarWCharSlice`] - immutable borrowed wide character string
113/// * [`self::VarWCharSliceMut`] - mutable borrowed input / output wide character string
114/// * [`self::VarWCharArray`] - stack allocated owned input / output wide character string
115/// * [`self::VarWCharBox`] - heap allocated owned input /output wide character string
116/// * [`self::VarBinarySlice`] - immutable borrowed parameter.
117/// * [`self::VarBinarySliceMut`] - mutable borrowed input / output parameter
118/// * [`self::VarBinaryArray`] - stack allocated owned input / output parameter
119/// * [`self::VarBinaryBox`] - heap allocated owned input /output parameter
120#[derive(Debug, Clone, Copy)]
121pub struct VarCell<B, K> {
122 /// Contains the value. Characters must be valid up to the index indicated by `indicator`. If
123 /// `indicator` is longer than buffer, the last element in buffer must be a terminating zero,
124 /// which is not regarded as being part of the payload itself.
125 buffer: B,
126 /// Indicates the length of the value stored in `buffer`. Should indicator exceed the buffer
127 /// length the value stored in buffer is truncated, and holds actually `buffer.len() - 1` valid
128 /// characters. The last element of the buffer being the terminating zero. If indicator is
129 /// exactly the buffer length, the value should be considered valid up to the last element,
130 /// unless the value is `\0`. In that case we assume `\0` to be a terminating zero left over
131 /// from truncation, rather than the last character of the string.
132 indicator: isize,
133 /// Variadic Kind, declaring wether the buffer holds text or binary data.
134 kind: PhantomData<K>,
135}
136
137pub type VarBinary<B> = VarCell<B, Binary>;
138pub type VarChar<B> = VarCell<B, Text>;
139pub type VarWChar<B> = VarCell<B, WideText>;
140
141/// Parameter type for owned, variable sized narrow character data.
142///
143/// We use `Box<[u8]>` rather than `Vec<u8>` as a buffer type since the indicator pointer already
144/// has the role of telling us how many bytes in the buffer are part of the payload.
145pub type VarCharBox = VarChar<Box<[u8]>>;
146
147/// Parameter type for owned, variable sized wide character data.
148///
149/// We use `Box<[u16]>` rather than `Vec<u16>` as a buffer type since the indicator pointer already
150/// has the role of telling us how many characters in the buffer are part of the payload.
151pub type VarWCharBox = VarWChar<Box<[u16]>>;
152
153/// Parameter type for owned, variable sized binary data.
154///
155/// We use `Box<[u8]>` rather than `Vec<u8>` as a buffer type since the indicator pointer already
156/// has the role of telling us how many bytes in the buffer are part of the payload.
157pub type VarBinaryBox = VarBinary<Box<[u8]>>;
158
159impl<K> VarCell<Box<[K::Element]>, K>
160where
161 K: VarKind,
162{
163 /// Constructs a 'missing' value.
164 pub fn null() -> Self {
165 // We do not want to use the empty buffer (`&[]`) here. It would be bound as `VARCHAR(0)`
166 // which caused errors with Microsoft Access and older versions of the Microsoft SQL Server
167 // ODBC driver.
168 Self::from_buffer(Box::new([K::ZERO]), Indicator::Null)
169 }
170
171 /// Create a VarChar box from a `Vec`.
172 pub fn from_vec(val: Vec<K::Element>) -> Self {
173 let indicator = Indicator::Length(val.len() * size_of::<K::Element>());
174 let buffer = val.into_boxed_slice();
175 Self::from_buffer(buffer, indicator)
176 }
177}
178
179impl<K> VarCell<Box<[u8]>, K>
180where
181 K: VarKind<Element = u8>,
182{
183 /// Create an owned parameter containing the character data from the passed string.
184 pub fn from_string(val: String) -> Self {
185 Self::from_vec(val.into_bytes())
186 }
187}
188
189impl<K> VarCell<Box<[u16]>, K>
190where
191 K: VarKind<Element = u16>,
192{
193 /// Create an owned parameter containing the character data from the passed string.
194 pub fn from_u16_string(val: U16String) -> Self {
195 Self::from_vec(val.into_vec())
196 }
197
198 /// Create an owned parameter containing the character data from the passed string. Converts it
199 /// to UTF-16 and allocates it.
200 pub fn from_str_slice(val: &str) -> Self {
201 let utf16 = U16String::from_str(val);
202 Self::from_u16_string(utf16)
203 }
204}
205
206impl<B, K> VarCell<B, K>
207where
208 K: VarKind,
209 B: Borrow<[K::Element]>,
210{
211 /// Creates a new instance from an existing buffer. For text should the indicator be `NoTotal`
212 /// or indicate a length longer than buffer, the last element in the buffer must be nul (`\0`).
213 pub fn from_buffer(buffer: B, indicator: Indicator) -> Self {
214 let buf = buffer.borrow();
215 if indicator.is_truncated(size_of_val(buf)) {
216 // Value is truncated. Let's check that all required terminating zeroes are at the end
217 // of the buffer.
218 if !ends_in_zeroes(buf, K::TERMINATING_ZEROES, K::ZERO) {
219 panic!("Truncated value must be terminated with zero.")
220 }
221 }
222
223 Self {
224 buffer,
225 indicator: indicator.to_isize(),
226 kind: PhantomData,
227 }
228 }
229
230 /// Call this method to ensure that the entire field content did fit into the buffer. If you
231 /// retrieve a field using [`crate::CursorRow::get_data`], you can repeat the call until this
232 /// method is false to read all the data.
233 ///
234 /// ```
235 /// use odbc_api::{CursorRow, parameter::VarCharArray, Error, handles::Statement};
236 ///
237 /// fn process_large_text(
238 /// col_index: u16,
239 /// row: &mut CursorRow<'_>
240 /// ) -> Result<(), Error>{
241 /// let mut buf = VarCharArray::<512>::NULL;
242 /// row.get_data(col_index, &mut buf)?;
243 /// while !buf.is_complete() {
244 /// // Process bytes in stream without allocation. We can assume repeated calls to
245 /// // get_data do not return `None` since it would have done so on the first call.
246 /// process_text_slice(buf.as_bytes().unwrap());
247 /// }
248 /// Ok(())
249 /// }
250 ///
251 /// fn process_text_slice(text: &[u8]) { /*...*/}
252 ///
253 /// ```
254 ///
255 /// ```
256 /// use odbc_api::{CursorRow, parameter::VarBinaryArray, Error, handles::Statement};
257 ///
258 /// fn process_large_binary(
259 /// col_index: u16,
260 /// row: &mut CursorRow<'_>
261 /// ) -> Result<(), Error>{
262 /// let mut buf = VarBinaryArray::<512>::NULL;
263 /// row.get_data(col_index, &mut buf)?;
264 /// while !buf.is_complete() {
265 /// // Process bytes in stream without allocation. We can assume repeated calls to
266 /// // get_data do not return `None` since it would have done so on the first call.
267 /// process_slice(buf.as_bytes().unwrap());
268 /// }
269 /// Ok(())
270 /// }
271 ///
272 /// fn process_slice(text: &[u8]) { /*...*/}
273 ///
274 /// ```
275 pub fn is_complete(&self) -> bool {
276 let slice = self.buffer.borrow();
277 let max_value_length = if ends_in_zeroes(slice, K::TERMINATING_ZEROES, K::ZERO) {
278 slice.len() - K::TERMINATING_ZEROES
279 } else {
280 slice.len()
281 };
282 !self
283 .indicator()
284 .is_truncated(max_value_length * size_of::<K::Element>())
285 }
286
287 /// Read access to the underlying ODBC indicator. After data has been fetched the indicator
288 /// value is set to the length the buffer should have had to hold the entire value. It may also
289 /// be [`Indicator::Null`] to indicate `NULL` or [`Indicator::NoTotal`] which tells us the data
290 /// source does not know how big the buffer must be to hold the complete value.
291 /// [`Indicator::NoTotal`] implies that the content of the current buffer is valid up to its
292 /// maximum capacity.
293 pub fn indicator(&self) -> Indicator {
294 Indicator::from_isize(self.indicator)
295 }
296
297 /// Call this method to reset the indicator to a value which matches the length returned by the
298 /// [`Self::as_bytes`] method. This is useful if you want to insert values into the database
299 /// despite the fact, that they might have been truncated. Otherwise the behaviour of databases
300 /// in this situation is driver specific. Some drivers insert up to the terminating zero, others
301 /// detect the truncation and throw an error.
302 pub fn hide_truncation(&mut self) {
303 if !self.is_complete() {
304 let binary_length = size_of_val(self.buffer.borrow());
305 self.indicator = (binary_length - K::TERMINATING_ZEROES).try_into().unwrap();
306 }
307 }
308
309 /// Length of the (potentially truncated) value within the cell in bytes. Excluding
310 /// terminating zero.
311 pub fn len_in_bytes(&self) -> Option<usize> {
312 // The maximum length is one larger for untruncated values without terminating zero. E.g.
313 // if instantiated from string literal.
314 let max_trunc_len_in_bytes =
315 (self.buffer.borrow().len() - K::TERMINATING_ZEROES) * size_of::<K::Element>();
316 match self.indicator() {
317 Indicator::Null => None,
318 Indicator::NoTotal => Some(max_trunc_len_in_bytes),
319 Indicator::Length(len) => {
320 if self.is_complete() {
321 Some(len)
322 } else {
323 Some(max_trunc_len_in_bytes)
324 }
325 }
326 }
327 }
328
329 /// The payload in bytes the buffer can hold including terminating zeroes
330 pub fn capacity_in_bytes(&self) -> usize {
331 size_of_val(self.buffer.borrow())
332 }
333
334 /// Method backing the implementation of the CElement trait
335 fn impl_assert_completness(&self) {
336 // There is one edge case in that this is different from `is_complete``, and this is with
337 // regards to values of which the payload ends with a terminating zero. All we care about
338 // is that the buffer we bind as input is valid. Not necessarily if the value in it is
339 // complete.
340 let slice = self.buffer.borrow();
341 // Terminating zero intenionally not accounted for. Since `VarCell` may hold values without
342 // it, if constructed from string literals.
343 let max_len_bytes = size_of_val(slice);
344 if self.indicator().is_truncated(max_len_bytes) {
345 panic!("Truncated values must not be used be bound as input parameters.")
346 }
347 }
348}
349
350impl<B, K> VarCell<B, K>
351where
352 B: Borrow<[K::Element]>,
353 K: VarKind,
354{
355 /// Valid payload of the buffer (excluding terminating zeroes) returned as slice or `None` in
356 /// case the indicator is `NULL_DATA`.
357 pub fn as_slice(&self) -> Option<&[K::Element]> {
358 let slice = self.buffer.borrow();
359 self.len_in_bytes()
360 .map(|len| &slice[..(len / size_of::<K::Element>())])
361 }
362}
363
364impl<B, K> VarCell<B, K>
365where
366 B: Borrow<[u8]>,
367 K: VarKind<Element = u8>,
368{
369 /// Valid payload of the buffer (excluding terminating zeroes) returned as slice or `None` in
370 /// case the indicator is `NULL_DATA`.
371 pub fn as_bytes(&self) -> Option<&[u8]> {
372 self.as_slice()
373 }
374}
375
376impl<B> VarCell<B, Text>
377where
378 B: Borrow<[u8]>,
379{
380 pub fn as_str(&self) -> Result<Option<&str>, Utf8Error> {
381 if let Some(bytes) = self.as_bytes() {
382 let text = std::str::from_utf8(bytes)?;
383 Ok(Some(text))
384 } else {
385 Ok(None)
386 }
387 }
388}
389
390impl<B> VarCell<B, WideText>
391where
392 B: Borrow<[u16]>,
393{
394 pub fn as_utf16(&self) -> Option<&U16Str> {
395 if let Some(chars) = self.as_slice() {
396 let text = U16Str::from_slice(chars);
397 Some(text)
398 } else {
399 None
400 }
401 }
402}
403
404unsafe impl<B, K> CData for VarCell<B, K>
405where
406 B: Borrow<[K::Element]>,
407 K: VarKind,
408{
409 fn cdata_type(&self) -> CDataType {
410 K::C_DATA_TYPE
411 }
412
413 fn indicator_ptr(&self) -> *const isize {
414 &self.indicator as *const isize
415 }
416
417 fn value_ptr(&self) -> *const c_void {
418 self.buffer.borrow().as_ptr() as *const c_void
419 }
420
421 fn buffer_length(&self) -> isize {
422 // This is the maximum buffer length, but it is NOT the length of an instance of Self due to
423 // the missing size of the indicator value. As such the buffer length can not be used to
424 // correctly index a columnar buffer of Self.
425 size_of_val(self.buffer.borrow()).try_into().unwrap()
426 }
427}
428
429impl<B, K> HasDataType for VarCell<B, K>
430where
431 B: Borrow<[K::Element]>,
432 K: VarKind,
433{
434 fn data_type(&self) -> DataType {
435 K::relational_type(self.buffer.borrow().len())
436 }
437}
438
439unsafe impl<B, K> CDataMut for VarCell<B, K>
440where
441 B: BorrowMut<[K::Element]>,
442 K: VarKind,
443{
444 fn mut_indicator_ptr(&mut self) -> *mut isize {
445 &mut self.indicator as *mut isize
446 }
447
448 fn mut_value_ptr(&mut self) -> *mut c_void {
449 self.buffer.borrow_mut().as_mut_ptr() as *mut c_void
450 }
451}
452
453/// Binds a byte array as a VarChar input parameter.
454///
455/// While a byte array can provide us with a pointer to the start of the array and the length of the
456/// array itself, it can not provide us with a pointer to the length of the buffer. So to bind
457/// strings which are not zero terminated we need to store the length in a separate value.
458///
459/// This type is created if `into_parameter` of the `IntoParameter` trait is called on a `&str`.
460///
461/// # Example
462///
463/// ```no_run
464/// use odbc_api::{Environment, ConnectionOptions, IntoParameter};
465///
466/// let env = Environment::new()?;
467///
468/// let mut conn = env.connect(
469/// "YourDatabase", "SA", "My@Test@Password1",
470/// ConnectionOptions::default()
471/// )?;
472/// if let Some(cursor) = conn.execute(
473/// "SELECT year FROM Birthdays WHERE name=?;",
474/// &"Bernd".into_parameter(),
475/// None)?
476/// {
477/// // Use cursor to process query results.
478/// };
479/// # Ok::<(), odbc_api::Error>(())
480/// ```
481pub type VarCharSlice<'a> = VarChar<&'a [u8]>;
482
483pub type VarWCharSlice<'a> = VarWChar<&'a [u16]>;
484
485/// Binds a byte array as a variadic binary input parameter.
486///
487/// While a byte array can provide us with a pointer to the start of the array and the length of the
488/// array itself, it can not provide us with a pointer to the length of the buffer. So to bind
489/// byte slices (`&[u8]`) we need to store the length in a separate value.
490///
491/// This type is created if `into_parameter` of the `IntoParameter` trait is called on a `&[u8]`.
492pub type VarBinarySlice<'a> = VarBinary<&'a [u8]>;
493
494impl<K> VarCell<&'_ [u8], K> {
495 /// Indicates missing data
496 pub const NULL: Self = Self {
497 // We do not want to use the empty buffer (`&[]`) here. It would be bound as `VARCHAR(0)`
498 // which caused errors with Microsoft Access and older versions of the Microsoft SQL Server
499 // ODBC driver.
500 buffer: &[0],
501 indicator: NULL_DATA,
502 kind: PhantomData,
503 };
504}
505
506impl<K> VarCell<&'_ [u16], K> {
507 /// Indicates missing data
508 pub const NULL: Self = Self {
509 // We do not want to use the empty buffer (`&[]`) here. It would be bound as `VARCHAR(0)`
510 // which caused errors with Microsoft Access and older versions of the Microsoft SQL Server
511 // ODBC driver.
512 buffer: &[0],
513 indicator: NULL_DATA,
514 kind: PhantomData,
515 };
516}
517
518impl<'a, K> VarCell<&'a [K::Element], K>
519where
520 K: VarKind,
521{
522 /// Constructs a new VarChar containing the text in the specified buffer.
523 ///
524 /// Caveat: This constructor is going to create a truncated value in case the input slice ends
525 /// with `nul`. Should you want to insert an actual string those payload ends with `nul` into
526 /// the database you need a buffer one byte longer than the string. You can instantiate such a
527 /// value using [`Self::from_buffer`].
528 pub fn new(value: &'a [K::Element]) -> Self {
529 Self::from_buffer(value, Indicator::Length(size_of_val(value)))
530 }
531}
532
533/// Wraps a slice so it can be used as an output parameter for narrow character data.
534pub type VarCharSliceMut<'a> = VarChar<&'a mut [u8]>;
535
536/// Wraps a slice so it can be used as an output parameter for wide character data.
537pub type VarWCharSliceMut<'a> = VarWChar<&'a mut [u8]>;
538
539/// Wraps a slice so it can be used as an output parameter for binary data.
540pub type VarBinarySliceMut<'a> = VarBinary<&'a mut [u8]>;
541
542/// A stack allocated VARCHAR type.
543///
544/// Due to its memory layout this type can be bound either as a single parameter, or as a column of
545/// a row-by-row output, but not be used in columnar parameter arrays or output buffers.
546///
547/// You can also use [`VarCharArray`] as an output type for statement execution using
548/// [`crate::parameter::Out`] or [`crate::parameter::InOut`].
549///
550/// # Example
551///
552/// ```no_run
553/// # use odbc_api::{Connection, Error, parameter::{VarCharArray, Out}};
554/// # fn output_example(connection: Connection<'_>) -> Result<(), Error> {
555/// let mut out_msg: VarCharArray<255> = VarCharArray::NULL;
556/// connection.execute("CALL PROCEDURE_NAME(?)", (Out(&mut out_msg),), None)?;
557/// # Ok(())
558/// # }
559/// ```
560pub type VarCharArray<const LENGTH: usize> = VarChar<[u8; LENGTH]>;
561
562/// A stack allocated NVARCHAR type.
563///
564/// Due to its memory layout this type can be bound either as a single parameter, or as a column of
565/// a row-by-row output, but not be used in columnar parameter arrays or output buffers.
566pub type VarWCharArray<const LENGTH: usize> = VarWChar<[u16; LENGTH]>;
567
568/// A stack allocated VARBINARY type.
569///
570/// Due to its memory layout this type can be bound either as a single parameter, or as a column of
571/// a row-by-row output, but not be used in columnar parameter arrays or output buffers.
572pub type VarBinaryArray<const LENGTH: usize> = VarBinary<[u8; LENGTH]>;
573
574impl<const LENGTH: usize, K, E> Default for VarCell<[E; LENGTH], K>
575where
576 E: Default + Copy,
577{
578 fn default() -> Self {
579 Self {
580 buffer: [E::default(); LENGTH],
581 indicator: Indicator::Null.to_isize(),
582 kind: Default::default(),
583 }
584 }
585}
586
587impl<const LENGTH: usize, K: VarKind> VarCell<[K::Element; LENGTH], K> {
588 /// Indicates a missing value.
589 pub const NULL: Self = Self {
590 buffer: [K::ZERO; LENGTH],
591 indicator: NULL_DATA,
592 kind: PhantomData,
593 };
594
595 /// Construct from a slice. If value is longer than `LENGTH` it will be truncated. In that case
596 /// the last byte will be set to `0`.
597 pub fn new(elements: &[K::Element]) -> Self {
598 let indicator = (size_of_val(elements)).try_into().unwrap();
599 let mut buffer = [K::ZERO; LENGTH];
600 if elements.len() > LENGTH {
601 buffer.copy_from_slice(&elements[..LENGTH]);
602 *buffer.last_mut().unwrap() = K::ZERO;
603 } else {
604 buffer[..elements.len()].copy_from_slice(elements);
605 };
606 Self {
607 buffer,
608 indicator,
609 kind: PhantomData,
610 }
611 }
612}
613
614/// Figures out, wether or not the buffer ends with a fixed number of zeroes.
615fn ends_in_zeroes<T>(buffer: &[T], number_of_zeroes: usize, zero: T) -> bool
616where
617 T: Copy + Eq,
618{
619 buffer.len() >= number_of_zeroes
620 && buffer
621 .iter()
622 .rev()
623 .copied()
624 .take(number_of_zeroes)
625 .all(|byte| byte == zero)
626}
627
628// We can't go all out and implement these traits for anything implementing Borrow and BorrowMut,
629// because erroneous but still safe implementation of these traits could cause invalid memory access
630// down the road. E.g. think about returning a different slice with a different length for borrow
631// and borrow_mut.
632unsafe impl<K: VarKind> CElement for VarCell<&'_ [K::Element], K> {
633 fn assert_completness(&self) {
634 self.impl_assert_completness()
635 }
636}
637
638unsafe impl<const LENGTH: usize, K: VarKind> CElement for VarCell<[K::Element; LENGTH], K> {
639 fn assert_completness(&self) {
640 self.impl_assert_completness()
641 }
642}
643unsafe impl<const LENGTH: usize, K: VarKind> OutputParameter for VarCell<[K::Element; LENGTH], K> {}
644
645unsafe impl<K: VarKind> CElement for VarCell<&'_ mut [K::Element], K> {
646 fn assert_completness(&self) {
647 self.impl_assert_completness()
648 }
649}
650unsafe impl<K: VarKind> OutputParameter for VarCell<&'_ mut [K::Element], K> {}
651
652unsafe impl<K: VarKind> CElement for VarCell<Box<[K::Element]>, K> {
653 fn assert_completness(&self) {
654 self.impl_assert_completness()
655 }
656}
657unsafe impl<K: VarKind> OutputParameter for VarCell<Box<[K::Element]>, K> {}
658
659unsafe impl<const LENGTH: usize> FetchRowMember for VarCharArray<LENGTH> {
660 fn indicator(&self) -> Option<Indicator> {
661 Some(self.indicator())
662 }
663}
664
665unsafe impl<const LENGTH: usize> FetchRowMember for VarWCharArray<LENGTH> {
666 fn indicator(&self) -> Option<Indicator> {
667 Some(self.indicator())
668 }
669}
670
671unsafe impl<const LENGTH: usize> FetchRowMember for VarBinaryArray<LENGTH> {
672 fn indicator(&self) -> Option<Indicator> {
673 Some(self.indicator())
674 }
675}
676
677#[cfg(test)]
678mod tests {
679
680 use super::{Indicator, VarCharSlice};
681
682 #[test]
683 fn must_accept_fitting_values_and_correctly_truncated_ones() {
684 // Fine: not truncated
685 VarCharSlice::from_buffer(b"12345", Indicator::Length(5));
686 // Fine: truncated, but ends in zero
687 VarCharSlice::from_buffer(b"1234\0", Indicator::Length(10));
688 }
689
690 #[test]
691 #[should_panic]
692 fn must_ensure_truncated_values_are_terminated() {
693 // Not fine, value is too long, but not terminated by zero
694 VarCharSlice::from_buffer(b"12345", Indicator::Length(10));
695 }
696}