Skip to main content

diesel/mysql/connection/
bind.rs

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