mysql_handler/hton/capabilities.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//! Engine-level capabilities declared by a [`Handlerton`](crate::hton::Handlerton).
24
25/// The set of engine-level features a [`Handlerton`](crate::hton::Handlerton)
26/// opts into.
27///
28/// Each capability gates a group of `handlerton` callbacks. A group will be
29/// wired into the `handlerton` struct only when its bit is set here, because
30/// MySQL reads a non-NULL function pointer as a declaration that the engine
31/// supports that feature — a non-NULL `commit`, for example, marks the engine
32/// transactional. Declaring a capability the engine does not implement would
33/// route work to callbacks that cannot honour it, so default to the smallest
34/// set that is actually backed by code.
35///
36/// Combine capabilities with `|`:
37///
38/// ```
39/// use mysql_handler::hton::HtonCapabilities;
40///
41/// let caps = HtonCapabilities::TRANSACTIONS | HtonCapabilities::SAVEPOINTS;
42/// assert!(caps.contains(HtonCapabilities::TRANSACTIONS));
43/// assert!(!caps.contains(HtonCapabilities::XA));
44/// ```
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46#[non_exhaustive]
47pub struct HtonCapabilities(u32);
48
49impl HtonCapabilities {
50 /// Transaction callbacks (`commit`, `rollback`, `prepare`)
51 pub const TRANSACTIONS: Self = Self(1 << 0);
52 /// XA / 2PC recovery callbacks (`recover`, `commit_by_xid`, ...)
53 pub const XA: Self = Self(1 << 1);
54 /// Savepoint callbacks (`savepoint_set`, `savepoint_rollback`, ...)
55 pub const SAVEPOINTS: Self = Self(1 << 2);
56 /// Serialized Dictionary Information callbacks (`sdi_*`)
57 pub const SDI: Self = Self(1 << 3);
58 /// Secondary-engine callbacks (`prepare_secondary_engine`, ...)
59 pub const SECONDARY_ENGINE: Self = Self(1 << 4);
60 /// Clone-interface sub-callbacks
61 pub const CLONE: Self = Self(1 << 5);
62 /// Page-tracking sub-callbacks
63 pub const PAGE_TRACKING: Self = Self(1 << 6);
64 /// Partitioning support: gates the `partition_flags` accessor on the
65 /// handlerton. A non-NULL `partition_flags` pointer signals MySQL that the
66 /// engine implements `handler::get_partition_handler`, so this must stay
67 /// off for a non-partitioning engine.
68 pub const PARTITIONING: Self = Self(1 << 7);
69 /// Tablespace ownership: gates the tablespace callbacks (`get_tablespace`,
70 /// `alter_tablespace`, `upgrade_tablespace`, ...). Non-NULL pointers tell
71 /// MySQL the engine owns tablespaces (InnoDB-style); leave off for a
72 /// tablespace-less engine to keep MySQL from routing tablespace work here.
73 pub const TABLESPACES: Self = Self(1 << 8);
74 /// Data-dictionary backend: gates the `dict_*` callbacks. A non-DD-backend
75 /// engine (anything other than the DD storage backend itself) must keep
76 /// these unwired, otherwise MySQL routes dictionary work to an engine that
77 /// cannot honour it.
78 pub const DICT_BACKEND: Self = Self(1 << 9);
79 /// Engine-owned redo / transaction log: gates `lock_hton_log`,
80 /// `unlock_hton_log`, `collect_hton_log_info`, and `redo_log_set_state`.
81 /// Declared by engines whose log is collected by
82 /// `performance_schema.log_status`.
83 pub const ENGINE_LOG: Self = Self(1 << 10);
84 /// Encryption support: gates `rotate_encryption_master_key`. Non-NULL
85 /// signals MySQL that the engine participates in master-key rotation, so
86 /// leave it off for a non-encrypting engine.
87 pub const ENCRYPTION: Self = Self(1 << 11);
88
89 /// An empty capability set: a handler-only engine (the zero-config default)
90 #[must_use]
91 pub const fn empty() -> Self {
92 Self(0)
93 }
94
95 /// The raw bits, for handing the set across the FFI boundary
96 #[must_use]
97 pub const fn bits(self) -> u32 {
98 self.0
99 }
100
101 /// Whether every capability in `other` is present in `self`
102 #[must_use]
103 pub const fn contains(self, other: Self) -> bool {
104 self.0 & other.0 == other.0
105 }
106
107 /// The union of two capability sets
108 #[must_use]
109 pub const fn union(self, other: Self) -> Self {
110 Self(self.0 | other.0)
111 }
112}
113
114impl core::ops::BitOr for HtonCapabilities {
115 type Output = Self;
116
117 fn bitor(self, rhs: Self) -> Self {
118 self.union(rhs)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn empty_contains_only_empty() {
128 let e = HtonCapabilities::empty();
129 assert_eq!(e.bits(), 0);
130 assert!(e.contains(HtonCapabilities::empty()));
131 assert!(!e.contains(HtonCapabilities::TRANSACTIONS));
132 }
133
134 #[test]
135 fn union_sets_both_bits() {
136 let c = HtonCapabilities::TRANSACTIONS | HtonCapabilities::SAVEPOINTS;
137 assert!(c.contains(HtonCapabilities::TRANSACTIONS));
138 assert!(c.contains(HtonCapabilities::SAVEPOINTS));
139 assert!(!c.contains(HtonCapabilities::XA));
140 }
141
142 #[test]
143 fn each_capability_has_a_distinct_bit() {
144 let all = [
145 HtonCapabilities::TRANSACTIONS,
146 HtonCapabilities::XA,
147 HtonCapabilities::SAVEPOINTS,
148 HtonCapabilities::SDI,
149 HtonCapabilities::SECONDARY_ENGINE,
150 HtonCapabilities::CLONE,
151 HtonCapabilities::PAGE_TRACKING,
152 HtonCapabilities::PARTITIONING,
153 HtonCapabilities::TABLESPACES,
154 HtonCapabilities::DICT_BACKEND,
155 HtonCapabilities::ENGINE_LOG,
156 HtonCapabilities::ENCRYPTION,
157 ];
158 for (i, a) in all.iter().enumerate() {
159 for b in &all[i + 1..] {
160 assert_ne!(a.bits(), b.bits());
161 }
162 }
163 }
164}