1use std::io::Write;
2
3use crate::cli::wprintln;
4use crate::innodb::sdi;
5use crate::IdbError;
6
7pub struct SdiOptions {
9 pub file: String,
11 pub pretty: bool,
13 pub page_size: Option<u32>,
15 pub keyring: Option<String>,
17 pub mmap: bool,
19}
20
21pub fn execute(opts: &SdiOptions, writer: &mut dyn Write) -> Result<(), IdbError> {
40 let mut ts = crate::cli::open_tablespace(&opts.file, opts.page_size, opts.mmap)?;
41
42 if let Some(ref keyring_path) = opts.keyring {
43 crate::cli::setup_decryption(&mut ts, keyring_path)?;
44 }
45
46 if ts.vendor_info().vendor == crate::innodb::vendor::InnoDbVendor::MariaDB {
48 return Err(IdbError::Argument(
49 "SDI is not available for MariaDB tablespaces. MariaDB does not use \
50 Serialized Dictionary Information (SDI); table metadata is stored \
51 in the data dictionary (mysql.* tables) or .frm files."
52 .to_string(),
53 ));
54 }
55
56 let sdi_pages = sdi::find_sdi_pages(&mut ts)?;
58
59 if sdi_pages.is_empty() {
60 wprintln!(writer, "No SDI pages found in {}.", opts.file)?;
61 wprintln!(writer, "SDI is only available in MySQL 8.0+ tablespaces.")?;
62 return Ok(());
63 }
64
65 wprintln!(
66 writer,
67 "Found {} SDI page(s): {:?}",
68 sdi_pages.len(),
69 sdi_pages
70 )?;
71
72 let records = sdi::extract_sdi_from_pages(&mut ts, &sdi_pages)?;
74
75 if records.is_empty() {
76 wprintln!(
77 writer,
78 "No SDI records found (pages may be non-leaf or empty)."
79 )?;
80 return Ok(());
81 }
82
83 for rec in &records {
84 wprintln!(writer)?;
85 wprintln!(
86 writer,
87 "=== SDI Record: type={} ({}), id={}",
88 rec.sdi_type,
89 sdi::sdi_type_name(rec.sdi_type),
90 rec.sdi_id
91 )?;
92 wprintln!(
93 writer,
94 "Compressed: {} bytes, Uncompressed: {} bytes",
95 rec.compressed_len,
96 rec.uncompressed_len
97 )?;
98
99 if rec.data.is_empty() {
100 wprintln!(
101 writer,
102 "(Data could not be decompressed - may span multiple pages)"
103 )?;
104 continue;
105 }
106
107 if opts.pretty {
108 match serde_json::from_str::<serde_json::Value>(&rec.data) {
110 Ok(json) => {
111 wprintln!(
112 writer,
113 "{}",
114 serde_json::to_string_pretty(&json).unwrap_or(rec.data.clone())
115 )?;
116 }
117 Err(_) => {
118 wprintln!(writer, "{}", rec.data)?;
119 }
120 }
121 } else {
122 wprintln!(writer, "{}", rec.data)?;
123 }
124 }
125
126 wprintln!(writer)?;
127 wprintln!(writer, "Total SDI records: {}", records.len())?;
128
129 Ok(())
130}