diff --git a/src/bin/page_explorer.rs b/src/bin/page_explorer.rs index af73fd6..89f410b 100644 --- a/src/bin/page_explorer.rs +++ b/src/bin/page_explorer.rs @@ -198,6 +198,7 @@ impl PageExplorer { BufReader::new(File::open(&self.arguments.file).expect("Can't open page file")); let mut buffer = Box::<[u8]>::from([0u8; FIL_PAGE_SIZE]); let mut counter = 0usize; + let mut index_counter = 0usize; if let Some(output) = &self.arguments.output { let file = File::create(output).expect("Can't open output file for write"); @@ -214,6 +215,9 @@ impl PageExplorer { break; } let page = Page::from_bytes(&buffer).unwrap(); + if page.header.page_type == PageType::Index { + index_counter += 1; + } if let Some(page_id) = self.arguments.page_id { if page.header.offset != page_id { continue; @@ -226,7 +230,7 @@ impl PageExplorer { } if let Some(limit) = self.arguments.limit { - if counter >= limit { + if index_counter >= limit { info!("Exiting early due to --limit argument"); break; } diff --git a/src/innodb/table/field.rs b/src/innodb/table/field.rs index 5591e24..9e2754d 100644 --- a/src/innodb/table/field.rs +++ b/src/innodb/table/field.rs @@ -1,7 +1,7 @@ use std::u64; use crate::innodb::charset::InnoDBCharset; -use tracing::trace; +use tracing::{info, trace}; #[derive(Debug, Clone, PartialEq, Eq)] pub enum FieldType { @@ -80,13 +80,22 @@ impl Field { if signed { let numeric_value = num & ((1u64 << (len * 8 - 1)) - 1); let is_positive = (num & (1u64 << (len * 8 - 1))) != 0; - FieldValue::SignedInt(if is_positive { - numeric_value as i64 + let mask = if is_positive { + 0u64 } else { - -(numeric_value as i64) - }) + u64::MAX << (len * 8 - 1) + }; + let signed_value = (numeric_value | mask) as i64; + if signed_value == -127 && len == 1 { + info!( + "DBG: numeric_value: {:#x}, pos: {}", + numeric_value, is_positive + ); + } + FieldValue::SignedInt(signed_value) } else { - FieldValue::UnsignedInt(num & !(u64::MAX << (len * 8))) + assert!(len == 8 || num < (1 << (len * 8))); + FieldValue::UnsignedInt(num) } } @@ -140,7 +149,7 @@ mod test { use super::{Field, FieldType}; #[test] - fn test_field_parse_int() { + fn test_field_parse_medium_int() { let buf = [0x80, 0x00, 0x00]; let field = Field { name: Default::default(), @@ -153,4 +162,19 @@ mod test { _ => unreachable!(), } } + + #[test] + fn test_field_parse_tiny_int() { + let buf = [0x7F]; + let field = Field { + name: Default::default(), + field_type: FieldType::TinyInt(true), + nullable: false, + }; + let result = field.parse_int(&buf, 1, true); + match result { + super::FieldValue::SignedInt(val) => assert_eq!(val, -1), + _ => unreachable!(), + } + } }