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 let slice = unsafe {
415 std::slice::from_raw_parts(
423 data.as_ptr(),
424 self.length.try_into().expect("Usize is at least 32 bit"),
425 )
426 };
427 Some(MysqlValue::new_internal(slice, tpe))
428 }
429 }
430
431 pub(super) fn is_null(&self) -> bool {
432 self.is_null != ffi::my_bool::default()
433 }
434
435 fn update_buffer_length(&mut self) {
436 use std::cmp::min;
437
438 let actual_bytes_in_buffer = min(
439 self.capacity,
440 self.length.try_into().expect("Usize is at least 32 bit"),
441 );
442 self.length = actual_bytes_in_buffer as libc::c_ulong;
443 }
444
445 unsafe fn mysql_bind(&mut self) -> ffi::MYSQL_BIND {
449 use std::ptr::addr_of_mut;
450
451 let mut bind: MaybeUninit<ffi::MYSQL_BIND> = mem::MaybeUninit::zeroed();
452 let ptr = bind.as_mut_ptr();
453
454 addr_of_mut!((*ptr).buffer_type).write(self.tpe);
455 addr_of_mut!((*ptr).buffer).write(
456 self.bytes
457 .map(|p| p.as_ptr())
458 .unwrap_or(std::ptr::null_mut()) as *mut libc::c_void,
459 );
460 addr_of_mut!((*ptr).buffer_length).write(self.capacity as libc::c_ulong);
461 addr_of_mut!((*ptr).length).write(&mut self.length);
462 addr_of_mut!((*ptr).is_null).write(&mut self.is_null);
463 addr_of_mut!((*ptr).is_unsigned)
464 .write(self.flags.contains(Flags::UNSIGNED_FLAG) as ffi::my_bool);
465
466 if let Some(ref mut is_truncated) = self.is_truncated {
467 addr_of_mut!((*ptr).error).write(is_truncated);
468 }
469
470 bind.assume_init()
472 }
473
474 unsafe fn bind_for_truncated_data(&mut self) -> Option<(ffi::MYSQL_BIND, usize)> {
481 if self.is_truncated() {
482 if let Some(bytes) = self.bytes {
483 let mut bytes = Vec::from_raw_parts(bytes.as_ptr(), self.capacity, self.capacity);
484 self.bytes = None;
485
486 let offset = self.capacity;
487 let truncated_amount =
488 usize::try_from(self.length).expect("Usize is at least 32 bit") - offset;
489
490 debug_assert!(
491 truncated_amount > 0,
492 "output buffers were invalidated \
493 without calling `mysql_stmt_bind_result`"
494 );
495
496 bytes.reserve(truncated_amount);
499 self.capacity = bytes.capacity();
500 self.bytes = NonNull::new(bytes.as_mut_ptr());
501 mem::forget(bytes);
502
503 let mut bind = self.mysql_bind();
504
505 if let Some(ptr) = self.bytes {
506 bind.buffer = ptr.as_ptr().add(offset) as *mut libc::c_void;
509 bind.buffer_length = truncated_amount as libc::c_ulong;
510 } else {
511 bind.buffer_length = 0;
512 }
513 Some((bind, offset))
514 } else {
515 let mut vec = vec![0_u8; self.length.try_into().expect("usize is at least 32 bit")];
519 self.capacity = vec.capacity();
520 self.bytes = NonNull::new(vec.as_mut_ptr());
521 mem::forget(vec);
522
523 let bind = self.mysql_bind();
524 Some((bind, 0))
528 }
529 } else {
530 None
531 }
532 }
533
534 fn did_numeric_overflow_occur(&self) -> QueryResult<()> {
535 use crate::result::Error::DeserializationError;
536
537 if self.is_truncated() && self.is_fixed_size_buffer() {
538 Err(DeserializationError(
539 "Numeric overflow/underflow occurred".into(),
540 ))
541 } else {
542 Ok(())
543 }
544 }
545}
546
547impl From<MysqlType> for (ffi::enum_field_types, Flags) {
548 fn from(tpe: MysqlType) -> Self {
549 use self::ffi::enum_field_types;
550 let mut flags = Flags::empty();
551 let tpe = match tpe {
552 MysqlType::Tiny => enum_field_types::MYSQL_TYPE_TINY,
553 MysqlType::Short => enum_field_types::MYSQL_TYPE_SHORT,
554 MysqlType::Long => enum_field_types::MYSQL_TYPE_LONG,
555 MysqlType::LongLong => enum_field_types::MYSQL_TYPE_LONGLONG,
556 MysqlType::Float => enum_field_types::MYSQL_TYPE_FLOAT,
557 MysqlType::Double => enum_field_types::MYSQL_TYPE_DOUBLE,
558 MysqlType::Time => enum_field_types::MYSQL_TYPE_TIME,
559 MysqlType::Date => enum_field_types::MYSQL_TYPE_DATE,
560 MysqlType::DateTime => enum_field_types::MYSQL_TYPE_DATETIME,
561 MysqlType::Timestamp => enum_field_types::MYSQL_TYPE_TIMESTAMP,
562 MysqlType::String => enum_field_types::MYSQL_TYPE_STRING,
563 MysqlType::Blob => enum_field_types::MYSQL_TYPE_BLOB,
564 MysqlType::Numeric => enum_field_types::MYSQL_TYPE_NEWDECIMAL,
565 MysqlType::Bit => enum_field_types::MYSQL_TYPE_BIT,
566 MysqlType::UnsignedTiny => {
567 flags = Flags::UNSIGNED_FLAG;
568 enum_field_types::MYSQL_TYPE_TINY
569 }
570 MysqlType::UnsignedShort => {
571 flags = Flags::UNSIGNED_FLAG;
572 enum_field_types::MYSQL_TYPE_SHORT
573 }
574 MysqlType::UnsignedLong => {
575 flags = Flags::UNSIGNED_FLAG;
576 enum_field_types::MYSQL_TYPE_LONG
577 }
578 MysqlType::UnsignedLongLong => {
579 flags = Flags::UNSIGNED_FLAG;
580 enum_field_types::MYSQL_TYPE_LONGLONG
581 }
582 MysqlType::Set => {
583 flags = Flags::SET_FLAG;
584 enum_field_types::MYSQL_TYPE_STRING
585 }
586 MysqlType::Enum => {
587 flags = Flags::ENUM_FLAG;
588 enum_field_types::MYSQL_TYPE_STRING
589 }
590 };
591 (tpe, flags)
592 }
593}
594
595impl From<(ffi::enum_field_types, Flags)> for MysqlType {
596 fn from((tpe, flags): (ffi::enum_field_types, Flags)) -> Self {
597 use self::ffi::enum_field_types;
598
599 let is_unsigned = flags.contains(Flags::UNSIGNED_FLAG);
600
601 match tpe {
606 enum_field_types::MYSQL_TYPE_TINY if is_unsigned => MysqlType::UnsignedTiny,
607 enum_field_types::MYSQL_TYPE_YEAR | enum_field_types::MYSQL_TYPE_SHORT
608 if is_unsigned =>
609 {
610 MysqlType::UnsignedShort
611 }
612 enum_field_types::MYSQL_TYPE_INT24 | enum_field_types::MYSQL_TYPE_LONG
613 if is_unsigned =>
614 {
615 MysqlType::UnsignedLong
616 }
617 enum_field_types::MYSQL_TYPE_LONGLONG if is_unsigned => MysqlType::UnsignedLongLong,
618 enum_field_types::MYSQL_TYPE_TINY => MysqlType::Tiny,
619 enum_field_types::MYSQL_TYPE_SHORT => MysqlType::Short,
620 enum_field_types::MYSQL_TYPE_INT24 | enum_field_types::MYSQL_TYPE_LONG => {
621 MysqlType::Long
622 }
623 enum_field_types::MYSQL_TYPE_LONGLONG => MysqlType::LongLong,
624 enum_field_types::MYSQL_TYPE_FLOAT => MysqlType::Float,
625 enum_field_types::MYSQL_TYPE_DOUBLE => MysqlType::Double,
626 enum_field_types::MYSQL_TYPE_DECIMAL | enum_field_types::MYSQL_TYPE_NEWDECIMAL => {
627 MysqlType::Numeric
628 }
629 enum_field_types::MYSQL_TYPE_BIT => MysqlType::Bit,
630
631 enum_field_types::MYSQL_TYPE_TIME => MysqlType::Time,
632 enum_field_types::MYSQL_TYPE_DATE => MysqlType::Date,
633 enum_field_types::MYSQL_TYPE_DATETIME => MysqlType::DateTime,
634 enum_field_types::MYSQL_TYPE_TIMESTAMP => MysqlType::Timestamp,
635 enum_field_types::MYSQL_TYPE_JSON => MysqlType::String,
638
639 enum_field_types::MYSQL_TYPE_BLOB
645 | enum_field_types::MYSQL_TYPE_TINY_BLOB
646 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
647 | enum_field_types::MYSQL_TYPE_LONG_BLOB
648 | enum_field_types::MYSQL_TYPE_VAR_STRING
649 | enum_field_types::MYSQL_TYPE_STRING
650 if flags.contains(Flags::ENUM_FLAG) =>
651 {
652 MysqlType::Enum
653 }
654 enum_field_types::MYSQL_TYPE_BLOB
655 | enum_field_types::MYSQL_TYPE_TINY_BLOB
656 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
657 | enum_field_types::MYSQL_TYPE_LONG_BLOB
658 | enum_field_types::MYSQL_TYPE_VAR_STRING
659 | enum_field_types::MYSQL_TYPE_STRING
660 if flags.contains(Flags::SET_FLAG) =>
661 {
662 MysqlType::Set
663 }
664
665 enum_field_types::MYSQL_TYPE_BLOB
670 | enum_field_types::MYSQL_TYPE_TINY_BLOB
671 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
672 | enum_field_types::MYSQL_TYPE_LONG_BLOB
673 | enum_field_types::MYSQL_TYPE_VAR_STRING
674 | enum_field_types::MYSQL_TYPE_STRING
675 if flags.contains(Flags::BINARY_FLAG) =>
676 {
677 MysqlType::Blob
678 }
679
680 enum_field_types::MYSQL_TYPE_BLOB
682 | enum_field_types::MYSQL_TYPE_TINY_BLOB
683 | enum_field_types::MYSQL_TYPE_MEDIUM_BLOB
684 | enum_field_types::MYSQL_TYPE_LONG_BLOB
685 | enum_field_types::MYSQL_TYPE_VAR_STRING
686 | enum_field_types::MYSQL_TYPE_STRING => MysqlType::String,
687
688 enum_field_types::MYSQL_TYPE_YEAR => unreachable!(
690 "The year type should have set the unsigned flag. If you ever \
691 see this error message, something has gone very wrong. Please \
692 open an issue at the diesel github repo in this case"
693 ),
694 enum_field_types::MYSQL_TYPE_NULL => unreachable!(
696 "We ensure at the call side that we do not hit this type here. \
697 If you ever see this error, something has gone very wrong. \
698 Please open an issue at the diesel github repo in this case"
699 ),
700 enum_field_types::MYSQL_TYPE_VARCHAR
704 | enum_field_types::MYSQL_TYPE_ENUM
705 | enum_field_types::MYSQL_TYPE_SET
706 | enum_field_types::MYSQL_TYPE_GEOMETRY => {
707 unimplemented!(
708 "Hit a type that should be unsupported in libmysqlclient. If \
709 you ever see this error, they probably have added support for \
710 one of those types. Please open an issue at the diesel github \
711 repo in this case."
712 )
713 }
714
715 enum_field_types::MYSQL_TYPE_NEWDATE
716 | enum_field_types::MYSQL_TYPE_TIME2
717 | enum_field_types::MYSQL_TYPE_DATETIME2
718 | enum_field_types::MYSQL_TYPE_TIMESTAMP2 => unreachable!(
719 "The mysql documentation states that these types are \
720 only used on the server side, so if you see this error \
721 something has gone wrong. Please open an issue at \
722 the diesel github repo."
723 ),
724 #[allow(unreachable_patterns)]
727 t => unreachable!(
728 "Unsupported type encountered: {t:?}. \
729 If you ever see this error, something has gone wrong. \
730 Please open an issue at the diesel github \
731 repo in this case."
732 ),
733 }
734 }
735}
736
737fn known_buffer_size_for_ffi_type(tpe: ffi::enum_field_types) -> Option<usize> {
738 use self::ffi::enum_field_types as t;
739 use std::mem::size_of;
740
741 match tpe {
742 t::MYSQL_TYPE_TINY => Some(1),
743 t::MYSQL_TYPE_YEAR | t::MYSQL_TYPE_SHORT => Some(2),
744 t::MYSQL_TYPE_INT24 | t::MYSQL_TYPE_LONG | t::MYSQL_TYPE_FLOAT => Some(4),
745 t::MYSQL_TYPE_LONGLONG | t::MYSQL_TYPE_DOUBLE => Some(8),
746 t::MYSQL_TYPE_TIME
747 | t::MYSQL_TYPE_DATE
748 | t::MYSQL_TYPE_DATETIME
749 | t::MYSQL_TYPE_TIMESTAMP => Some(size_of::<MysqlTime>()),
750 _ => None,
751 }
752}
753
754#[cfg(test)]
755mod tests {
756 use super::*;
757 use crate::connection::statement_cache::MaybeCached;
758 use crate::deserialize::FromSql;
759 use crate::mysql::connection::stmt::Statement;
760 use crate::prelude::*;
761 use crate::sql_types::*;
762 #[cfg(feature = "numeric")]
763 use std::str::FromStr;
764
765 fn to_value<ST, T>(
766 bind: &BindData,
767 ) -> Result<T, Box<(dyn std::error::Error + Send + Sync + 'static)>>
768 where
769 T: FromSql<ST, crate::mysql::Mysql> + std::fmt::Debug,
770 {
771 let meta = (bind.tpe, bind.flags).into();
772 dbg!(meta);
773
774 let value = bind.value().expect("Is not null");
775 let value = MysqlValue::new_internal(value.as_bytes(), meta);
776
777 dbg!(T::from_sql(value))
778 }
779
780 #[cfg(feature = "extras")]
781 #[test]
782 fn check_all_the_types() {
783 let conn = &mut crate::test_helpers::connection();
784
785 crate::sql_query("DROP TABLE IF EXISTS all_mysql_types CASCADE")
786 .execute(conn)
787 .unwrap();
788 crate::sql_query(
789 "CREATE TABLE all_mysql_types (
790 tiny_int TINYINT NOT NULL,
791 small_int SMALLINT NOT NULL,
792 medium_int MEDIUMINT NOT NULL,
793 int_col INTEGER NOT NULL,
794 big_int BIGINT NOT NULL,
795 unsigned_int INTEGER UNSIGNED NOT NULL,
796 zero_fill_int INTEGER ZEROFILL NOT NULL,
797 numeric_col NUMERIC(20,5) NOT NULL,
798 decimal_col DECIMAL(20,5) NOT NULL,
799 float_col FLOAT NOT NULL,
800 double_col DOUBLE NOT NULL,
801 bit_col BIT(8) NOT NULL,
802 date_col DATE NOT NULL,
803 date_time DATETIME NOT NULL,
804 timestamp_col TIMESTAMP NOT NULL,
805 time_col TIME NOT NULL,
806 year_col YEAR NOT NULL,
807 char_col CHAR(30) NOT NULL,
808 varchar_col VARCHAR(30) NOT NULL,
809 binary_col BINARY(30) NOT NULL,
810 varbinary_col VARBINARY(30) NOT NULL,
811 blob_col BLOB NOT NULL,
812 text_col TEXT NOT NULL,
813 enum_col ENUM('red', 'green', 'blue') NOT NULL,
814 set_col SET('one', 'two') NOT NULL,
815 geom GEOMETRY NOT NULL,
816 point_col POINT NOT NULL,
817 linestring_col LINESTRING NOT NULL,
818 polygon_col POLYGON NOT NULL,
819 multipoint_col MULTIPOINT NOT NULL,
820 multilinestring_col MULTILINESTRING NOT NULL,
821 multipolygon_col MULTIPOLYGON NOT NULL,
822 geometry_collection GEOMETRYCOLLECTION NOT NULL,
823 json_col JSON NOT NULL
824 )",
825 )
826 .execute(conn)
827 .unwrap();
828 crate::sql_query(
829 "INSERT INTO all_mysql_types VALUES (
830 0, -- tiny_int
831 1, -- small_int
832 2, -- medium_int
833 3, -- int_col
834 -5, -- big_int
835 42, -- unsigned_int
836 1, -- zero_fill_int
837 -999.999, -- numeric_col,
838 3.14, -- decimal_col,
839 1.23, -- float_col
840 4.5678, -- double_col
841 b'10101010', -- bit_col
842 '1000-01-01', -- date_col
843 '9999-12-31 12:34:45.012345', -- date_time
844 '2020-01-01 10:10:10', -- timestamp_col
845 '23:01:01', -- time_col
846 2020, -- year_col
847 'abc', -- char_col
848 'foo', -- varchar_col
849 'a ', -- binary_col
850 'a ', -- varbinary_col
851 'binary', -- blob_col
852 'some text whatever', -- text_col
853 'red', -- enum_col
854 'one', -- set_col
855 ST_GeomFromText('POINT(1 1)'), -- geom
856 ST_PointFromText('POINT(1 1)'), -- point_col
857 ST_LineStringFromText('LINESTRING(0 0,1 1,2 2)'), -- linestring_col
858 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
859 ST_MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)'), -- multipoint_col
860 ST_MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))'), -- multilinestring_col
861 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
862 ST_GeomCollFromText('GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))'), -- geometry_collection
863 '{\"key1\": \"value1\", \"key2\": \"value2\"}' -- json_col
864)",
865 ).execute(conn)
866 .unwrap();
867
868 let stmt = crate::mysql::connection::prepared_query(
869 &crate::sql_query(
870 "SELECT
871 tiny_int, small_int, medium_int, int_col,
872 big_int, unsigned_int, zero_fill_int,
873 numeric_col, decimal_col, float_col, double_col, bit_col,
874 date_col, date_time, timestamp_col, time_col, year_col,
875 char_col, varchar_col, binary_col, varbinary_col, blob_col,
876 text_col, enum_col, set_col, ST_AsText(geom), ST_AsText(point_col), ST_AsText(linestring_col),
877 ST_AsText(polygon_col), ST_AsText(multipoint_col), ST_AsText(multilinestring_col),
878 ST_AsText(multipolygon_col), ST_AsText(geometry_collection), json_col
879 FROM all_mysql_types",
880 ),
881 &mut conn.statement_cache,
882 &mut conn.raw_connection,
883 &mut conn.instrumentation,
884 ).unwrap();
885
886 let metadata = stmt.metadata().unwrap();
887 let mut output_binds =
888 OutputBinds::from_output_types(&vec![None; metadata.fields().len()], &metadata);
889 let stmt = stmt.execute_statement(&mut output_binds).unwrap();
890 stmt.populate_row_buffers(&mut output_binds).unwrap();
891
892 let results: Vec<(BindData, &_)> = output_binds
893 .0
894 .data
895 .into_iter()
896 .zip(metadata.fields())
897 .collect::<Vec<_>>();
898
899 let tiny_int_col = &results[0].0;
900 assert_eq!(tiny_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_TINY);
901 assert!(tiny_int_col.flags.contains(Flags::NUM_FLAG));
902 assert!(!tiny_int_col.flags.contains(Flags::UNSIGNED_FLAG));
903 assert!(matches!(to_value::<TinyInt, i8>(tiny_int_col), Ok(0)));
904
905 let small_int_col = &results[1].0;
906 assert_eq!(small_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_SHORT);
907 assert!(small_int_col.flags.contains(Flags::NUM_FLAG));
908 assert!(!small_int_col.flags.contains(Flags::UNSIGNED_FLAG));
909 assert!(matches!(to_value::<SmallInt, i16>(small_int_col), Ok(1)));
910
911 let medium_int_col = &results[2].0;
912 assert_eq!(medium_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_INT24);
913 assert!(medium_int_col.flags.contains(Flags::NUM_FLAG));
914 assert!(!medium_int_col.flags.contains(Flags::UNSIGNED_FLAG));
915 assert!(matches!(to_value::<Integer, i32>(medium_int_col), Ok(2)));
916
917 let int_col = &results[3].0;
918 assert_eq!(int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG);
919 assert!(int_col.flags.contains(Flags::NUM_FLAG));
920 assert!(!int_col.flags.contains(Flags::UNSIGNED_FLAG));
921 assert!(matches!(to_value::<Integer, i32>(int_col), Ok(3)));
922
923 let big_int_col = &results[4].0;
924 assert_eq!(big_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONGLONG);
925 assert!(big_int_col.flags.contains(Flags::NUM_FLAG));
926 assert!(!big_int_col.flags.contains(Flags::UNSIGNED_FLAG));
927 assert!(matches!(to_value::<TinyInt, i8>(big_int_col), Ok(-5)));
928
929 let unsigned_int_col = &results[5].0;
930 assert_eq!(unsigned_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG);
931 assert!(unsigned_int_col.flags.contains(Flags::NUM_FLAG));
932 assert!(unsigned_int_col.flags.contains(Flags::UNSIGNED_FLAG));
933 assert!(matches!(
934 to_value::<Unsigned<Integer>, u32>(unsigned_int_col),
935 Ok(42)
936 ));
937
938 let zero_fill_int_col = &results[6].0;
939 assert_eq!(
940 zero_fill_int_col.tpe,
941 ffi::enum_field_types::MYSQL_TYPE_LONG
942 );
943 assert!(zero_fill_int_col.flags.contains(Flags::NUM_FLAG));
944 assert!(zero_fill_int_col.flags.contains(Flags::ZEROFILL_FLAG));
945 assert!(matches!(to_value::<Integer, i32>(zero_fill_int_col), Ok(1)));
946
947 let numeric_col = &results[7].0;
948 assert_eq!(
949 numeric_col.tpe,
950 ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL
951 );
952 assert!(numeric_col.flags.contains(Flags::NUM_FLAG));
953 assert!(!numeric_col.flags.contains(Flags::UNSIGNED_FLAG));
954 assert_eq!(
955 to_value::<Numeric, bigdecimal::BigDecimal>(numeric_col).unwrap(),
956 bigdecimal::BigDecimal::from_str("-999.99900").unwrap()
957 );
958
959 let decimal_col = &results[8].0;
960 assert_eq!(
961 decimal_col.tpe,
962 ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL
963 );
964 assert!(decimal_col.flags.contains(Flags::NUM_FLAG));
965 assert!(!decimal_col.flags.contains(Flags::UNSIGNED_FLAG));
966 assert_eq!(
967 to_value::<Numeric, bigdecimal::BigDecimal>(decimal_col).unwrap(),
968 bigdecimal::BigDecimal::from_str("3.14000").unwrap()
969 );
970
971 let float_col = &results[9].0;
972 assert_eq!(float_col.tpe, ffi::enum_field_types::MYSQL_TYPE_FLOAT);
973 assert!(float_col.flags.contains(Flags::NUM_FLAG));
974 assert!(!float_col.flags.contains(Flags::UNSIGNED_FLAG));
975 assert_eq!(to_value::<Float, f32>(float_col).unwrap(), 1.23);
976
977 let double_col = &results[10].0;
978 assert_eq!(double_col.tpe, ffi::enum_field_types::MYSQL_TYPE_DOUBLE);
979 assert!(double_col.flags.contains(Flags::NUM_FLAG));
980 assert!(!double_col.flags.contains(Flags::UNSIGNED_FLAG));
981 assert_eq!(to_value::<Double, f64>(double_col).unwrap(), 4.5678);
982
983 let bit_col = &results[11].0;
984 assert_eq!(bit_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BIT);
985 assert!(!bit_col.flags.contains(Flags::NUM_FLAG));
986 assert!(bit_col.flags.contains(Flags::UNSIGNED_FLAG));
987 assert!(!bit_col.flags.contains(Flags::BINARY_FLAG));
988 assert_eq!(to_value::<Blob, Vec<u8>>(bit_col).unwrap(), vec![170]);
989
990 let date_col = &results[12].0;
991 assert_eq!(date_col.tpe, ffi::enum_field_types::MYSQL_TYPE_DATE);
992 assert!(!date_col.flags.contains(Flags::NUM_FLAG));
993 assert_eq!(
994 to_value::<Date, chrono::NaiveDate>(date_col).unwrap(),
995 chrono::NaiveDate::from_ymd_opt(1000, 1, 1).unwrap(),
996 );
997
998 let date_time_col = &results[13].0;
999 assert_eq!(
1000 date_time_col.tpe,
1001 ffi::enum_field_types::MYSQL_TYPE_DATETIME
1002 );
1003 assert!(!date_time_col.flags.contains(Flags::NUM_FLAG));
1004 assert_eq!(
1005 to_value::<Datetime, chrono::NaiveDateTime>(date_time_col).unwrap(),
1006 chrono::NaiveDateTime::parse_from_str("9999-12-31 12:34:45", "%Y-%m-%d %H:%M:%S")
1007 .unwrap()
1008 );
1009
1010 let timestamp_col = &results[14].0;
1011 assert_eq!(
1012 timestamp_col.tpe,
1013 ffi::enum_field_types::MYSQL_TYPE_TIMESTAMP
1014 );
1015 assert!(!timestamp_col.flags.contains(Flags::NUM_FLAG));
1016 assert_eq!(
1017 to_value::<Datetime, chrono::NaiveDateTime>(timestamp_col).unwrap(),
1018 chrono::NaiveDateTime::parse_from_str("2020-01-01 10:10:10", "%Y-%m-%d %H:%M:%S")
1019 .unwrap()
1020 );
1021
1022 let time_col = &results[15].0;
1023 assert_eq!(time_col.tpe, ffi::enum_field_types::MYSQL_TYPE_TIME);
1024 assert!(!time_col.flags.contains(Flags::NUM_FLAG));
1025 assert_eq!(
1026 to_value::<Time, chrono::NaiveTime>(time_col).unwrap(),
1027 chrono::NaiveTime::from_hms_opt(23, 01, 01).unwrap()
1028 );
1029
1030 let year_col = &results[16].0;
1031 assert_eq!(year_col.tpe, ffi::enum_field_types::MYSQL_TYPE_YEAR);
1032 assert!(year_col.flags.contains(Flags::NUM_FLAG));
1033 assert!(year_col.flags.contains(Flags::UNSIGNED_FLAG));
1034 assert!(matches!(to_value::<SmallInt, i16>(year_col), Ok(2020)));
1035
1036 let char_col = &results[17].0;
1037 assert_eq!(char_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1038 assert!(!char_col.flags.contains(Flags::NUM_FLAG));
1039 assert!(!char_col.flags.contains(Flags::BLOB_FLAG));
1040 assert!(!char_col.flags.contains(Flags::SET_FLAG));
1041 assert!(!char_col.flags.contains(Flags::ENUM_FLAG));
1042 assert!(!char_col.flags.contains(Flags::BINARY_FLAG));
1043 assert_eq!(to_value::<Text, String>(char_col).unwrap(), "abc");
1044
1045 let varchar_col = &results[18].0;
1046 assert_eq!(
1047 varchar_col.tpe,
1048 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING
1049 );
1050 assert!(!varchar_col.flags.contains(Flags::NUM_FLAG));
1051 assert!(!varchar_col.flags.contains(Flags::BLOB_FLAG));
1052 assert!(!varchar_col.flags.contains(Flags::SET_FLAG));
1053 assert!(!varchar_col.flags.contains(Flags::ENUM_FLAG));
1054 assert!(!varchar_col.flags.contains(Flags::BINARY_FLAG));
1055 assert_eq!(to_value::<Text, String>(varchar_col).unwrap(), "foo");
1056
1057 let binary_col = &results[19].0;
1058 assert_eq!(binary_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1059 assert!(!binary_col.flags.contains(Flags::NUM_FLAG));
1060 assert!(!binary_col.flags.contains(Flags::BLOB_FLAG));
1061 assert!(!binary_col.flags.contains(Flags::SET_FLAG));
1062 assert!(!binary_col.flags.contains(Flags::ENUM_FLAG));
1063 assert!(binary_col.flags.contains(Flags::BINARY_FLAG));
1064 assert_eq!(
1065 to_value::<Blob, Vec<u8>>(binary_col).unwrap(),
1066 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"
1067 );
1068
1069 let varbinary_col = &results[20].0;
1070 assert_eq!(
1071 varbinary_col.tpe,
1072 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING
1073 );
1074 assert!(!varbinary_col.flags.contains(Flags::NUM_FLAG));
1075 assert!(!varbinary_col.flags.contains(Flags::BLOB_FLAG));
1076 assert!(!varbinary_col.flags.contains(Flags::SET_FLAG));
1077 assert!(!varbinary_col.flags.contains(Flags::ENUM_FLAG));
1078 assert!(varbinary_col.flags.contains(Flags::BINARY_FLAG));
1079 assert_eq!(to_value::<Blob, Vec<u8>>(varbinary_col).unwrap(), b"a ");
1080
1081 let blob_col = &results[21].0;
1082 assert_eq!(blob_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1083 assert!(!blob_col.flags.contains(Flags::NUM_FLAG));
1084 assert!(blob_col.flags.contains(Flags::BLOB_FLAG));
1085 assert!(!blob_col.flags.contains(Flags::SET_FLAG));
1086 assert!(!blob_col.flags.contains(Flags::ENUM_FLAG));
1087 assert!(blob_col.flags.contains(Flags::BINARY_FLAG));
1088 assert_eq!(to_value::<Blob, Vec<u8>>(blob_col).unwrap(), b"binary");
1089
1090 let text_col = &results[22].0;
1091 assert_eq!(text_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1092 assert!(!text_col.flags.contains(Flags::NUM_FLAG));
1093 assert!(text_col.flags.contains(Flags::BLOB_FLAG));
1094 assert!(!text_col.flags.contains(Flags::SET_FLAG));
1095 assert!(!text_col.flags.contains(Flags::ENUM_FLAG));
1096 assert!(!text_col.flags.contains(Flags::BINARY_FLAG));
1097 assert_eq!(
1098 to_value::<Text, String>(text_col).unwrap(),
1099 "some text whatever"
1100 );
1101
1102 let enum_col = &results[23].0;
1103 assert_eq!(enum_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1104 assert!(!enum_col.flags.contains(Flags::NUM_FLAG));
1105 assert!(!enum_col.flags.contains(Flags::BLOB_FLAG));
1106 assert!(!enum_col.flags.contains(Flags::SET_FLAG));
1107 assert!(enum_col.flags.contains(Flags::ENUM_FLAG));
1108 assert!(!enum_col.flags.contains(Flags::BINARY_FLAG));
1109 assert_eq!(to_value::<Text, String>(enum_col).unwrap(), "red");
1110
1111 let set_col = &results[24].0;
1112 assert_eq!(set_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1113 assert!(!set_col.flags.contains(Flags::NUM_FLAG));
1114 assert!(!set_col.flags.contains(Flags::BLOB_FLAG));
1115 assert!(set_col.flags.contains(Flags::SET_FLAG));
1116 assert!(!set_col.flags.contains(Flags::ENUM_FLAG));
1117 assert!(!set_col.flags.contains(Flags::BINARY_FLAG));
1118 assert_eq!(to_value::<Text, String>(set_col).unwrap(), "one");
1119
1120 let geom = &results[25].0;
1121 assert_eq!(geom.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1122 assert!(!geom.flags.contains(Flags::NUM_FLAG));
1123 assert!(!geom.flags.contains(Flags::BLOB_FLAG));
1124 assert!(!geom.flags.contains(Flags::SET_FLAG));
1125 assert!(!geom.flags.contains(Flags::ENUM_FLAG));
1126 assert!(!geom.flags.contains(Flags::BINARY_FLAG));
1127 assert_eq!(to_value::<Text, String>(geom).unwrap(), "POINT(1 1)");
1128
1129 let point_col = &results[26].0;
1130 assert_eq!(point_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1131 assert!(!point_col.flags.contains(Flags::NUM_FLAG));
1132 assert!(!point_col.flags.contains(Flags::BLOB_FLAG));
1133 assert!(!point_col.flags.contains(Flags::SET_FLAG));
1134 assert!(!point_col.flags.contains(Flags::ENUM_FLAG));
1135 assert!(!point_col.flags.contains(Flags::BINARY_FLAG));
1136 assert_eq!(to_value::<Text, String>(point_col).unwrap(), "POINT(1 1)");
1137
1138 let linestring_col = &results[27].0;
1139 assert_eq!(
1140 linestring_col.tpe,
1141 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1142 );
1143 assert!(!linestring_col.flags.contains(Flags::NUM_FLAG));
1144 assert!(!linestring_col.flags.contains(Flags::BLOB_FLAG));
1145 assert!(!linestring_col.flags.contains(Flags::SET_FLAG));
1146 assert!(!linestring_col.flags.contains(Flags::ENUM_FLAG));
1147 assert!(!linestring_col.flags.contains(Flags::BINARY_FLAG));
1148 assert_eq!(
1149 to_value::<Text, String>(linestring_col).unwrap(),
1150 "LINESTRING(0 0,1 1,2 2)"
1151 );
1152
1153 let polygon_col = &results[28].0;
1154 assert_eq!(polygon_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1155 assert!(!polygon_col.flags.contains(Flags::NUM_FLAG));
1156 assert!(!polygon_col.flags.contains(Flags::BLOB_FLAG));
1157 assert!(!polygon_col.flags.contains(Flags::SET_FLAG));
1158 assert!(!polygon_col.flags.contains(Flags::ENUM_FLAG));
1159 assert!(!polygon_col.flags.contains(Flags::BINARY_FLAG));
1160 assert_eq!(
1161 to_value::<Text, String>(polygon_col).unwrap(),
1162 "POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))"
1163 );
1164
1165 let multipoint_col = &results[29].0;
1166 assert_eq!(
1167 multipoint_col.tpe,
1168 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1169 );
1170 assert!(!multipoint_col.flags.contains(Flags::NUM_FLAG));
1171 assert!(!multipoint_col.flags.contains(Flags::BLOB_FLAG));
1172 assert!(!multipoint_col.flags.contains(Flags::SET_FLAG));
1173 assert!(!multipoint_col.flags.contains(Flags::ENUM_FLAG));
1174 assert!(!multipoint_col.flags.contains(Flags::BINARY_FLAG));
1175 let multipoint_res = to_value::<Text, String>(multipoint_col).unwrap();
1179 assert!(
1180 multipoint_res == "MULTIPOINT((0 0),(10 10),(10 20),(20 20))"
1181 || multipoint_res == "MULTIPOINT(0 0,10 10,10 20,20 20)"
1182 );
1183
1184 let multilinestring_col = &results[30].0;
1185 assert_eq!(
1186 multilinestring_col.tpe,
1187 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1188 );
1189 assert!(!multilinestring_col.flags.contains(Flags::NUM_FLAG));
1190 assert!(!multilinestring_col.flags.contains(Flags::BLOB_FLAG));
1191 assert!(!multilinestring_col.flags.contains(Flags::SET_FLAG));
1192 assert!(!multilinestring_col.flags.contains(Flags::ENUM_FLAG));
1193 assert!(!multilinestring_col.flags.contains(Flags::BINARY_FLAG));
1194 assert_eq!(
1195 to_value::<Text, String>(multilinestring_col).unwrap(),
1196 "MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))"
1197 );
1198
1199 let polygon_col = &results[31].0;
1200 assert_eq!(polygon_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1201 assert!(!polygon_col.flags.contains(Flags::NUM_FLAG));
1202 assert!(!polygon_col.flags.contains(Flags::BLOB_FLAG));
1203 assert!(!polygon_col.flags.contains(Flags::SET_FLAG));
1204 assert!(!polygon_col.flags.contains(Flags::ENUM_FLAG));
1205 assert!(!polygon_col.flags.contains(Flags::BINARY_FLAG));
1206 assert_eq!(
1207 to_value::<Text, String>(polygon_col).unwrap(),
1208 "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)))"
1209 );
1210
1211 let geometry_collection = &results[32].0;
1212 assert_eq!(
1213 geometry_collection.tpe,
1214 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1215 );
1216 assert!(!geometry_collection.flags.contains(Flags::NUM_FLAG));
1217 assert!(!geometry_collection.flags.contains(Flags::BLOB_FLAG));
1218 assert!(!geometry_collection.flags.contains(Flags::SET_FLAG));
1219 assert!(!geometry_collection.flags.contains(Flags::ENUM_FLAG));
1220 assert!(!geometry_collection.flags.contains(Flags::BINARY_FLAG));
1221 assert_eq!(
1222 to_value::<Text, String>(geometry_collection).unwrap(),
1223 "GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))"
1224 );
1225
1226 let json_col = &results[33].0;
1227 assert!(
1232 json_col.tpe == ffi::enum_field_types::MYSQL_TYPE_JSON
1233 || json_col.tpe == ffi::enum_field_types::MYSQL_TYPE_BLOB
1234 );
1235 assert!(!json_col.flags.contains(Flags::NUM_FLAG));
1236 assert!(json_col.flags.contains(Flags::BLOB_FLAG));
1237 assert!(!json_col.flags.contains(Flags::SET_FLAG));
1238 assert!(!json_col.flags.contains(Flags::ENUM_FLAG));
1239 assert!(json_col.flags.contains(Flags::BINARY_FLAG));
1240 assert_eq!(
1241 to_value::<Text, String>(json_col).unwrap(),
1242 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1243 );
1244 }
1245
1246 fn query_single_table(
1247 query: &'static str,
1248 conn: &MysqlConnection,
1249 bind_tpe: impl Into<(ffi::enum_field_types, Flags)>,
1250 ) -> BindData {
1251 let stmt: Statement = conn.raw_connection.prepare(query).unwrap();
1252 let stmt = MaybeCached::CannotCache(stmt);
1253
1254 let bind = BindData::from_tpe_and_flags(bind_tpe.into());
1255
1256 let mut binds = OutputBinds(Binds { data: vec![bind] });
1257
1258 let stmt = stmt.execute_statement(&mut binds).unwrap();
1259 stmt.populate_row_buffers(&mut binds).unwrap();
1260
1261 binds.0.data.remove(0)
1262 }
1263
1264 fn input_bind(
1265 query: &'static str,
1266 conn: &MysqlConnection,
1267 id: i32,
1268 (mut field, tpe): (Vec<u8>, impl Into<(ffi::enum_field_types, Flags)>),
1269 ) {
1270 let mut stmt = conn.raw_connection.prepare(query).unwrap();
1271 let length = field.len() as _;
1272 let (tpe, flags) = tpe.into();
1273 let capacity = field.capacity();
1274 let ptr = NonNull::new(field.as_mut_ptr());
1275 mem::forget(field);
1276
1277 let field_bind = BindData {
1278 tpe,
1279 bytes: ptr,
1280 capacity,
1281 length,
1282 flags,
1283 is_null: ffi::FALSE,
1284 is_truncated: None,
1285 };
1286
1287 let mut bytes = id.to_be_bytes().to_vec();
1288 let length = bytes.len() as _;
1289 let capacity = bytes.capacity();
1290 let ptr = NonNull::new(bytes.as_mut_ptr());
1291 mem::forget(bytes);
1292
1293 let id_bind = BindData {
1294 tpe: ffi::enum_field_types::MYSQL_TYPE_LONG,
1295 bytes: ptr,
1296 capacity,
1297 length,
1298 flags: Flags::empty(),
1299 is_null: ffi::FALSE,
1300 is_truncated: None,
1301 };
1302
1303 let binds = PreparedStatementBinds(Binds {
1304 data: vec![id_bind, field_bind],
1305 });
1306 stmt.input_bind(binds).unwrap();
1307 stmt.did_an_error_occur().unwrap();
1308 let stmt = MaybeCached::CannotCache(stmt);
1309 unsafe {
1310 stmt.execute().unwrap();
1311 }
1312 }
1313
1314 #[test]
1315 fn check_json_bind() {
1316 table! {
1317 json_test {
1318 id -> Integer,
1319 json_field -> Text,
1320 }
1321 }
1322
1323 let conn = &mut crate::test_helpers::connection();
1324
1325 crate::sql_query("DROP TABLE IF EXISTS json_test CASCADE")
1326 .execute(conn)
1327 .unwrap();
1328
1329 crate::sql_query(
1330 "CREATE TABLE json_test(id INTEGER PRIMARY KEY, json_field JSON NOT NULL)",
1331 )
1332 .execute(conn)
1333 .unwrap();
1334
1335 crate::sql_query("INSERT INTO json_test(id, json_field) VALUES (1, '{\"key1\": \"value1\", \"key2\": \"value2\"}')").execute(conn).unwrap();
1336
1337 let json_col_as_json = query_single_table(
1338 "SELECT json_field FROM json_test",
1339 conn,
1340 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1341 );
1342
1343 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1344 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1345 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1346 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1347 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1348 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1349 assert_eq!(
1350 to_value::<Text, String>(&json_col_as_json).unwrap(),
1351 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1352 );
1353
1354 let json_col_as_text = query_single_table(
1355 "SELECT json_field FROM json_test",
1356 conn,
1357 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1358 );
1359
1360 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1361 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1362 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1363 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1364 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1365 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1366 assert_eq!(
1367 to_value::<Text, String>(&json_col_as_text).unwrap(),
1368 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1369 );
1370 assert_eq!(
1371 json_col_as_json.value().unwrap().as_bytes(),
1372 json_col_as_text.value().unwrap().as_bytes()
1373 );
1374
1375 crate::sql_query("DELETE FROM json_test")
1376 .execute(conn)
1377 .unwrap();
1378
1379 input_bind(
1380 "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1381 conn,
1382 41,
1383 (
1384 b"{\"abc\": 42}".to_vec(),
1385 MysqlType::String,
1386 ),
1388 );
1389
1390 let json_col_as_json = query_single_table(
1391 "SELECT json_field FROM json_test",
1392 conn,
1393 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1394 );
1395
1396 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1397 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1398 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1399 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1400 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1401 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1402 assert_eq!(
1403 to_value::<Text, String>(&json_col_as_json).unwrap(),
1404 "{\"abc\": 42}"
1405 );
1406
1407 let json_col_as_text = query_single_table(
1408 "SELECT json_field FROM json_test",
1409 conn,
1410 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1411 );
1412
1413 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1414 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1415 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1416 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1417 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1418 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1419 assert_eq!(
1420 to_value::<Text, String>(&json_col_as_text).unwrap(),
1421 "{\"abc\": 42}"
1422 );
1423 assert_eq!(
1424 json_col_as_json.value().unwrap().as_bytes(),
1425 json_col_as_text.value().unwrap().as_bytes()
1426 );
1427
1428 crate::sql_query("DELETE FROM json_test")
1429 .execute(conn)
1430 .unwrap();
1431
1432 input_bind(
1433 "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1434 conn,
1435 41,
1436 (b"{\"abca\": 42}".to_vec(), MysqlType::String),
1437 );
1438
1439 let json_col_as_json = query_single_table(
1440 "SELECT json_field FROM json_test",
1441 conn,
1442 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1443 );
1444
1445 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1446 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1447 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1448 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1449 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1450 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1451 assert_eq!(
1452 to_value::<Text, String>(&json_col_as_json).unwrap(),
1453 "{\"abca\": 42}"
1454 );
1455
1456 let json_col_as_text = query_single_table(
1457 "SELECT json_field FROM json_test",
1458 conn,
1459 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1460 );
1461
1462 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1463 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1464 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1465 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1466 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1467 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1468 assert_eq!(
1469 to_value::<Text, String>(&json_col_as_text).unwrap(),
1470 "{\"abca\": 42}"
1471 );
1472 assert_eq!(
1473 json_col_as_json.value().unwrap().as_bytes(),
1474 json_col_as_text.value().unwrap().as_bytes()
1475 );
1476 }
1477
1478 #[test]
1479 fn check_enum_bind() {
1480 let conn = &mut crate::test_helpers::connection();
1481
1482 crate::sql_query("DROP TABLE IF EXISTS enum_test CASCADE")
1483 .execute(conn)
1484 .unwrap();
1485
1486 crate::sql_query("CREATE TABLE enum_test(id INTEGER PRIMARY KEY, enum_field ENUM('red', 'green', 'blue') NOT NULL)").execute(conn)
1487 .unwrap();
1488
1489 crate::sql_query("INSERT INTO enum_test(id, enum_field) VALUES (1, 'green')")
1490 .execute(conn)
1491 .unwrap();
1492
1493 let enum_col_as_enum: BindData =
1494 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1495
1496 assert_eq!(
1497 enum_col_as_enum.tpe,
1498 ffi::enum_field_types::MYSQL_TYPE_STRING
1499 );
1500 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1501 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1502 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1503 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1504 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1505 assert_eq!(
1506 to_value::<Text, String>(&enum_col_as_enum).unwrap(),
1507 "green"
1508 );
1509
1510 for tpe in &[
1511 ffi::enum_field_types::MYSQL_TYPE_BLOB,
1512 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1513 ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1514 ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1515 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1516 ] {
1517 let enum_col_as_text = query_single_table(
1518 "SELECT enum_field FROM enum_test",
1519 conn,
1520 (*tpe, Flags::ENUM_FLAG),
1521 );
1522
1523 assert_eq!(enum_col_as_text.tpe, *tpe);
1524 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1525 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1526 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1527 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1528 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1529 assert_eq!(
1530 to_value::<Text, String>(&enum_col_as_text).unwrap(),
1531 "green"
1532 );
1533 assert_eq!(
1534 enum_col_as_enum.value().unwrap().as_bytes(),
1535 enum_col_as_text.value().unwrap().as_bytes()
1536 );
1537 }
1538
1539 let enum_col_as_text = query_single_table(
1540 "SELECT enum_field FROM enum_test",
1541 conn,
1542 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1543 );
1544
1545 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1546 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1547 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1548 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1549 assert!(!enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1550 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1551 assert_eq!(
1552 to_value::<Text, String>(&enum_col_as_text).unwrap(),
1553 "green"
1554 );
1555 assert_eq!(
1556 enum_col_as_enum.value().unwrap().as_bytes(),
1557 enum_col_as_text.value().unwrap().as_bytes()
1558 );
1559
1560 crate::sql_query("DELETE FROM enum_test")
1561 .execute(conn)
1562 .unwrap();
1563
1564 input_bind(
1565 "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1566 conn,
1567 41,
1568 (b"blue".to_vec(), MysqlType::Enum),
1569 );
1570
1571 let enum_col_as_enum =
1572 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1573
1574 assert_eq!(
1575 enum_col_as_enum.tpe,
1576 ffi::enum_field_types::MYSQL_TYPE_STRING
1577 );
1578 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1579 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1580 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1581 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1582 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1583 assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "blue");
1584
1585 let enum_col_as_text = query_single_table(
1586 "SELECT enum_field FROM enum_test",
1587 conn,
1588 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1589 );
1590
1591 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1592 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1593 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1594 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1595 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1596 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1597 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1598 assert_eq!(
1599 enum_col_as_enum.value().unwrap().as_bytes(),
1600 enum_col_as_text.value().unwrap().as_bytes()
1601 );
1602
1603 let enum_col_as_text = query_single_table(
1604 "SELECT enum_field FROM enum_test",
1605 conn,
1606 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1607 );
1608
1609 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1610 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1611 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1612 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1613 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1614 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1615 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1616 assert_eq!(
1617 enum_col_as_enum.value().unwrap().as_bytes(),
1618 enum_col_as_text.value().unwrap().as_bytes()
1619 );
1620
1621 crate::sql_query("DELETE FROM enum_test")
1622 .execute(conn)
1623 .unwrap();
1624
1625 input_bind(
1626 "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1627 conn,
1628 41,
1629 (
1630 b"red".to_vec(),
1631 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1632 ),
1633 );
1634
1635 let enum_col_as_enum =
1636 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1637
1638 assert_eq!(
1639 enum_col_as_enum.tpe,
1640 ffi::enum_field_types::MYSQL_TYPE_STRING
1641 );
1642 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1643 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1644 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1645 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1646 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1647 assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "red");
1648
1649 let enum_col_as_text = query_single_table(
1650 "SELECT enum_field FROM enum_test",
1651 conn,
1652 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1653 );
1654
1655 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1656 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1657 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1658 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1659 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1660 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1661 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "red");
1662 assert_eq!(
1663 enum_col_as_enum.value().unwrap().as_bytes(),
1664 enum_col_as_text.value().unwrap().as_bytes()
1665 );
1666 }
1667
1668 #[test]
1669 fn check_set_bind() {
1670 let conn = &mut crate::test_helpers::connection();
1671
1672 crate::sql_query("DROP TABLE IF EXISTS set_test CASCADE")
1673 .execute(conn)
1674 .unwrap();
1675
1676 crate::sql_query("CREATE TABLE set_test(id INTEGER PRIMARY KEY, set_field SET('red', 'green', 'blue') NOT NULL)").execute(conn)
1677 .unwrap();
1678
1679 crate::sql_query("INSERT INTO set_test(id, set_field) VALUES (1, 'green')")
1680 .execute(conn)
1681 .unwrap();
1682
1683 let set_col_as_set: BindData =
1684 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1685
1686 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1687 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1688 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1689 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1690 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1691 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1692 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "green");
1693
1694 for tpe in &[
1695 ffi::enum_field_types::MYSQL_TYPE_BLOB,
1696 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1697 ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1698 ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1699 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1700 ] {
1701 let set_col_as_text = query_single_table(
1702 "SELECT set_field FROM set_test",
1703 conn,
1704 (*tpe, Flags::SET_FLAG),
1705 );
1706
1707 assert_eq!(set_col_as_text.tpe, *tpe);
1708 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1709 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1710 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1711 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1712 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1713 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1714 assert_eq!(
1715 set_col_as_set.value().unwrap().as_bytes(),
1716 set_col_as_text.value().unwrap().as_bytes()
1717 );
1718 }
1719 let set_col_as_text = query_single_table(
1720 "SELECT set_field FROM set_test",
1721 conn,
1722 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1723 );
1724
1725 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1726 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1727 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1728 assert!(!set_col_as_text.flags.contains(Flags::SET_FLAG));
1729 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1730 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1731 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1732 assert_eq!(
1733 set_col_as_set.value().unwrap().as_bytes(),
1734 set_col_as_text.value().unwrap().as_bytes()
1735 );
1736
1737 crate::sql_query("DELETE FROM set_test")
1738 .execute(conn)
1739 .unwrap();
1740
1741 input_bind(
1742 "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1743 conn,
1744 41,
1745 (b"blue".to_vec(), MysqlType::Set),
1746 );
1747
1748 let set_col_as_set =
1749 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1750
1751 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1752 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1753 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1754 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1755 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1756 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1757 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "blue");
1758
1759 let set_col_as_text = query_single_table(
1760 "SELECT set_field FROM set_test",
1761 conn,
1762 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1763 );
1764
1765 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1766 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1767 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1768 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1769 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1770 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1771 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "blue");
1772 assert_eq!(
1773 set_col_as_set.value().unwrap().as_bytes(),
1774 set_col_as_text.value().unwrap().as_bytes()
1775 );
1776
1777 crate::sql_query("DELETE FROM set_test")
1778 .execute(conn)
1779 .unwrap();
1780
1781 input_bind(
1782 "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1783 conn,
1784 41,
1785 (b"red".to_vec(), MysqlType::String),
1786 );
1787
1788 let set_col_as_set =
1789 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1790
1791 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1792 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1793 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1794 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1795 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1796 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1797 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "red");
1798
1799 let set_col_as_text = query_single_table(
1800 "SELECT set_field FROM set_test",
1801 conn,
1802 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1803 );
1804
1805 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1806 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1807 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1808 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1809 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1810 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1811 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "red");
1812 assert_eq!(
1813 set_col_as_set.value().unwrap().as_bytes(),
1814 set_col_as_text.value().unwrap().as_bytes()
1815 );
1816 }
1817}