1#![allow(unsafe_code)] use mysqlclient_sys as ffi;
3use std::mem::MaybeUninit;
4use std::mem::{self, ManuallyDrop};
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
15fn bind_buffer(data: Vec<u8>) -> (Option<NonNull<u8>>, libc::c_ulong, usize) {
16 let mut data = ManuallyDrop::new(data);
17 (
18 NonNull::new(data.as_mut_ptr()),
19 data.len() as libc::c_ulong,
20 data.capacity(),
21 )
22}
23
24pub(super) struct PreparedStatementBinds(Binds);
25
26pub(super) struct OutputBinds(Binds);
27
28impl Clone for OutputBinds {
29 fn clone(&self) -> Self {
30 Self(Binds {
31 data: self.0.data.clone(),
32 })
33 }
34}
35
36struct Binds {
37 data: Vec<BindData>,
38}
39
40impl PreparedStatementBinds {
41 pub(super) fn from_input_data<Iter>(input: Iter) -> Self
42 where
43 Iter: IntoIterator<Item = (MysqlType, Option<Vec<u8>>)>,
44 {
45 let data = input
46 .into_iter()
47 .map(BindData::for_input)
48 .collect::<Vec<_>>();
49
50 Self(Binds { data })
51 }
52
53 pub(super) fn with_mysql_binds<F, T>(&mut self, f: F) -> T
54 where
55 F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
56 {
57 self.0.with_mysql_binds(f)
58 }
59}
60
61impl OutputBinds {
62 pub(super) fn from_output_types(
63 types: &[Option<MysqlType>],
64 metadata: &StatementMetadata,
65 ) -> Self {
66 let data = metadata
67 .fields()
68 .iter()
69 .zip(types.iter().copied().chain(std::iter::repeat(None)))
70 .map(|(field, tpe)| BindData::for_output(tpe, field))
71 .collect();
72
73 Self(Binds { data })
74 }
75
76 pub(super) fn populate_dynamic_buffers(&mut self, stmt: &StatementUse<'_>) -> QueryResult<()> {
77 for (i, data) in self.0.data.iter_mut().enumerate() {
78 data.did_numeric_overflow_occur()?;
79 unsafe {
82 if let Some((mut bind, offset)) = data.bind_for_truncated_data() {
83 stmt.fetch_column(&mut bind, i, offset)?
84 } else {
85 data.update_buffer_length()
86 }
87 }
88 }
89
90 unsafe { self.with_mysql_binds(|bind_ptr| stmt.bind_result(bind_ptr)) }
91 }
92
93 pub(super) fn update_buffer_lengths(&mut self) {
94 for data in &mut self.0.data {
95 data.update_buffer_length();
96 }
97 }
98
99 pub(super) fn with_mysql_binds<F, T>(&mut self, f: F) -> T
100 where
101 F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
102 {
103 self.0.with_mysql_binds(f)
104 }
105}
106
107impl Binds {
108 fn with_mysql_binds<F, T>(&mut self, f: F) -> T
109 where
110 F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
111 {
112 let mut binds = self
113 .data
114 .iter_mut()
115 .map(|x| unsafe { x.mysql_bind() })
116 .collect::<Vec<_>>();
117 f(binds.as_mut_ptr())
118 }
119}
120
121impl Index<usize> for OutputBinds {
122 type Output = BindData;
123 fn index(&self, index: usize) -> &Self::Output {
124 &self.0.data[index]
125 }
126}
127
128bitflags::bitflags! {
129 #[derive(Clone, Copy, Debug)]
130 pub(crate) struct Flags: u32 {
131 const NOT_NULL_FLAG = 1;
132 const PRI_KEY_FLAG = 2;
133 const UNIQUE_KEY_FLAG = 4;
134 const MULTIPLE_KEY_FLAG = 8;
135 const BLOB_FLAG = 16;
136 const UNSIGNED_FLAG = 32;
137 const ZEROFILL_FLAG = 64;
138 const BINARY_FLAG = 128;
139 const ENUM_FLAG = 256;
140 const AUTO_INCREMENT_FLAG = 512;
141 const TIMESTAMP_FLAG = 1024;
142 const SET_FLAG = 2048;
143 const NO_DEFAULT_VALUE_FLAG = 4096;
144 const ON_UPDATE_NOW_FLAG = 8192;
145 const NUM_FLAG = 32768;
146 const PART_KEY_FLAG = 16384;
147 const GROUP_FLAG = 32768;
148 const UNIQUE_FLAG = 65536;
149 const BINCMP_FLAG = 130_172;
150 const GET_FIXED_FIELDS_FLAG = (1<<18);
151 const FIELD_IN_PART_FUNC_FLAG = (1 << 19);
152 }
153}
154
155impl From<u32> for Flags {
156 fn from(flags: u32) -> Self {
157 Flags::from_bits(flags).expect(
158 "We encountered an unknown type flag while parsing \
159 Mysql's type information. If you see this error message \
160 please open an issue at diesels github page.",
161 )
162 }
163}
164
165#[derive(Debug)]
166pub(super) struct BindData {
167 tpe: ffi::enum_field_types,
168 bytes: Option<NonNull<u8>>,
169 length: libc::c_ulong,
170 capacity: usize,
171 flags: Flags,
172 is_null: ffi::my_bool,
173 is_truncated: Option<ffi::my_bool>,
174}
175
176impl Clone for BindData {
180 fn clone(&self) -> Self {
181 let (ptr, len, capacity) = if let Some(ptr) = self.bytes {
182 let slice = unsafe {
183 std::slice::from_raw_parts(
191 ptr.as_ptr(),
192 self.length.try_into().expect("usize is at least 32bit"),
193 )
194 };
195 bind_buffer(slice.to_owned())
196 } else {
197 (None, 0, 0)
198 };
199 Self {
200 tpe: self.tpe,
201 bytes: ptr,
202 length: len,
203 capacity,
204 flags: self.flags,
205 is_null: self.is_null,
206 is_truncated: self.is_truncated,
207 }
208 }
209}
210
211impl Drop for BindData {
212 fn drop(&mut self) {
213 if let Some(bytes) = self.bytes {
214 std::mem::drop(unsafe {
215 Vec::from_raw_parts(bytes.as_ptr(), 0, self.capacity)
222 });
223 self.bytes = None;
224 }
225 }
226}
227
228impl BindData {
229 fn for_input((tpe, data): (MysqlType, Option<Vec<u8>>)) -> Self {
230 let (tpe, flags) = tpe.into();
231 let is_null = ffi::my_bool::from(data.is_none());
232 let (ptr, len, capacity) = bind_buffer(data.unwrap_or_default());
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 (ptr, length, capacity) = bind_buffer(vec![0; len]);
383
384 Self {
385 tpe,
386 bytes: ptr,
387 length,
388 capacity,
389 flags,
390 is_null: super::raw::ffi_false(),
391 is_truncated: Some(super::raw::ffi_false()),
392 }
393 }
394
395 fn is_truncated(&self) -> bool {
396 self.is_truncated.unwrap_or(super::raw::ffi_false()) != super::raw::ffi_false()
397 }
398
399 fn is_fixed_size_buffer(&self) -> bool {
400 known_buffer_size_for_ffi_type(self.tpe).is_some()
401 }
402
403 pub(super) fn value(&'_ self) -> Option<MysqlValue<'_>> {
404 if self.is_null() {
405 None
406 } else {
407 let data = self.bytes?;
408 let tpe = (self.tpe, self.flags).into();
409 if self.tpe == self::ffi::enum_field_types::MYSQL_TYPE_LONGLONG && self.length == 0 {
412 return None;
413 }
414
415 let slice = unsafe {
416 std::slice::from_raw_parts(
424 data.as_ptr(),
425 self.length.try_into().expect("Usize is at least 32 bit"),
426 )
427 };
428 Some(MysqlValue::new_internal(slice, tpe))
429 }
430 }
431
432 pub(super) fn is_null(&self) -> bool {
433 self.is_null != ffi::my_bool::default()
434 }
435
436 fn update_buffer_length(&mut self) {
437 use std::cmp::min;
438
439 let actual_bytes_in_buffer = min(
440 self.capacity,
441 self.length.try_into().expect("Usize is at least 32 bit"),
442 );
443 self.length = actual_bytes_in_buffer as libc::c_ulong;
444 }
445
446 unsafe fn mysql_bind(&mut self) -> ffi::MYSQL_BIND {
450 use std::ptr::addr_of_mut;
451
452 let mut bind: MaybeUninit<ffi::MYSQL_BIND> = mem::MaybeUninit::zeroed();
453 let ptr = bind.as_mut_ptr();
454
455 unsafe {
456 addr_of_mut!((*ptr).buffer_type).write(self.tpe);
457 addr_of_mut!((*ptr).buffer).write(
458 self.bytes
459 .map(|p| p.as_ptr())
460 .unwrap_or(std::ptr::null_mut()) as *mut libc::c_void,
461 );
462 addr_of_mut!((*ptr).buffer_length).write(self.capacity as libc::c_ulong);
463 addr_of_mut!((*ptr).length).write(&mut self.length);
464 addr_of_mut!((*ptr).is_null).write(&mut self.is_null);
465 addr_of_mut!((*ptr).is_unsigned)
466 .write(self.flags.contains(Flags::UNSIGNED_FLAG) as ffi::my_bool);
467
468 if let Some(ref mut is_truncated) = self.is_truncated {
469 addr_of_mut!((*ptr).error).write(is_truncated);
470 }
471
472 bind.assume_init()
474 }
475 }
476
477 unsafe fn bind_for_truncated_data(&mut self) -> Option<(ffi::MYSQL_BIND, usize)> {
484 if self.is_truncated() {
485 if let Some(bytes) = self.bytes {
486 let mut bytes =
487 unsafe { Vec::from_raw_parts(bytes.as_ptr(), self.capacity, self.capacity) };
488 self.bytes = None;
489
490 let offset = self.capacity;
491 let truncated_amount =
492 usize::try_from(self.length).expect("Usize is at least 32 bit") - offset;
493
494 debug_assert!(
495 truncated_amount > 0,
496 "output buffers were invalidated \
497 without calling `mysql_stmt_bind_result`"
498 );
499
500 bytes.reserve(truncated_amount);
503 let (ptr, _length, capacity) = bind_buffer(bytes);
504 self.capacity = capacity;
505 self.bytes = ptr;
506
507 let mut bind = unsafe { self.mysql_bind() };
508
509 if let Some(ptr) = self.bytes {
510 bind.buffer = unsafe { ptr.as_ptr().add(offset) as *mut libc::c_void };
513 bind.buffer_length = truncated_amount as libc::c_ulong;
514 } else {
515 bind.buffer_length = 0;
516 }
517 Some((bind, offset))
518 } else {
519 let (ptr, _length, capacity) = bind_buffer(vec![
523 0_u8;
524 self.length.try_into().expect(
525 "usize is at least 32 bit"
526 )
527 ]);
528 self.capacity = capacity;
529 self.bytes = ptr;
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 (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 (ptr, _length, capacity) = bind_buffer(field);
1288
1289 let field_bind = BindData {
1290 tpe,
1291 bytes: ptr,
1292 capacity,
1293 length,
1294 flags,
1295 is_null: ffi::FALSE,
1296 is_truncated: None,
1297 };
1298
1299 let (ptr, length, capacity) = bind_buffer(id.to_be_bytes().to_vec());
1300
1301 let id_bind = BindData {
1302 tpe: ffi::enum_field_types::MYSQL_TYPE_LONG,
1303 bytes: ptr,
1304 capacity,
1305 length,
1306 flags: Flags::empty(),
1307 is_null: ffi::FALSE,
1308 is_truncated: None,
1309 };
1310
1311 let binds = PreparedStatementBinds(Binds {
1312 data: vec![id_bind, field_bind],
1313 });
1314 stmt.input_bind(binds).unwrap();
1315 stmt.did_an_error_occur().unwrap();
1316 let stmt = MaybeCached::CannotCache(stmt);
1317 unsafe {
1318 stmt.execute().unwrap();
1319 }
1320 }
1321
1322 #[diesel_test_helper::test]
1323 fn check_json_bind() {
1324 table! {
1325 json_test {
1326 id -> Integer,
1327 json_field -> Text,
1328 }
1329 }
1330
1331 let conn = &mut crate::test_helpers::connection();
1332
1333 crate::sql_query("DROP TABLE IF EXISTS json_test CASCADE")
1334 .execute(conn)
1335 .unwrap();
1336
1337 crate::sql_query(
1338 "CREATE TABLE json_test(id INTEGER PRIMARY KEY, json_field JSON NOT NULL)",
1339 )
1340 .execute(conn)
1341 .unwrap();
1342
1343 crate::sql_query("INSERT INTO json_test(id, json_field) VALUES (1, '{\"key1\": \"value1\", \"key2\": \"value2\"}')").execute(conn).unwrap();
1344
1345 let json_col_as_json = query_single_table(
1346 "SELECT json_field FROM json_test",
1347 conn,
1348 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1349 );
1350
1351 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1352 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1353 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1354 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1355 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1356 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1357 assert_eq!(
1358 to_value::<Text, String>(&json_col_as_json).unwrap(),
1359 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1360 );
1361
1362 let json_col_as_text = query_single_table(
1363 "SELECT json_field FROM json_test",
1364 conn,
1365 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1366 );
1367
1368 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1369 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1370 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1371 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1372 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1373 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1374 assert_eq!(
1375 to_value::<Text, String>(&json_col_as_text).unwrap(),
1376 "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1377 );
1378 assert_eq!(
1379 json_col_as_json.value().unwrap().as_bytes(),
1380 json_col_as_text.value().unwrap().as_bytes()
1381 );
1382
1383 crate::sql_query("DELETE FROM json_test")
1384 .execute(conn)
1385 .unwrap();
1386
1387 input_bind(
1388 "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1389 conn,
1390 41,
1391 (
1392 b"{\"abc\": 42}".to_vec(),
1393 MysqlType::String,
1394 ),
1396 );
1397
1398 let json_col_as_json = query_single_table(
1399 "SELECT json_field FROM json_test",
1400 conn,
1401 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1402 );
1403
1404 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1405 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1406 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1407 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1408 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1409 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1410 assert_eq!(
1411 to_value::<Text, String>(&json_col_as_json).unwrap(),
1412 "{\"abc\": 42}"
1413 );
1414
1415 let json_col_as_text = query_single_table(
1416 "SELECT json_field FROM json_test",
1417 conn,
1418 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1419 );
1420
1421 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1422 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1423 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1424 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1425 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1426 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1427 assert_eq!(
1428 to_value::<Text, String>(&json_col_as_text).unwrap(),
1429 "{\"abc\": 42}"
1430 );
1431 assert_eq!(
1432 json_col_as_json.value().unwrap().as_bytes(),
1433 json_col_as_text.value().unwrap().as_bytes()
1434 );
1435
1436 crate::sql_query("DELETE FROM json_test")
1437 .execute(conn)
1438 .unwrap();
1439
1440 input_bind(
1441 "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1442 conn,
1443 41,
1444 (b"{\"abca\": 42}".to_vec(), MysqlType::String),
1445 );
1446
1447 let json_col_as_json = query_single_table(
1448 "SELECT json_field FROM json_test",
1449 conn,
1450 (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1451 );
1452
1453 assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1454 assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1455 assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1456 assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1457 assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1458 assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1459 assert_eq!(
1460 to_value::<Text, String>(&json_col_as_json).unwrap(),
1461 "{\"abca\": 42}"
1462 );
1463
1464 let json_col_as_text = query_single_table(
1465 "SELECT json_field FROM json_test",
1466 conn,
1467 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1468 );
1469
1470 assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1471 assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1472 assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1473 assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1474 assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1475 assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1476 assert_eq!(
1477 to_value::<Text, String>(&json_col_as_text).unwrap(),
1478 "{\"abca\": 42}"
1479 );
1480 assert_eq!(
1481 json_col_as_json.value().unwrap().as_bytes(),
1482 json_col_as_text.value().unwrap().as_bytes()
1483 );
1484 }
1485
1486 #[diesel_test_helper::test]
1487 fn check_enum_bind() {
1488 let conn = &mut crate::test_helpers::connection();
1489
1490 crate::sql_query("DROP TABLE IF EXISTS enum_test CASCADE")
1491 .execute(conn)
1492 .unwrap();
1493
1494 crate::sql_query("CREATE TABLE enum_test(id INTEGER PRIMARY KEY, enum_field ENUM('red', 'green', 'blue') NOT NULL)").execute(conn)
1495 .unwrap();
1496
1497 crate::sql_query("INSERT INTO enum_test(id, enum_field) VALUES (1, 'green')")
1498 .execute(conn)
1499 .unwrap();
1500
1501 let enum_col_as_enum: BindData =
1502 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1503
1504 assert_eq!(
1505 enum_col_as_enum.tpe,
1506 ffi::enum_field_types::MYSQL_TYPE_STRING
1507 );
1508 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1509 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1510 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1511 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1512 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1513 assert_eq!(
1514 to_value::<Text, String>(&enum_col_as_enum).unwrap(),
1515 "green"
1516 );
1517
1518 for tpe in &[
1519 ffi::enum_field_types::MYSQL_TYPE_BLOB,
1520 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1521 ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1522 ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1523 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1524 ] {
1525 let enum_col_as_text = query_single_table(
1526 "SELECT enum_field FROM enum_test",
1527 conn,
1528 (*tpe, Flags::ENUM_FLAG),
1529 );
1530
1531 assert_eq!(enum_col_as_text.tpe, *tpe);
1532 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1533 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1534 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1535 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1536 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1537 assert_eq!(
1538 to_value::<Text, String>(&enum_col_as_text).unwrap(),
1539 "green"
1540 );
1541 assert_eq!(
1542 enum_col_as_enum.value().unwrap().as_bytes(),
1543 enum_col_as_text.value().unwrap().as_bytes()
1544 );
1545 }
1546
1547 let enum_col_as_text = query_single_table(
1548 "SELECT enum_field FROM enum_test",
1549 conn,
1550 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1551 );
1552
1553 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1554 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1555 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1556 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1557 assert!(!enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1558 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1559 assert_eq!(
1560 to_value::<Text, String>(&enum_col_as_text).unwrap(),
1561 "green"
1562 );
1563 assert_eq!(
1564 enum_col_as_enum.value().unwrap().as_bytes(),
1565 enum_col_as_text.value().unwrap().as_bytes()
1566 );
1567
1568 crate::sql_query("DELETE FROM enum_test")
1569 .execute(conn)
1570 .unwrap();
1571
1572 input_bind(
1573 "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1574 conn,
1575 41,
1576 (b"blue".to_vec(), MysqlType::Enum),
1577 );
1578
1579 let enum_col_as_enum =
1580 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1581
1582 assert_eq!(
1583 enum_col_as_enum.tpe,
1584 ffi::enum_field_types::MYSQL_TYPE_STRING
1585 );
1586 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1587 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1588 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1589 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1590 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1591 assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "blue");
1592
1593 let enum_col_as_text = query_single_table(
1594 "SELECT enum_field FROM enum_test",
1595 conn,
1596 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1597 );
1598
1599 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1600 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1601 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1602 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1603 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1604 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1605 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1606 assert_eq!(
1607 enum_col_as_enum.value().unwrap().as_bytes(),
1608 enum_col_as_text.value().unwrap().as_bytes()
1609 );
1610
1611 let enum_col_as_text = query_single_table(
1612 "SELECT enum_field FROM enum_test",
1613 conn,
1614 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1615 );
1616
1617 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1618 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1619 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1620 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1621 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1622 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1623 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1624 assert_eq!(
1625 enum_col_as_enum.value().unwrap().as_bytes(),
1626 enum_col_as_text.value().unwrap().as_bytes()
1627 );
1628
1629 crate::sql_query("DELETE FROM enum_test")
1630 .execute(conn)
1631 .unwrap();
1632
1633 input_bind(
1634 "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1635 conn,
1636 41,
1637 (
1638 b"red".to_vec(),
1639 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1640 ),
1641 );
1642
1643 let enum_col_as_enum =
1644 query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1645
1646 assert_eq!(
1647 enum_col_as_enum.tpe,
1648 ffi::enum_field_types::MYSQL_TYPE_STRING
1649 );
1650 assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1651 assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1652 assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1653 assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1654 assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1655 assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "red");
1656
1657 let enum_col_as_text = query_single_table(
1658 "SELECT enum_field FROM enum_test",
1659 conn,
1660 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1661 );
1662
1663 assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1664 assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1665 assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1666 assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1667 assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1668 assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1669 assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "red");
1670 assert_eq!(
1671 enum_col_as_enum.value().unwrap().as_bytes(),
1672 enum_col_as_text.value().unwrap().as_bytes()
1673 );
1674 }
1675
1676 #[diesel_test_helper::test]
1677 fn check_set_bind() {
1678 let conn = &mut crate::test_helpers::connection();
1679
1680 crate::sql_query("DROP TABLE IF EXISTS set_test CASCADE")
1681 .execute(conn)
1682 .unwrap();
1683
1684 crate::sql_query("CREATE TABLE set_test(id INTEGER PRIMARY KEY, set_field SET('red', 'green', 'blue') NOT NULL)").execute(conn)
1685 .unwrap();
1686
1687 crate::sql_query("INSERT INTO set_test(id, set_field) VALUES (1, 'green')")
1688 .execute(conn)
1689 .unwrap();
1690
1691 let set_col_as_set: BindData =
1692 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1693
1694 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1695 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1696 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1697 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1698 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1699 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1700 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "green");
1701
1702 for tpe in &[
1703 ffi::enum_field_types::MYSQL_TYPE_BLOB,
1704 ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1705 ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1706 ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1707 ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1708 ] {
1709 let set_col_as_text = query_single_table(
1710 "SELECT set_field FROM set_test",
1711 conn,
1712 (*tpe, Flags::SET_FLAG),
1713 );
1714
1715 assert_eq!(set_col_as_text.tpe, *tpe);
1716 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1717 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1718 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1719 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1720 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1721 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1722 assert_eq!(
1723 set_col_as_set.value().unwrap().as_bytes(),
1724 set_col_as_text.value().unwrap().as_bytes()
1725 );
1726 }
1727 let set_col_as_text = query_single_table(
1728 "SELECT set_field FROM set_test",
1729 conn,
1730 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1731 );
1732
1733 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1734 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1735 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1736 assert!(!set_col_as_text.flags.contains(Flags::SET_FLAG));
1737 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1738 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1739 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1740 assert_eq!(
1741 set_col_as_set.value().unwrap().as_bytes(),
1742 set_col_as_text.value().unwrap().as_bytes()
1743 );
1744
1745 crate::sql_query("DELETE FROM set_test")
1746 .execute(conn)
1747 .unwrap();
1748
1749 input_bind(
1750 "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1751 conn,
1752 41,
1753 (b"blue".to_vec(), MysqlType::Set),
1754 );
1755
1756 let set_col_as_set =
1757 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1758
1759 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1760 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1761 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1762 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1763 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1764 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1765 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "blue");
1766
1767 let set_col_as_text = query_single_table(
1768 "SELECT set_field FROM set_test",
1769 conn,
1770 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1771 );
1772
1773 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1774 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1775 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1776 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1777 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1778 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1779 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "blue");
1780 assert_eq!(
1781 set_col_as_set.value().unwrap().as_bytes(),
1782 set_col_as_text.value().unwrap().as_bytes()
1783 );
1784
1785 crate::sql_query("DELETE FROM set_test")
1786 .execute(conn)
1787 .unwrap();
1788
1789 input_bind(
1790 "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1791 conn,
1792 41,
1793 (b"red".to_vec(), MysqlType::String),
1794 );
1795
1796 let set_col_as_set =
1797 query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1798
1799 assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1800 assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1801 assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1802 assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1803 assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1804 assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1805 assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "red");
1806
1807 let set_col_as_text = query_single_table(
1808 "SELECT set_field FROM set_test",
1809 conn,
1810 (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1811 );
1812
1813 assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1814 assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1815 assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1816 assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1817 assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1818 assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1819 assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "red");
1820 assert_eq!(
1821 set_col_as_set.value().unwrap().as_bytes(),
1822 set_col_as_text.value().unwrap().as_bytes()
1823 );
1824 }
1825}