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
128pub(crate) struct Flags(<Flags as
::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
impl ::core::clone::Clone for Flags {
#[inline]
fn clone(&self) -> Flags {
let _:
::core::clone::AssertParamIsClone<<Flags as
::bitflags::__private::PublicFlags>::Internal>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for Flags { }
#[automatically_derived]
impl ::core::fmt::Debug for Flags {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Flags",
&&self.0)
}
}
impl Flags {
#[allow(deprecated, non_upper_case_globals,)]
pub const NOT_NULL_FLAG: Self = Self::from_bits_retain(1);
#[allow(deprecated, non_upper_case_globals,)]
pub const PRI_KEY_FLAG: Self = Self::from_bits_retain(2);
#[allow(deprecated, non_upper_case_globals,)]
pub const UNIQUE_KEY_FLAG: Self = Self::from_bits_retain(4);
#[allow(deprecated, non_upper_case_globals,)]
pub const MULTIPLE_KEY_FLAG: Self = Self::from_bits_retain(8);
#[allow(deprecated, non_upper_case_globals,)]
pub const BLOB_FLAG: Self = Self::from_bits_retain(16);
#[allow(deprecated, non_upper_case_globals,)]
pub const UNSIGNED_FLAG: Self = Self::from_bits_retain(32);
#[allow(deprecated, non_upper_case_globals,)]
pub const ZEROFILL_FLAG: Self = Self::from_bits_retain(64);
#[allow(deprecated, non_upper_case_globals,)]
pub const BINARY_FLAG: Self = Self::from_bits_retain(128);
#[allow(deprecated, non_upper_case_globals,)]
pub const ENUM_FLAG: Self = Self::from_bits_retain(256);
#[allow(deprecated, non_upper_case_globals,)]
pub const AUTO_INCREMENT_FLAG: Self = Self::from_bits_retain(512);
#[allow(deprecated, non_upper_case_globals,)]
pub const TIMESTAMP_FLAG: Self = Self::from_bits_retain(1024);
#[allow(deprecated, non_upper_case_globals,)]
pub const SET_FLAG: Self = Self::from_bits_retain(2048);
#[allow(deprecated, non_upper_case_globals,)]
pub const NO_DEFAULT_VALUE_FLAG: Self = Self::from_bits_retain(4096);
#[allow(deprecated, non_upper_case_globals,)]
pub const ON_UPDATE_NOW_FLAG: Self = Self::from_bits_retain(8192);
#[allow(deprecated, non_upper_case_globals,)]
pub const NUM_FLAG: Self = Self::from_bits_retain(32768);
#[allow(deprecated, non_upper_case_globals,)]
pub const PART_KEY_FLAG: Self = Self::from_bits_retain(16384);
#[allow(deprecated, non_upper_case_globals,)]
pub const GROUP_FLAG: Self = Self::from_bits_retain(32768);
#[allow(deprecated, non_upper_case_globals,)]
pub const UNIQUE_FLAG: Self = Self::from_bits_retain(65536);
#[allow(deprecated, non_upper_case_globals,)]
pub const BINCMP_FLAG: Self = Self::from_bits_retain(130_172);
#[allow(deprecated, non_upper_case_globals,)]
pub const GET_FIXED_FIELDS_FLAG: Self = Self::from_bits_retain((1 << 18));
#[allow(deprecated, non_upper_case_globals,)]
pub const FIELD_IN_PART_FUNC_FLAG: Self =
Self::from_bits_retain((1 << 19));
}
impl ::bitflags::Flags for Flags {
const FLAGS: &'static [::bitflags::Flag<Flags>] =
&[{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("NOT_NULL_FLAG", Flags::NOT_NULL_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("PRI_KEY_FLAG", Flags::PRI_KEY_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("UNIQUE_KEY_FLAG",
Flags::UNIQUE_KEY_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("MULTIPLE_KEY_FLAG",
Flags::MULTIPLE_KEY_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("BLOB_FLAG", Flags::BLOB_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("UNSIGNED_FLAG", Flags::UNSIGNED_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("ZEROFILL_FLAG", Flags::ZEROFILL_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("BINARY_FLAG", Flags::BINARY_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("ENUM_FLAG", Flags::ENUM_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("AUTO_INCREMENT_FLAG",
Flags::AUTO_INCREMENT_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("TIMESTAMP_FLAG",
Flags::TIMESTAMP_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("SET_FLAG", Flags::SET_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("NO_DEFAULT_VALUE_FLAG",
Flags::NO_DEFAULT_VALUE_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("ON_UPDATE_NOW_FLAG",
Flags::ON_UPDATE_NOW_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("NUM_FLAG", Flags::NUM_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("PART_KEY_FLAG", Flags::PART_KEY_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("GROUP_FLAG", Flags::GROUP_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("UNIQUE_FLAG", Flags::UNIQUE_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("BINCMP_FLAG", Flags::BINCMP_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("GET_FIXED_FIELDS_FLAG",
Flags::GET_FIXED_FIELDS_FLAG)
},
{
#[allow(deprecated, non_upper_case_globals,)]
::bitflags::Flag::new("FIELD_IN_PART_FUNC_FLAG",
Flags::FIELD_IN_PART_FUNC_FLAG)
}];
type Bits = u32;
fn bits(&self) -> u32 { Flags::bits(self) }
fn from_bits_retain(bits: u32) -> Flags { Flags::from_bits_retain(bits) }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy ::
assign_op_pattern, clippy :: indexing_slicing, clippy :: same_name_method,
clippy :: iter_without_into_iter,)]
const _: () =
{
#[repr(transparent)]
pub(crate) struct InternalBitFlags(u32);
#[automatically_derived]
impl ::core::clone::Clone for InternalBitFlags {
#[inline]
fn clone(&self) -> InternalBitFlags {
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for InternalBitFlags { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
#[automatically_derived]
impl ::core::cmp::PartialEq for InternalBitFlags {
#[inline]
fn eq(&self, other: &InternalBitFlags) -> bool {
self.0 == other.0
}
}
#[automatically_derived]
impl ::core::cmp::Eq for InternalBitFlags {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for InternalBitFlags {
#[inline]
fn partial_cmp(&self, other: &InternalBitFlags)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::cmp::Ord for InternalBitFlags {
#[inline]
fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}
#[automatically_derived]
impl ::core::hash::Hash for InternalBitFlags {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.0, state)
}
}
impl ::bitflags::__private::PublicFlags for Flags {
type Primitive = u32;
type Internal = InternalBitFlags;
}
impl ::bitflags::__private::core::default::Default for
InternalBitFlags {
#[inline]
fn default() -> Self { InternalBitFlags::empty() }
}
impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
if self.is_empty() {
f.write_fmt(format_args!("{0:#x}",
<u32 as ::bitflags::Bits>::EMPTY))
} else {
::bitflags::__private::core::fmt::Display::fmt(self, f)
}
}
}
impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
fn fmt(&self,
f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
-> ::bitflags::__private::core::fmt::Result {
::bitflags::parser::to_writer(&Flags(*self), f)
}
}
impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
type Err = ::bitflags::parser::ParseError;
fn from_str(s: &str)
->
::bitflags::__private::core::result::Result<Self,
Self::Err> {
::bitflags::parser::from_str::<Flags>(s).map(|flags| flags.0)
}
}
impl ::bitflags::__private::core::convert::AsRef<u32> for
InternalBitFlags {
fn as_ref(&self) -> &u32 { &self.0 }
}
impl ::bitflags::__private::core::convert::From<u32> for
InternalBitFlags {
fn from(bits: u32) -> Self { Self::from_bits_retain(bits) }
}
#[allow(dead_code, deprecated, unused_attributes)]
impl InternalBitFlags {
#[inline]
pub const fn empty() -> Self {
Self(<u32 as ::bitflags::Bits>::EMPTY)
}
#[inline]
pub const fn all() -> Self {
let mut truncated = <u32 as ::bitflags::Bits>::EMPTY;
let mut i = 0;
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
{
{
let flag =
<Flags as ::bitflags::Flags>::FLAGS[i].value().bits();
truncated = truncated | flag;
i += 1;
}
};
let _ = i;
Self(truncated)
}
#[inline]
pub const fn bits(&self) -> u32 { self.0 }
#[inline]
pub const fn from_bits(bits: u32)
-> ::bitflags::__private::core::option::Option<Self> {
let truncated = Self::from_bits_truncate(bits).0;
if truncated == bits {
::bitflags::__private::core::option::Option::Some(Self(bits))
} else { ::bitflags::__private::core::option::Option::None }
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(bits & Self::all().0)
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self { Self(bits) }
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
{
if name == "NOT_NULL_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::NOT_NULL_FLAG.bits()));
}
};
;
{
if name == "PRI_KEY_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::PRI_KEY_FLAG.bits()));
}
};
;
{
if name == "UNIQUE_KEY_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::UNIQUE_KEY_FLAG.bits()));
}
};
;
{
if name == "MULTIPLE_KEY_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::MULTIPLE_KEY_FLAG.bits()));
}
};
;
{
if name == "BLOB_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::BLOB_FLAG.bits()));
}
};
;
{
if name == "UNSIGNED_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::UNSIGNED_FLAG.bits()));
}
};
;
{
if name == "ZEROFILL_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::ZEROFILL_FLAG.bits()));
}
};
;
{
if name == "BINARY_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::BINARY_FLAG.bits()));
}
};
;
{
if name == "ENUM_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::ENUM_FLAG.bits()));
}
};
;
{
if name == "AUTO_INCREMENT_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::AUTO_INCREMENT_FLAG.bits()));
}
};
;
{
if name == "TIMESTAMP_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::TIMESTAMP_FLAG.bits()));
}
};
;
{
if name == "SET_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::SET_FLAG.bits()));
}
};
;
{
if name == "NO_DEFAULT_VALUE_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::NO_DEFAULT_VALUE_FLAG.bits()));
}
};
;
{
if name == "ON_UPDATE_NOW_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::ON_UPDATE_NOW_FLAG.bits()));
}
};
;
{
if name == "NUM_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::NUM_FLAG.bits()));
}
};
;
{
if name == "PART_KEY_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::PART_KEY_FLAG.bits()));
}
};
;
{
if name == "GROUP_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::GROUP_FLAG.bits()));
}
};
;
{
if name == "UNIQUE_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::UNIQUE_FLAG.bits()));
}
};
;
{
if name == "BINCMP_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::BINCMP_FLAG.bits()));
}
};
;
{
if name == "GET_FIXED_FIELDS_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::GET_FIXED_FIELDS_FLAG.bits()));
}
};
;
{
if name == "FIELD_IN_PART_FUNC_FLAG" {
return ::bitflags::__private::core::option::Option::Some(Self(Flags::FIELD_IN_PART_FUNC_FLAG.bits()));
}
};
;
let _ = name;
::bitflags::__private::core::option::Option::None
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.0 == <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn is_all(&self) -> bool {
Self::all().0 | self.0 == self.0
}
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0 & other.0 != <u32 as ::bitflags::Bits>::EMPTY
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0 & other.0 == other.0
}
#[inline]
pub fn insert(&mut self, other: Self) {
*self = Self(self.0).union(other);
}
#[inline]
pub fn remove(&mut self, other: Self) {
*self = Self(self.0).difference(other);
}
#[inline]
pub fn toggle(&mut self, other: Self) {
*self = Self(self.0).symmetric_difference(other);
}
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
if value { self.insert(other); } else { self.remove(other); }
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0 ^ other.0)
}
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self::from_bits_truncate(!self.0)
}
}
impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
type Output = Self;
#[inline]
fn bitor(self, other: InternalBitFlags) -> Self {
self.union(other)
}
}
impl ::bitflags::__private::core::ops::BitOrAssign for
InternalBitFlags {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for
InternalBitFlags {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for
InternalBitFlags {
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
{
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
InternalBitFlags {
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
for InternalBitFlags {
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl InternalBitFlags {
#[inline]
pub const fn iter(&self) -> ::bitflags::iter::Iter<Flags> {
::bitflags::iter::Iter::__private_const_new(<Flags as
::bitflags::Flags>::FLAGS,
Flags::from_bits_retain(self.bits()),
Flags::from_bits_retain(self.bits()))
}
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<Flags> {
::bitflags::iter::IterNames::__private_const_new(<Flags as
::bitflags::Flags>::FLAGS,
Flags::from_bits_retain(self.bits()),
Flags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for
InternalBitFlags {
type Item = Flags;
type IntoIter = ::bitflags::iter::Iter<Flags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
impl InternalBitFlags {
#[inline]
pub fn bits_mut(&mut self) -> &mut u32 { &mut self.0 }
}
#[allow(dead_code, deprecated, unused_attributes)]
impl Flags {
#[inline]
pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
#[inline]
pub const fn all() -> Self { Self(InternalBitFlags::all()) }
#[inline]
pub const fn bits(&self) -> u32 { self.0.bits() }
#[inline]
pub const fn from_bits(bits: u32)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_bits(bits) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
#[inline]
pub const fn from_bits_truncate(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_truncate(bits))
}
#[inline]
pub const fn from_bits_retain(bits: u32) -> Self {
Self(InternalBitFlags::from_bits_retain(bits))
}
#[inline]
pub fn from_name(name: &str)
-> ::bitflags::__private::core::option::Option<Self> {
match InternalBitFlags::from_name(name) {
::bitflags::__private::core::option::Option::Some(bits) =>
::bitflags::__private::core::option::Option::Some(Self(bits)),
::bitflags::__private::core::option::Option::None =>
::bitflags::__private::core::option::Option::None,
}
}
#[inline]
pub const fn is_empty(&self) -> bool { self.0.is_empty() }
#[inline]
pub const fn is_all(&self) -> bool { self.0.is_all() }
#[inline]
pub const fn intersects(&self, other: Self) -> bool {
self.0.intersects(other.0)
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
self.0.contains(other.0)
}
#[inline]
pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
#[inline]
pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
#[inline]
pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
#[inline]
pub fn set(&mut self, other: Self, value: bool) {
self.0.set(other.0, value)
}
#[inline]
#[must_use]
pub const fn intersection(self, other: Self) -> Self {
Self(self.0.intersection(other.0))
}
#[inline]
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0.union(other.0))
}
#[inline]
#[must_use]
pub const fn difference(self, other: Self) -> Self {
Self(self.0.difference(other.0))
}
#[inline]
#[must_use]
pub const fn symmetric_difference(self, other: Self) -> Self {
Self(self.0.symmetric_difference(other.0))
}
#[inline]
#[must_use]
pub const fn complement(self) -> Self {
Self(self.0.complement())
}
}
impl ::bitflags::__private::core::fmt::Binary for Flags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::Octal for Flags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::LowerHex for Flags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::fmt::UpperHex for Flags {
fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
-> ::bitflags::__private::core::fmt::Result {
let inner = self.0;
::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
}
}
impl ::bitflags::__private::core::ops::BitOr for Flags {
type Output = Self;
#[inline]
fn bitor(self, other: Flags) -> Self { self.union(other) }
}
impl ::bitflags::__private::core::ops::BitOrAssign for Flags {
#[inline]
fn bitor_assign(&mut self, other: Self) { self.insert(other); }
}
impl ::bitflags::__private::core::ops::BitXor for Flags {
type Output = Self;
#[inline]
fn bitxor(self, other: Self) -> Self {
self.symmetric_difference(other)
}
}
impl ::bitflags::__private::core::ops::BitXorAssign for Flags {
#[inline]
fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
}
impl ::bitflags::__private::core::ops::BitAnd for Flags {
type Output = Self;
#[inline]
fn bitand(self, other: Self) -> Self { self.intersection(other) }
}
impl ::bitflags::__private::core::ops::BitAndAssign for Flags {
#[inline]
fn bitand_assign(&mut self, other: Self) {
*self =
Self::from_bits_retain(self.bits()).intersection(other);
}
}
impl ::bitflags::__private::core::ops::Sub for Flags {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self { self.difference(other) }
}
impl ::bitflags::__private::core::ops::SubAssign for Flags {
#[inline]
fn sub_assign(&mut self, other: Self) { self.remove(other); }
}
impl ::bitflags::__private::core::ops::Not for Flags {
type Output = Self;
#[inline]
fn not(self) -> Self { self.complement() }
}
impl ::bitflags::__private::core::iter::Extend<Flags> for Flags {
fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(&mut self, iterator: T) {
for item in iterator { self.insert(item) }
}
}
impl ::bitflags::__private::core::iter::FromIterator<Flags> for Flags
{
fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
= Self>>(iterator: T) -> Self {
use ::bitflags::__private::core::iter::Extend;
let mut result = Self::empty();
result.extend(iterator);
result
}
}
impl Flags {
#[inline]
pub const fn iter(&self) -> ::bitflags::iter::Iter<Flags> {
::bitflags::iter::Iter::__private_const_new(<Flags as
::bitflags::Flags>::FLAGS,
Flags::from_bits_retain(self.bits()),
Flags::from_bits_retain(self.bits()))
}
#[inline]
pub const fn iter_names(&self)
-> ::bitflags::iter::IterNames<Flags> {
::bitflags::iter::IterNames::__private_const_new(<Flags as
::bitflags::Flags>::FLAGS,
Flags::from_bits_retain(self.bits()),
Flags::from_bits_retain(self.bits()))
}
}
impl ::bitflags::__private::core::iter::IntoIterator for Flags {
type Item = Flags;
type IntoIter = ::bitflags::iter::Iter<Flags>;
fn into_iter(self) -> Self::IntoIter { self.iter() }
}
};bitflags::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(#[automatically_derived]
impl ::core::fmt::Debug for BindData {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["tpe", "bytes", "length", "capacity", "flags", "is_null",
"is_truncated"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.tpe, &self.bytes, &self.length, &self.capacity,
&self.flags, &self.is_null, &&self.is_truncated];
::core::fmt::Formatter::debug_struct_fields_finish(f, "BindData",
names, values)
}
}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(::alloc::vec::from_elem(0, len)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 &raw mut (*ptr).buffer_typeaddr_of_mut!((*ptr).buffer_type).write(self.tpe);
457 &raw mut (*ptr).bufferaddr_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 &raw mut (*ptr).buffer_lengthaddr_of_mut!((*ptr).buffer_length).write(self.capacity as libc::c_ulong);
463 &raw mut (*ptr).lengthaddr_of_mut!((*ptr).length).write(&mut self.length);
464 &raw mut (*ptr).is_nulladdr_of_mut!((*ptr).is_null).write(&mut self.is_null);
465 &raw mut (*ptr).is_unsignedaddr_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 &raw mut (*ptr).erroraddr_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 if true {
if !(truncated_amount > 0) {
{
::core::panicking::panic_fmt(format_args!("output buffers were invalidated without calling `mysql_stmt_bind_result`"));
}
};
};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(::alloc::vec::from_elem(0_u8,
self.length.try_into().expect("usize is at least 32 bit"))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 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("The year type should have set the unsigned flag. If you ever see this error message, something has gone very wrong. Please open an issue at the diesel github repo in this case")));
}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 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("We ensure at the call side that we do not hit this type here. If you ever see this error, something has gone very wrong. Please open an issue at the diesel github repo in this case")));
}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 {
::core::panicking::panic_fmt(format_args!("not implemented: {0}",
format_args!("Hit a type that should be unsupported in libmysqlclient. If you ever see this error, they probably have added support for one of those types. Please open an issue at the diesel github repo in this case.")));
}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 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("The mysql documentation states that these types are only used on the server side, so if you see this error something has gone wrong. Please open an issue at the diesel github repo.")));
}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 => {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("Unsupported type encountered: {0:?}. If you ever see this error, something has gone wrong. Please open an issue at the diesel github repo in this case.",
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}