1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use super::Handler;
use crate::thd::ThdKillLevel;
use crate::{bindings, MemRoot, TableShare, Thd};

pub enum Error {}
pub type Result<T = (), E = Error> = std::result::Result<T, E>;

pub struct HandlertonCtx<'a> {
    hton: &'a mut bindings::handlerton,
    thd: &'a mut bindings::THD,
}

impl<'a> HandlertonCtx<'a> {
    unsafe fn new(hton: *mut bindings::handlerton, thd: *mut bindings::THD) -> Self {
        debug_assert!(!hton.is_null());
        debug_assert!(!thd.is_null());
        Self {
            hton: unsafe { &mut *hton },
            thd: unsafe { &mut *thd },
        }
    }
}

pub struct HandlertonThd<'a> {
    thd: &'a mut Thd<'a>,
    slot: usize,
}

impl<'a> HandlertonThd<'a> {
    unsafe fn new(hton: *mut bindings::handlerton, thd: *mut bindings::THD) -> Self {
        debug_assert!(!hton.is_null());
        debug_assert!(!thd.is_null());
        Self {
            thd: unsafe { Thd::new_mut(thd) },
            slot: unsafe { (*hton).slot }.try_into().unwrap(),
        }
    }

    fn data(&self) {
        todo!()
        // let x = self.thd.0.ha_data[self.slot];
    }
}

// TODO: do we really have a `self`? I.e., can a `handlerton` contain arbitrary data?

/// A "handlerton" ("handler singleton") is the entrypoint for a storage engine handler.
///
/// This defines registration and creation information.
pub trait Handlerton {
    type Handler: Handler;
    /// A type of data that is stored during a savepoint.
    type SavePoint;
    const FLAGS: u32 = 0;

    /// Extensions of files created for a single table in the database directory
    /// (`datadir/db_name/`).
    const TABLEFILE_EXTENSIONS: &'static [&'static str] = &[];

    // fn close_connection(thd: &HandlertonThd) -> Result;
    // fn kill_query(thd: &HandlertonThd, level: ThdKillLevel);

    // TODO: should Savepoint be its own trait?

    // /// Create a new savepoint
    // fn savepoint_set(thd: &HandlertonThd) -> Result<Self::SavePoint>;
    // /// Restore to a previous savepoint
    // fn savepoint_rollback(thd: &HandlertonThd, sv: &mut Self::SavePoint) -> Result;
    // fn savepoint_rollback_can_release_mdl(thd: &HandlertonThd) -> bool {
    //     false
    // }
    // fn savepoint_release(thd: &HandlertonThd, sv: &mut Self::SavePoint) -> Result;

    // /// Perform the commit.
    // ///
    // /// If `is_true_commit` is false, we are in an end of statement within a transaction
    // fn commit(thd: &HandlertonThd, is_true_commit: bool) -> Result;
    // fn commit_ordered(thd: &HandlertonThd, is_true_commit: bool) -> Result;
    // fn rollback(thd: &HandlertonThd, is_true_commit: bool) -> Result;
    // fn prepare(thd: &HandlertonThd, is_true_commit: bool) -> Result;
    // fn prepare_ordered(thd: &HandlertonThd, is_true_commit: bool) -> Result;

    //... more to do
}

// TODO: also take table_options, field_options, and index_options. Maybe we can put these
// into traits?
pub fn initialize_handlerton<T: Handlerton>(hton: &mut bindings::handlerton) {
    hton.kill_query = Some(wrap_kill_query::<T>);
}

#[allow(clippy::extra_unused_type_parameters)] // expected until H is used
#[allow(improper_ctypes_definitions)] // level is not FFI-safe
unsafe extern "C" fn wrap_kill_query<H: Handlerton>(
    hton: *mut bindings::handlerton,
    thd: *mut bindings::THD,
    level: bindings::thd_kill_levels::Type,
) {
    let ctx = unsafe { HandlertonCtx::new(hton, thd) };
    todo!()
}