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