Skip to main content

mysql_handler/dd/
column.rs

1// Copyright (C) 2026 ren-yamanashi
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of this program hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, see <https://www.gnu.org/licenses/>.
22
23//! [`DdColumn`] safe accessors and the [`ColumnType`] enum mirroring
24//! `dd::enum_column_types` from `sql/dd/types/column.h`.
25
26#![allow(unsafe_code)]
27
28use crate::dd::ffi;
29use crate::sys::DdColumn;
30
31/// MySQL data-dictionary column type. Mirrors `dd::enum_column_types`.
32#[non_exhaustive]
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34#[allow(missing_docs)] // Variants mirror upstream `dd::enum_column_types` 1:1.
35pub enum ColumnType {
36    Decimal,
37    Tiny,
38    Short,
39    Long,
40    Float,
41    Double,
42    Null,
43    Timestamp,
44    LongLong,
45    Int24,
46    Date,
47    Time,
48    DateTime,
49    Year,
50    NewDate,
51    VarChar,
52    Bit,
53    Timestamp2,
54    DateTime2,
55    Time2,
56    NewDecimal,
57    Enum,
58    Set,
59    TinyBlob,
60    MediumBlob,
61    LongBlob,
62    Blob,
63    VarString,
64    String,
65    Geometry,
66    Json,
67    /// Unknown / out-of-range value. Future MySQL versions may add new types.
68    Unknown,
69}
70
71impl ColumnType {
72    /// Map the raw `dd::enum_column_types` integer to a [`ColumnType`].
73    /// Returns [`ColumnType::Unknown`] for unrecognised values.
74    #[must_use]
75    pub const fn from_raw(raw: i32) -> Self {
76        match raw {
77            1 => Self::Decimal,
78            2 => Self::Tiny,
79            3 => Self::Short,
80            4 => Self::Long,
81            5 => Self::Float,
82            6 => Self::Double,
83            7 => Self::Null,
84            8 => Self::Timestamp,
85            9 => Self::LongLong,
86            10 => Self::Int24,
87            11 => Self::Date,
88            12 => Self::Time,
89            13 => Self::DateTime,
90            14 => Self::Year,
91            15 => Self::NewDate,
92            16 => Self::VarChar,
93            17 => Self::Bit,
94            18 => Self::Timestamp2,
95            19 => Self::DateTime2,
96            20 => Self::Time2,
97            21 => Self::NewDecimal,
98            22 => Self::Enum,
99            23 => Self::Set,
100            24 => Self::TinyBlob,
101            25 => Self::MediumBlob,
102            26 => Self::LongBlob,
103            27 => Self::Blob,
104            28 => Self::VarString,
105            29 => Self::String,
106            30 => Self::Geometry,
107            31 => Self::Json,
108            _ => Self::Unknown,
109        }
110    }
111}
112
113impl DdColumn {
114    /// Column name as stored in the data dictionary.
115    #[must_use]
116    pub fn name(&self) -> String {
117        let p: *const DdColumn = self;
118        // SAFETY: `self` is a valid borrow; the FFI accessor only reads from `p`
119        // and writes into the caller-owned buffer.
120        ffi::read_name(|buf, cap| unsafe { ffi::mysql__DdColumn__name(p, buf, cap) })
121    }
122
123    /// Column type.
124    #[must_use]
125    pub fn column_type(&self) -> ColumnType {
126        let p: *const DdColumn = self;
127        // SAFETY: `self` is a valid borrow.
128        let raw = unsafe { ffi::mysql__DdColumn__type(p) };
129        ColumnType::from_raw(raw)
130    }
131
132    /// `true` when the column allows `NULL`.
133    #[must_use]
134    pub fn is_nullable(&self) -> bool {
135        let p: *const DdColumn = self;
136        // SAFETY: `self` is a valid borrow.
137        unsafe { ffi::mysql__DdColumn__is_nullable(p) }
138    }
139
140    /// `true` for unsigned integer columns.
141    #[must_use]
142    pub fn is_unsigned(&self) -> bool {
143        let p: *const DdColumn = self;
144        // SAFETY: `self` is a valid borrow.
145        unsafe { ffi::mysql__DdColumn__is_unsigned(p) }
146    }
147
148    /// Declared character length (`VARCHAR(N)` returns `N`).
149    #[must_use]
150    pub fn char_length(&self) -> u32 {
151        let p: *const DdColumn = self;
152        // SAFETY: `self` is a valid borrow.
153        unsafe { ffi::mysql__DdColumn__char_length(p) }
154    }
155
156    /// `true` for any non-`HT_VISIBLE` column (SE-hidden, SQL-hidden,
157    /// USER-hidden). Engines that build their own row layout should skip these.
158    #[must_use]
159    pub fn is_hidden(&self) -> bool {
160        let p: *const DdColumn = self;
161        // SAFETY: `self` is a valid borrow.
162        unsafe { ffi::mysql__DdColumn__is_hidden(p) }
163    }
164
165    /// 1-based ordinal position within the table.
166    #[must_use]
167    pub fn ordinal_position(&self) -> u32 {
168        let p: *const DdColumn = self;
169        // SAFETY: `self` is a valid borrow.
170        unsafe { ffi::mysql__DdColumn__ordinal_position(p) }
171    }
172}
173
174#[cfg(test)]
175mod tests {
176    use super::ColumnType;
177
178    #[test]
179    fn from_raw_maps_known_variants() {
180        assert_eq!(ColumnType::from_raw(2), ColumnType::Tiny);
181        assert_eq!(ColumnType::from_raw(4), ColumnType::Long);
182        assert_eq!(ColumnType::from_raw(9), ColumnType::LongLong);
183        assert_eq!(ColumnType::from_raw(16), ColumnType::VarChar);
184        assert_eq!(ColumnType::from_raw(31), ColumnType::Json);
185    }
186
187    #[test]
188    fn from_raw_returns_unknown_for_out_of_range() {
189        assert_eq!(ColumnType::from_raw(0), ColumnType::Unknown);
190        assert_eq!(ColumnType::from_raw(-1), ColumnType::Unknown);
191        assert_eq!(ColumnType::from_raw(99), ColumnType::Unknown);
192    }
193}