diesel/mysql/connection/
bind.rs

1#![allow(unsafe_code)] // module uses ffi
2use mysqlclient_sys as ffi;
3use std::mem::MaybeUninit;
4use std::mem::{self, ManuallyDrop};
5use std::ops::Index;
6use std::os::raw as libc;
7use std::ptr::NonNull;
8
9use super::stmt::{MysqlFieldMetadata, StatementUse};
10use crate::mysql::connection::stmt::StatementMetadata;
11use crate::mysql::types::date_and_time::MysqlTime;
12use crate::mysql::{MysqlType, MysqlValue};
13use crate::result::QueryResult;
14
15fn bind_buffer(data: Vec<u8>) -> (Option<NonNull<u8>>, libc::c_ulong, usize) {
16    let mut data = ManuallyDrop::new(data);
17    (
18        NonNull::new(data.as_mut_ptr()),
19        data.len() as libc::c_ulong,
20        data.capacity(),
21    )
22}
23
24pub(super) struct PreparedStatementBinds(Binds);
25
26pub(super) struct OutputBinds(Binds);
27
28impl Clone for OutputBinds {
29    fn clone(&self) -> Self {
30        Self(Binds {
31            data: self.0.data.clone(),
32        })
33    }
34}
35
36struct Binds {
37    data: Vec<BindData>,
38}
39
40impl PreparedStatementBinds {
41    pub(super) fn from_input_data<Iter>(input: Iter) -> Self
42    where
43        Iter: IntoIterator<Item = (MysqlType, Option<Vec<u8>>)>,
44    {
45        let data = input
46            .into_iter()
47            .map(BindData::for_input)
48            .collect::<Vec<_>>();
49
50        Self(Binds { data })
51    }
52
53    pub(super) fn with_mysql_binds<F, T>(&mut self, f: F) -> T
54    where
55        F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
56    {
57        self.0.with_mysql_binds(f)
58    }
59}
60
61impl OutputBinds {
62    pub(super) fn from_output_types(
63        types: &[Option<MysqlType>],
64        metadata: &StatementMetadata,
65    ) -> Self {
66        let data = metadata
67            .fields()
68            .iter()
69            .zip(types.iter().copied().chain(std::iter::repeat(None)))
70            .map(|(field, tpe)| BindData::for_output(tpe, field))
71            .collect();
72
73        Self(Binds { data })
74    }
75
76    pub(super) fn populate_dynamic_buffers(&mut self, stmt: &StatementUse<'_>) -> QueryResult<()> {
77        for (i, data) in self.0.data.iter_mut().enumerate() {
78            data.did_numeric_overflow_occur()?;
79            // This is safe because we are re-binding the invalidated buffers
80            // at the end of this function
81            unsafe {
82                if let Some((mut bind, offset)) = data.bind_for_truncated_data() {
83                    stmt.fetch_column(&mut bind, i, offset)?
84                } else {
85                    data.update_buffer_length()
86                }
87            }
88        }
89
90        unsafe { self.with_mysql_binds(|bind_ptr| stmt.bind_result(bind_ptr)) }
91    }
92
93    pub(super) fn update_buffer_lengths(&mut self) {
94        for data in &mut self.0.data {
95            data.update_buffer_length();
96        }
97    }
98
99    pub(super) fn with_mysql_binds<F, T>(&mut self, f: F) -> T
100    where
101        F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
102    {
103        self.0.with_mysql_binds(f)
104    }
105}
106
107impl Binds {
108    fn with_mysql_binds<F, T>(&mut self, f: F) -> T
109    where
110        F: FnOnce(*mut ffi::MYSQL_BIND) -> T,
111    {
112        let mut binds = self
113            .data
114            .iter_mut()
115            .map(|x| unsafe { x.mysql_bind() })
116            .collect::<Vec<_>>();
117        f(binds.as_mut_ptr())
118    }
119}
120
121impl Index<usize> for OutputBinds {
122    type Output = BindData;
123    fn index(&self, index: usize) -> &Self::Output {
124        &self.0.data[index]
125    }
126}
127
128pub(crate) struct Flags(<Flags as
    ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
impl ::core::clone::Clone for Flags {
    #[inline]
    fn clone(&self) -> Flags {
        let _:
                ::core::clone::AssertParamIsClone<<Flags as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]
impl ::core::marker::Copy for Flags { }
#[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)
    }
}
impl Flags {
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NOT_NULL_FLAG: Self = Self::from_bits_retain(1);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const PRI_KEY_FLAG: Self = Self::from_bits_retain(2);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNIQUE_KEY_FLAG: Self = Self::from_bits_retain(4);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const MULTIPLE_KEY_FLAG: Self = Self::from_bits_retain(8);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BLOB_FLAG: Self = Self::from_bits_retain(16);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNSIGNED_FLAG: Self = Self::from_bits_retain(32);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ZEROFILL_FLAG: Self = Self::from_bits_retain(64);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BINARY_FLAG: Self = Self::from_bits_retain(128);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ENUM_FLAG: Self = Self::from_bits_retain(256);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const AUTO_INCREMENT_FLAG: Self = Self::from_bits_retain(512);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const TIMESTAMP_FLAG: Self = Self::from_bits_retain(1024);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const SET_FLAG: Self = Self::from_bits_retain(2048);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NO_DEFAULT_VALUE_FLAG: Self = Self::from_bits_retain(4096);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ON_UPDATE_NOW_FLAG: Self = Self::from_bits_retain(8192);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NUM_FLAG: Self = Self::from_bits_retain(32768);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const PART_KEY_FLAG: Self = Self::from_bits_retain(16384);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const GROUP_FLAG: Self = Self::from_bits_retain(32768);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNIQUE_FLAG: Self = Self::from_bits_retain(65536);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BINCMP_FLAG: Self = Self::from_bits_retain(130_172);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const GET_FIXED_FIELDS_FLAG: Self = Self::from_bits_retain((1 << 18));
    #[allow(deprecated, non_upper_case_globals,)]
    pub const FIELD_IN_PART_FUNC_FLAG: Self =
        Self::from_bits_retain((1 << 19));
}
impl ::bitflags::Flags for Flags {
    const FLAGS: &'static [::bitflags::Flag<Flags>] =
        &[{

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("NOT_NULL_FLAG", Flags::NOT_NULL_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("PRI_KEY_FLAG", Flags::PRI_KEY_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("UNIQUE_KEY_FLAG",
                            Flags::UNIQUE_KEY_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("MULTIPLE_KEY_FLAG",
                            Flags::MULTIPLE_KEY_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("BLOB_FLAG", Flags::BLOB_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("UNSIGNED_FLAG", Flags::UNSIGNED_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("ZEROFILL_FLAG", Flags::ZEROFILL_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("BINARY_FLAG", Flags::BINARY_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("ENUM_FLAG", Flags::ENUM_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("AUTO_INCREMENT_FLAG",
                            Flags::AUTO_INCREMENT_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("TIMESTAMP_FLAG",
                            Flags::TIMESTAMP_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("SET_FLAG", Flags::SET_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("NO_DEFAULT_VALUE_FLAG",
                            Flags::NO_DEFAULT_VALUE_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("ON_UPDATE_NOW_FLAG",
                            Flags::ON_UPDATE_NOW_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("NUM_FLAG", Flags::NUM_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("PART_KEY_FLAG", Flags::PART_KEY_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("GROUP_FLAG", Flags::GROUP_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("UNIQUE_FLAG", Flags::UNIQUE_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("BINCMP_FLAG", Flags::BINCMP_FLAG)
                    },
                    {

                        #[allow(deprecated, non_upper_case_globals,)]
                        ::bitflags::Flag::new("GET_FIXED_FIELDS_FLAG",
                            Flags::GET_FIXED_FIELDS_FLAG)
                    },
                    {

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