Skip to main content

diesel/mysql_like/connection/stmt/
metadata.rs

1#![allow(unsafe_code)] // module uses ffi
2use core::ffi::CStr;
3use core::ptr::NonNull;
4use core::slice;
5
6use super::ffi;
7use crate::mysql_like::connection::bind::Flags;
8
9pub(in crate::mysql_like::connection) struct StatementMetadata {
10    fields: Vec<MysqlFieldMetadata>,
11}
12
13impl StatementMetadata {
14    pub(in crate::mysql_like::connection) fn new(mut result: NonNull<ffi::MYSQL_RES>) -> Self {
15        let fields: &[ffi::MYSQL_FIELD] = unsafe {
16            let num_fields = ffi::mysql_num_fields(result.as_ptr());
17            let field_ptr = ffi::mysql_fetch_fields(result.as_ptr());
18            if field_ptr.is_null() {
19                &[]
20            } else {
21                slice::from_raw_parts(field_ptr, num_fields as usize)
22            }
23        };
24        let fields = fields
25            .iter()
26            .map(|f| {
27                let field_name = if f.name.is_null() {
28                    None
29                } else {
30                    unsafe {
31                        Some(CStr::from_ptr(f.name).to_str().expect(
32                            "Expect mysql field names to be UTF-8, because we \
33                     requested UTF-8 encoding on connection setup",
34                        ))
35                    }
36                };
37                MysqlFieldMetadata {
38                    field_name: field_name.map(Into::into),
39                    field_type: f.type_,
40                    flags: f.flags,
41                }
42            })
43            .collect::<Vec<_>>();
44        unsafe {
45            ffi::mysql_free_result(result.as_mut());
46        }
47        StatementMetadata { fields }
48    }
49
50    pub(in crate::mysql_like::connection) fn fields(&'_ self) -> &'_ [MysqlFieldMetadata] {
51        &self.fields
52    }
53}
54
55pub(in crate::mysql_like::connection) struct MysqlFieldMetadata {
56    field_name: Option<Box<str>>,
57    field_type: ffi::enum_field_types,
58    flags: core::ffi::c_uint,
59}
60
61impl MysqlFieldMetadata {
62    pub(in crate::mysql_like::connection) fn field_name(&self) -> Option<&str> {
63        self.field_name.as_deref()
64    }
65
66    pub(in crate::mysql_like::connection) fn field_type(&self) -> ffi::enum_field_types {
67        self.field_type
68    }
69
70    pub(in crate::mysql_like::connection) fn flags(
71        &self,
72    ) -> Result<Flags, Box<dyn core::error::Error + Send + Sync>> {
73        Flags::try_from(self.flags)
74    }
75}