Skip to main content

diesel/mysql/connection/
bind.rs

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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