Skip to main content

diesel/mysql/connection/
bind.rs

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