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        dbg!(meta);
827
828        let value = bind.value().expect("Is not null");
829        let value = MysqlValue::new_internal(value.as_bytes(), meta);
830
831        dbg!(T::from_sql(value))
832    }
833
834    #[cfg(feature = "extras")]
835    #[diesel_test_helper::test]
836    fn check_all_the_types() {
837        let conn = &mut crate::test_helpers::connection();
838
839        crate::sql_query("DROP TABLE IF EXISTS all_mysql_types CASCADE")
840            .execute(conn)
841            .unwrap();
842        crate::sql_query(
843            "CREATE TABLE all_mysql_types (
844                    tiny_int TINYINT NOT NULL,
845                    small_int SMALLINT NOT NULL,
846                    medium_int MEDIUMINT NOT NULL,
847                    int_col INTEGER NOT NULL,
848                    big_int BIGINT NOT NULL,
849                    unsigned_int INTEGER UNSIGNED NOT NULL,
850                    zero_fill_int INTEGER ZEROFILL NOT NULL,
851                    numeric_col NUMERIC(20,5) NOT NULL,
852                    decimal_col DECIMAL(20,5) NOT NULL,
853                    float_col FLOAT NOT NULL,
854                    double_col DOUBLE NOT NULL,
855                    bit_col BIT(8) NOT NULL,
856                    date_col DATE NOT NULL,
857                    date_time DATETIME NOT NULL,
858                    timestamp_col TIMESTAMP NOT NULL,
859                    time_col TIME NOT NULL,
860                    year_col YEAR NOT NULL,
861                    char_col CHAR(30) NOT NULL,
862                    varchar_col VARCHAR(30) NOT NULL,
863                    binary_col BINARY(30) NOT NULL,
864                    varbinary_col VARBINARY(30) NOT NULL,
865                    blob_col BLOB NOT NULL,
866                    text_col TEXT NOT NULL,
867                    enum_col ENUM('red', 'green', 'blue') NOT NULL,
868                    set_col SET('one', 'two') NOT NULL,
869                    geom GEOMETRY NOT NULL,
870                    point_col POINT NOT NULL,
871                    linestring_col LINESTRING NOT NULL,
872                    polygon_col POLYGON NOT NULL,
873                    multipoint_col MULTIPOINT NOT NULL,
874                    multilinestring_col MULTILINESTRING NOT NULL,
875                    multipolygon_col MULTIPOLYGON NOT NULL,
876                    geometry_collection GEOMETRYCOLLECTION NOT NULL,
877                    json_col JSON NOT NULL
878            )",
879        )
880        .execute(conn)
881        .unwrap();
882        crate::sql_query(
883                "INSERT INTO all_mysql_types VALUES (
884                    0, -- tiny_int
885                    1, -- small_int
886                    2, -- medium_int
887                    3, -- int_col
888                    -5, -- big_int
889                    42, -- unsigned_int
890                    1, -- zero_fill_int
891                    -999.999, -- numeric_col,
892                    3.14, -- decimal_col,
893                    1.23, -- float_col
894                    4.5678, -- double_col
895                    b'10101010', -- bit_col
896                    '1000-01-01', -- date_col
897                    '9999-12-31 12:34:45.012345', -- date_time
898                    '2020-01-01 10:10:10', -- timestamp_col
899                    '23:01:01', -- time_col
900                    2020, -- year_col
901                    'abc', -- char_col
902                    'foo', -- varchar_col
903                    'a ', -- binary_col
904                    'a ', -- varbinary_col
905                    'binary', -- blob_col
906                    'some text whatever', -- text_col
907                    'red', -- enum_col
908                    'one', -- set_col
909                    ST_GeomFromText('POINT(1 1)'), -- geom
910                    ST_PointFromText('POINT(1 1)'), -- point_col
911                    ST_LineStringFromText('LINESTRING(0 0,1 1,2 2)'), -- linestring_col
912                    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
913                    ST_MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)'), -- multipoint_col
914                    ST_MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))'), -- multilinestring_col
915                    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
916                    ST_GeomCollFromText('GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))'), -- geometry_collection
917                    '{\"key1\": \"value1\", \"key2\": \"value2\"}' -- json_col
918)",
919            ).execute(conn)
920            .unwrap();
921
922        let stmt = crate::mysql::connection::prepared_query(
923            &crate::sql_query(
924                "SELECT
925                    tiny_int, small_int, medium_int, int_col,
926                    big_int, unsigned_int, zero_fill_int,
927                    numeric_col, decimal_col, float_col, double_col, bit_col,
928                    date_col, date_time, timestamp_col, time_col, year_col,
929                    char_col, varchar_col, binary_col, varbinary_col, blob_col,
930                    text_col, enum_col, set_col, ST_AsText(geom), ST_AsText(point_col), ST_AsText(linestring_col),
931                    ST_AsText(polygon_col), ST_AsText(multipoint_col), ST_AsText(multilinestring_col),
932                    ST_AsText(multipolygon_col), ST_AsText(geometry_collection), json_col
933                 FROM all_mysql_types",
934            ),
935            &mut conn.statement_cache,
936            &mut conn.raw_connection,
937            &mut *conn.instrumentation,
938        ).unwrap();
939
940        let metadata = stmt.metadata().unwrap();
941        let mut output_binds =
942            OutputBinds::from_output_types(&vec![None; metadata.fields().len()], &metadata);
943        let stmt = stmt.execute_statement(&mut output_binds).unwrap();
944        stmt.populate_row_buffers(&mut output_binds).unwrap();
945
946        let results: Vec<(BindData, &_)> = output_binds
947            .0
948            .data
949            .into_iter()
950            .zip(metadata.fields())
951            .collect::<Vec<_>>();
952
953        let tiny_int_col = &results[0].0;
954        assert_eq!(tiny_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_TINY);
955        assert!(tiny_int_col.flags.contains(Flags::NUM_FLAG));
956        assert!(!tiny_int_col.flags.contains(Flags::UNSIGNED_FLAG));
957        assert!(matches!(to_value::<TinyInt, i8>(tiny_int_col), Ok(0)));
958
959        let small_int_col = &results[1].0;
960        assert_eq!(small_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_SHORT);
961        assert!(small_int_col.flags.contains(Flags::NUM_FLAG));
962        assert!(!small_int_col.flags.contains(Flags::UNSIGNED_FLAG));
963        assert!(matches!(to_value::<SmallInt, i16>(small_int_col), Ok(1)));
964
965        let medium_int_col = &results[2].0;
966        assert_eq!(medium_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_INT24);
967        assert!(medium_int_col.flags.contains(Flags::NUM_FLAG));
968        assert!(!medium_int_col.flags.contains(Flags::UNSIGNED_FLAG));
969        assert!(matches!(to_value::<Integer, i32>(medium_int_col), Ok(2)));
970
971        let int_col = &results[3].0;
972        assert_eq!(int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG);
973        assert!(int_col.flags.contains(Flags::NUM_FLAG));
974        assert!(!int_col.flags.contains(Flags::UNSIGNED_FLAG));
975        assert!(matches!(to_value::<Integer, i32>(int_col), Ok(3)));
976
977        let big_int_col = &results[4].0;
978        assert_eq!(big_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONGLONG);
979        assert!(big_int_col.flags.contains(Flags::NUM_FLAG));
980        assert!(!big_int_col.flags.contains(Flags::UNSIGNED_FLAG));
981        assert!(matches!(to_value::<TinyInt, i8>(big_int_col), Ok(-5)));
982
983        let unsigned_int_col = &results[5].0;
984        assert_eq!(unsigned_int_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG);
985        assert!(unsigned_int_col.flags.contains(Flags::NUM_FLAG));
986        assert!(unsigned_int_col.flags.contains(Flags::UNSIGNED_FLAG));
987        assert!(matches!(
988            to_value::<Unsigned<Integer>, u32>(unsigned_int_col),
989            Ok(42)
990        ));
991
992        let zero_fill_int_col = &results[6].0;
993        assert_eq!(
994            zero_fill_int_col.tpe,
995            ffi::enum_field_types::MYSQL_TYPE_LONG
996        );
997        assert!(zero_fill_int_col.flags.contains(Flags::NUM_FLAG));
998        assert!(zero_fill_int_col.flags.contains(Flags::ZEROFILL_FLAG));
999        assert!(matches!(to_value::<Integer, i32>(zero_fill_int_col), Ok(1)));
1000
1001        let numeric_col = &results[7].0;
1002        assert_eq!(
1003            numeric_col.tpe,
1004            ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL
1005        );
1006        assert!(numeric_col.flags.contains(Flags::NUM_FLAG));
1007        assert!(!numeric_col.flags.contains(Flags::UNSIGNED_FLAG));
1008        assert_eq!(
1009            to_value::<Numeric, bigdecimal::BigDecimal>(numeric_col).unwrap(),
1010            bigdecimal::BigDecimal::from_str("-999.99900").unwrap()
1011        );
1012
1013        let decimal_col = &results[8].0;
1014        assert_eq!(
1015            decimal_col.tpe,
1016            ffi::enum_field_types::MYSQL_TYPE_NEWDECIMAL
1017        );
1018        assert!(decimal_col.flags.contains(Flags::NUM_FLAG));
1019        assert!(!decimal_col.flags.contains(Flags::UNSIGNED_FLAG));
1020        assert_eq!(
1021            to_value::<Numeric, bigdecimal::BigDecimal>(decimal_col).unwrap(),
1022            bigdecimal::BigDecimal::from_str("3.14000").unwrap()
1023        );
1024
1025        let float_col = &results[9].0;
1026        assert_eq!(float_col.tpe, ffi::enum_field_types::MYSQL_TYPE_FLOAT);
1027        assert!(float_col.flags.contains(Flags::NUM_FLAG));
1028        assert!(!float_col.flags.contains(Flags::UNSIGNED_FLAG));
1029        assert_eq!(to_value::<Float, f32>(float_col).unwrap(), 1.23);
1030
1031        let double_col = &results[10].0;
1032        assert_eq!(double_col.tpe, ffi::enum_field_types::MYSQL_TYPE_DOUBLE);
1033        assert!(double_col.flags.contains(Flags::NUM_FLAG));
1034        assert!(!double_col.flags.contains(Flags::UNSIGNED_FLAG));
1035        assert_eq!(to_value::<Double, f64>(double_col).unwrap(), 4.5678);
1036
1037        let bit_col = &results[11].0;
1038        assert_eq!(bit_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BIT);
1039        assert!(!bit_col.flags.contains(Flags::NUM_FLAG));
1040        assert!(bit_col.flags.contains(Flags::UNSIGNED_FLAG));
1041        assert!(!bit_col.flags.contains(Flags::BINARY_FLAG));
1042        assert_eq!(to_value::<Blob, Vec<u8>>(bit_col).unwrap(), vec![170]);
1043
1044        let date_col = &results[12].0;
1045        assert_eq!(date_col.tpe, ffi::enum_field_types::MYSQL_TYPE_DATE);
1046        assert!(!date_col.flags.contains(Flags::NUM_FLAG));
1047        assert_eq!(
1048            to_value::<Date, chrono::NaiveDate>(date_col).unwrap(),
1049            chrono::NaiveDate::from_ymd_opt(1000, 1, 1).unwrap(),
1050        );
1051
1052        let date_time_col = &results[13].0;
1053        assert_eq!(
1054            date_time_col.tpe,
1055            ffi::enum_field_types::MYSQL_TYPE_DATETIME
1056        );
1057        assert!(!date_time_col.flags.contains(Flags::NUM_FLAG));
1058        assert_eq!(
1059            to_value::<Datetime, chrono::NaiveDateTime>(date_time_col).unwrap(),
1060            chrono::NaiveDateTime::parse_from_str("9999-12-31 12:34:45", "%Y-%m-%d %H:%M:%S")
1061                .unwrap()
1062        );
1063
1064        let timestamp_col = &results[14].0;
1065        assert_eq!(
1066            timestamp_col.tpe,
1067            ffi::enum_field_types::MYSQL_TYPE_TIMESTAMP
1068        );
1069        assert!(!timestamp_col.flags.contains(Flags::NUM_FLAG));
1070        assert_eq!(
1071            to_value::<Datetime, chrono::NaiveDateTime>(timestamp_col).unwrap(),
1072            chrono::NaiveDateTime::parse_from_str("2020-01-01 10:10:10", "%Y-%m-%d %H:%M:%S")
1073                .unwrap()
1074        );
1075
1076        let time_col = &results[15].0;
1077        assert_eq!(time_col.tpe, ffi::enum_field_types::MYSQL_TYPE_TIME);
1078        assert!(!time_col.flags.contains(Flags::NUM_FLAG));
1079        assert_eq!(
1080            to_value::<Time, chrono::NaiveTime>(time_col).unwrap(),
1081            chrono::NaiveTime::from_hms_opt(23, 1, 1).unwrap()
1082        );
1083
1084        let year_col = &results[16].0;
1085        assert_eq!(year_col.tpe, ffi::enum_field_types::MYSQL_TYPE_YEAR);
1086        assert!(year_col.flags.contains(Flags::NUM_FLAG));
1087        assert!(year_col.flags.contains(Flags::UNSIGNED_FLAG));
1088        assert!(matches!(to_value::<SmallInt, i16>(year_col), Ok(2020)));
1089
1090        let char_col = &results[17].0;
1091        assert_eq!(char_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1092        assert!(!char_col.flags.contains(Flags::NUM_FLAG));
1093        assert!(!char_col.flags.contains(Flags::BLOB_FLAG));
1094        assert!(!char_col.flags.contains(Flags::SET_FLAG));
1095        assert!(!char_col.flags.contains(Flags::ENUM_FLAG));
1096        assert!(!char_col.flags.contains(Flags::BINARY_FLAG));
1097        assert_eq!(to_value::<Text, String>(char_col).unwrap(), "abc");
1098
1099        let varchar_col = &results[18].0;
1100        assert_eq!(
1101            varchar_col.tpe,
1102            ffi::enum_field_types::MYSQL_TYPE_VAR_STRING
1103        );
1104        assert!(!varchar_col.flags.contains(Flags::NUM_FLAG));
1105        assert!(!varchar_col.flags.contains(Flags::BLOB_FLAG));
1106        assert!(!varchar_col.flags.contains(Flags::SET_FLAG));
1107        assert!(!varchar_col.flags.contains(Flags::ENUM_FLAG));
1108        assert!(!varchar_col.flags.contains(Flags::BINARY_FLAG));
1109        assert_eq!(to_value::<Text, String>(varchar_col).unwrap(), "foo");
1110
1111        let binary_col = &results[19].0;
1112        assert_eq!(binary_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1113        assert!(!binary_col.flags.contains(Flags::NUM_FLAG));
1114        assert!(!binary_col.flags.contains(Flags::BLOB_FLAG));
1115        assert!(!binary_col.flags.contains(Flags::SET_FLAG));
1116        assert!(!binary_col.flags.contains(Flags::ENUM_FLAG));
1117        assert!(binary_col.flags.contains(Flags::BINARY_FLAG));
1118        assert_eq!(
1119            to_value::<Blob, Vec<u8>>(binary_col).unwrap(),
1120            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"
1121        );
1122
1123        let varbinary_col = &results[20].0;
1124        assert_eq!(
1125            varbinary_col.tpe,
1126            ffi::enum_field_types::MYSQL_TYPE_VAR_STRING
1127        );
1128        assert!(!varbinary_col.flags.contains(Flags::NUM_FLAG));
1129        assert!(!varbinary_col.flags.contains(Flags::BLOB_FLAG));
1130        assert!(!varbinary_col.flags.contains(Flags::SET_FLAG));
1131        assert!(!varbinary_col.flags.contains(Flags::ENUM_FLAG));
1132        assert!(varbinary_col.flags.contains(Flags::BINARY_FLAG));
1133        assert_eq!(to_value::<Blob, Vec<u8>>(varbinary_col).unwrap(), b"a ");
1134
1135        let blob_col = &results[21].0;
1136        assert_eq!(blob_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1137        assert!(!blob_col.flags.contains(Flags::NUM_FLAG));
1138        assert!(blob_col.flags.contains(Flags::BLOB_FLAG));
1139        assert!(!blob_col.flags.contains(Flags::SET_FLAG));
1140        assert!(!blob_col.flags.contains(Flags::ENUM_FLAG));
1141        assert!(blob_col.flags.contains(Flags::BINARY_FLAG));
1142        assert_eq!(to_value::<Blob, Vec<u8>>(blob_col).unwrap(), b"binary");
1143
1144        let text_col = &results[22].0;
1145        assert_eq!(text_col.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1146        assert!(!text_col.flags.contains(Flags::NUM_FLAG));
1147        assert!(text_col.flags.contains(Flags::BLOB_FLAG));
1148        assert!(!text_col.flags.contains(Flags::SET_FLAG));
1149        assert!(!text_col.flags.contains(Flags::ENUM_FLAG));
1150        assert!(!text_col.flags.contains(Flags::BINARY_FLAG));
1151        assert_eq!(
1152            to_value::<Text, String>(text_col).unwrap(),
1153            "some text whatever"
1154        );
1155
1156        let enum_col = &results[23].0;
1157        assert_eq!(enum_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1158        assert!(!enum_col.flags.contains(Flags::NUM_FLAG));
1159        assert!(!enum_col.flags.contains(Flags::BLOB_FLAG));
1160        assert!(!enum_col.flags.contains(Flags::SET_FLAG));
1161        assert!(enum_col.flags.contains(Flags::ENUM_FLAG));
1162        assert!(!enum_col.flags.contains(Flags::BINARY_FLAG));
1163        assert_eq!(to_value::<Text, String>(enum_col).unwrap(), "red");
1164
1165        let set_col = &results[24].0;
1166        assert_eq!(set_col.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1167        assert!(!set_col.flags.contains(Flags::NUM_FLAG));
1168        assert!(!set_col.flags.contains(Flags::BLOB_FLAG));
1169        assert!(set_col.flags.contains(Flags::SET_FLAG));
1170        assert!(!set_col.flags.contains(Flags::ENUM_FLAG));
1171        assert!(!set_col.flags.contains(Flags::BINARY_FLAG));
1172        assert_eq!(to_value::<Text, String>(set_col).unwrap(), "one");
1173
1174        let geom = &results[25].0;
1175        assert_eq!(geom.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1176        assert!(!geom.flags.contains(Flags::NUM_FLAG));
1177        assert!(!geom.flags.contains(Flags::BLOB_FLAG));
1178        assert!(!geom.flags.contains(Flags::SET_FLAG));
1179        assert!(!geom.flags.contains(Flags::ENUM_FLAG));
1180        assert!(!geom.flags.contains(Flags::BINARY_FLAG));
1181        assert_eq!(to_value::<Text, String>(geom).unwrap(), "POINT(1 1)");
1182
1183        let point_col = &results[26].0;
1184        assert_eq!(point_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1185        assert!(!point_col.flags.contains(Flags::NUM_FLAG));
1186        assert!(!point_col.flags.contains(Flags::BLOB_FLAG));
1187        assert!(!point_col.flags.contains(Flags::SET_FLAG));
1188        assert!(!point_col.flags.contains(Flags::ENUM_FLAG));
1189        assert!(!point_col.flags.contains(Flags::BINARY_FLAG));
1190        assert_eq!(to_value::<Text, String>(point_col).unwrap(), "POINT(1 1)");
1191
1192        let linestring_col = &results[27].0;
1193        assert_eq!(
1194            linestring_col.tpe,
1195            ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1196        );
1197        assert!(!linestring_col.flags.contains(Flags::NUM_FLAG));
1198        assert!(!linestring_col.flags.contains(Flags::BLOB_FLAG));
1199        assert!(!linestring_col.flags.contains(Flags::SET_FLAG));
1200        assert!(!linestring_col.flags.contains(Flags::ENUM_FLAG));
1201        assert!(!linestring_col.flags.contains(Flags::BINARY_FLAG));
1202        assert_eq!(
1203            to_value::<Text, String>(linestring_col).unwrap(),
1204            "LINESTRING(0 0,1 1,2 2)"
1205        );
1206
1207        let polygon_col = &results[28].0;
1208        assert_eq!(polygon_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1209        assert!(!polygon_col.flags.contains(Flags::NUM_FLAG));
1210        assert!(!polygon_col.flags.contains(Flags::BLOB_FLAG));
1211        assert!(!polygon_col.flags.contains(Flags::SET_FLAG));
1212        assert!(!polygon_col.flags.contains(Flags::ENUM_FLAG));
1213        assert!(!polygon_col.flags.contains(Flags::BINARY_FLAG));
1214        assert_eq!(
1215            to_value::<Text, String>(polygon_col).unwrap(),
1216            "POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7,5 5))"
1217        );
1218
1219        let multipoint_col = &results[29].0;
1220        assert_eq!(
1221            multipoint_col.tpe,
1222            ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1223        );
1224        assert!(!multipoint_col.flags.contains(Flags::NUM_FLAG));
1225        assert!(!multipoint_col.flags.contains(Flags::BLOB_FLAG));
1226        assert!(!multipoint_col.flags.contains(Flags::SET_FLAG));
1227        assert!(!multipoint_col.flags.contains(Flags::ENUM_FLAG));
1228        assert!(!multipoint_col.flags.contains(Flags::BINARY_FLAG));
1229        // older mysql and mariadb versions get back another encoding here
1230        // we test for both as there seems to be no clear pattern when one or
1231        // the other is returned
1232        let multipoint_res = to_value::<Text, String>(multipoint_col).unwrap();
1233        assert!(
1234            multipoint_res == "MULTIPOINT((0 0),(10 10),(10 20),(20 20))"
1235                || multipoint_res == "MULTIPOINT(0 0,10 10,10 20,20 20)"
1236        );
1237
1238        let multilinestring_col = &results[30].0;
1239        assert_eq!(
1240            multilinestring_col.tpe,
1241            ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1242        );
1243        assert!(!multilinestring_col.flags.contains(Flags::NUM_FLAG));
1244        assert!(!multilinestring_col.flags.contains(Flags::BLOB_FLAG));
1245        assert!(!multilinestring_col.flags.contains(Flags::SET_FLAG));
1246        assert!(!multilinestring_col.flags.contains(Flags::ENUM_FLAG));
1247        assert!(!multilinestring_col.flags.contains(Flags::BINARY_FLAG));
1248        assert_eq!(
1249            to_value::<Text, String>(multilinestring_col).unwrap(),
1250            "MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))"
1251        );
1252
1253        let polygon_col = &results[31].0;
1254        assert_eq!(polygon_col.tpe, ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB);
1255        assert!(!polygon_col.flags.contains(Flags::NUM_FLAG));
1256        assert!(!polygon_col.flags.contains(Flags::BLOB_FLAG));
1257        assert!(!polygon_col.flags.contains(Flags::SET_FLAG));
1258        assert!(!polygon_col.flags.contains(Flags::ENUM_FLAG));
1259        assert!(!polygon_col.flags.contains(Flags::BINARY_FLAG));
1260        assert_eq!(
1261            to_value::<Text, String>(polygon_col).unwrap(),
1262            "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)))"
1263        );
1264
1265        let geometry_collection = &results[32].0;
1266        assert_eq!(
1267            geometry_collection.tpe,
1268            ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB
1269        );
1270        assert!(!geometry_collection.flags.contains(Flags::NUM_FLAG));
1271        assert!(!geometry_collection.flags.contains(Flags::BLOB_FLAG));
1272        assert!(!geometry_collection.flags.contains(Flags::SET_FLAG));
1273        assert!(!geometry_collection.flags.contains(Flags::ENUM_FLAG));
1274        assert!(!geometry_collection.flags.contains(Flags::BINARY_FLAG));
1275        assert_eq!(
1276            to_value::<Text, String>(geometry_collection).unwrap(),
1277            "GEOMETRYCOLLECTION(POINT(1 1),LINESTRING(0 0,1 1,2 2,3 3,4 4))"
1278        );
1279
1280        let json_col = &results[33].0;
1281        // mariadb >= 10.2 and mysql >=8.0 are supporting a json type
1282        // from those mariadb >= 10.3 and mysql >= 8.0 are reporting
1283        // json here, so we assert that we get back json
1284        // mariadb 10.5 returns again blob
1285        assert!(
1286            json_col.tpe == ffi::enum_field_types::MYSQL_TYPE_JSON
1287                || json_col.tpe == ffi::enum_field_types::MYSQL_TYPE_BLOB
1288        );
1289        assert!(!json_col.flags.contains(Flags::NUM_FLAG));
1290        assert!(json_col.flags.contains(Flags::BLOB_FLAG));
1291        assert!(!json_col.flags.contains(Flags::SET_FLAG));
1292        assert!(!json_col.flags.contains(Flags::ENUM_FLAG));
1293        assert!(json_col.flags.contains(Flags::BINARY_FLAG));
1294        assert_eq!(
1295            to_value::<Text, String>(json_col).unwrap(),
1296            "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1297        );
1298    }
1299
1300    fn query_single_table(
1301        query: &'static str,
1302        conn: &MysqlConnection,
1303        bind_tpe: impl Into<(ffi::enum_field_types, Flags)>,
1304    ) -> BindData {
1305        let stmt: Statement = conn
1306            .raw_connection
1307            .prepare(query, PrepareForCache::No, &[])
1308            .unwrap();
1309        let stmt = MaybeCached::CannotCache(stmt);
1310
1311        let bind = BindData::from_tpe_and_flags(bind_tpe.into());
1312
1313        let mut binds = OutputBinds(Binds { data: vec![bind] });
1314
1315        let stmt = stmt.execute_statement(&mut binds).unwrap();
1316        stmt.populate_row_buffers(&mut binds).unwrap();
1317
1318        binds.0.data.remove(0)
1319    }
1320
1321    fn input_bind(
1322        query: &'static str,
1323        conn: &MysqlConnection,
1324        id: i32,
1325        (field, tpe): (Vec<u8>, impl Into<(ffi::enum_field_types, Flags)>),
1326    ) {
1327        let mut stmt = conn
1328            .raw_connection
1329            .prepare(query, PrepareForCache::No, &[])
1330            .unwrap();
1331        let length = field.len() as _;
1332        let (tpe, flags) = tpe.into();
1333        let (ptr, _length, capacity) = bind_buffer(field);
1334
1335        let field_bind = BindData {
1336            tpe,
1337            bytes: ptr,
1338            capacity,
1339            length,
1340            flags,
1341            is_null: ffi::FALSE,
1342            is_truncated: None,
1343        };
1344
1345        let (ptr, length, capacity) = bind_buffer(id.to_be_bytes().to_vec());
1346
1347        let id_bind = BindData {
1348            tpe: ffi::enum_field_types::MYSQL_TYPE_LONG,
1349            bytes: ptr,
1350            capacity,
1351            length,
1352            flags: Flags::empty(),
1353            is_null: ffi::FALSE,
1354            is_truncated: None,
1355        };
1356
1357        let binds = PreparedStatementBinds(Binds {
1358            data: vec![id_bind, field_bind],
1359        });
1360        stmt.input_bind(binds).unwrap();
1361        stmt.did_an_error_occur().unwrap();
1362        let stmt = MaybeCached::CannotCache(stmt);
1363        unsafe {
1364            stmt.execute().unwrap();
1365        }
1366    }
1367
1368    #[diesel_test_helper::test]
1369    fn check_json_bind() {
1370        table! {
1371            json_test {
1372                id -> Integer,
1373                json_field -> Text,
1374            }
1375        }
1376
1377        let conn = &mut crate::test_helpers::connection();
1378
1379        crate::sql_query("DROP TABLE IF EXISTS json_test CASCADE")
1380            .execute(conn)
1381            .unwrap();
1382
1383        crate::sql_query(
1384            "CREATE TABLE json_test(id INTEGER PRIMARY KEY, json_field JSON NOT NULL)",
1385        )
1386        .execute(conn)
1387        .unwrap();
1388
1389        crate::sql_query("INSERT INTO json_test(id, json_field) VALUES (1, '{\"key1\": \"value1\", \"key2\": \"value2\"}')").execute(conn).unwrap();
1390
1391        let json_col_as_json = query_single_table(
1392            "SELECT json_field FROM json_test",
1393            conn,
1394            (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1395        );
1396
1397        assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1398        assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1399        assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1400        assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1401        assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1402        assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1403        assert_eq!(
1404            to_value::<Text, String>(&json_col_as_json).unwrap(),
1405            "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1406        );
1407
1408        let json_col_as_text = query_single_table(
1409            "SELECT json_field FROM json_test",
1410            conn,
1411            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1412        );
1413
1414        assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1415        assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1416        assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1417        assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1418        assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1419        assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1420        assert_eq!(
1421            to_value::<Text, String>(&json_col_as_text).unwrap(),
1422            "{\"key1\": \"value1\", \"key2\": \"value2\"}"
1423        );
1424        assert_eq!(
1425            json_col_as_json.value().unwrap().as_bytes(),
1426            json_col_as_text.value().unwrap().as_bytes()
1427        );
1428
1429        crate::sql_query("DELETE FROM json_test")
1430            .execute(conn)
1431            .unwrap();
1432
1433        input_bind(
1434            "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1435            conn,
1436            41,
1437            (
1438                b"{\"abc\": 42}".to_vec(),
1439                MysqlType::String,
1440                //                (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1441            ),
1442        );
1443
1444        let json_col_as_json = query_single_table(
1445            "SELECT json_field FROM json_test",
1446            conn,
1447            (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1448        );
1449
1450        assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1451        assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1452        assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1453        assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1454        assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1455        assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1456        assert_eq!(
1457            to_value::<Text, String>(&json_col_as_json).unwrap(),
1458            "{\"abc\": 42}"
1459        );
1460
1461        let json_col_as_text = query_single_table(
1462            "SELECT json_field FROM json_test",
1463            conn,
1464            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1465        );
1466
1467        assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1468        assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1469        assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1470        assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1471        assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1472        assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1473        assert_eq!(
1474            to_value::<Text, String>(&json_col_as_text).unwrap(),
1475            "{\"abc\": 42}"
1476        );
1477        assert_eq!(
1478            json_col_as_json.value().unwrap().as_bytes(),
1479            json_col_as_text.value().unwrap().as_bytes()
1480        );
1481
1482        crate::sql_query("DELETE FROM json_test")
1483            .execute(conn)
1484            .unwrap();
1485
1486        input_bind(
1487            "INSERT INTO json_test(id, json_field) VALUES (?, ?)",
1488            conn,
1489            41,
1490            (b"{\"abca\": 42}".to_vec(), MysqlType::String),
1491        );
1492
1493        let json_col_as_json = query_single_table(
1494            "SELECT json_field FROM json_test",
1495            conn,
1496            (ffi::enum_field_types::MYSQL_TYPE_JSON, Flags::empty()),
1497        );
1498
1499        assert_eq!(json_col_as_json.tpe, ffi::enum_field_types::MYSQL_TYPE_JSON);
1500        assert!(!json_col_as_json.flags.contains(Flags::NUM_FLAG));
1501        assert!(!json_col_as_json.flags.contains(Flags::BLOB_FLAG));
1502        assert!(!json_col_as_json.flags.contains(Flags::SET_FLAG));
1503        assert!(!json_col_as_json.flags.contains(Flags::ENUM_FLAG));
1504        assert!(!json_col_as_json.flags.contains(Flags::BINARY_FLAG));
1505        assert_eq!(
1506            to_value::<Text, String>(&json_col_as_json).unwrap(),
1507            "{\"abca\": 42}"
1508        );
1509
1510        let json_col_as_text = query_single_table(
1511            "SELECT json_field FROM json_test",
1512            conn,
1513            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1514        );
1515
1516        assert_eq!(json_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1517        assert!(!json_col_as_text.flags.contains(Flags::NUM_FLAG));
1518        assert!(!json_col_as_text.flags.contains(Flags::BLOB_FLAG));
1519        assert!(!json_col_as_text.flags.contains(Flags::SET_FLAG));
1520        assert!(!json_col_as_text.flags.contains(Flags::ENUM_FLAG));
1521        assert!(!json_col_as_text.flags.contains(Flags::BINARY_FLAG));
1522        assert_eq!(
1523            to_value::<Text, String>(&json_col_as_text).unwrap(),
1524            "{\"abca\": 42}"
1525        );
1526        assert_eq!(
1527            json_col_as_json.value().unwrap().as_bytes(),
1528            json_col_as_text.value().unwrap().as_bytes()
1529        );
1530    }
1531
1532    #[diesel_test_helper::test]
1533    fn check_enum_bind() {
1534        let conn = &mut crate::test_helpers::connection();
1535
1536        crate::sql_query("DROP TABLE IF EXISTS enum_test CASCADE")
1537            .execute(conn)
1538            .unwrap();
1539
1540        crate::sql_query("CREATE TABLE enum_test(id INTEGER PRIMARY KEY, enum_field ENUM('red', 'green', 'blue') NOT NULL)").execute(conn)
1541            .unwrap();
1542
1543        crate::sql_query("INSERT INTO enum_test(id, enum_field) VALUES (1, 'green')")
1544            .execute(conn)
1545            .unwrap();
1546
1547        let enum_col_as_enum: BindData =
1548            query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1549
1550        assert_eq!(
1551            enum_col_as_enum.tpe,
1552            ffi::enum_field_types::MYSQL_TYPE_STRING
1553        );
1554        assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1555        assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1556        assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1557        assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1558        assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1559        assert_eq!(
1560            to_value::<Text, String>(&enum_col_as_enum).unwrap(),
1561            "green"
1562        );
1563
1564        for tpe in &[
1565            ffi::enum_field_types::MYSQL_TYPE_BLOB,
1566            ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1567            ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1568            ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1569            ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1570        ] {
1571            let enum_col_as_text = query_single_table(
1572                "SELECT enum_field FROM enum_test",
1573                conn,
1574                (*tpe, Flags::ENUM_FLAG),
1575            );
1576
1577            assert_eq!(enum_col_as_text.tpe, *tpe);
1578            assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1579            assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1580            assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1581            assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1582            assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1583            assert_eq!(
1584                to_value::<Text, String>(&enum_col_as_text).unwrap(),
1585                "green"
1586            );
1587            assert_eq!(
1588                enum_col_as_enum.value().unwrap().as_bytes(),
1589                enum_col_as_text.value().unwrap().as_bytes()
1590            );
1591        }
1592
1593        let enum_col_as_text = query_single_table(
1594            "SELECT enum_field FROM enum_test",
1595            conn,
1596            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1597        );
1598
1599        assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1600        assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1601        assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1602        assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1603        assert!(!enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1604        assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1605        assert_eq!(
1606            to_value::<Text, String>(&enum_col_as_text).unwrap(),
1607            "green"
1608        );
1609        assert_eq!(
1610            enum_col_as_enum.value().unwrap().as_bytes(),
1611            enum_col_as_text.value().unwrap().as_bytes()
1612        );
1613
1614        crate::sql_query("DELETE FROM enum_test")
1615            .execute(conn)
1616            .unwrap();
1617
1618        input_bind(
1619            "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1620            conn,
1621            41,
1622            (b"blue".to_vec(), MysqlType::Enum),
1623        );
1624
1625        let enum_col_as_enum =
1626            query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1627
1628        assert_eq!(
1629            enum_col_as_enum.tpe,
1630            ffi::enum_field_types::MYSQL_TYPE_STRING
1631        );
1632        assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1633        assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1634        assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1635        assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1636        assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1637        assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "blue");
1638
1639        let enum_col_as_text = query_single_table(
1640            "SELECT enum_field FROM enum_test",
1641            conn,
1642            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1643        );
1644
1645        assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1646        assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1647        assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1648        assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1649        assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1650        assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1651        assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1652        assert_eq!(
1653            enum_col_as_enum.value().unwrap().as_bytes(),
1654            enum_col_as_text.value().unwrap().as_bytes()
1655        );
1656
1657        let enum_col_as_text = query_single_table(
1658            "SELECT enum_field FROM enum_test",
1659            conn,
1660            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1661        );
1662
1663        assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1664        assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1665        assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1666        assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1667        assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1668        assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1669        assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "blue");
1670        assert_eq!(
1671            enum_col_as_enum.value().unwrap().as_bytes(),
1672            enum_col_as_text.value().unwrap().as_bytes()
1673        );
1674
1675        crate::sql_query("DELETE FROM enum_test")
1676            .execute(conn)
1677            .unwrap();
1678
1679        input_bind(
1680            "INSERT INTO enum_test(id, enum_field) VALUES (?, ?)",
1681            conn,
1682            41,
1683            (
1684                b"red".to_vec(),
1685                (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1686            ),
1687        );
1688
1689        let enum_col_as_enum =
1690            query_single_table("SELECT enum_field FROM enum_test", conn, MysqlType::Enum);
1691
1692        assert_eq!(
1693            enum_col_as_enum.tpe,
1694            ffi::enum_field_types::MYSQL_TYPE_STRING
1695        );
1696        assert!(!enum_col_as_enum.flags.contains(Flags::NUM_FLAG));
1697        assert!(!enum_col_as_enum.flags.contains(Flags::BLOB_FLAG));
1698        assert!(!enum_col_as_enum.flags.contains(Flags::SET_FLAG));
1699        assert!(enum_col_as_enum.flags.contains(Flags::ENUM_FLAG));
1700        assert!(!enum_col_as_enum.flags.contains(Flags::BINARY_FLAG));
1701        assert_eq!(to_value::<Text, String>(&enum_col_as_enum).unwrap(), "red");
1702
1703        let enum_col_as_text = query_single_table(
1704            "SELECT enum_field FROM enum_test",
1705            conn,
1706            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::ENUM_FLAG),
1707        );
1708
1709        assert_eq!(enum_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1710        assert!(!enum_col_as_text.flags.contains(Flags::NUM_FLAG));
1711        assert!(!enum_col_as_text.flags.contains(Flags::BLOB_FLAG));
1712        assert!(!enum_col_as_text.flags.contains(Flags::SET_FLAG));
1713        assert!(enum_col_as_text.flags.contains(Flags::ENUM_FLAG));
1714        assert!(!enum_col_as_text.flags.contains(Flags::BINARY_FLAG));
1715        assert_eq!(to_value::<Text, String>(&enum_col_as_text).unwrap(), "red");
1716        assert_eq!(
1717            enum_col_as_enum.value().unwrap().as_bytes(),
1718            enum_col_as_text.value().unwrap().as_bytes()
1719        );
1720    }
1721
1722    #[diesel_test_helper::test]
1723    fn check_set_bind() {
1724        let conn = &mut crate::test_helpers::connection();
1725
1726        crate::sql_query("DROP TABLE IF EXISTS set_test CASCADE")
1727            .execute(conn)
1728            .unwrap();
1729
1730        crate::sql_query("CREATE TABLE set_test(id INTEGER PRIMARY KEY, set_field SET('red', 'green', 'blue') NOT NULL)").execute(conn)
1731            .unwrap();
1732
1733        crate::sql_query("INSERT INTO set_test(id, set_field) VALUES (1, 'green')")
1734            .execute(conn)
1735            .unwrap();
1736
1737        let set_col_as_set: BindData =
1738            query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1739
1740        assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1741        assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1742        assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1743        assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1744        assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1745        assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1746        assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "green");
1747
1748        for tpe in &[
1749            ffi::enum_field_types::MYSQL_TYPE_BLOB,
1750            ffi::enum_field_types::MYSQL_TYPE_VAR_STRING,
1751            ffi::enum_field_types::MYSQL_TYPE_TINY_BLOB,
1752            ffi::enum_field_types::MYSQL_TYPE_MEDIUM_BLOB,
1753            ffi::enum_field_types::MYSQL_TYPE_LONG_BLOB,
1754        ] {
1755            let set_col_as_text = query_single_table(
1756                "SELECT set_field FROM set_test",
1757                conn,
1758                (*tpe, Flags::SET_FLAG),
1759            );
1760
1761            assert_eq!(set_col_as_text.tpe, *tpe);
1762            assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1763            assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1764            assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1765            assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1766            assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1767            assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1768            assert_eq!(
1769                set_col_as_set.value().unwrap().as_bytes(),
1770                set_col_as_text.value().unwrap().as_bytes()
1771            );
1772        }
1773        let set_col_as_text = query_single_table(
1774            "SELECT set_field FROM set_test",
1775            conn,
1776            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::empty()),
1777        );
1778
1779        assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1780        assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1781        assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1782        assert!(!set_col_as_text.flags.contains(Flags::SET_FLAG));
1783        assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1784        assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1785        assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "green");
1786        assert_eq!(
1787            set_col_as_set.value().unwrap().as_bytes(),
1788            set_col_as_text.value().unwrap().as_bytes()
1789        );
1790
1791        crate::sql_query("DELETE FROM set_test")
1792            .execute(conn)
1793            .unwrap();
1794
1795        input_bind(
1796            "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1797            conn,
1798            41,
1799            (b"blue".to_vec(), MysqlType::Set),
1800        );
1801
1802        let set_col_as_set =
1803            query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1804
1805        assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1806        assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1807        assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1808        assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1809        assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1810        assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1811        assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "blue");
1812
1813        let set_col_as_text = query_single_table(
1814            "SELECT set_field FROM set_test",
1815            conn,
1816            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1817        );
1818
1819        assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1820        assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1821        assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1822        assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1823        assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1824        assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1825        assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "blue");
1826        assert_eq!(
1827            set_col_as_set.value().unwrap().as_bytes(),
1828            set_col_as_text.value().unwrap().as_bytes()
1829        );
1830
1831        crate::sql_query("DELETE FROM set_test")
1832            .execute(conn)
1833            .unwrap();
1834
1835        input_bind(
1836            "INSERT INTO set_test(id, set_field) VALUES (?, ?)",
1837            conn,
1838            41,
1839            (b"red".to_vec(), MysqlType::String),
1840        );
1841
1842        let set_col_as_set =
1843            query_single_table("SELECT set_field FROM set_test", conn, MysqlType::Set);
1844
1845        assert_eq!(set_col_as_set.tpe, ffi::enum_field_types::MYSQL_TYPE_STRING);
1846        assert!(!set_col_as_set.flags.contains(Flags::NUM_FLAG));
1847        assert!(!set_col_as_set.flags.contains(Flags::BLOB_FLAG));
1848        assert!(set_col_as_set.flags.contains(Flags::SET_FLAG));
1849        assert!(!set_col_as_set.flags.contains(Flags::ENUM_FLAG));
1850        assert!(!set_col_as_set.flags.contains(Flags::BINARY_FLAG));
1851        assert_eq!(to_value::<Text, String>(&set_col_as_set).unwrap(), "red");
1852
1853        let set_col_as_text = query_single_table(
1854            "SELECT set_field FROM set_test",
1855            conn,
1856            (ffi::enum_field_types::MYSQL_TYPE_BLOB, Flags::SET_FLAG),
1857        );
1858
1859        assert_eq!(set_col_as_text.tpe, ffi::enum_field_types::MYSQL_TYPE_BLOB);
1860        assert!(!set_col_as_text.flags.contains(Flags::NUM_FLAG));
1861        assert!(!set_col_as_text.flags.contains(Flags::BLOB_FLAG));
1862        assert!(set_col_as_text.flags.contains(Flags::SET_FLAG));
1863        assert!(!set_col_as_text.flags.contains(Flags::ENUM_FLAG));
1864        assert!(!set_col_as_text.flags.contains(Flags::BINARY_FLAG));
1865        assert_eq!(to_value::<Text, String>(&set_col_as_text).unwrap(), "red");
1866        assert_eq!(
1867            set_col_as_set.value().unwrap().as_bytes(),
1868            set_col_as_text.value().unwrap().as_bytes()
1869        );
1870    }
1871}