quill_sql/storage/codec/
tuple.rs

1use 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        // null map
13        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}