Skip to main content

diesel/mysql/connection/
bind.rs

1#![allow(unsafe_code)] // module uses ffi
2use core::ffi as libc;
3use core::mem::MaybeUninit;
4use core::mem::{self, ManuallyDrop};
5use core::ops::Index;
6use core::ptr::NonNull;
7use mysqlclient_sys as ffi;
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(core::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
128bitflags::bitflags! {
129    #[derive(#[automatically_derived]
impl ::core::clone::Clone for Flags {
    #[inline]
    fn clone(&self) -> Flags {
        let _:
                ::core::clone::AssertParamIsClone<<Flags as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
impl Flags {
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NOT_NULL_FLAG: Self = Self::from_bits_retain(1);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const PRI_KEY_FLAG: Self = Self::from_bits_retain(2);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNIQUE_KEY_FLAG: Self = Self::from_bits_retain(4);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const MULTIPLE_KEY_FLAG: Self = Self::from_bits_retain(8);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BLOB_FLAG: Self = Self::from_bits_retain(16);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNSIGNED_FLAG: Self = Self::from_bits_retain(32);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ZEROFILL_FLAG: Self = Self::from_bits_retain(64);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BINARY_FLAG: Self = Self::from_bits_retain(128);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ENUM_FLAG: Self = Self::from_bits_retain(256);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const AUTO_INCREMENT_FLAG: Self = Self::from_bits_retain(512);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const TIMESTAMP_FLAG: Self = Self::from_bits_retain(1024);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const SET_FLAG: Self = Self::from_bits_retain(2048);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NO_DEFAULT_VALUE_FLAG: Self = Self::from_bits_retain(4096);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ON_UPDATE_NOW_FLAG: Self = Self::from_bits_retain(8192);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NUM_FLAG: Self = Self::from_bits_retain(32768);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const PART_KEY_FLAG: Self = Self::from_bits_retain(16384);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const GROUP_FLAG: Self = Self::from_bits_retain(32768);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNIQUE_FLAG: Self = Self::from_bits_retain(65536);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BINCMP_FLAG: Self = Self::from_bits_retain(130_172);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const GET_FIXED_FIELDS_FLAG: Self = Self::from_bits_retain((1 << 18));
    #[allow(deprecated, non_upper_case_globals,)]
    pub const FIELD_IN_PART_FUNC_FLAG: Self =
        Self::from_bits_retain((1 << 19));
}
impl ::bitflags::Flags for Flags {
    const FLAGS: &'static [::bitflags::Flag<Flags>] =
        &[{

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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