Skip to main content

hematite/catalog/
column.rs

1//! Column definitions for database tables.
2
3use super::types::{
4    DataType, DateTimeValue, DateValue, DecimalValue, TimeValue, TimeWithTimeZoneValue, Value,
5};
6use super::ColumnId;
7use crate::error::HematiteError;
8
9#[derive(Debug, Clone)]
10pub struct Column {
11    pub id: ColumnId,
12    pub name: String,
13    pub data_type: DataType,
14    pub character_set: Option<String>,
15    pub collation: Option<String>,
16    pub nullable: bool,
17    pub primary_key: bool,
18    pub auto_increment: bool,
19    pub default_value: Option<Value>,
20}
21
22impl Column {
23    pub fn new(id: ColumnId, name: String, data_type: DataType) -> Self {
24        Self {
25            id,
26            name,
27            data_type,
28            character_set: None,
29            collation: None,
30            nullable: true,
31            primary_key: false,
32            auto_increment: false,
33            default_value: None,
34        }
35    }
36
37    pub fn nullable(mut self, nullable: bool) -> Self {
38        self.nullable = nullable;
39        self
40    }
41
42    pub fn primary_key(mut self, primary_key: bool) -> Self {
43        self.primary_key = primary_key;
44        if primary_key {
45            self.nullable = false;
46        }
47        self
48    }
49
50    pub fn auto_increment(mut self, auto_increment: bool) -> Self {
51        self.auto_increment = auto_increment;
52        if auto_increment {
53            self.nullable = false;
54        }
55        self
56    }
57
58    pub fn default_value(mut self, value: Value) -> Self {
59        self.default_value = Some(value);
60        self
61    }
62
63    pub fn character_set(mut self, character_set: Option<String>) -> Self {
64        self.character_set = character_set;
65        self
66    }
67
68    pub fn collation(mut self, collation: Option<String>) -> Self {
69        self.collation = collation;
70        self
71    }
72
73    pub fn validate_value(&self, value: &Value) -> bool {
74        if value.is_null() {
75            return self.nullable;
76        }
77
78        if !value.is_compatible_with(self.data_type.clone()) {
79            return false;
80        }
81
82        match (&self.data_type, value) {
83            (DataType::Int8, Value::Integer(value)) => i8::try_from(*value).is_ok(),
84            (DataType::Int16, Value::Integer(value)) => i16::try_from(*value).is_ok(),
85            (DataType::UInt8, Value::UInteger(value)) => u8::try_from(*value).is_ok(),
86            (DataType::UInt16, Value::UInteger(value)) => u16::try_from(*value).is_ok(),
87            (DataType::Char(length), Value::Text(text)) => text.chars().count() == *length as usize,
88            (DataType::VarChar(length), Value::Text(text)) => {
89                text.chars().count() <= *length as usize
90            }
91            (DataType::Binary(length), Value::Blob(bytes)) => bytes.len() == *length as usize,
92            (DataType::VarBinary(length), Value::Blob(bytes)) => bytes.len() <= *length as usize,
93            (DataType::Enum(values), Value::Enum(value)) => values.contains(value),
94            (DataType::Decimal { precision, scale }, Value::Decimal(value)) => {
95                value.fits_precision_scale(*precision, *scale)
96            }
97            _ => true,
98        }
99    }
100
101    pub fn get_default_or_null(&self) -> Value {
102        match &self.default_value {
103            Some(value) => value.clone(),
104            None => {
105                if self.nullable {
106                    Value::Null
107                } else {
108                    match &self.data_type {
109                        DataType::Int8 | DataType::Int16 | DataType::Int => Value::Integer(0),
110                        DataType::Int64 => Value::BigInt(0),
111                        DataType::Int128 => Value::Int128(0),
112                        DataType::UInt8 | DataType::UInt16 | DataType::UInt => Value::UInteger(0),
113                        DataType::UInt64 => Value::UBigInt(0),
114                        DataType::UInt128 => Value::UInt128(0),
115                        DataType::Text => Value::Text(String::new()),
116                        DataType::Char(length) => Value::Text(pad_text_to_char_length("", *length)),
117                        DataType::VarChar(_) => Value::Text(String::new()),
118                        DataType::Binary(length) => Value::Blob(vec![0; *length as usize]),
119                        DataType::VarBinary(_) | DataType::Blob => Value::Blob(Vec::new()),
120                        DataType::Enum(values) => {
121                            Value::Enum(values.first().cloned().unwrap_or_default())
122                        }
123                        DataType::Boolean => Value::Boolean(false),
124                        DataType::Float32 => Value::Float32(0.0),
125                        DataType::Float => Value::Float(0.0),
126                        DataType::Decimal { .. } => Value::Decimal(DecimalValue::zero()),
127                        DataType::Date => Value::Date(DateValue::epoch()),
128                        DataType::Time => Value::Time(TimeValue::midnight()),
129                        DataType::DateTime => Value::DateTime(DateTimeValue::epoch()),
130                        DataType::TimeWithTimeZone => {
131                            Value::TimeWithTimeZone(TimeWithTimeZoneValue::utc_midnight())
132                        }
133                        DataType::IntervalYearMonth | DataType::IntervalDaySecond => {
134                            panic!("interval runtime types are not valid column data types")
135                        }
136                    }
137                }
138            }
139        }
140    }
141
142    pub fn size(&self) -> usize {
143        self.data_type.size()
144    }
145
146    pub fn serialize(&self, buffer: &mut Vec<u8>) -> Result<(), HematiteError> {
147        buffer.extend_from_slice(&self.id.as_u32().to_le_bytes());
148
149        let name_bytes = self.name.as_bytes();
150        buffer.extend_from_slice(&(name_bytes.len() as u32).to_le_bytes());
151        buffer.extend_from_slice(name_bytes);
152
153        write_data_type(buffer, &self.data_type);
154
155        let mut flags = 0;
156        if self.nullable {
157            flags |= 0x01;
158        }
159        if self.primary_key {
160            flags |= 0x02;
161        }
162        if self.auto_increment {
163            flags |= 0x04;
164        }
165        if self.character_set.is_some() {
166            flags |= 0x08;
167        }
168        if self.collation.is_some() {
169            flags |= 0x10;
170        }
171        buffer.push(flags);
172
173        if let Some(character_set) = &self.character_set {
174            write_string(buffer, character_set);
175        }
176        if let Some(collation) = &self.collation {
177            write_string(buffer, collation);
178        }
179        write_optional_value(buffer, self.default_value.as_ref());
180        Ok(())
181    }
182
183    pub fn deserialize(buffer: &[u8], offset: &mut usize) -> Result<Self, HematiteError> {
184        if *offset + 4 > buffer.len() {
185            return Err(HematiteError::CorruptedData(
186                "Invalid column data".to_string(),
187            ));
188        }
189
190        let id = ColumnId::new(u32::from_le_bytes(
191            buffer[*offset..*offset + 4]
192                .try_into()
193                .map_err(|_| HematiteError::CorruptedData("Invalid column id".to_string()))?,
194        ));
195        *offset += 4;
196
197        let name_len = read_u32(buffer, offset, "column name length")? as usize;
198        if *offset + name_len > buffer.len() {
199            return Err(HematiteError::CorruptedData(
200                "Invalid column name".to_string(),
201            ));
202        }
203        let name =
204            String::from_utf8(buffer[*offset..*offset + name_len].to_vec()).map_err(|_| {
205                HematiteError::CorruptedData("Invalid UTF-8 in column name".to_string())
206            })?;
207        *offset += name_len;
208
209        let data_type = read_data_type(buffer, offset)?;
210
211        if *offset >= buffer.len() {
212            return Err(HematiteError::CorruptedData(
213                "Invalid column flags".to_string(),
214            ));
215        }
216        let flags = buffer[*offset];
217        *offset += 1;
218        let nullable = (flags & 0x01) != 0;
219        let primary_key = (flags & 0x02) != 0;
220        let auto_increment = (flags & 0x04) != 0;
221        let character_set = if (flags & 0x08) != 0 {
222            Some(read_string(buffer, offset, "column character set")?)
223        } else {
224            None
225        };
226        let collation = if (flags & 0x10) != 0 {
227            Some(read_string(buffer, offset, "column collation")?)
228        } else {
229            None
230        };
231
232        let default_value = read_optional_value(buffer, offset)?;
233
234        Ok(Self {
235            id,
236            name,
237            data_type,
238            character_set,
239            collation,
240            nullable,
241            primary_key,
242            auto_increment,
243            default_value,
244        })
245    }
246}
247
248pub(crate) fn pad_text_to_char_length(value: &str, length: u32) -> String {
249    let char_count = value.chars().count();
250    if char_count >= length as usize {
251        value.to_string()
252    } else {
253        let mut padded = String::with_capacity(value.len() + (length as usize - char_count));
254        padded.push_str(value);
255        padded.push_str(&" ".repeat(length as usize - char_count));
256        padded
257    }
258}
259
260pub(crate) fn pad_binary_to_length(value: &[u8], length: u32) -> Vec<u8> {
261    let mut padded = value.to_vec();
262    padded.resize(length as usize, 0);
263    padded
264}
265
266pub(crate) fn normalize_text_for_collation(value: &str, collation: Option<&str>) -> String {
267    if collation_is_nocase(collation) {
268        value.to_lowercase()
269    } else {
270        value.to_string()
271    }
272}
273
274pub(crate) fn collation_is_nocase(collation: Option<&str>) -> bool {
275    let Some(collation) = collation else {
276        return false;
277    };
278    let normalized = collation.to_ascii_lowercase();
279    normalized == "nocase" || normalized.ends_with("_nocase")
280}
281
282fn write_data_type(buffer: &mut Vec<u8>, data_type: &DataType) {
283    match data_type {
284        DataType::Int8 => buffer.push(0),
285        DataType::Int16 => buffer.push(1),
286        DataType::Int => buffer.push(2),
287        DataType::Int64 => buffer.push(3),
288        DataType::UInt8 => buffer.push(22),
289        DataType::UInt16 => buffer.push(23),
290        DataType::Int128 => buffer.push(24),
291        DataType::UInt => buffer.push(25),
292        DataType::UInt64 => buffer.push(26),
293        DataType::UInt128 => buffer.push(27),
294        DataType::Text => buffer.push(4),
295        DataType::Char(length) => {
296            buffer.push(5);
297            buffer.extend_from_slice(&length.to_le_bytes());
298        }
299        DataType::VarChar(length) => {
300            buffer.push(6);
301            buffer.extend_from_slice(&length.to_le_bytes());
302        }
303        DataType::Binary(length) => {
304            buffer.push(7);
305            buffer.extend_from_slice(&length.to_le_bytes());
306        }
307        DataType::VarBinary(length) => {
308            buffer.push(8);
309            buffer.extend_from_slice(&length.to_le_bytes());
310        }
311        DataType::Enum(values) => {
312            buffer.push(9);
313            buffer.extend_from_slice(&(values.len() as u32).to_le_bytes());
314            for value in values {
315                buffer.extend_from_slice(&(value.len() as u32).to_le_bytes());
316                buffer.extend_from_slice(value.as_bytes());
317            }
318        }
319        DataType::Boolean => buffer.push(10),
320        DataType::Float => buffer.push(11),
321        DataType::Float32 => buffer.push(12),
322        DataType::Decimal { precision, scale } => {
323            buffer.push(14);
324            write_optional_u32(buffer, *precision);
325            write_optional_u32(buffer, *scale);
326        }
327        DataType::Blob => buffer.push(16),
328        DataType::Date => buffer.push(17),
329        DataType::Time => buffer.push(18),
330        DataType::DateTime => buffer.push(19),
331        DataType::TimeWithTimeZone => buffer.push(21),
332        DataType::IntervalYearMonth | DataType::IntervalDaySecond => {
333            panic!("interval runtime types cannot be serialized as column data types")
334        }
335    }
336}
337
338fn read_data_type(buffer: &[u8], offset: &mut usize) -> Result<DataType, HematiteError> {
339    if *offset >= buffer.len() {
340        return Err(HematiteError::CorruptedData(
341            "Invalid column data type".to_string(),
342        ));
343    }
344
345    let tag = buffer[*offset];
346    *offset += 1;
347
348    Ok(match tag {
349        0 => DataType::Int8,
350        1 => DataType::Int16,
351        2 => DataType::Int,
352        3 => DataType::Int64,
353        22 => DataType::UInt8,
354        23 => DataType::UInt16,
355        4 => DataType::Text,
356        5 => DataType::Char(read_u32(buffer, offset, "CHAR length")?),
357        6 => DataType::VarChar(read_u32(buffer, offset, "VARCHAR length")?),
358        7 => DataType::Binary(read_u32(buffer, offset, "BINARY length")?),
359        8 => DataType::VarBinary(read_u32(buffer, offset, "VARBINARY length")?),
360        9 => {
361            let count = read_u32(buffer, offset, "ENUM value count")? as usize;
362            let mut values = Vec::with_capacity(count);
363            for _ in 0..count {
364                let len = read_u32(buffer, offset, "ENUM value length")? as usize;
365                let bytes = read_fixed(buffer, offset, len, "ENUM value")?;
366                let value = String::from_utf8(bytes.to_vec()).map_err(|_| {
367                    HematiteError::CorruptedData("Invalid UTF-8 in ENUM value".to_string())
368                })?;
369                values.push(value);
370            }
371            DataType::Enum(values)
372        }
373        10 => DataType::Boolean,
374        11 => DataType::Float,
375        12 => DataType::Float32,
376        14 => DataType::Decimal {
377            precision: read_optional_u32(buffer, offset, "DECIMAL precision")?,
378            scale: read_optional_u32(buffer, offset, "DECIMAL scale")?,
379        },
380        16 => DataType::Blob,
381        17 => DataType::Date,
382        18 => DataType::Time,
383        19 => DataType::DateTime,
384        21 => DataType::TimeWithTimeZone,
385        24 => DataType::Int128,
386        25 => DataType::UInt,
387        26 => DataType::UInt64,
388        27 => DataType::UInt128,
389        _ => {
390            return Err(HematiteError::CorruptedData(
391                "Invalid data type".to_string(),
392            ))
393        }
394    })
395}
396
397fn write_optional_u32(buffer: &mut Vec<u8>, value: Option<u32>) {
398    buffer.extend_from_slice(&value.unwrap_or(u32::MAX).to_le_bytes());
399}
400
401fn write_string(buffer: &mut Vec<u8>, value: &str) {
402    buffer.extend_from_slice(&(value.len() as u32).to_le_bytes());
403    buffer.extend_from_slice(value.as_bytes());
404}
405
406fn read_optional_u32(
407    buffer: &[u8],
408    offset: &mut usize,
409    label: &str,
410) -> Result<Option<u32>, HematiteError> {
411    let value = read_u32(buffer, offset, label)?;
412    if value == u32::MAX {
413        Ok(None)
414    } else {
415        Ok(Some(value))
416    }
417}
418
419fn read_u32(buffer: &[u8], offset: &mut usize, label: &str) -> Result<u32, HematiteError> {
420    if *offset + 4 > buffer.len() {
421        return Err(HematiteError::CorruptedData(format!("Invalid {label}")));
422    }
423    let value = u32::from_le_bytes(
424        buffer[*offset..*offset + 4]
425            .try_into()
426            .map_err(|_| HematiteError::CorruptedData(format!("Invalid {label}")))?,
427    );
428    *offset += 4;
429    Ok(value)
430}
431
432fn read_string(buffer: &[u8], offset: &mut usize, label: &str) -> Result<String, HematiteError> {
433    let len = read_u32(buffer, offset, label)? as usize;
434    let bytes = read_fixed(buffer, offset, len, label)?;
435    String::from_utf8(bytes.to_vec())
436        .map_err(|_| HematiteError::CorruptedData(format!("Invalid UTF-8 in {label}")))
437}
438
439fn write_optional_value(buffer: &mut Vec<u8>, value: Option<&Value>) {
440    match value {
441        None => buffer.push(255),
442        Some(Value::Integer(value)) => {
443            buffer.push(0);
444            buffer.extend_from_slice(&value.to_le_bytes());
445        }
446        Some(Value::Text(value)) => {
447            buffer.push(1);
448            buffer.extend_from_slice(&(value.len() as u32).to_le_bytes());
449            buffer.extend_from_slice(value.as_bytes());
450        }
451        Some(Value::Enum(value)) => {
452            buffer.push(10);
453            buffer.extend_from_slice(&(value.len() as u32).to_le_bytes());
454            buffer.extend_from_slice(value.as_bytes());
455        }
456        Some(Value::Boolean(value)) => {
457            buffer.push(2);
458            buffer.push(u8::from(*value));
459        }
460        Some(Value::Float(value)) => {
461            buffer.push(3);
462            buffer.extend_from_slice(&value.to_le_bytes());
463        }
464        Some(Value::Float32(value)) => {
465            buffer.push(20);
466            buffer.extend_from_slice(&value.to_le_bytes());
467        }
468        Some(Value::BigInt(value)) => {
469            buffer.push(4);
470            buffer.extend_from_slice(&value.to_le_bytes());
471        }
472        Some(Value::Int128(value)) => {
473            buffer.push(16);
474            buffer.extend_from_slice(&value.to_le_bytes());
475        }
476        Some(Value::UInteger(value)) => {
477            buffer.push(17);
478            buffer.extend_from_slice(&value.to_le_bytes());
479        }
480        Some(Value::UBigInt(value)) => {
481            buffer.push(18);
482            buffer.extend_from_slice(&value.to_le_bytes());
483        }
484        Some(Value::UInt128(value)) => {
485            buffer.push(19);
486            buffer.extend_from_slice(&value.to_le_bytes());
487        }
488        Some(Value::Decimal(value)) => {
489            buffer.push(5);
490            let text = value.to_string();
491            buffer.extend_from_slice(&(text.len() as u32).to_le_bytes());
492            buffer.extend_from_slice(text.as_bytes());
493        }
494        Some(Value::Blob(value)) => {
495            buffer.push(6);
496            buffer.extend_from_slice(&(value.len() as u32).to_le_bytes());
497            buffer.extend_from_slice(value);
498        }
499        Some(Value::Date(value)) => {
500            buffer.push(7);
501            buffer.extend_from_slice(&value.days_since_epoch().to_le_bytes());
502        }
503        Some(Value::Time(value)) => {
504            buffer.push(11);
505            buffer.extend_from_slice(&value.seconds_since_midnight().to_le_bytes());
506        }
507        Some(Value::DateTime(value)) => {
508            buffer.push(8);
509            buffer.extend_from_slice(&value.seconds_since_epoch().to_le_bytes());
510        }
511        Some(Value::TimeWithTimeZone(value)) => {
512            buffer.push(13);
513            buffer.extend_from_slice(&value.seconds_since_midnight().to_le_bytes());
514            buffer.extend_from_slice(&value.offset_minutes().to_le_bytes());
515        }
516        Some(Value::IntervalYearMonth(value)) => {
517            buffer.push(14);
518            buffer.extend_from_slice(&value.total_months().to_le_bytes());
519        }
520        Some(Value::IntervalDaySecond(value)) => {
521            buffer.push(15);
522            buffer.extend_from_slice(&value.total_seconds().to_le_bytes());
523        }
524        Some(Value::Null) => buffer.push(9),
525    }
526}
527
528fn read_optional_value(buffer: &[u8], offset: &mut usize) -> Result<Option<Value>, HematiteError> {
529    if *offset >= buffer.len() {
530        return Err(HematiteError::CorruptedData(
531            "Invalid default value".to_string(),
532        ));
533    }
534
535    let tag = buffer[*offset];
536    *offset += 1;
537    Ok(match tag {
538        0 => {
539            let value = i32::from_le_bytes(
540                read_fixed(buffer, offset, 4, "default integer")?
541                    .try_into()
542                    .unwrap(),
543            );
544            Some(Value::Integer(value))
545        }
546        1 => {
547            let len = read_u32(buffer, offset, "default text length")? as usize;
548            let bytes = read_fixed(buffer, offset, len, "default text")?;
549            let text = String::from_utf8(bytes.to_vec()).map_err(|_| {
550                HematiteError::CorruptedData("Invalid UTF-8 in default text".to_string())
551            })?;
552            Some(Value::Text(text))
553        }
554        10 => {
555            let len = read_u32(buffer, offset, "default enum length")? as usize;
556            let bytes = read_fixed(buffer, offset, len, "default enum")?;
557            let text = String::from_utf8(bytes.to_vec()).map_err(|_| {
558                HematiteError::CorruptedData("Invalid UTF-8 in default enum".to_string())
559            })?;
560            Some(Value::Enum(text))
561        }
562        2 => {
563            let value = read_fixed(buffer, offset, 1, "default boolean")?[0] != 0;
564            Some(Value::Boolean(value))
565        }
566        3 => {
567            let value = f64::from_le_bytes(
568                read_fixed(buffer, offset, 8, "default float")?
569                    .try_into()
570                    .unwrap(),
571            );
572            Some(Value::Float(value))
573        }
574        20 => {
575            let value = f32::from_le_bytes(
576                read_fixed(buffer, offset, 4, "default float32")?
577                    .try_into()
578                    .unwrap(),
579            );
580            Some(Value::Float32(value))
581        }
582        4 => {
583            let value = i64::from_le_bytes(
584                read_fixed(buffer, offset, 8, "default bigint")?
585                    .try_into()
586                    .unwrap(),
587            );
588            Some(Value::BigInt(value))
589        }
590        5 => {
591            let len = read_u32(buffer, offset, "default decimal length")? as usize;
592            let bytes = read_fixed(buffer, offset, len, "default decimal")?;
593            let text = String::from_utf8(bytes.to_vec()).map_err(|_| {
594                HematiteError::CorruptedData("Invalid UTF-8 in default decimal".to_string())
595            })?;
596            Some(Value::Decimal(DecimalValue::parse(&text).map_err(
597                |_| HematiteError::CorruptedData("Invalid default decimal".to_string()),
598            )?))
599        }
600        6 => {
601            let len = read_u32(buffer, offset, "default blob length")? as usize;
602            Some(Value::Blob(
603                read_fixed(buffer, offset, len, "default blob")?.to_vec(),
604            ))
605        }
606        16 => {
607            let value = i128::from_le_bytes(
608                read_fixed(buffer, offset, 16, "default int128")?
609                    .try_into()
610                    .unwrap(),
611            );
612            Some(Value::Int128(value))
613        }
614        17 => {
615            let value = u32::from_le_bytes(
616                read_fixed(buffer, offset, 4, "default uint")?
617                    .try_into()
618                    .unwrap(),
619            );
620            Some(Value::UInteger(value))
621        }
622        18 => {
623            let value = u64::from_le_bytes(
624                read_fixed(buffer, offset, 8, "default uint64")?
625                    .try_into()
626                    .unwrap(),
627            );
628            Some(Value::UBigInt(value))
629        }
630        19 => {
631            let value = u128::from_le_bytes(
632                read_fixed(buffer, offset, 16, "default uint128")?
633                    .try_into()
634                    .unwrap(),
635            );
636            Some(Value::UInt128(value))
637        }
638        7 => {
639            let days = i32::from_le_bytes(
640                read_fixed(buffer, offset, 4, "default date")?
641                    .try_into()
642                    .unwrap(),
643            );
644            Some(Value::Date(DateValue::from_days_since_epoch(days)))
645        }
646        11 => {
647            let seconds = u32::from_le_bytes(
648                read_fixed(buffer, offset, 4, "default time")?
649                    .try_into()
650                    .unwrap(),
651            );
652            Some(Value::Time(TimeValue::from_seconds_since_midnight(seconds)))
653        }
654        8 => {
655            let seconds = i64::from_le_bytes(
656                read_fixed(buffer, offset, 8, "default datetime")?
657                    .try_into()
658                    .unwrap(),
659            );
660            Some(Value::DateTime(DateTimeValue::from_seconds_since_epoch(
661                seconds,
662            )))
663        }
664        13 => {
665            let seconds = u32::from_le_bytes(
666                read_fixed(buffer, offset, 4, "default time with time zone seconds")?
667                    .try_into()
668                    .unwrap(),
669            );
670            let offset_minutes = i16::from_le_bytes(
671                read_fixed(buffer, offset, 2, "default time with time zone offset")?
672                    .try_into()
673                    .unwrap(),
674            );
675            Some(Value::TimeWithTimeZone(TimeWithTimeZoneValue::from_parts(
676                seconds,
677                offset_minutes,
678            )))
679        }
680        14 => {
681            let total_months = i32::from_le_bytes(
682                read_fixed(buffer, offset, 4, "default interval year to month")?
683                    .try_into()
684                    .unwrap(),
685            );
686            Some(Value::IntervalYearMonth(
687                crate::catalog::types::IntervalYearMonthValue::new(total_months),
688            ))
689        }
690        15 => {
691            let total_seconds = i64::from_le_bytes(
692                read_fixed(buffer, offset, 8, "default interval day to second")?
693                    .try_into()
694                    .unwrap(),
695            );
696            Some(Value::IntervalDaySecond(
697                crate::catalog::types::IntervalDaySecondValue::new(total_seconds),
698            ))
699        }
700        9 => Some(Value::Null),
701        255 => None,
702        _ => {
703            return Err(HematiteError::CorruptedData(
704                "Invalid default value type".to_string(),
705            ))
706        }
707    })
708}
709
710fn read_fixed<'a>(
711    buffer: &'a [u8],
712    offset: &mut usize,
713    len: usize,
714    label: &str,
715) -> Result<&'a [u8], HematiteError> {
716    if *offset + len > buffer.len() {
717        return Err(HematiteError::CorruptedData(format!("Invalid {label}")));
718    }
719    let slice = &buffer[*offset..*offset + len];
720    *offset += len;
721    Ok(slice)
722}