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