Skip to main content

mysql_handler/hton/
stat_print_sink.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-facing handle to MySQL's `stat_print_fn` for emitting
24//! `SHOW ENGINE <name> STATUS` rows.
25
26#![allow(unsafe_code)]
27
28use core::ffi::c_void;
29
30use crate::sys;
31
32unsafe extern "C" {
33    fn mysql__hton__emit_status_row(
34        thd: *const c_void,
35        print_fn: *const c_void,
36        kind: *const u8,
37        kind_len: usize,
38        key: *const u8,
39        key_len: usize,
40        value: *const u8,
41        value_len: usize,
42    ) -> bool;
43}
44
45/// A handle that lets a [`Handlerton::show_status`] implementation push one or
46/// more rows of engine status back to MySQL. Bound to the connection and
47/// `stat_print_fn` MySQL handed in, so it does not outlive the callback.
48///
49/// Each [`Self::emit`] call surfaces as one row of `SHOW ENGINE <name> STATUS`:
50/// `kind` is the row's type (typically the engine name), `key` a sub-label, and
51/// `value` the displayed text.
52///
53/// [`Handlerton::show_status`]: crate::hton::Handlerton::show_status
54#[derive(Debug)]
55pub struct StatPrintSink<'a> {
56    thd: Option<&'a sys::THD>,
57    print_fn: *const c_void,
58}
59
60impl<'a> StatPrintSink<'a> {
61    /// Bind a sink to the connection and `stat_print_fn` MySQL handed in.
62    /// `print_fn` is opaque to Rust; the reverse callback re-casts it before
63    /// invoking it on the C++ side. Crate-private: external `Handlerton`
64    /// implementors receive a sink as a parameter and call [`Self::emit`];
65    /// they never construct one.
66    #[must_use]
67    pub(crate) fn new(thd: Option<&'a sys::THD>, print_fn: *const c_void) -> Self {
68        Self { thd, print_fn }
69    }
70
71    /// Push one row. Returns `true` when MySQL accepted the row, `false` when
72    /// the print function reported back-pressure / failure.
73    #[must_use]
74    pub fn emit(&self, kind: &str, key: &str, value: &str) -> bool {
75        if self.print_fn.is_null() {
76            return false;
77        }
78        let thd = match self.thd {
79            Some(t) => std::ptr::from_ref(t).cast::<c_void>(),
80            None => std::ptr::null(),
81        };
82        // SAFETY: the shim implements mysql__hton__emit_status_row; the byte
83        // pointers cover their stated lengths for the duration of this call.
84        let ok = unsafe {
85            mysql__hton__emit_status_row(
86                thd,
87                self.print_fn,
88                kind.as_ptr(),
89                kind.len(),
90                key.as_ptr(),
91                key.len(),
92                value.as_ptr(),
93                value.len(),
94            )
95        };
96        // stat_print_fn returns true on error in MySQL convention; invert so
97        // Rust callers can write `if !sink.emit(...) { ... }` on failure.
98        !ok
99    }
100}