1#![allow(unsafe_code)] use mysqlclient_sys as ffi;
3use std::mem;
4use std::mem::MaybeUninit;
5use std::ops::Index;
6use std::os::raw as libc;
7use std::ptr::NonNull;
8
9use super::stmt::MysqlFieldMetadata;
10use super::stmt::StatementUse;
11use crate::mysql::connection::stmt::StatementMetadata;
12use crate::mysql::types::date_and_time::MysqlTime;
13use crate::mysql::{MysqlType, MysqlValue};
14use crate::result::QueryResult;
15
16pub(super) struct PreparedStatementBinds(Binds);
17
18pub(super) struct OutputBinds(Binds);
19
20impl Clone for OutputBinds {
21 fn clone(&self) -> Self {
22 Self(Binds {
23 data: self.0.data.clone(),
24 })
25 }
26}
27
28struct Binds {
29 data: Vec<BindData>,
30}
31
32impl PreparedStatementBinds {
33 pub(super) fn from_input_data<Iter>(input: Iter) -> Self
34 where
35 Iter: IntoIterator<Item = (MysqlType, Option<Vec<u8>>)>,
36 {
37 let data = input
38 .into_iter()
39 .map(BindData::for_input)
40 .collect::<Vec<_>>();
41
42 Self(Binds { data })
43 }
44
45 pub(super) fn with_mysql_binds<F, T>(&mut self, f: F) -> T
46 where
47 F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
48 {
49 self.0.with_mysql_binds(f)
50 }
51}
52
53impl OutputBinds {
54 pub(super) fn from_output_types(
55 types: &[Option<MysqlType>],
56 metadata: &StatementMetadata,
57 ) -> Self {
58 let data = metadata
59 .fields()
60 .iter()
61 .zip(types.iter().copied().chain(std::iter::repeat(None)))
62 .map(|(field, tpe)| BindData::for_output(tpe, field))
63 .collect();
64
65 Self(Binds { data })
66 }
67
68 pub(super) fn populate_dynamic_buffers(&mut self, stmt: &StatementUse<'_>) -> QueryResult<()> {
69 for (i, data) in self.0.data.iter_mut().enumerate() {
70 data.did_numeric_overflow_occur()?;
71 unsafe {
74 if let Some((mut bind, offset)) = data.bind_for_truncated_data() {
75 stmt.fetch_column(&mut bind, i, offset)?
76 } else {
77 data.update_buffer_length()
78 }
79 }
80 }
81
82 unsafe { self.with_mysql_binds(|bind_ptr| stmt.bind_result(bind_ptr)) }
83 }
84
85 pub(super) fn update_buffer_lengths(&mut self) {
86 for data in &mut self.0.data {
87 data.update_buffer_length();
88 }
89 }
90
91 pub(super) fn with_mysql_binds<F, T>(&mut self, f: F) -> T
92 where
93 F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
94 {
95 self.0.with_mysql_binds(f)
96 }
97}
98
99impl Binds {
100 fn with_mysql_binds<F, T>(&mut self, f: F) -> T
101 where
102 F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
103 {
104 let mut binds = self
105 .data
106 .iter_mut()
107 .map(|x| unsafe { x.mysql_bind() })
108 .collect::<Vec<_>>();
109 f(binds.as_mut_ptr())
110 }
111}
112
113impl Index<usize> for OutputBinds {
114 type Output = BindData;
115 fn index(&self, index: usize) -> &Self::Output {
116 &self.0.data[index]
117 }
118}
119
120bitflags::bitflags! {
121 #[derive(Clone, Copy, Debug)]
122 pub(crate) struct Flags: u32 {
123 const NOT_NULL_FLAG = 1;
124 const PRI_KEY_FLAG = 2;
125 const UNIQUE_KEY_FLAG = 4;
126 const MULTIPLE_KEY_FLAG = 8;
127 const BLOB_FLAG = 16;
128 const UNSIGNED_FLAG = 32;
129 const ZEROFILL_FLAG = 64;
130 const BINARY_FLAG = 128;
131 const ENUM_FLAG = 256;
132 const AUTO_INCREMENT_FLAG = 512;
133 const TIMESTAMP_FLAG = 1024;
134 const SET_FLAG = 2048;
135 const NO_DEFAULT_VALUE_FLAG = 4096;
136 const ON_UPDATE_NOW_FLAG = 8192;
137 const NUM_FLAG = 32768;
138 const PART_KEY_FLAG = 16384;
139 const GROUP_FLAG = 32768;
140 const UNIQUE_FLAG = 65536;
141 const BINCMP_FLAG = 130_172;
142 const GET_FIXED_FIELDS_FLAG = (1<<18);
143 const FIELD_IN_PART_FUNC_FLAG = (1 << 19);
144 }
145}
146
147impl From<u32> for Flags {
148 fn from(flags: u32) -> Self {
149 Flags::from_bits(flags).expect(
150 "We encountered an unknown type flag while parsing \
151 Mysql's type information. If you see this error message \
152 please open an issue at diesels github page.",
153 )
154 }
155}
156
157#[derive(Debug)]
158pub(super) struct BindData {
159 tpe: ffi::enum_field_types,
160 bytes: Option<NonNull<u8>>,
161 length: libc::c_ulong,
162 capacity: usize,
163 flags: Flags,
164 is_null: ffi::my_bool,
165 is_truncated: Option<ffi::my_bool>,
166}
167
168impl Clone for BindData {
172 fn clone(&self) -> Self {
173 let (ptr, len, capacity) = if let Some(ptr) = self.bytes {
174 let slice = unsafe {
175 std::slice::from_raw_parts(
183 ptr.as_ptr(),
184 self.length.try_into().expect("usize is at least 32bit"),
185 )
186 };
187 let mut vec = slice.to_owned();
188 let ptr = NonNull::new(vec.as_mut_ptr());
189 let len = vec.len() as libc::c_ulong;
190 let capacity = vec.capacity();
191 mem::forget(vec);
192 (ptr, len, capacity)
193 } else {
194 (None, 0, 0)
195 };
196 Self {
197 tpe: self.tpe,
198 bytes: ptr,
199 length: len,
200 capacity,
201 flags: self.flags,
202 is_null: self.is_null,
203 is_truncated: self.is_truncated,
204 }
205 }
206}
207
208impl Drop for BindData {
209 fn drop(&mut self) {
210 if let Some(bytes) = self.bytes {
211 std::mem::drop(unsafe {
212 Vec::from_raw_parts(bytes.as_ptr(), 0, self.capacity)
219 });
220 self.bytes = None;
221 }
222 }
223}
224
225impl BindData {
226 fn for_input((tpe, data): (MysqlType, Option<Vec<u8>>)) -> Self {
227 let (tpe, flags) = tpe.into();
228 let is_null = ffi::my_bool::from(data.is_none());
229 let mut bytes = data.unwrap_or_default();
230 let ptr = NonNull::new(bytes.as_mut_ptr());
231 let len = bytes.len() as libc::c_ulong;
232 let capacity = bytes.capacity();
233 mem::forget(bytes);
234 Self {
235 tpe,
236 bytes: ptr,
237 length: len,
238 capacity,
239 flags,
240 is_null,
241 is_truncated: None,
242 }
243 }
244
245 fn for_output(tpe: Option<MysqlType>, metadata: &MysqlFieldMetadata<'_>) -> Self {
246 let (tpe, flags) = if let Some(tpe) = tpe {
247 match (tpe, metadata.field_type()) {
248 (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
251 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_TINY)
252 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_SHORT)
253 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_LONG)
254 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
255 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
256 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_INT24)
257 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
258 | (MysqlType::Tiny, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
259 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
260 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_TINY)
261 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_SHORT)
262 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_LONG)
263 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
264 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
265 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_INT24)
266 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
267 | (MysqlType::UnsignedTiny, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
268 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
269 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_TINY)
270 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_SHORT)
271 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_LONG)
272 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
273 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
274 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_INT24)
275 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
276 | (MysqlType::Short, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
277 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
278 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_TINY)
279 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_SHORT)
280 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_LONG)
281 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
282 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
283 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_INT24)
284 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
285 | (MysqlType::UnsignedShort, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
286 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
287 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_TINY)
288 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_SHORT)
289 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_LONG)
290 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
291 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
292 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_INT24)
293 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
294 | (MysqlType::Long, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
295 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
296 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_TINY)
297 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_SHORT)
298 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_LONG)
299 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
300 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
301 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_INT24)
302 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
303 | (MysqlType::UnsignedLong, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
304 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
305 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_TINY)
306 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_SHORT)
307 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_LONG)
308 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
309 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
310 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_INT24)
311 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
312 | (MysqlType::LongLong, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
313 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
314 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_TINY)
315 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_SHORT)
316 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_LONG)
317 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
318 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
319 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_INT24)
320 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
321 | (MysqlType::UnsignedLongLong, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
322 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
323 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_TINY)
324 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_SHORT)
325 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_LONG)
326 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
327 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
328 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_INT24)
329 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
330 | (MysqlType::Float, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
331 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_DECIMAL)
332 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_TINY)
333 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_SHORT)
334 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_LONG)
335 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_FLOAT)
336 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_DOUBLE)
337 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_INT24)
338 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL)
339 | (MysqlType::Numeric, ffi::enum_field_types::MYSQL_TYPE_LONGLONG)
340 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_JSON)
341 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_ENUM)
342 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_SET)
343 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB)
344 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB)
345 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB)
346 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_BLOB)
347 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_VAR_STRING)
348 | (MysqlType::String, ffi::enum_field_types::MYSQL_TYPE_STRING)
349 | (MysqlType::Blob, ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB)
350 | (MysqlType::Blob, ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB)
351 | (MysqlType::Blob, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB)
352 | (MysqlType::Blob, ffi::enum_field_types::MYSQL_TYPE_BLOB)
353 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_ENUM)
354 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_SET)
355 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB)
356 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB)
357 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB)
358 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_BLOB)
359 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_VAR_STRING)
360 | (MysqlType::Set, ffi::enum_field_types::MYSQL_TYPE_STRING)
361 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_ENUM)
362 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_SET)
363 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB)
364 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB)
365 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB)
366 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_BLOB)
367 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_VAR_STRING)
368 | (MysqlType::Enum, ffi::enum_field_types::MYSQL_TYPE_STRING) => {
369 (metadata.field_type(), metadata.flags())
370 }
371
372 (tpe, _) => tpe.into(),
373 }
374 } else {
375 (metadata.field_type(), metadata.flags())
376 };
377 Self::from_tpe_and_flags((tpe, flags))
378 }
379
380 fn from_tpe_and_flags((tpe, flags): (ffi::enum_field_types, Flags)) -> Self {
381 let len = known_buffer_size_for_ffi_type(tpe).unwrap_or(1);
383 let mut bytes = vec![0; len];
384 let length = bytes.len() as libc::c_ulong;
385 let capacity = bytes.capacity();
386 let ptr = NonNull::new(bytes.as_mut_ptr());
387 mem::forget(bytes);
388
389 Self {
390 tpe,
391 bytes: ptr,
392 length,
393 capacity,
394 flags,
395 is_null: super::raw::ffi_false(),
396 is_truncated: Some(super::raw::ffi_false()),
397 }
398 }
399
400 fn is_truncated(&self) -> bool {
401 self.is_truncated.unwrap_or(super::raw::ffi_false()) != super::raw::ffi_false()
402 }
403
404 fn is_fixed_size_buffer(&self) -> bool {
405 known_buffer_size_for_ffi_type(self.tpe).is_some()
406 }
407
408 pub(super) fn value(&'_ self) -> Option<MysqlValue<'_>> {
409 if self.is_null() {
410 None
411 } else {
412 let data = self.bytes?;
413 let tpe = (self.tpe, self.flags).into();
414 if self.tpe == self::ffi::enum_field_types::MYSQL_TYPE_LONGLONG && self.length == 0 {
417 return None;
418 }
419
420 let slice = unsafe {
421 std::slice::from_raw_parts(
429 data.as_ptr(),
430 self.length.try_into().expect("Usize is at least 32 bit"),
431 )
432 };
433 Some(MysqlValue::new_internal(slice, tpe))
434 }
435 }
436
437 pub(super) fn is_null(&self) -> bool {
438 self.is_null != ffi::my_bool::default()
439 }
440
441 fn update_buffer_length(&mut self) {
442 use std::cmp::min;
443
444 let actual_bytes_in_buffer = min(
445 self.capacity,
446 self.length.try_into().expect("Usize is at least 32 bit"),
447 );
448 self.length = actual_bytes_in_buffer as libc::c_ulong;
449 }
450
451 unsafe fn mysql_bind(&mut self) -> ffi::MYSQL_BIND {
455 use std::ptr::addr_of_mut;
456
457 let mut bind: MaybeUninit<ffi::MYSQL_BIND> = mem::MaybeUninit::zeroed();
458 let ptr = bind.as_mut_ptr();
459
460 addr_of_mut!((*ptr).buffer_type).write(self.tpe);
461 addr_of_mut!((*ptr).buffer).write(
462 self.bytes
463 .map(|p| p.as_ptr())
464 .unwrap_or(std::ptr::null_mut()) as *mut libc::c_void,
465 );
466 addr_of_mut!((*ptr).buffer_length).write(self.capacity as libc::c_ulong);
467 addr_of_mut!((*ptr).length).write(&mut self.length);
468 addr_of_mut!((*ptr).is_null).write(&mut self.is_null);
469 addr_of_mut!((*ptr).is_unsigned)
470 .write(self.flags.contains(Flags::UNSIGNED_FLAG) as ffi::my_bool);
471
472 if let Some(ref mut is_truncated) = self.is_truncated {
473 addr_of_mut!((*ptr).error).write(is_truncated);
474 }
475
476 bind.assume_init()
478 }
479
480 unsafe fn bind_for_truncated_data(&mut self) -> Option<(ffi::MYSQL_BIND, usize)> {
487 if self.is_truncated() {
488 if let Some(bytes) = self.bytes {
489 let mut bytes = Vec::from_raw_parts(bytes.as_ptr(), self.capacity, self.capacity);
490 self.bytes = None;
491
492 let offset = self.capacity;
493 let truncated_amount =
494 usize::try_from(self.length).expect("Usize is at least 32 bit") - offset;
495
496 debug_assert!(
497 truncated_amount > 0,
498 "output buffers were invalidated \
499 without calling `mysql_stmt_bind_result`"
500 );
501
502 bytes.reserve(truncated_amount);
505 self.capacity = bytes.capacity();
506 self.bytes = NonNull::new(bytes.as_mut_ptr());
507 mem::forget(bytes);
508
509 let mut bind = self.mysql_bind();
510
511 if let Some(ptr) = self.bytes {
512 bind.buffer = ptr.as_ptr().add(offset) as *mut libc::c_void;
515 bind.buffer_length = truncated_amount as libc::c_ulong;
516 } else {
517 bind.buffer_length = 0;
518 }
519 Some((bind, offset))
520 } else {
521 let mut vec = vec![0_u8; self.length.try_into().expect("usize is at least 32 bit")];
525 self.capacity = vec.capacity();
526 self.bytes = NonNull::new(vec.as_mut_ptr());
527 mem::forget(vec);
528
529 let bind = self.mysql_bind();
530 Some((bind, 0))
534 }
535 } else {
536 None
537 }
538 }
539
540 fn did_numeric_overflow_occur(&self) -> QueryResult<()> {
541 use crate::result::Error::DeserializationError;
542
543 if self.is_truncated() && self.is_fixed_size_buffer() {
544 Err(DeserializationError(
545 "Numeric overflow/underflow occurred".into(),
546 ))
547 } else {
548 Ok(())
549 }
550 }
551}
552
553impl From<MysqlType> for (ffi::enum_field_types, Flags) {
554 fn from(tpe: MysqlType) -> Self {
555 use self::ffi::enum_field_types;
556 let mut flags = Flags::empty();
557 let tpe = match tpe {
558 MysqlType::Tiny => enum_field_types::MYSQL_TYPE_TINY,
559 MysqlType::Short => enum_field_types::MYSQL_TYPE_SHORT,
560 MysqlType::Long => enum_field_types::MYSQL_TYPE_LONG,
561 MysqlType::LongLong => enum_field_types::MYSQL_TYPE_LONGLONG,
562 MysqlType::Float => enum_field_types::MYSQL_TYPE_FLOAT,
563 MysqlType::Double => enum_field_types::MYSQL_TYPE_DOUBLE,
564 MysqlType::Time => enum_field_types::MYSQL_TYPE_TIME,
565 MysqlType::Date => enum_field_types::MYSQL_TYPE_DATE,
566 MysqlType::DateTime => enum_field_types::MYSQL_TYPE_DATETIME,
567 MysqlType::Timestamp => enum_field_types::MYSQL_TYPE_TIMESTAMP,
568 MysqlType::String => enum_field_types::MYSQL_TYPE_STRING,
569 MysqlType::Blob => enum_field_types::MYSQL_TYPE_BLOB,
570 MysqlType::Numeric => enum_field_types::MYSQL_TYPE_NEWDECIMAL,
571 MysqlType::Bit => enum_field_types::MYSQL_TYPE_BIT,
572 MysqlType::UnsignedTiny => {
573 flags = Flags::UNSIGNED_FLAG;
574 enum_field_types::MYSQL_TYPE_TINY
575 }
576 MysqlType::UnsignedShort => {
577 flags = Flags::UNSIGNED_FLAG;
578 enum_field_types::MYSQL_TYPE_SHORT
579 }
580 MysqlType::UnsignedLong => {
581 flags = Flags::UNSIGNED_FLAG;
582 enum_field_types::MYSQL_TYPE_LONG
583 }
584 MysqlType::UnsignedLongLong => {
585 flags = Flags::UNSIGNED_FLAG;
586 enum_field_types::MYSQL_TYPE_LONGLONG
587 }
588 MysqlType::Set => {
589 flags = Flags::SET_FLAG;
590 enum_field_types::MYSQL_TYPE_STRING
591 }
592 MysqlType::Enum => {
593 flags = Flags::ENUM_FLAG;
594 enum_field_types::MYSQL_TYPE_STRING
595 }
596 };
597 (tpe, flags)
598 }
599}
600
601impl From<(ffi::enum_field_types, Flags)> for MysqlType {
602 fn from((tpe, flags): (ffi::enum_field_types, Flags)) -> Self {
603 use self::ffi::enum_field_types;
604
605 let is_unsigned = flags.contains(Flags::UNSIGNED_FLAG);
606
607 match tpe {
612 enum_field_types::MYSQL_TYPE_TINY if is_unsigned => MysqlType::UnsignedTiny,
613 enum_field_types::MYSQL_TYPE_YEAR | enum_field_types::MYSQL_TYPE_SHORT
614 if is_unsigned =>
615 {
616 MysqlType::UnsignedShort
617 }
618 enum_field_types::MYSQL_TYPE_INT24 | enum_field_types::MYSQL_TYPE_LONG
619 if is_unsigned =>
620 {
621 MysqlType::UnsignedLong
622 }
623 enum_field_types::MYSQL_TYPE_LONGLONG if is_unsigned => MysqlType::UnsignedLongLong,
624 enum_field_types::MYSQL_TYPE_TINY => MysqlType::Tiny,
625 enum_field_types::MYSQL_TYPE_SHORT => MysqlType::Short,
626 enum_field_types::MYSQL_TYPE_INT24 | enum_field_types::MYSQL_TYPE_LONG => {
627 MysqlType::Long
628 }
629 enum_field_types::MYSQL_TYPE_LONGLONG => MysqlType::LongLong,
630 enum_field_types::MYSQL_TYPE_FLOAT => MysqlType::Float,
631 enum_field_types::MYSQL_TYPE_DOUBLE => MysqlType::Double,
632 enum_field_types::MYSQL_TYPE_DECIMAL | enum_field_types::MYSQL_TYPE_NEWDECIMAL => {
633 MysqlType::Numeric
634 }
635 enum_field_types::MYSQL_TYPE_BIT => MysqlType::Bit,
636
637 enum_field_types::MYSQL_TYPE_TIME => MysqlType::Time,
638 enum_field_types::MYSQL_TYPE_DATE => MysqlType::Date,
639 enum_field_types::MYSQL_TYPE_DATETIME => MysqlType::DateTime,
640 enum_field_types::MYSQL_TYPE_TIMESTAMP => MysqlType::Timestamp,
641 enum_field_types::MYSQL_TYPE_JSON => MysqlType::String,
644
645 enum_field_types::MYSQL_TYPE_BLOB
651 | enum_field_types::MYSQL_TYPE_TINY_BLOB
652 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
653 | enum_field_types::MYSQL_TYPE_LONG_BLOB
654 | enum_field_types::MYSQL_TYPE_VAR_STRING
655 | enum_field_types::MYSQL_TYPE_STRING
656 if flags.contains(Flags::ENUM_FLAG) =>
657 {
658 MysqlType::Enum
659 }
660 enum_field_types::MYSQL_TYPE_BLOB
661 | enum_field_types::MYSQL_TYPE_TINY_BLOB
662 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
663 | enum_field_types::MYSQL_TYPE_LONG_BLOB
664 | enum_field_types::MYSQL_TYPE_VAR_STRING
665 | enum_field_types::MYSQL_TYPE_STRING
666 if flags.contains(Flags::SET_FLAG) =>
667 {
668 MysqlType::Set
669 }
670
671 enum_field_types::MYSQL_TYPE_BLOB
676 | enum_field_types::MYSQL_TYPE_TINY_BLOB
677 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
678 | enum_field_types::MYSQL_TYPE_LONG_BLOB
679 | enum_field_types::MYSQL_TYPE_VAR_STRING
680 | enum_field_types::MYSQL_TYPE_STRING
681 if flags.contains(Flags::BINARY_FLAG) =>
682 {
683 MysqlType::Blob
684 }
685
686 enum_field_types::MYSQL_TYPE_BLOB
688 | enum_field_types::MYSQL_TYPE_TINY_BLOB
689 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
690 | enum_field_types::MYSQL_TYPE_LONG_BLOB
691 | enum_field_types::MYSQL_TYPE_VAR_STRING
692 | enum_field_types::MYSQL_TYPE_STRING => MysqlType::String,
693
694 enum_field_types::MYSQL_TYPE_YEAR => unreachable!(
696 "The year type should have set the unsigned flag. If you ever \
697 see this error message, something has gone very wrong. Please \
698 open an issue at the diesel github repo in this case"
699 ),
700 enum_field_types::MYSQL_TYPE_NULL => unreachable!(
702 "We ensure at the call side that we do not hit this type here. \
703 If you ever see this error, something has gone very wrong. \
704 Please open an issue at the diesel github repo in this case"
705 ),
706 enum_field_types::MYSQL_TYPE_VARCHAR
710 | enum_field_types::MYSQL_TYPE_ENUM
711 | enum_field_types::MYSQL_TYPE_SET
712 | enum_field_types::MYSQL_TYPE_GEOMETRY => {
713 unimplemented!(
714 "Hit a type that should be unsupported in libmysqlclient. If \
715 you ever see this error, they probably have added support for \
716 one of those types. Please open an issue at the diesel github \
717 repo in this case."
718 )
719 }
720
721 enum_field_types::MYSQL_TYPE_NEWDATE
722 | enum_field_types::MYSQL_TYPE_TIME2
723 | enum_field_types::MYSQL_TYPE_DATETIME2
724 | enum_field_types::MYSQL_TYPE_TIMESTAMP2 => unreachable!(
725 "The mysql documentation states that these types are \
726 only used on the server side, so if you see this error \
727 something has gone wrong. Please open an issue at \
728 the diesel github repo."
729 ),
730 #[allow(unreachable_patterns)]
733 t => unreachable!(
734 "Unsupported type encountered: {t:?}. \
735 If you ever see this error, something has gone wrong. \
736 Please open an issue at the diesel github \
737 repo in this case."
738 ),
739 }
740 }
741}
742
743fn known_buffer_size_for_ffi_type(tpe: ffi::enum_field_types) -> Option<usize> {
744 use self::ffi::enum_field_types as t;
745 use std::mem::size_of;
746
747 match tpe {
748 t::MYSQL_TYPE_TINY => Some(1),
749 t::MYSQL_TYPE_YEAR | t::MYSQL_TYPE_SHORT => Some(2),
750 t::MYSQL_TYPE_INT24 | t::MYSQL_TYPE_LONG | t::MYSQL_TYPE_FLOAT => Some(4),
751 t::MYSQL_TYPE_LONGLONG | t::MYSQL_TYPE_DOUBLE => Some(8),
752 t::MYSQL_TYPE_TIME
753 | t::MYSQL_TYPE_DATE
754 | t::MYSQL_TYPE_DATETIME
755 | t::MYSQL_TYPE_TIMESTAMP => Some(size_of::<MysqlTime>()),
756 _ => None,
757 }
758}
759
760#[cfg(test)]
761mod tests {
762 use super::*;
763 use crate::connection::statement_cache::MaybeCached;
764 use crate::deserialize::FromSql;
765 use crate::mysql::connection::stmt::Statement;
766 use crate::prelude::*;
767 use crate::sql_types::*;
768 #[cfg(feature = "numeric")]
769 use std::str::FromStr;
770
771 fn to_value<ST, T>(
772 bind: &BindData,
773 ) -> Result<T, Box<(dyn std::error::Error + Send + Sync + 'static)>>
774 where
775 T: FromSql<ST, crate::mysql::Mysql> + std::fmt::Debug,
776 {
777 let meta = (bind.tpe, bind.flags).into();
778 dbg!(meta);
779
780 let value = bind.value().expect("Is not null");
781 let value = MysqlValue::new_internal(value.as_bytes(), meta);
782
783 dbg!(T::from_sql(value))
784 }
785
786 #[cfg(feature = "extras")]
787 #[test]
788 fn check_all_the_types() {
789 let conn = &mut crate::test_helpers::connection();
790
791 crate::sql_query("DROP TABLE IF EXISTS all_mysql_types CASCADE")
792 .execute(conn)
793 .unwrap();
794 crate::sql_query(
795 "CREATE TABLE all_mysql_types (
796 tiny_int TINYINT NOT NULL,
797 small_int SMALLINT NOT NULL,
798 medium_int MEDIUMINT NOT NULL,
799 int_col INTEGER NOT NULL,
800 big_int BIGINT NOT NULL,
801 unsigned_int INTEGER UNSIGNED NOT NULL,
802 zero_fill_int INTEGER ZEROFILL NOT NULL,
803 numeric_col NUMERIC(20,5) NOT NULL,
804 decimal_col DECIMAL(20,5) NOT NULL,
805 float_col FLOAT NOT NULL,
806 double_col DOUBLE NOT NULL,
807 bit_col BIT(8) NOT NULL,
808 date_col DATE NOT NULL,
809 date_time DATETIME NOT NULL,
810 timestamp_col TIMESTAMP NOT NULL,
811 time_col TIME NOT NULL,
812 year_col YEAR NOT NULL,
813 char_col CHAR(30) NOT NULL,
814 varchar_col VARCHAR(30) NOT NULL,
815 binary_col BINARY(30) NOT NULL,
816 varbinary_col VARBINARY(30) NOT NULL,
817 blob_col BLOB NOT NULL,
818 text_col TEXT NOT NULL,
819 enum_col ENUM('red', 'green', 'blue') NOT NULL,
820 set_col SET('one', 'two') NOT NULL,
821 geom GEOMETRY NOT NULL,
822 point_col POINT NOT NULL,
823 linestring_col LINESTRING NOT NULL,
824 polygon_col POLYGON NOT NULL,
825 multipoint_col MULTIPOINT NOT NULL,
826 multilinestring_col MULTILINESTRING NOT NULL,
827 multipolygon_col MULTIPOLYGON NOT NULL,
828 geometry_collection GEOMETRYCOLLECTION NOT NULL,
829 json_col JSON NOT NULL
830 )",
831 )
832 .execute(conn)
833 .unwrap();
834 crate::sql_query(
835 "INSERT INTO all_mysql_types VALUES (
836 0, -- tiny_int
837 1, -- small_int
838 2, -- medium_int
839 3, -- int_col
840 -5, -- big_int
841 42, -- unsigned_int
842 1, -- zero_fill_int
843 -999.999, -- numeric_col,
844 3.14, -- decimal_col,
845 1.23, -- float_col
846 4.5678, -- double_col
847 b'10101010', -- bit_col
848 '1000-01-01', -- date_col
849 '9999-12-31 12:34:45.012345', -- date_time
850 '2020-01-01 10:10:10', -- timestamp_col
851 '23:01:01', -- time_col
852 2020, -- year_col
853 'abc', -- char_col
854 'foo', -- varchar_col
855 'a ', -- binary_col
856 'a ', -- varbinary_col
857 'binary', -- blob_col
858 'some text whatever', -- text_col
859 'red', -- enum_col
860 'one', -- set_col
861 ST_GeomFromText('POINT(1 1)'), -- geom
862 ST_PointFromText('POINT(1 1)'), -- point_col
863 ST_LineStringFromText('LINESTRING(0 0,1 1,2 2)'), -- linestring_col
864 ST_PolygonFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))'), -- polygon_col
865 ST_MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)'), -- multipoint_col
866 ST_MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))'), -- multilinestring_col
867 ST_MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))'), -- multipolygon_col
868 ST_GeomCollFromText('GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))'), -- geometry_collection
869 '{\"key1\": \"value1\", \"key2\": \"value2\"}' -- json_col
870)",
871 ).execute(conn)
872 .unwrap();
873
874 let stmt = crate::mysql::connection::prepared_query(
875 &crate::sql_query(
876 "SELECT
877 tiny_int, small_int, medium_int, int_col,
878 big_int, unsigned_int, zero_fill_int,
879 numeric_col, decimal_col, float_col, double_col, bit_col,
880 date_col, date_time, timestamp_col, time_col, year_col,
881 char_col, varchar_col, binary_col, varbinary_col, blob_col,
882 text_col, enum_col, set_col, ST_AsText(geom), ST_AsText(point_col), ST_AsText(linestring_col),
883 ST_AsText(polygon_col), ST_AsText(multipoint_col), ST_AsText(multilinestring_col),
884 ST_AsText(multipolygon_col), ST_AsText(geometry_collection), json_col
885 FROM all_mysql_types",
886 ),
887 &mut conn.statement_cache,
888 &mut conn.raw_connection,
889 &mut conn.instrumentation,
890 ).unwrap();
891
892 let metadata = stmt.metadata().unwrap();
893 let mut output_binds =
894 OutputBinds::from_output_types(&vec![None; metadata.fields().len()], &metadata);
895 let stmt = stmt.execute_statement(&mut output_binds).unwrap();
896 stmt.populate_row_buffers(&mut output_binds).unwrap();
897
898 let results: Vec<(BindData, &_)> = output_binds
899 .0
900 .data
901 .into_iter()
902 .zip(metadata.fields())
903 .collect::<Vec<_>>();
904
905 let tiny_int_col = &results[0].0;
906 assert_eq!(tiny_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_TINY);
907 assert!(tiny_int_col.flags.contains(Flags::NUM_FLAG));
908 assert!(!tiny_int_col.flags.contains(Flags::UNSIGNED_FLAG));
909 assert!(matches!(to_value::<TinyInt, i8>(tiny_int_col), Ok(0)));
910
911 let small_int_col = &results[1].0;
912 assert_eq!(small_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_SHORT);
913 assert!(small_int_col.flags.contains(Flags::NUM_FLAG));
914 assert!(!small_int_col.flags.contains(Flags::UNSIGNED_FLAG));
915 assert!(matches!(to_value::<SmallInt, i16>(small_int_col), Ok(1)));
916
917 let medium_int_col = &results[2].0;
918 assert_eq!(medium_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_INT24);
919 assert!(medium_int_col.flags.contains(Flags::NUM_FLAG));
920 assert!(!medium_int_col.flags.contains(Flags::UNSIGNED_FLAG));
921 assert!(matches!(to_value::<Integer, i32>(medium_int_col), Ok(2)));
922
923 let int_col = &results[3].0;
924 assert_eq!(int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG);
925 assert!(int_col.flags.contains(Flags::NUM_FLAG));
926 assert!(!int_col.flags.contains(Flags::UNSIGNED_FLAG));
927 assert!(matches!(to_value::<Integer, i32>(int_col), Ok(3)));
928
929 let big_int_col = &results[4].0;
930 assert_eq!(big_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONGLONG);
931 assert!(big_int_col.flags.contains(Flags::NUM_FLAG));
932 assert!(!big_int_col.flags.contains(Flags::UNSIGNED_FLAG));
933 assert!(matches!(to_value::<TinyInt, i8>(big_int_col), Ok(-5)));
934
935 let unsigned_int_col = &results[5].0;
936 assert_eq!(unsigned_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG);
937 assert!(unsigned_int_col.flags.contains(Flags::NUM_FLAG));
938 assert!(unsigned_int_col.flags.contains(Flags::UNSIGNED_FLAG));
939 assert!(matches!(
940 to_value::<Unsigned<Integer>, u32>(unsigned_int_col),
941 Ok(42)
942 ));
943
944 let zero_fill_int_col = &results[6].0;
945 assert_eq!(
946 zero_fill_int_col.tpe,
947 ffi::enum_field_types::MYSQL_TYPE_LONG
948 );
949 assert!(zero_fill_int_col.flags.contains(Flags::NUM_FLAG));
950 assert!(zero_fill_int_col.flags.contains(Flags::ZEROFILL_FLAG));
951 assert!(matches!(to_value::<Integer, i32>(zero_fill_int_col), Ok(1)));
952
953 let numeric_col = &results[7].0;
954 assert_eq!(
955 numeric_col.tpe,
956 ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL
957 );
958 assert!(numeric_col.flags.contains(Flags::NUM_FLAG));
959 assert!(!numeric_col.flags.contains(Flags::UNSIGNED_FLAG));
960 assert_eq!(
961 to_value::<Numeric, bigdecimal::BigDecimal>(numeric_col).unwrap(),
962 bigdecimal::BigDecimal::from_str("-999.99900").unwrap()
963 );
964
965 let decimal_col = &results[8].0;
966 assert_eq!(
967 decimal_col.tpe,
968 ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL
969 );
970 assert!(decimal_col.flags.contains(Flags::NUM_FLAG));
971 assert!(!decimal_col.flags.contains(Flags::UNSIGNED_FLAG));
972 assert_eq!(
973 to_value::<Numeric, bigdecimal::BigDecimal>(decimal_col).unwrap(),
974 bigdecimal::BigDecimal::from_str("3.14000").unwrap()
975 );
976
977 let float_col = &results[9].0;
978 assert_eq!(float_col.tpe, ffi::enum_field_types::MYSQL_TYPE_FLOAT);
979 assert!(float_col.flags.contains(Flags::NUM_FLAG));
980 assert!(!float_col.flags.contains(Flags::UNSIGNED_FLAG));
981 assert_eq!(to_value::<Float, f32>(float_col).unwrap(), 1.23);
982
983 let double_col = &results[10].0;
984 assert_eq!(double_col.tpe, ffi::enum_field_types::MYSQL_TYPE_DOUBLE);
985 assert!(double_col.flags.contains(Flags::NUM_FLAG));
986 assert!(!double_col.flags.contains(Flags::UNSIGNED_FLAG));
987 assert_eq!(to_value::<Double, f64>(double_col).unwrap(), 4.5678);
988
989 let bit_col = &results[11].0;
990 assert_eq!(bit_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BIT);
991 assert!(!bit_col.flags.contains(Flags::NUM_FLAG));
992 assert!(bit_col.flags.contains(Flags::UNSIGNED_FLAG));
993 assert!(!bit_col.flags.contains(Flags::BINARY_FLAG));
994 assert_eq!(to_value::<Blob, Vec<u8>>(bit_col).unwrap(), vec![170]);
995
996 let date_col = &results[12].0;
997 assert_eq!(date_col.tpe, ffi::enum_field_types::MYSQL_TYPE_DATE);
998 assert!(!date_col.flags.contains(Flags::NUM_FLAG));
999 assert_eq!(
1000 to_value::<Date, chrono::NaiveDate>(date_col).unwrap(),
1001 chrono::NaiveDate::from_ymd_opt(1000, 1, 1).unwrap(),
1002 );
1003
1004 let date_time_col = &results[13].0;
1005 assert_eq!(
1006 date_time_col.tpe,
1007 ffi::enum_field_types::MYSQL_TYPE_DATETIME
1008 );
1009 assert!(!date_time_col.flags.contains(Flags::NUM_FLAG));
1010 assert_eq!(
1011 to_value::<Datetime, chrono::NaiveDateTime>(date_time_col).unwrap(),
1012 chrono::NaiveDateTime::parse_from_str("9999-12-31 12:34:45", "%Y-%m-%d %H:%M:%S")
1013 .unwrap()
1014 );
1015
1016 let timestamp_col = &results[14].0;
1017 assert_eq!(
1018 timestamp_col.tpe,
1019 ffi::enum_field_types::MYSQL_TYPE_TIMESTAMP
1020 );
1021 assert!(!timestamp_col.flags.contains(Flags::NUM_FLAG));
1022 assert_eq!(
1023 to_value::<Datetime, chrono::NaiveDateTime>(timestamp_col).unwrap(),
1024 chrono::NaiveDateTime::parse_from_str("2020-01-01 10:10:10", "%Y-%m-%d %H:%M:%S")
1025 .unwrap()
1026 );
1027
1028 let time_col = &results[15].0;
1029 assert_eq!(time_col.tpe, ffi::enum_field_types::MYSQL_TYPE_TIME);
1030 assert!(!time_col.flags.contains(Flags::NUM_FLAG));
1031 assert_eq!(
1032 to_value::<Time, chrono::NaiveTime>(time_col).unwrap(),
1033 chrono::NaiveTime::from_hms_opt(23, 01, 01).unwrap()
1034 );
1035
1036 let year_col = &results[16].0;
1037 assert_eq!(year_col.tpe, ffi::enum_field_types::MYSQL_TYPE_YEAR);
1038 assert!(year_col.flags.contains(Flags::NUM_FLAG));
1039 assert!(year_col.flags.contains(Flags::UNSIGNED_FLAG));
1040 assert!(matches!(to_value::<SmallInt, i16>(year_col), Ok(2020)));
1041
1042 let char_col = &results[17].0;
1043 assert_eq!(char_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1044 assert!(!char_col.flags.contains(Flags::NUM_FLAG));
1045 assert!(!char_col.flags.contains(Flags::BLOB_FLAG));
1046 assert!(!char_col.flags.contains(Flags::SET_FLAG));
1047 assert!(!char_col.flags.contains(Flags::ENUM_FLAG));
1048 assert!(!char_col.flags.contains(Flags::BINARY_FLAG));
1049 assert_eq!(to_value::<Text, String>(char_col).unwrap(), "abc");
1050
1051 let varchar_col = &results[18].0;
1052 assert_eq!(
1053 varchar_col.tpe,
1054 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING
1055 );
1056 assert!(!varchar_col.flags.contains(Flags::NUM_FLAG));
1057 assert!(!varchar_col.flags.contains(Flags::BLOB_FLAG));
1058 assert!(!varchar_col.flags.contains(Flags::SET_FLAG));
1059 assert!(!varchar_col.flags.contains(Flags::ENUM_FLAG));
1060 assert!(!varchar_col.flags.contains(Flags::BINARY_FLAG));
1061 assert_eq!(to_value::<Text, String>(varchar_col).unwrap(), "foo");
1062
1063 let binary_col = &results[19].0;
1064 assert_eq!(binary_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1065 assert!(!binary_col.flags.contains(Flags::NUM_FLAG));
1066 assert!(!binary_col.flags.contains(Flags::BLOB_FLAG));
1067 assert!(!binary_col.flags.contains(Flags::SET_FLAG));
1068 assert!(!binary_col.flags.contains(Flags::ENUM_FLAG));
1069 assert!(binary_col.flags.contains(Flags::BINARY_FLAG));
1070 assert_eq!(
1071 to_value::<Blob, Vec<u8>>(binary_col).unwrap(),
1072 b"a \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1073 );
1074
1075 let varbinary_col = &results[20].0;
1076 assert_eq!(
1077 varbinary_col.tpe,
1078 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING
1079 );
1080 assert!(!varbinary_col.flags.contains(Flags::NUM_FLAG));
1081 assert!(!varbinary_col.flags.contains(Flags::BLOB_FLAG));
1082 assert!(!varbinary_col.flags.contains(Flags::SET_FLAG));
1083 assert!(!varbinary_col.flags.contains(Flags::ENUM_FLAG));
1084 assert!(varbinary_col.flags.contains(Flags::BINARY_FLAG));
1085 assert_eq!(to_value::<Blob, Vec<u8>>(varbinary_col).unwrap(), b"a ");
1086
1087 let blob_col = &results[21].0;
1088 assert_eq!(blob_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1089 assert!(!blob_col.flags.contains(Flags::NUM_FLAG));
1090 assert!(blob_col.flags.contains(Flags::BLOB_FLAG));
1091 assert!(!blob_col.flags.contains(Flags::SET_FLAG));
1092 assert!(!blob_col.flags.contains(Flags::ENUM_FLAG));
1093 assert!(blob_col.flags.contains(Flags::BINARY_FLAG));
1094 assert_eq!(to_value::<Blob, Vec<u8>>(blob_col).unwrap(), b"binary");
1095
1096 let text_col = &results[22].0;
1097 assert_eq!(text_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1098 assert!(!text_col.flags.contains(Flags::NUM_FLAG));
1099 assert!(text_col.flags.contains(Flags::BLOB_FLAG));
1100 assert!(!text_col.flags.contains(Flags::SET_FLAG));
1101 assert!(!text_col.flags.contains(Flags::ENUM_FLAG));
1102 assert!(!text_col.flags.contains(Flags::BINARY_FLAG));
1103 assert_eq!(
1104 to_value::<Text, String>(text_col).unwrap(),
1105 "some text whatever"
1106 );
1107
1108 let enum_col = &results[23].0;
1109 assert_eq!(enum_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1110 assert!(!enum_col.flags.contains(Flags::NUM_FLAG));
1111 assert!(!enum_col.flags.contains(Flags::BLOB_FLAG));
1112 assert!(!enum_col.flags.contains(Flags::SET_FLAG));
1113 assert!(enum_col.flags.contains(Flags::ENUM_FLAG));
1114 assert!(!enum_col.flags.contains(Flags::BINARY_FLAG));
1115 assert_eq!(to_value::<Text, String>(enum_col).unwrap(), "red");
1116
1117 let set_col = &results[24].0;
1118 assert_eq!(set_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1119 assert!(!set_col.flags.contains(Flags::NUM_FLAG));
1120 assert!(!set_col.flags.contains(Flags::BLOB_FLAG));
1121 assert!(set_col.flags.contains(Flags::SET_FLAG));
1122 assert!(!set_col.flags.contains(Flags::ENUM_FLAG));
1123 assert!(!set_col.flags.contains(Flags::BINARY_FLAG));
1124 assert_eq!(to_value::<Text, String>(set_col).unwrap(), "one");
1125
1126 let geom = &results[25].0;
1127 assert_eq!(geom.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1128 assert!(!geom.flags.contains(Flags::NUM_FLAG));
1129 assert!(!geom.flags.contains(Flags::BLOB_FLAG));
1130 assert!(!geom.flags.contains(Flags::SET_FLAG));
1131 assert!(!geom.flags.contains(Flags::ENUM_FLAG));
1132 assert!(!geom.flags.contains(Flags::BINARY_FLAG));
1133 assert_eq!(to_value::<Text, String>(geom).unwrap(), "POINT(1 1)");
1134
1135 let point_col = &results[26].0;
1136 assert_eq!(point_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1137 assert!(!point_col.flags.contains(Flags::NUM_FLAG));
1138 assert!(!point_col.flags.contains(Flags::BLOB_FLAG));
1139 assert!(!point_col.flags.contains(Flags::SET_FLAG));
1140 assert!(!point_col.flags.contains(Flags::ENUM_FLAG));
1141 assert!(!point_col.flags.contains(Flags::BINARY_FLAG));
1142 assert_eq!(to_value::<Text, String>(point_col).unwrap(), "POINT(1 1)");
1143
1144 let linestring_col = &results[27].0;
1145 assert_eq!(
1146 linestring_col.tpe,
1147 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1148 );
1149 assert!(!linestring_col.flags.contains(Flags::NUM_FLAG));
1150 assert!(!linestring_col.flags.contains(Flags::BLOB_FLAG));
1151 assert!(!linestring_col.flags.contains(Flags::SET_FLAG));
1152 assert!(!linestring_col.flags.contains(Flags::ENUM_FLAG));
1153 assert!(!linestring_col.flags.contains(Flags::BINARY_FLAG));
1154 assert_eq!(
1155 to_value::<Text, String>(linestring_col).unwrap(),
1156 "LINESTRING(0 0,1 1,2 2)"
1157 );
1158
1159 let polygon_col = &results[28].0;
1160 assert_eq!(polygon_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1161 assert!(!polygon_col.flags.contains(Flags::NUM_FLAG));
1162 assert!(!polygon_col.flags.contains(Flags::BLOB_FLAG));
1163 assert!(!polygon_col.flags.contains(Flags::SET_FLAG));
1164 assert!(!polygon_col.flags.contains(Flags::ENUM_FLAG));
1165 assert!(!polygon_col.flags.contains(Flags::BINARY_FLAG));
1166 assert_eq!(
1167 to_value::<Text, String>(polygon_col).unwrap(),
1168 "POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))"
1169 );
1170
1171 let multipoint_col = &results[29].0;
1172 assert_eq!(
1173 multipoint_col.tpe,
1174 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1175 );
1176 assert!(!multipoint_col.flags.contains(Flags::NUM_FLAG));
1177 assert!(!multipoint_col.flags.contains(Flags::BLOB_FLAG));
1178 assert!(!multipoint_col.flags.contains(Flags::SET_FLAG));
1179 assert!(!multipoint_col.flags.contains(Flags::ENUM_FLAG));
1180 assert!(!multipoint_col.flags.contains(Flags::BINARY_FLAG));
1181 let multipoint_res = to_value::<Text, String>(multipoint_col).unwrap();
1185 assert!(
1186 multipoint_res == "MULTIPOINT((0 0),(10 10),(10 20),(20 20))"
1187 || multipoint_res == "MULTIPOINT(0 0,10 10,10 20,20 20)"
1188 );
1189
1190 let multilinestring_col = &results[30].0;
1191 assert_eq!(
1192 multilinestring_col.tpe,
1193 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1194 );
1195 assert!(!multilinestring_col.flags.contains(Flags::NUM_FLAG));
1196 assert!(!multilinestring_col.flags.contains(Flags::BLOB_FLAG));
1197 assert!(!multilinestring_col.flags.contains(Flags::SET_FLAG));
1198 assert!(!multilinestring_col.flags.contains(Flags::ENUM_FLAG));
1199 assert!(!multilinestring_col.flags.contains(Flags::BINARY_FLAG));
1200 assert_eq!(
1201 to_value::<Text, String>(multilinestring_col).unwrap(),
1202 "MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))"
1203 );
1204
1205 let polygon_col = &results[31].0;
1206 assert_eq!(polygon_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1207 assert!(!polygon_col.flags.contains(Flags::NUM_FLAG));
1208 assert!(!polygon_col.flags.contains(Flags::BLOB_FLAG));
1209 assert!(!polygon_col.flags.contains(Flags::SET_FLAG));
1210 assert!(!polygon_col.flags.contains(Flags::ENUM_FLAG));
1211 assert!(!polygon_col.flags.contains(Flags::BINARY_FLAG));
1212 assert_eq!(
1213 to_value::<Text, String>(polygon_col).unwrap(),
1214 "MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))"
1215 );
1216
1217 let geometry_collection = &results[32].0;
1218 assert_eq!(
1219 geometry_collection.tpe,
1220 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1221 );
1222 assert!(!geometry_collection.flags.contains(Flags::NUM_FLAG));
1223 assert!(!geometry_collection.flags.contains(Flags::BLOB_FLAG));
1224 assert!(!geometry_collection.flags.contains(Flags::SET_FLAG));
1225 assert!(!geometry_collection.flags.contains(Flags::ENUM_FLAG));
1226 assert!(!geometry_collection.flags.contains(Flags::BINARY_FLAG));
1227 assert_eq!(
1228 to_value::<Text, String>(geometry_collection).unwrap(),
1229 "GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))"
1230 );
1231
1232 let json_col = &results[33].0;
1233 assert!(
1238 json_col.tpe == ffi::enum_field_types::MYSQL_TYPE_JSON
1239 || json_col.tpe == ffi::enum_field_types::MYSQL_TYPE_BLOB
1240 );
1241 assert!(!json_col.flags.contains(Flags::NUM_FLAG));
1242 assert!(json_col.flags.contains(Flags::BLOB_FLAG));
1243 assert!(!json_col.flags.contains(Flags::SET_FLAG));
1244 assert!(!json_col.flags.contains(Flags::ENUM_FLAG));
1245 assert!(json_col.flags.contains(Flags::BINARY_FLAG));
1246 assert_eq!(
1247 to_value::<Text, String>(json_col).unwrap(),
1248 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1249 );
1250 }
1251
1252 fn query_single_table(
1253 query: &'static str,
1254 conn: &MysqlConnection,
1255 bind_tpe: impl Into<(ffi::enum_field_types, Flags)>,
1256 ) -> BindData {
1257 let stmt: Statement = conn.raw_connection.prepare(query).unwrap();
1258 let stmt = MaybeCached::CannotCache(stmt);
1259
1260 let bind = BindData::from_tpe_and_flags(bind_tpe.into());
1261
1262 let mut binds = OutputBinds(Binds { data: vec![bind] });
1263
1264 let stmt = stmt.execute_statement(&mut binds).unwrap();
1265 stmt.populate_row_buffers(&mut binds).unwrap();
1266
1267 binds.0.data.remove(0)
1268 }
1269
1270 fn input_bind(
1271 query: &'static str,
1272 conn: &MysqlConnection,
1273 id: i32,
1274 (mut field, tpe): (Vec<u8>, impl Into<(ffi::enum_field_types, Flags)>),
1275 ) {
1276 let mut stmt = conn.raw_connection.prepare(query).unwrap();
1277 let length = field.len() as _;
1278 let (tpe, flags) = tpe.into();
1279 let capacity = field.capacity();
1280 let ptr = NonNull::new(field.as_mut_ptr());
1281 mem::forget(field);
1282
1283 let field_bind = BindData {
1284 tpe,
1285 bytes: ptr,
1286 capacity,
1287 length,
1288 flags,
1289 is_null: ffi::FALSE,
1290 is_truncated: None,
1291 };
1292
1293 let mut bytes = id.to_be_bytes().to_vec();
1294 let length = bytes.len() as _;
1295 let capacity = bytes.capacity();
1296 let ptr = NonNull::new(bytes.as_mut_ptr());
1297 mem::forget(bytes);
1298
1299 let id_bind = BindData {
1300 tpe: ffi::enum_field_types::MYSQL_TYPE_LONG,
1301 bytes: ptr,
1302 capacity,
1303 length,
1304 flags: Flags::empty(),
1305 is_null: ffi::FALSE,
1306 is_truncated: None,
1307 };
1308
1309 let binds = PreparedStatementBinds(Binds {
1310 data: vec![id_bind, field_bind],
1311 });
1312 stmt.input_bind(binds).unwrap();
1313 stmt.did_an_error_occur().unwrap();
1314 let stmt = MaybeCached::CannotCache(stmt);
1315 unsafe {
1316 stmt.execute().unwrap();
1317 }
1318 }
1319
1320 #[test]
1321 fn check_json_bind() {
1322 table! {
1323 json_test {
1324 id -> Integer,
1325 json_field -> Text,
1326 }
1327 }
1328
1329 let conn = &mut crate::test_helpers::connection();
1330
1331 crate::sql_query("DROP TABLE IF EXISTS json_test CASCADE")
1332 .execute(conn)
1333 .unwrap();
1334
1335 crate::sql_query(
1336 "CREATE TABLE json_test(id INTEGER PRIMARY KEY, json_field JSON NOT NULL)",
1337 )
1338 .execute(conn)
1339 .unwrap();
1340
1341 crate::sql_query("INSERT INTO json_test(id, json_field) VALUES (1, '{\"key1\": \"value1\", \"key2\": \"value2\"}')").execute(conn).unwrap();
1342
1343 let json_col_as_json = query_single_table(
1344 "SELECT json_field FROM json_test",
1345 conn,
1346 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1347 );
1348
1349 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1350 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1351 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1352 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1353 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1354 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1355 assert_eq!(
1356 to_value::<Text, String>(&json_col_as_json).unwrap(),
1357 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1358 );
1359
1360 let json_col_as_text = query_single_table(
1361 "SELECT json_field FROM json_test",
1362 conn,
1363 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1364 );
1365
1366 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1367 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1368 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1369 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1370 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1371 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1372 assert_eq!(
1373 to_value::<Text, String>(&json_col_as_text).unwrap(),
1374 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1375 );
1376 assert_eq!(
1377 json_col_as_json.value().unwrap().as_bytes(),
1378 json_col_as_text.value().unwrap().as_bytes()
1379 );
1380
1381 crate::sql_query("DELETE FROM json_test")
1382 .execute(conn)
1383 .unwrap();
1384
1385 input_bind(
1386 "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1387 conn,
1388 41,
1389 (
1390 b"{\"abc\": 42}".to_vec(),
1391 MysqlType::String,
1392 ),
1394 );
1395
1396 let json_col_as_json = query_single_table(
1397 "SELECT json_field FROM json_test",
1398 conn,
1399 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1400 );
1401
1402 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1403 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1404 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1405 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1406 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1407 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1408 assert_eq!(
1409 to_value::<Text, String>(&json_col_as_json).unwrap(),
1410 "{\"abc\": 42}"
1411 );
1412
1413 let json_col_as_text = query_single_table(
1414 "SELECT json_field FROM json_test",
1415 conn,
1416 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1417 );
1418
1419 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1420 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1421 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1422 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1423 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1424 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1425 assert_eq!(
1426 to_value::<Text, String>(&json_col_as_text).unwrap(),
1427 "{\"abc\": 42}"
1428 );
1429 assert_eq!(
1430 json_col_as_json.value().unwrap().as_bytes(),
1431 json_col_as_text.value().unwrap().as_bytes()
1432 );
1433
1434 crate::sql_query("DELETE FROM json_test")
1435 .execute(conn)
1436 .unwrap();
1437
1438 input_bind(
1439 "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1440 conn,
1441 41,
1442 (b"{\"abca\": 42}".to_vec(), MysqlType::String),
1443 );
1444
1445 let json_col_as_json = query_single_table(
1446 "SELECT json_field FROM json_test",
1447 conn,
1448 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1449 );
1450
1451 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1452 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1453 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1454 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1455 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1456 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1457 assert_eq!(
1458 to_value::<Text, String>(&json_col_as_json).unwrap(),
1459 "{\"abca\": 42}"
1460 );
1461
1462 let json_col_as_text = query_single_table(
1463 "SELECT json_field FROM json_test",
1464 conn,
1465 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1466 );
1467
1468 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1469 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1470 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1471 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1472 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1473 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1474 assert_eq!(
1475 to_value::<Text, String>(&json_col_as_text).unwrap(),
1476 "{\"abca\": 42}"
1477 );
1478 assert_eq!(
1479 json_col_as_json.value().unwrap().as_bytes(),
1480 json_col_as_text.value().unwrap().as_bytes()
1481 );
1482 }
1483
1484 #[test]
1485 fn check_enum_bind() {
1486 let conn = &mut crate::test_helpers::connection();
1487
1488 crate::sql_query("DROP TABLE IF EXISTS enum_test CASCADE")
1489 .execute(conn)
1490 .unwrap();
1491
1492 crate::sql_query("CREATE TABLE enum_test(id INTEGER PRIMARY KEY, enum_field ENUM('red', 'green', 'blue') NOT NULL)").execute(conn)
1493 .unwrap();
1494
1495 crate::sql_query("INSERT INTO enum_test(id, enum_field) VALUES (1, 'green')")
1496 .execute(conn)
1497 .unwrap();
1498
1499 let enum_col_as_enum: BindData =
1500 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1501
1502 assert_eq!(
1503 enum_col_as_enum.tpe,
1504 ffi::enum_field_types::MYSQL_TYPE_STRING
1505 );
1506 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1507 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1508 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1509 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1510 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1511 assert_eq!(
1512 to_value::<Text, String>(&enum_col_as_enum).unwrap(),
1513 "green"
1514 );
1515
1516 for tpe in &[
1517 ffi::enum_field_types::MYSQL_TYPE_BLOB,
1518 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1519 ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1520 ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1521 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1522 ] {
1523 let enum_col_as_text = query_single_table(
1524 "SELECT enum_field FROM enum_test",
1525 conn,
1526 (*tpe, Flags::ENUM_FLAG),
1527 );
1528
1529 assert_eq!(enum_col_as_text.tpe, *tpe);
1530 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1531 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1532 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1533 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1534 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1535 assert_eq!(
1536 to_value::<Text, String>(&enum_col_as_text).unwrap(),
1537 "green"
1538 );
1539 assert_eq!(
1540 enum_col_as_enum.value().unwrap().as_bytes(),
1541 enum_col_as_text.value().unwrap().as_bytes()
1542 );
1543 }
1544
1545 let enum_col_as_text = query_single_table(
1546 "SELECT enum_field FROM enum_test",
1547 conn,
1548 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1549 );
1550
1551 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1552 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1553 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1554 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1555 assert!(!enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1556 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1557 assert_eq!(
1558 to_value::<Text, String>(&enum_col_as_text).unwrap(),
1559 "green"
1560 );
1561 assert_eq!(
1562 enum_col_as_enum.value().unwrap().as_bytes(),
1563 enum_col_as_text.value().unwrap().as_bytes()
1564 );
1565
1566 crate::sql_query("DELETE FROM enum_test")
1567 .execute(conn)
1568 .unwrap();
1569
1570 input_bind(
1571 "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1572 conn,
1573 41,
1574 (b"blue".to_vec(), MysqlType::Enum),
1575 );
1576
1577 let enum_col_as_enum =
1578 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1579
1580 assert_eq!(
1581 enum_col_as_enum.tpe,
1582 ffi::enum_field_types::MYSQL_TYPE_STRING
1583 );
1584 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1585 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1586 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1587 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1588 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1589 assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "blue");
1590
1591 let enum_col_as_text = query_single_table(
1592 "SELECT enum_field FROM enum_test",
1593 conn,
1594 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1595 );
1596
1597 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1598 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1599 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1600 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1601 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1602 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1603 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1604 assert_eq!(
1605 enum_col_as_enum.value().unwrap().as_bytes(),
1606 enum_col_as_text.value().unwrap().as_bytes()
1607 );
1608
1609 let enum_col_as_text = query_single_table(
1610 "SELECT enum_field FROM enum_test",
1611 conn,
1612 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1613 );
1614
1615 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1616 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1617 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1618 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1619 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1620 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1621 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1622 assert_eq!(
1623 enum_col_as_enum.value().unwrap().as_bytes(),
1624 enum_col_as_text.value().unwrap().as_bytes()
1625 );
1626
1627 crate::sql_query("DELETE FROM enum_test")
1628 .execute(conn)
1629 .unwrap();
1630
1631 input_bind(
1632 "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1633 conn,
1634 41,
1635 (
1636 b"red".to_vec(),
1637 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1638 ),
1639 );
1640
1641 let enum_col_as_enum =
1642 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1643
1644 assert_eq!(
1645 enum_col_as_enum.tpe,
1646 ffi::enum_field_types::MYSQL_TYPE_STRING
1647 );
1648 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1649 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1650 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1651 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1652 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1653 assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "red");
1654
1655 let enum_col_as_text = query_single_table(
1656 "SELECT enum_field FROM enum_test",
1657 conn,
1658 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1659 );
1660
1661 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1662 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1663 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1664 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1665 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1666 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1667 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "red");
1668 assert_eq!(
1669 enum_col_as_enum.value().unwrap().as_bytes(),
1670 enum_col_as_text.value().unwrap().as_bytes()
1671 );
1672 }
1673
1674 #[test]
1675 fn check_set_bind() {
1676 let conn = &mut crate::test_helpers::connection();
1677
1678 crate::sql_query("DROP TABLE IF EXISTS set_test CASCADE")
1679 .execute(conn)
1680 .unwrap();
1681
1682 crate::sql_query("CREATE TABLE set_test(id INTEGER PRIMARY KEY, set_field SET('red', 'green', 'blue') NOT NULL)").execute(conn)
1683 .unwrap();
1684
1685 crate::sql_query("INSERT INTO set_test(id, set_field) VALUES (1, 'green')")
1686 .execute(conn)
1687 .unwrap();
1688
1689 let set_col_as_set: BindData =
1690 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1691
1692 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1693 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1694 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1695 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1696 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1697 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1698 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "green");
1699
1700 for tpe in &[
1701 ffi::enum_field_types::MYSQL_TYPE_BLOB,
1702 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1703 ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1704 ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1705 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1706 ] {
1707 let set_col_as_text = query_single_table(
1708 "SELECT set_field FROM set_test",
1709 conn,
1710 (*tpe, Flags::SET_FLAG),
1711 );
1712
1713 assert_eq!(set_col_as_text.tpe, *tpe);
1714 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1715 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1716 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1717 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1718 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1719 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1720 assert_eq!(
1721 set_col_as_set.value().unwrap().as_bytes(),
1722 set_col_as_text.value().unwrap().as_bytes()
1723 );
1724 }
1725 let set_col_as_text = query_single_table(
1726 "SELECT set_field FROM set_test",
1727 conn,
1728 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1729 );
1730
1731 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1732 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1733 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1734 assert!(!set_col_as_text.flags.contains(Flags::SET_FLAG));
1735 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1736 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1737 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1738 assert_eq!(
1739 set_col_as_set.value().unwrap().as_bytes(),
1740 set_col_as_text.value().unwrap().as_bytes()
1741 );
1742
1743 crate::sql_query("DELETE FROM set_test")
1744 .execute(conn)
1745 .unwrap();
1746
1747 input_bind(
1748 "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1749 conn,
1750 41,
1751 (b"blue".to_vec(), MysqlType::Set),
1752 );
1753
1754 let set_col_as_set =
1755 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1756
1757 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1758 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1759 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1760 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1761 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1762 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1763 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "blue");
1764
1765 let set_col_as_text = query_single_table(
1766 "SELECT set_field FROM set_test",
1767 conn,
1768 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1769 );
1770
1771 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1772 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1773 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1774 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1775 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1776 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1777 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "blue");
1778 assert_eq!(
1779 set_col_as_set.value().unwrap().as_bytes(),
1780 set_col_as_text.value().unwrap().as_bytes()
1781 );
1782
1783 crate::sql_query("DELETE FROM set_test")
1784 .execute(conn)
1785 .unwrap();
1786
1787 input_bind(
1788 "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1789 conn,
1790 41,
1791 (b"red".to_vec(), MysqlType::String),
1792 );
1793
1794 let set_col_as_set =
1795 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1796
1797 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1798 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1799 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1800 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1801 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1802 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1803 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "red");
1804
1805 let set_col_as_text = query_single_table(
1806 "SELECT set_field FROM set_test",
1807 conn,
1808 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1809 );
1810
1811 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1812 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1813 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1814 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1815 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1816 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1817 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "red");
1818 assert_eq!(
1819 set_col_as_set.value().unwrap().as_bytes(),
1820 set_col_as_text.value().unwrap().as_bytes()
1821 );
1822 }
1823}