Skip to main content

diesel/mysql/connection/
bind.rs

1#![allow(unsafe_code)] // module uses ffi
2use core::cmp;
3use core::ffi as libc;
4use core::mem::MaybeUninit;
5use core::mem::{self, ManuallyDrop};
6use core::ops::Index;
7use core::ptr::NonNull;
8use mysqlclient_sys as ffi;
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(core::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(1_024);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const SET_FLAG: Self = Self::from_bits_retain(2_048);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NO_DEFAULT_VALUE_FLAG: Self = Self::from_bits_retain(4_096);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const ON_UPDATE_NOW_FLAG: Self = Self::from_bits_retain(8_192);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NUM_FLAG: Self = Self::from_bits_retain(32_768);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const PART_KEY_FLAG: Self = Self::from_bits_retain(16_384);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const GROUP_FLAG: Self = Self::from_bits_retain((1 << 28));
    #[allow(deprecated, non_upper_case_globals,)]
    pub const UNIQUE_FLAG: Self = Self::from_bits_retain(65_536);
    #[allow(deprecated, non_upper_case_globals,)]
    pub const BINCMP_FLAG: Self = Self::from_bits_retain(131_072);
    #[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));
    #[allow(deprecated, non_upper_case_globals,)]
    pub const EXPLICIT_NULL_FLAG: Self = Self::from_bits_retain((1 << 27));
    #[allow(deprecated, non_upper_case_globals,)]
    pub const NOT_SECONDARY_FLAG: Self = Self::from_bits_retain((1 << 29));
}
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)
                    },
                    {

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

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