Skip to main content

diesel/mysql/connection/
bind.rs

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