quill_sql/storage/codec/
tuple.rs1use crate::catalog::SchemaRef;
2use crate::error::{QuillSQLError, QuillSQLResult};
3use crate::storage::codec::{DecodedData, ScalarValueCodec};
4use crate::storage::tuple::Tuple;
5use crate::utils::bitmap::DynamicBitmap;
6use crate::utils::scalar::ScalarValue;
7
8pub struct TupleCodec;
9
10impl TupleCodec {
11 pub fn encode(tuple: &Tuple) -> Vec<u8> {
12 let mut null_map = DynamicBitmap::new();
14 let mut attributes = Vec::new();
15 for (idx, value) in tuple.data.iter().enumerate() {
16 null_map.set(idx, value.is_null());
17 if !value.is_null() {
18 attributes.extend(ScalarValueCodec::encode(value));
19 }
20 }
21
22 let mut bytes = null_map.to_bytes();
23 bytes.extend(attributes);
24 bytes
25 }
26
27 pub fn decode(bytes: &[u8], schema: SchemaRef) -> QuillSQLResult<DecodedData<Tuple>> {
28 let mut total_offset = 0;
29
30 let null_map_bytes = schema.column_count().div_ceil(8);
31 let null_map = DynamicBitmap::from_bytes(&bytes[0..null_map_bytes]);
32 total_offset += null_map_bytes;
33 let mut bytes = &bytes[null_map_bytes..];
34
35 let mut data = vec![];
36 for (idx, col) in schema.columns.iter().enumerate() {
37 let null = null_map.get(idx).ok_or(QuillSQLError::Internal(
38 "null map size should be greater than or equal to col count".to_string(),
39 ))?;
40 if null {
41 data.push(ScalarValue::new_empty(col.data_type));
42 } else {
43 let (value, offset) = ScalarValueCodec::decode(bytes, col.data_type)?;
44 data.push(value);
45 total_offset += offset;
46 bytes = &bytes[offset..];
47 }
48 }
49
50 Ok((Tuple::new(schema, data), total_offset))
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use crate::catalog::{Column, DataType, Schema};
57 use crate::storage::codec::TupleCodec;
58 use crate::storage::tuple::Tuple;
59 use crate::utils::scalar::ScalarValue;
60 use std::sync::Arc;
61
62 #[test]
63 fn tuple_codec() {
64 let schema = Arc::new(Schema::new(vec![
65 Column::new("a", DataType::Boolean, true),
66 Column::new("b", DataType::Int32, true),
67 Column::new("c", DataType::UInt64, true),
68 Column::new("d", DataType::Varchar(None), true),
69 ]));
70 let tuple = Tuple::new(
71 schema.clone(),
72 vec![
73 true.into(),
74 ScalarValue::Int32(None),
75 1234u64.into(),
76 "aabb".to_string().into(),
77 ],
78 );
79 let new_tuple = TupleCodec::decode(&TupleCodec::encode(&tuple), schema)
80 .unwrap()
81 .0;
82 assert_eq!(new_tuple, tuple);
83 }
84}