use std::io::Write;
use crate::cli::wprintln;
use crate::innodb::sdi;
use crate::IdbError;
pub struct SdiOptions {
pub file: String,
pub pretty: bool,
pub page_size: Option<u32>,
pub keyring: Option<String>,
pub mmap: bool,
}
pub fn execute(opts: &SdiOptions, writer: &mut dyn Write) -> Result<(), IdbError> {
let mut ts = crate::cli::open_tablespace(&opts.file, opts.page_size, opts.mmap)?;
if let Some(ref keyring_path) = opts.keyring {
crate::cli::setup_decryption(&mut ts, keyring_path)?;
}
if ts.vendor_info().vendor == crate::innodb::vendor::InnoDbVendor::MariaDB {
return Err(IdbError::Argument(
"SDI is not available for MariaDB tablespaces. MariaDB does not use \
Serialized Dictionary Information (SDI); table metadata is stored \
in the data dictionary (mysql.* tables) or .frm files."
.to_string(),
));
}
let sdi_pages = sdi::find_sdi_pages(&mut ts)?;
if sdi_pages.is_empty() {
wprintln!(writer, "No SDI pages found in {}.", opts.file)?;
wprintln!(writer, "SDI is only available in MySQL 8.0+ tablespaces.")?;
return Ok(());
}
wprintln!(
writer,
"Found {} SDI page(s): {:?}",
sdi_pages.len(),
sdi_pages
)?;
let records = sdi::extract_sdi_from_pages(&mut ts, &sdi_pages)?;
if records.is_empty() {
wprintln!(
writer,
"No SDI records found (pages may be non-leaf or empty)."
)?;
return Ok(());
}
for rec in &records {
wprintln!(writer)?;
wprintln!(
writer,
"=== SDI Record: type={} ({}), id={}",
rec.sdi_type,
sdi::sdi_type_name(rec.sdi_type),
rec.sdi_id
)?;
wprintln!(
writer,
"Compressed: {} bytes, Uncompressed: {} bytes",
rec.compressed_len,
rec.uncompressed_len
)?;
if rec.data.is_empty() {
wprintln!(
writer,
"(Data could not be decompressed - may span multiple pages)"
)?;
continue;
}
if opts.pretty {
match serde_json::from_str::<serde_json::Value>(&rec.data) {
Ok(json) => {
wprintln!(
writer,
"{}",
serde_json::to_string_pretty(&json).unwrap_or(rec.data.clone())
)?;
}
Err(_) => {
wprintln!(writer, "{}", rec.data)?;
}
}
} else {
wprintln!(writer, "{}", rec.data)?;
}
}
wprintln!(writer)?;
wprintln!(writer, "Total SDI records: {}", records.len())?;
Ok(())
}