diesel/mysql/connection/
bind.rs

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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