Skip to main content

diesel/mysql/connection/
bind.rs

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