Skip to content

Commit

Permalink
Begin writing unit test for Float/Double
Browse files Browse the repository at this point in the history
  • Loading branch information
Codetector1374 committed Aug 9, 2024
1 parent ec4c2f5 commit a5b234f
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 12 deletions.
22 changes: 18 additions & 4 deletions src/innodb/table/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pub enum FieldType {
Int6(bool), // 6
BigInt(bool), // 8

Float,
Double,

Enum(Vec<String>),

Text(usize, InnoDBCharset), // CHAR type with non-latin charset also uses this apparently
Expand All @@ -37,12 +40,18 @@ impl FieldType {
FieldType::Int(_) => 4,
FieldType::Int6(_) => 6,
FieldType::BigInt(_) => 8,

FieldType::Float => 4,
FieldType::Double => 8,

FieldType::Enum(_) => 2,

FieldType::Text(len, charset) => (*len as u64) * charset.max_len(),
FieldType::Char(len, charset) => (*len as u64) * charset.max_len(),

FieldType::Date => 3,
FieldType::DateTime => 8,
FieldType::Timestamp => 4,
FieldType::Text(len, charset) => (*len as u64) * charset.max_len(),
FieldType::Char(len, charset) => (*len as u64) * charset.max_len(),
}
}
}
Expand Down Expand Up @@ -194,9 +203,14 @@ impl Field {
let variant_index = num - 1;
assert!(
(variant_index as usize) < values.len(),
"Enum Value is larger than expected? {} vs {}", variant_index, values.len()
"Enum Value is larger than expected? {} vs {}",
variant_index,
values.len()
);
(FieldValue::String(values[variant_index as usize].clone()), len)
(
FieldValue::String(values[variant_index as usize].clone()),
len,
)
}
}
#[allow(unreachable_patterns)]
Expand Down
10 changes: 6 additions & 4 deletions src/innodb/table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,17 @@ impl TableDefinition {
DataType::MediumInt(_) => FieldType::MediumInt(true),
DataType::Int(_) => FieldType::Int(true),
DataType::BigInt(_) => FieldType::BigInt(true),
DataType::Enum(values) => FieldType::Enum(values.clone()),
DataType::Date => FieldType::Date,
DataType::Datetime(_) => FieldType::DateTime,
DataType::Timestamp(_, _) => FieldType::Timestamp,
DataType::Float(opt) => FieldType::Float,
DataType::Double => FieldType::Double,
DataType::Custom(name, _) => match name.0[0].value.as_str() {
"mediumtext" => FieldType::Text((1 << 24) - 1, charset),
"longtext" => FieldType::Text((1 << 32) - 1, charset),
_ => unimplemented!("Custom: {} unhandled", name.0[0].value),
},
DataType::Enum(values) => FieldType::Enum(values.clone()),
DataType::Date => FieldType::Date,
DataType::Datetime(_)=> FieldType::DateTime,
DataType::Timestamp(_,_) => FieldType::Timestamp,
_ => unimplemented!("mapping of {:?}", column.data_type),
};

Expand Down
8 changes: 4 additions & 4 deletions src/innodb/table/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl<'a> Row<'a> {
fn load_extern(
&self,
extern_header: &ExternReference,
buffer_mgr: &mut dyn BufferManager,
buffer_mgr: &dyn BufferManager,
) -> Result<Box<[u8]>> {
let space_id = extern_header.space_id;
let first_page_number = extern_header.page_number;
Expand Down Expand Up @@ -198,7 +198,7 @@ impl<'a> Row<'a> {
&self,
f: &Field,
extern_header: &ExternReference,
buffer_mgr: &mut dyn BufferManager,
buffer_mgr: &dyn BufferManager,
) -> FieldValue {
// Load a page
match self.load_extern(extern_header, buffer_mgr) {
Expand All @@ -218,7 +218,7 @@ impl<'a> Row<'a> {
f: &Field,
buf: &[u8],
idx: usize,
buf_mgr: &mut dyn BufferManager,
buf_mgr: &dyn BufferManager,
) -> (FieldValue, usize) {
if self.extern_fields.contains(&idx) {
let len = *self.field_len_map.get(&idx).unwrap() as usize;
Expand All @@ -237,7 +237,7 @@ impl<'a> Row<'a> {
}

/// Only call on primary index
pub fn parse_values(&self, buffer_mgr: &mut dyn BufferManager) -> Vec<FieldValue> {
pub fn parse_values(&self, buffer_mgr: &dyn BufferManager) -> Vec<FieldValue> {
let mut values = Vec::new();
let mut current_offset = self.record.offset;
let num_pk = self.td.cluster_columns.len();
Expand Down
6 changes: 6 additions & 0 deletions test_data/double_test_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE `float_sample` (
`text` char(20) NOT NULL,
`single_f` float DEFAULT NULL,
`double_f` double DEFAULT NULL,
PRIMARY KEY (`text`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Binary file added test_data/float_sample.ibd
Binary file not shown.
74 changes: 74 additions & 0 deletions tests/table_parsing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::{
fs::{read_to_string, File},
io::Read,
path::PathBuf, sync::Arc,
};

use innodb::innodb::{
buffer_manager::DummyBufferMangaer, charset::InnoDBCharset, page::{index::{record::RecordType, IndexPage}, Page, PageType}, table::{
field::{Field, FieldType}, row::Row, TableDefinition
}
};

#[test]
#[ignore]
fn test_parsing_table_with_floats() {
let sql = read_to_string(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("test_data")
.join("double_test_table.sql"),
)
.unwrap();

let reference = TableDefinition {
name: String::from("float_sample"),
cluster_columns: vec![Field::new(
"text",
FieldType::Text(20, InnoDBCharset::Utf8mb4),
false,
)],
data_columns: vec![
Field::new("single_f", FieldType::Float, true),
Field::new("double_f", FieldType::Double, true),
],
};

let parsed_table = Arc::new(TableDefinition::try_from_sql_statement(&sql).expect("Failed to parse SQL"));
assert_eq!(parsed_table.as_ref(), &reference);

let mut table_content_file = File::open(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("test_data")
.join("float_sample.ibd"),
)
.expect("Can't open test table");


let buf_mgr = DummyBufferMangaer;
let mut buffer = Vec::<u8>::new();
buffer.resize(16384, 0);

loop {
match table_content_file.read_exact(&mut buffer) {
Ok(_) => {
let page = Page::from_bytes(&buffer).unwrap();
if page.header.page_type == PageType::Index {
let index = IndexPage::try_from_page(page).unwrap();
assert_eq!(index.index_header.index_id, 960, "Wrong Index ID");
let mut record = index.infimum().unwrap();
while record.next().is_some() {

if record.header.record_type == RecordType::Conventional {
let row = Row::try_from_record_and_table(&record, &parsed_table).expect("Failed to parse row");
let values = row.parse_values(&buf_mgr);
}

record = record.next().unwrap();
}
assert_eq!(record.header.record_type, RecordType::Supremum);
}
}
Err(_) => break,
}
}
}

0 comments on commit a5b234f

Please sign in to comment.