mysql_handler/engine/rkey_function.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//! Index-lookup search semantics, mirroring MySQL's `ha_rkey_function`.
24
25/// Search semantics for an index lookup, mirroring MySQL's `ha_rkey_function`.
26///
27/// Passed to [`StorageEngine::index_read_map`] to describe how the supplied key
28/// should be matched: an exact hit, the nearest neighbour in a direction, a
29/// prefix, or one of the spatial (minimum-bounding-rectangle) relations.
30///
31/// [`StorageEngine::index_read_map`]: crate::engine::StorageEngine::index_read_map
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33#[non_exhaustive]
34pub enum RKeyFunction {
35 /// Find the first record with exactly this key, else error
36 KeyExact,
37 /// This record or the next one
38 KeyOrNext,
39 /// This record or the previous one
40 KeyOrPrev,
41 /// First record after this key
42 AfterKey,
43 /// First record before this key
44 BeforeKey,
45 /// First record sharing this key prefix
46 Prefix,
47 /// Last record sharing this key prefix
48 PrefixLast,
49 /// Last record with this prefix, or the previous one
50 PrefixLastOrPrev,
51 /// Minimum bounding rectangle contains the key
52 MbrContain,
53 /// Minimum bounding rectangle intersects the key
54 MbrIntersect,
55 /// Minimum bounding rectangle is within the key
56 MbrWithin,
57 /// Minimum bounding rectangle is disjoint from the key
58 MbrDisjoint,
59 /// Minimum bounding rectangle equals the key
60 MbrEqual,
61 /// Nearest-neighbour spatial search
62 NearestNeighbor,
63 /// Unrecognised value; MySQL's `HA_READ_INVALID` or an out-of-range code
64 Invalid,
65}
66
67impl RKeyFunction {
68 /// Map the raw `ha_rkey_function` integer supplied at the FFI boundary to a
69 /// variant. Any unknown code (including `HA_READ_INVALID == -1`) becomes
70 /// [`RKeyFunction::Invalid`] so the engine never observes an undefined value.
71 pub(crate) fn from_raw(raw: i32) -> Self {
72 match raw {
73 0 => Self::KeyExact,
74 1 => Self::KeyOrNext,
75 2 => Self::KeyOrPrev,
76 3 => Self::AfterKey,
77 4 => Self::BeforeKey,
78 5 => Self::Prefix,
79 6 => Self::PrefixLast,
80 7 => Self::PrefixLastOrPrev,
81 8 => Self::MbrContain,
82 9 => Self::MbrIntersect,
83 10 => Self::MbrWithin,
84 11 => Self::MbrDisjoint,
85 12 => Self::MbrEqual,
86 13 => Self::NearestNeighbor,
87 _ => Self::Invalid,
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn maps_known_codes() {
98 assert_eq!(RKeyFunction::from_raw(0), RKeyFunction::KeyExact);
99 assert_eq!(RKeyFunction::from_raw(7), RKeyFunction::PrefixLastOrPrev);
100 assert_eq!(RKeyFunction::from_raw(13), RKeyFunction::NearestNeighbor);
101 }
102
103 #[test]
104 fn unknown_codes_become_invalid() {
105 assert_eq!(RKeyFunction::from_raw(-1), RKeyFunction::Invalid);
106 assert_eq!(RKeyFunction::from_raw(14), RKeyFunction::Invalid);
107 assert_eq!(RKeyFunction::from_raw(i32::MAX), RKeyFunction::Invalid);
108 }
109}