Skip to main content

mysql_handler/
runtime.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-instance lifecycle across the FFI boundary: the factory registry,
24//! the per-handler [`EngineContext`], create/destroy entry points, and the
25//! `FfiPtr` pointer helpers. Per-method `rust__handler__*` callbacks live in
26//! [`crate::handler`]; both modules share the safety contract documented there.
27
28#![allow(unsafe_code)]
29
30mod context;
31#[doc(hidden)]
32pub mod hton_registry;
33#[doc(hidden)]
34pub mod ptr;
35#[doc(hidden)]
36pub mod registry;
37
38pub use context::EngineContext;
39use hton_registry::HandlertonRegistry;
40pub(crate) use ptr::FfiPtr;
41pub use registry::EngineFactory;
42use registry::EngineRegistry;
43
44use crate::hton::Handlerton;
45use crate::panic_guard::FfiBoundary;
46
47static REGISTRY: EngineRegistry = EngineRegistry::new();
48
49/// Install `factory` on the process-wide engine registry. Call this once
50/// from the plugin's `rust__plugin_init`; later calls are ignored.
51pub fn register_engine_factory(factory: EngineFactory) {
52    REGISTRY.register(factory);
53}
54
55static HANDLERTON: HandlertonRegistry = HandlertonRegistry::new();
56
57/// Install `handlerton` as the process-wide engine-level handlerton.
58///
59/// Optional and independent of [`register_engine_factory`]: call it once from
60/// the plugin's `rust__plugin_init` only when the engine implements
61/// engine-level behaviour (transactions, savepoints, ...). Later calls are
62/// ignored, and an engine that never calls it keeps the zero-config handlerton
63/// defaults.
64pub fn register_handlerton(handlerton: Box<dyn Handlerton>) {
65    HANDLERTON.register(handlerton);
66}
67
68/// The registered engine-level handlerton, or `None` when the engine kept the
69/// zero-config defaults. Read by the `rust__hton__*` FFI accessors.
70pub(crate) fn handlerton() -> Option<&'static dyn Handlerton> {
71    HANDLERTON.get()
72}
73
74/// Allocate an `EngineContext`; null if no factory or the factory panics
75///
76/// # Safety
77/// Safe after `rust__plugin_init`; release via `rust__destroy_engine` once.
78#[unsafe(no_mangle)]
79pub unsafe extern "C" fn rust__create_engine() -> *mut EngineContext {
80    FfiBoundary::run_default(std::ptr::null_mut(), || match REGISTRY.create_context() {
81        Some(ctx) => Box::into_raw(Box::new(ctx)),
82        None => std::ptr::null_mut(),
83    })
84}
85
86/// Drop a context returned by `rust__create_engine`
87///
88/// # Safety
89/// `ctx` must come from `rust__create_engine` and not be released twice; null
90/// is ignored.
91#[unsafe(no_mangle)]
92pub unsafe extern "C" fn rust__destroy_engine(ctx: *mut EngineContext) {
93    FfiBoundary::run_void(|| {
94        if !ctx.is_null() {
95            // SAFETY: pointer originates from `Box::into_raw` and is dropped once.
96            drop(unsafe { Box::from_raw(ctx) });
97        }
98    });
99}