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