diesel/mysql/connection/
bind.rs

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