Skip to main content

diesel/mysql/connection/
bind.rs

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