voltdb_client_rust/
table.rs

1use std::collections::HashMap;
2use std::io::Read;
3
4use bigdecimal::BigDecimal;
5use bigdecimal::num_bigint::BigInt;
6use bytebuffer::ByteBuffer;
7use chrono::{DateTime, TimeZone, Utc};
8
9use crate::encode::*;
10use crate::response::ResponseStatus::Success;
11use crate::response::VoltResponseInfo;
12
13const MIN_INT8: i8 = -1 << 7;
14
15#[derive(Debug, Clone, PartialEq)]
16pub struct Column {
17    pub header_name: String,
18    pub header_type: i8,
19}
20
21#[derive(Debug)]
22#[allow(dead_code)]
23pub struct VoltTable {
24    info: VoltResponseInfo,
25    column_count: i16,
26    info_bytes: ByteBuffer,
27    column_info_bytes: ByteBuffer,
28    columns: Vec<Column>,
29    num_rows: i32,
30    rows: Vec<ByteBuffer>,
31    row_index: i32,
32    cn_to_ci: HashMap<String, i16>,
33    column_offsets: Vec<i32>,
34    header_size: i32,
35    total_size: i32,
36}
37
38impl Value for VoltTable {
39    fn get_write_length(&self) -> i32 {
40        self.total_size + 5
41    }
42
43    fn marshal(&self, bytebuffer: &mut ByteBuffer) {
44        bytebuffer.write_i8(TABLE);
45        bytebuffer.write_u32(self.total_size as u32);
46        bytebuffer.write_u32(self.header_size as u32);
47        bytebuffer.write_u8(128);
48        bytebuffer.write_bytes(self.column_info_bytes.as_bytes());
49        bytebuffer.write_u32(self.num_rows as u32);
50        self.rows.iter().for_each(|f| {
51            bytebuffer.write_u32(f.len() as u32);
52            bytebuffer.write_bytes(f.as_bytes());
53        });
54        println!("{}", bytebuffer.len())
55    }
56
57    fn marshal_in_table(&self, _bytebuffer: &mut ByteBuffer, _column_type: i8) {
58        //
59    }
60
61    fn to_value_string(&self) -> String {
62        "table".to_owned()
63    }
64
65    fn from_bytes(_bs: Vec<u8>, _column: &Column) -> Result<Self, VoltError>
66    where
67        Self: Sized,
68    {
69        todo!()
70    }
71}
72
73impl VoltTable {
74    /// COLUMN HEADER:
75    /// [int: column header size in bytes (non-inclusive)]
76    /// [byte: table status code]
77    /// [short: num columns]
78    /// [byte: column type] * num columns
79    /// [string: column name] * num columns
80    /// TABLE BODY DATA:
81    /// [int: num tuples]
82    /// [int: row size (non inclusive), blob row data] * num tuples
83    pub fn new_table(types: Vec<i8>, header: Vec<String>) -> Self {
84        let mut columns = Vec::with_capacity(types.len());
85        for (i, tp) in types.iter().enumerate() {
86            columns.push(Column {
87                header_name: header.get(i).unwrap().clone(),
88                header_type: *tp,
89            })
90        }
91        VoltTable::new_voltdb_table(columns)
92    }
93
94    pub fn new_voltdb_table(columns: Vec<Column>) -> Self {
95        let mut column_info_bytes = ByteBuffer::new();
96
97        let column_count = columns.len() as i16;
98        column_info_bytes.write_i16(column_count);
99        columns
100            .iter()
101            .for_each(|f| column_info_bytes.write_i8(f.header_type));
102        columns
103            .iter()
104            .for_each(|f| column_info_bytes.write_string(f.header_name.as_str()));
105        let header_size = (1 + column_info_bytes.len()) as i32;
106        let total_size = header_size + 8;
107        //
108        VoltTable {
109            info: Default::default(),
110            column_count,
111            info_bytes: Default::default(),
112            column_info_bytes,
113            columns,
114            num_rows: 0,
115            rows: vec![],
116            row_index: 0,
117            cn_to_ci: Default::default(),
118            column_offsets: vec![],
119            header_size,
120            total_size,
121        }
122    }
123
124    pub fn add_row(&mut self, row: Vec<&dyn Value>) -> Result<i16, VoltError> {
125        let mut bf: ByteBuffer = ByteBuffer::new();
126        self.columns.iter().enumerate().for_each(|(f, v)| {
127            let da = *row.get(f).unwrap();
128            da.marshal_in_table(&mut bf, v.header_type);
129        });
130        let len = bf.len();
131        self.rows.push(bf);
132        self.num_rows += 1;
133        self.total_size += (len + 4) as i32;
134        Ok(1)
135    }
136
137    pub fn get_column_index(&mut self, column: &str) -> Result<i16, VoltError> {
138        let idx = self
139            .cn_to_ci
140            .get(column.to_uppercase().as_str())
141            .ok_or(VoltError::NoValue(column.to_owned()))?;
142        Ok(*idx)
143    }
144
145    pub fn map_row<'a, T: From<&'a mut VoltTable>>(&'a mut self) -> T {
146        T::from(self)
147    }
148    pub fn take<T: Value>(&mut self, column: i16) -> Result<T, VoltError> {
149        let bs = self.get_bytes_by_idx(column)?;
150        let column = self.get_column_by_index(column)?;
151        T::from_bytes(bs, column)
152    }
153
154    pub fn fetch<T: Value>(&mut self, column: &str) -> Result<T, VoltError> {
155        let idx = self.get_column_index(column)?;
156        let bs = self.get_bytes_by_idx(idx)?;
157        let column = self.get_column_by_index(idx)?;
158        T::from_bytes(bs, column)
159    }
160
161    pub fn debug_row(&mut self) -> String {
162        let x: Vec<String> = self
163            .columns()
164            .into_iter()
165            .enumerate()
166            .map(|(idx, column)| {
167                format!(
168                    "{} {:?}",
169                    column.header_name,
170                    self.get_value_by_idx_type(idx as i16, column.header_type)
171                )
172            })
173            .collect();
174        x.join(" ")
175    }
176
177    pub fn has_error(&mut self) -> Option<VoltError> {
178        if self.info.get_status() == Success {
179            return Option::None;
180        }
181        Option::Some(VoltError::ExecuteFail(self.info.clone()))
182    }
183
184    pub fn advance_row(&mut self) -> bool {
185        self.advance_to_row(self.row_index + 1)
186    }
187
188    pub fn columns(&self) -> Vec<Column> {
189        self.columns.clone()
190    }
191
192    pub fn col_length(r: &mut ByteBuffer, offset: i32, col_type: i8) -> Result<i32, VoltError> {
193        match col_type {
194            crate::encode::ARRAY_COLUMN => Err(VoltError::InvalidColumnType(col_type)),
195            crate::encode::NULL_COLUMN => Ok(0),
196            crate::encode::TINYINT_COLUMN => Ok(1),
197            //SHORT_COLUMN
198            crate::encode::SHORT_COLUMN => Ok(2),
199
200            crate::encode::INT_COLUMN => Ok(4),
201            crate::encode::LONG_COLUMN => Ok(8),
202            crate::encode::FLOAT_COLUMN => Ok(8),
203            crate::encode::STRING_COLUMN => {
204                r.set_rpos(offset as usize);
205                let str_len = r.read_i32()?;
206                if str_len == -1 {
207                    // encoding for null string.
208                    return Ok(4);
209                }
210                Ok(4 + str_len)
211            }
212            crate::encode::TIMESTAMP_COLUMN => Ok(8),
213            crate::encode::DECIMAL_COLUMN => Ok(16),
214            crate::encode::VAR_BIN_COLUMN => {
215                r.set_rpos(offset as usize);
216                let str_len = r.read_i32()?;
217                if str_len == -1 {
218                    // encoding for null string.
219                    return Ok(4);
220                }
221                Ok(4 + str_len) //   4 + str_len;
222            }
223            _ => Err(VoltError::InvalidColumnType(col_type)),
224        }
225    }
226
227    fn calc_offsets(&mut self) -> Result<(), VoltError> {
228        let mut offsets = Vec::with_capacity((self.column_count + 1) as usize);
229        let reader = self
230            .rows
231            .get_mut(self.row_index as usize)
232            .ok_or(VoltError::NoValue(self.row_index.to_string()))?;
233        offsets.push(0);
234        let mut offset = 0;
235        for i in 0..self.column_count {
236            let column = self
237                .columns
238                .get(i as usize)
239                .ok_or(VoltError::NoValue(i.to_string()))?;
240            let length = crate::table::VoltTable::col_length(reader, offset, column.header_type)?;
241            offset += length;
242            offsets.push(offset);
243        }
244        reader.set_rpos(0);
245        self.column_offsets = offsets;
246        Ok(())
247    }
248
249    pub fn get_value_by_column(
250        &mut self,
251        column: &str,
252    ) -> Result<Option<Box<dyn Value>>, VoltError> {
253        let idx = self.get_column_index(column)?;
254        self.get_value_by_idx(idx)
255    }
256
257    pub(crate) fn get_value_by_idx_column(
258        column: &Column,
259        bs: Vec<u8>,
260    ) -> Result<Option<Box<dyn Value>>, VoltError> {
261        match column.header_type {
262            crate::encode::TINYINT_COLUMN => {
263                let res = i8::from_bytes(bs, column)?;
264                match res {
265                    i8::MIN => Ok(None),
266                    _ => Ok(Some(Box::new(res))),
267                }
268            }
269            crate::encode::SHORT_COLUMN => {
270                let res = i16::from_bytes(bs, column)?;
271                match res {
272                    i16::MIN => Ok(None),
273                    _ => Ok(Some(Box::new(res))),
274                }
275            }
276            crate::encode::INT_COLUMN => {
277                let res = i32::from_bytes(bs, column)?;
278                match res {
279                    i32::MIN => Ok(None),
280                    _ => Ok(Some(Box::new(res))),
281                }
282            }
283
284            crate::encode::LONG_COLUMN => {
285                let res = i64::from_bytes(bs, column)?;
286                match res {
287                    i64::MIN => Ok(None),
288                    _ => Ok(Some(Box::new(res))),
289                }
290            }
291
292            crate::encode::FLOAT_COLUMN => {
293                if bs == NULL_FLOAT_VALUE {
294                    return Ok(None);
295                }
296                let res = f64::from_bytes(bs, column)?;
297                Ok(Some(Box::new(res)))
298            }
299
300            crate::encode::STRING_COLUMN => {
301                if bs.len() == 4 {
302                    return Ok(None);
303                }
304                let res = String::from_bytes(bs, column)?;
305                Ok(Some(Box::new(res)))
306            }
307
308            crate::encode::TIMESTAMP_COLUMN => {
309                if bs == NULL_TIMESTAMP {
310                    return Ok(None);
311                }
312                let res = DateTime::from_bytes(bs, column)?;
313                Ok(Some(Box::new(res)))
314            }
315            crate::encode::DECIMAL_COLUMN => {
316                if bs == NULL_DECIMAL {
317                    return Ok(None);
318                }
319                let res = DateTime::from_bytes(bs, column)?;
320                Ok(Some(Box::new(res)))
321            }
322            crate::encode::VAR_BIN_COLUMN => {
323                if bs.len() == 4 {
324                    return Ok(None);
325                }
326                let res = Vec::from_bytes(bs, column)?;
327                Ok(Some(Box::new(res)))
328            }
329            _ => {
330                let res = i16::from_bytes(bs, column)?;
331                // match res {
332                //     Some(v) => {
333                Ok(Some(Box::new(res)))
334                //     }
335                // }
336            }
337        }
338    }
339
340    pub(crate) fn get_value_by_idx_type(
341        &mut self,
342        column: i16,
343        _tp: i8,
344    ) -> Result<Option<Box<dyn Value>>, VoltError> {
345        let bs = self.get_bytes_by_idx(column)?;
346        let column = self.get_column_by_index(column)?;
347        crate::table::VoltTable::get_value_by_idx_column(column, bs)
348    }
349
350    pub fn get_value_by_idx(&mut self, column: i16) -> Result<Option<Box<dyn Value>>, VoltError> {
351        let tp = self.get_column_type_by_idx(column)?;
352        self.get_value_by_idx_type(column, tp)
353    }
354
355    pub fn get_bool_by_column(&mut self, column: &str) -> Result<Option<bool>, VoltError> {
356        let idx = self.get_column_index(column)?;
357        self.get_bool_by_idx(idx)
358    }
359
360    pub fn get_bool_by_idx(&mut self, column: i16) -> Result<Option<bool>, VoltError> {
361        let bs = self.get_bytes_by_idx(column)?;
362        if bs == NULL_BIT_VALUE {
363            return Ok(Option::None);
364        }
365        if bs[0] == 0 {
366            return Ok(Some(false));
367        }
368        Ok(Some(true))
369    }
370
371    pub fn get_bytes_op_by_column(&mut self, column: &str) -> Result<Option<Vec<u8>>, VoltError> {
372        let idx = self.get_column_index(column)?;
373        self.get_bytes_op_by_idx(idx)
374    }
375
376    pub fn get_bytes_op_by_idx(&mut self, column: i16) -> Result<Option<Vec<u8>>, VoltError> {
377        let mut bs = self.get_bytes_by_idx(column)?;
378        if bs == NULL_VARCHAR {
379            return Ok(Option::None);
380        }
381        bs.drain(0..4);
382        Ok(Option::Some(bs))
383    }
384
385    pub fn get_bytes_by_column(&mut self, column: &str) -> Result<Vec<u8>, VoltError> {
386        let idx = self.get_column_index(column)?;
387        self.get_bytes_by_idx(idx)
388    }
389
390    pub fn get_decimal_by_column(&mut self, column: &str) -> Result<Option<BigDecimal>, VoltError> {
391        let idx = self.get_column_index(column)?;
392        self.get_decimal_by_idx(idx)
393    }
394
395    pub fn get_decimal_by_idx(&mut self, column: i16) -> Result<Option<BigDecimal>, VoltError> {
396        let bs = self.get_bytes_by_idx(column)?;
397        if bs == NULL_DECIMAL {
398            return Ok(Option::None);
399        }
400        let int = BigInt::from_signed_bytes_be(&bs);
401        let decimal = BigDecimal::new(int, 12);
402        Ok(Some(decimal))
403    }
404
405    pub fn get_string_by_column(&mut self, column: &str) -> Result<Option<String>, VoltError> {
406        let idx = self.get_column_index(column)?;
407        self.get_string_by_idx(idx)
408    }
409
410    pub fn get_column_by_index(&self, column: i16) -> Result<&Column, VoltError> {
411        let res = self.columns.get(column as usize);
412        match res {
413            None => Err(VoltError::NoValue(self.row_index.to_string())),
414            Some(e) => Ok(e),
415        }
416    }
417
418    pub fn get_string_by_idx(&mut self, column: i16) -> Result<Option<String>, VoltError> {
419        let table_column = self.get_column_by_index(column)?; // will change type and name into one map
420        match table_column.header_type {
421            STRING_COLUMN => {
422                let bs = self.get_bytes_by_idx(column)?;
423                if bs == NULL_VARCHAR {
424                    return Ok(Option::None);
425                }
426                let mut buffer = ByteBuffer::from_bytes(&bs);
427                Ok(Option::Some(buffer.read_string()?))
428            }
429            _ => {
430                let res = self.get_value_by_idx_type(column, table_column.header_type)?;
431                match res {
432                    Some(v) => Ok(Option::Some(v.to_value_string())),
433                    None => Ok(Option::None),
434                }
435            }
436        }
437    }
438
439    pub fn get_time_by_column(&mut self, column: &str) -> Result<Option<DateTime<Utc>>, VoltError> {
440        let idx = self.get_column_index(column)?;
441        self.get_time_by_idx(idx)
442    }
443
444    pub fn get_time_by_idx(&mut self, column: i16) -> Result<Option<DateTime<Utc>>, VoltError> {
445        let bs = self.get_bytes_by_idx(column)?;
446        if bs == NULL_TIMESTAMP {
447            return Ok(Option::None);
448        }
449        let mut buffer = ByteBuffer::from_bytes(&bs);
450        let time = buffer.read_i64()?;
451        Ok(Option::Some(Utc.timestamp_millis_opt(time / 1000).unwrap()))
452    }
453
454    pub fn get_bytes_by_idx(&mut self, column_index: i16) -> Result<Vec<u8>, VoltError> {
455        if self.column_offsets.is_empty() {
456            self.calc_offsets()?;
457        }
458        let buffer = self
459            .rows
460            .get_mut(self.row_index as usize)
461            .ok_or(VoltError::NoValue(self.row_index.to_string()))?;
462        let start = self
463            .column_offsets
464            .get(column_index as usize)
465            .ok_or(VoltError::NoValue(column_index.to_string()))?;
466        let end = self
467            .column_offsets
468            .get(column_index as usize + 1)
469            .ok_or(VoltError::NoValue(column_index.to_string()))?;
470        buffer.set_rpos(*start as usize);
471        let rsize = (*end - *start) as usize;
472        Ok(buffer.read_bytes(rsize)?)
473    }
474
475    pub fn advance_to_row(&mut self, row_index: i32) -> bool {
476        if row_index >= self.num_rows {
477            return false;
478        }
479        self.column_offsets = vec![];
480        self.row_index = row_index;
481        true
482    }
483
484    fn get_column_type_by_idx(&self, column_idx: i16) -> Result<i8, VoltError> {
485        if let Some(v) = self.columns.get(column_idx as usize) {
486            return Ok(v.header_type);
487        }
488        Err(VoltError::NoValue(column_idx.to_string()))
489    }
490}
491
492pub fn new_volt_table(
493    bytebuffer: &mut ByteBuffer,
494    info: VoltResponseInfo,
495) -> Result<VoltTable, VoltError> {
496    if info.get_status() != Success {
497        return Ok(VoltTable {
498            info,
499            column_count: -1,
500            info_bytes: Default::default(),
501            column_info_bytes: Default::default(),
502            columns: vec![],
503            num_rows: -1,
504            rows: vec![],
505            row_index: -1,
506            cn_to_ci: Default::default(),
507            column_offsets: vec![],
508            header_size: 0,
509            total_size: 0,
510        });
511    }
512
513    let column_counts = decode_table_common(bytebuffer)?;
514    let mut column_types: Vec<i8> = Vec::with_capacity(column_counts as usize);
515    let mut column_info_bytes = ByteBuffer::new();
516    for _ in 0..column_counts {
517        let tp = bytebuffer.read_i8()?;
518        column_types.push(tp);
519        column_info_bytes.write_i8(tp);
520    }
521    let mut columns: Vec<Column> = Vec::with_capacity(column_counts as usize);
522    let mut cn_to_ci = HashMap::with_capacity(column_counts as usize);
523    for i in 0..column_counts {
524        let name = bytebuffer.read_string()?;
525        columns.push(Column {
526            header_name: name.clone(),
527            header_type: *(column_types.get(i as usize).unwrap()),
528        });
529        column_info_bytes.write_string(name.as_str());
530        cn_to_ci.insert(name, i);
531    }
532    let row_count = bytebuffer.read_i32()?;
533    let mut rows: Vec<ByteBuffer> = Vec::with_capacity(column_counts as usize);
534    for _ in 0..row_count {
535        let row_len = bytebuffer.read_i32()?;
536        let mut build = vec![0; row_len as usize];
537        bytebuffer.read_exact(&mut build)?;
538        let row = ByteBuffer::from_bytes(&build);
539        rows.push(row);
540    }
541    Ok(VoltTable {
542        info,
543        column_count: column_counts,
544        info_bytes: Default::default(),
545        column_info_bytes,
546        columns,
547        num_rows: row_count,
548        rows,
549        row_index: -1,
550        cn_to_ci,
551        column_offsets: vec![],
552        header_size: 0,
553        total_size: 0,
554    })
555}
556
557fn decode_table_common(bytebuffer: &mut ByteBuffer) -> Result<i16, VoltError> {
558    let _ttl_length = bytebuffer.read_i32();
559    let _meta_length = bytebuffer.read_i32();
560    let status_code = bytebuffer.read_i8()?;
561    if status_code != 0 && status_code != MIN_INT8 {
562        // copy from golang , but why ?
563        return Err(VoltError::BadReturnStatusOnTable(status_code));
564    }
565    Ok(bytebuffer.read_i16()?)
566}
567
568#[cfg(test)]
569mod tests {
570    use crate::encode::{
571        DECIMAL_COLUMN, FLOAT_COLUMN, INT_COLUMN, LONG_COLUMN, SHORT_COLUMN, STRING_COLUMN,
572        TIMESTAMP_COLUMN, TINYINT_COLUMN, VAR_BIN_COLUMN,
573    };
574    use crate::volt_param;
575
576    use super::*;
577
578    fn template(tps: Vec<&str>, none: &str) {
579        for tp in tps {
580            let shader = r#"
581                pub fn get_${type}_by_column (&mut self, column: &str) -> Result<Option<${type}>, VoltError> {
582                    let idx = self.get_column_index(column)?;
583                    return Ok(self.get_${type}_by_idx>](idx)?);
584                }
585
586                pub fn get_${type}_by_idx (&mut self, column: i16) -> Result<Option<${type}>, VoltError> {
587                    let bs = self.get_bytes_by_idx(column)?;
588                    if bs == ${none} {
589                       return Ok(Option::None);
590                    }
591                    let mut buffer = ByteBuffer::from_bytes(&bs);
592                    let value = buffer.read_${type}()?;
593                    return Ok(Some(value));
594                }
595"#;
596            println!("{}", shader.replace("${type}", tp).replace("${none}", none));
597        }
598    }
599
600    #[test]
601    fn test_encode_table() -> Result<(), VoltError> {
602        let bs = vec![
603            21, 0, 0, 0, 86, 0, 0, 0, 49, 128, 0, 4, 6, 6, 3, 6, 0, 0, 0, 2, 73, 68, 0, 0, 0, 7,
604            86, 69, 82, 83, 73, 79, 78, 0, 0, 0, 7, 68, 69, 76, 69, 84, 69, 68, 0, 0, 0, 10, 67,
605            82, 69, 65, 84, 69, 68, 95, 66, 89, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 1, 0,
606            0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
607        ];
608        let header = vec!["ID", "VERSION", "DELETED", "CREATED_BY"];
609        let tp = vec![LONG_COLUMN, LONG_COLUMN, TINYINT_COLUMN, LONG_COLUMN];
610        let header: Vec<String> = header
611            .iter()
612            .map(|f| f.to_string())
613            .collect::<Vec<String>>();
614        let mut x = VoltTable::new_table(tp, header);
615        let data = volt_param! {1 as i64, 1 as i64, false,  1 as i64 };
616        x.add_row(data)?;
617        let mut bf = ByteBuffer::new();
618        x.marshal(&mut bf);
619        assert_eq!(bs, bf.into_vec());
620        Ok({})
621    }
622
623    #[test]
624    fn test_table() {
625        let bs = vec![
626            0 as u8, 1, 128, 0, 0, 0, 3, 0, 1, 0, 0, 0, 133, 0, 0, 0, 66, 128, 0, 9, 3, 4, 5, 6, 8,
627            22, 9, 25, 11, 0, 0, 0, 2, 84, 49, 0, 0, 0, 2, 84, 50, 0, 0, 0, 2, 84, 51, 0, 0, 0, 2,
628            84, 52, 0, 0, 0, 2, 84, 53, 0, 0, 0, 2, 84, 54, 0, 0, 0, 2, 84, 55, 0, 0, 0, 2, 84, 56,
629            0, 0, 0, 2, 84, 57, 0, 0, 0, 1, 0, 0, 0, 55, 128, 128, 0, 128, 0, 0, 0, 128, 0, 0, 0,
630            0, 0, 0, 0, 255, 239, 255, 255, 255, 255, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
631            0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 128, 0, 0, 0, 0, 0, 0, 0,
632        ];
633        let mut b = ByteBuffer::from_bytes(&bs);
634        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
635        let mut table = new_volt_table(&mut b, info).unwrap();
636        table.advance_row();
637
638        let header = table.columns();
639        assert_eq!(header.len(), 9);
640        assert_eq!(
641            *header.get(0).unwrap(),
642            Column {
643                header_name: "T1".to_owned(),
644                header_type: TINYINT_COLUMN,
645            }
646        );
647        assert_eq!(
648            *header.get(1).unwrap(),
649            Column {
650                header_name: "T2".to_owned(),
651                header_type: SHORT_COLUMN,
652            }
653        );
654        assert_eq!(
655            *header.get(2).unwrap(),
656            Column {
657                header_name: "T3".to_owned(),
658                header_type: INT_COLUMN,
659            }
660        );
661        assert_eq!(
662            *header.get(3).unwrap(),
663            Column {
664                header_name: "T4".to_owned(),
665                header_type: LONG_COLUMN,
666            }
667        );
668        assert_eq!(
669            *header.get(4).unwrap(),
670            Column {
671                header_name: "T5".to_owned(),
672                header_type: FLOAT_COLUMN,
673            }
674        );
675        assert_eq!(
676            *header.get(5).unwrap(),
677            Column {
678                header_name: "T6".to_owned(),
679                header_type: DECIMAL_COLUMN,
680            }
681        );
682        assert_eq!(
683            *header.get(6).unwrap(),
684            Column {
685                header_name: "T7".to_owned(),
686                header_type: STRING_COLUMN,
687            }
688        );
689        assert_eq!(
690            *header.get(7).unwrap(),
691            Column {
692                header_name: "T8".to_owned(),
693                header_type: VAR_BIN_COLUMN,
694            }
695        );
696        assert_eq!(
697            *header.get(8).unwrap(),
698            Column {
699                header_name: "T9".to_owned(),
700                header_type: TIMESTAMP_COLUMN,
701            }
702        );
703
704        let i1 = table.get_bool_by_idx(0).unwrap();
705        let i2 = table.get_i16_by_idx(1).unwrap();
706        let i3 = table.get_i32_by_idx(2).unwrap();
707        let i4 = table.get_i64_by_idx(3).unwrap();
708        let i5 = table.get_f64_by_idx(4).unwrap();
709        let i6 = table.get_decimal_by_idx(5).unwrap();
710        let i7 = table.get_string_by_idx(6).unwrap();
711        let i8 = table.get_bytes_op_by_idx(7).unwrap();
712        let i9 = table.get_time_by_idx(8).unwrap();
713
714        assert_eq!(i1, None);
715        assert_eq!(i2, None);
716        assert_eq!(i3, None);
717        assert_eq!(i4, None);
718        assert_eq!(i5, None);
719        assert_eq!(i6, None);
720        assert_eq!(i7, None);
721        assert_eq!(i8, None);
722        assert_eq!(i9, None);
723        let offsets = vec![0, 1, 3, 7, 15, 23, 39, 43, 47, 55];
724        assert_eq!(offsets, table.column_offsets);
725    }
726
727    #[test]
728    fn test_big_decimal() {
729        template(vec!["i8", "u8"], "NULL_BYTE_VALUE");
730        template(vec!["i16", "u16"], "NULL_SHORT_VALUE");
731        template(vec!["i32", "u32"], "NULL_INT_VALUE");
732        template(vec!["i64", "u64"], "NULL_LONG_VALUE");
733        template(vec!["f32", "f64"], "NULL_FLOAT_VALUE");
734    }
735
736    // Helper to create a test table with actual non-null values
737    fn get_value_test_bytes() -> Vec<u8> {
738        // Row data: 1 + 2 + 4 + 8 + 8 + 16 + 9 + 7 + 8 = 63 bytes
739        vec![
740            0, 1, 128, 0, 0, 0, 3, 0, 1, 0, 0, 0, 133, 0, 0, 0, 66, 128, 0, 9, 3, 4, 5, 6, 8, 22,
741            9, 25, 11, 0, 0, 0, 2, 84, 49, // T1
742            0, 0, 0, 2, 84, 50, // T2
743            0, 0, 0, 2, 84, 51, // T3
744            0, 0, 0, 2, 84, 52, // T4
745            0, 0, 0, 2, 84, 53, // T5
746            0, 0, 0, 2, 84, 54, // T6
747            0, 0, 0, 2, 84, 55, // T7
748            0, 0, 0, 2, 84, 56, // T8
749            0, 0, 0, 2, 84, 57, // T9
750            0, 0, 0, 1, // 1 row
751            0, 0, 0, 63, // row length = 63 bytes
752            1,  // T1: bool = true (1 byte)
753            0, 100, // T2: short = 100 (2 bytes)
754            0, 0, 1, 0, // T3: int = 256 (4 bytes)
755            0, 0, 0, 0, 0, 0, 0, 42, // T4: long = 42 (8 bytes)
756            64, 9, 33, 251, 84, 68, 45, 24, // T5: f64 ~ 3.14159 (8 bytes)
757            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 212, 165, 16, 0, // T6: decimal (16 bytes)
758            0, 0, 0, 5, 104, 101, 108, 108, 111, // T7: string "hello" (4 + 5 = 9 bytes)
759            0, 0, 0, 3, 1, 2, 3, // T8: varbinary [1,2,3] (4 + 3 = 7 bytes)
760            0, 0, 0, 0, 0, 15, 66, 64, // T9: timestamp (8 bytes)
761        ]
762    }
763
764    #[test]
765    fn test_get_bool_by_column() {
766        let bs = get_value_test_bytes();
767        let mut b = ByteBuffer::from_bytes(&bs);
768        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
769        let mut table = new_volt_table(&mut b, info).unwrap();
770        table.advance_row();
771
772        let result = table.get_bool_by_column("T1").unwrap();
773        assert_eq!(result, Some(true));
774    }
775
776    #[test]
777    fn test_get_string_by_column() {
778        let bs = get_value_test_bytes();
779        let mut b = ByteBuffer::from_bytes(&bs);
780        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
781        let mut table = new_volt_table(&mut b, info).unwrap();
782        table.advance_row();
783
784        let result = table.get_string_by_column("T7").unwrap();
785        assert_eq!(result, Some("hello".to_string()));
786    }
787
788    #[test]
789    fn test_get_string_by_idx_from_int() {
790        let bs = get_value_test_bytes();
791        let mut b = ByteBuffer::from_bytes(&bs);
792        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
793        let mut table = new_volt_table(&mut b, info).unwrap();
794        table.advance_row();
795
796        // Get string representation of integer column
797        let result = table.get_string_by_idx(2).unwrap();
798        assert_eq!(result, Some("256".to_string()));
799    }
800
801    #[test]
802    fn test_get_bytes_op_by_column() {
803        let bs = get_value_test_bytes();
804        let mut b = ByteBuffer::from_bytes(&bs);
805        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
806        let mut table = new_volt_table(&mut b, info).unwrap();
807        table.advance_row();
808
809        let result = table.get_bytes_op_by_column("T8").unwrap();
810        assert_eq!(result, Some(vec![1, 2, 3]));
811    }
812
813    #[test]
814    fn test_get_decimal_by_column() {
815        let bs = get_value_test_bytes();
816        let mut b = ByteBuffer::from_bytes(&bs);
817        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
818        let mut table = new_volt_table(&mut b, info).unwrap();
819        table.advance_row();
820
821        let result = table.get_decimal_by_column("T6").unwrap();
822        assert!(result.is_some());
823    }
824
825    #[test]
826    fn test_get_time_by_column() {
827        let bs = get_value_test_bytes();
828        let mut b = ByteBuffer::from_bytes(&bs);
829        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
830        let mut table = new_volt_table(&mut b, info).unwrap();
831        table.advance_row();
832
833        let result = table.get_time_by_column("T9").unwrap();
834        assert!(result.is_some());
835    }
836
837    #[test]
838    fn test_get_bytes_by_column() {
839        let bs = get_value_test_bytes();
840        let mut b = ByteBuffer::from_bytes(&bs);
841        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
842        let mut table = new_volt_table(&mut b, info).unwrap();
843        table.advance_row();
844
845        let result = table.get_bytes_by_column("T1").unwrap();
846        assert_eq!(result, vec![1]); // bool true = 1
847    }
848
849    #[test]
850    fn test_get_value_by_idx_tinyint() {
851        let bs = get_value_test_bytes();
852        let mut b = ByteBuffer::from_bytes(&bs);
853        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
854        let mut table = new_volt_table(&mut b, info).unwrap();
855        table.advance_row();
856
857        let result = table.get_value_by_idx(0).unwrap();
858        assert!(result.is_some());
859    }
860
861    #[test]
862    fn test_get_value_by_idx_short() {
863        let bs = get_value_test_bytes();
864        let mut b = ByteBuffer::from_bytes(&bs);
865        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
866        let mut table = new_volt_table(&mut b, info).unwrap();
867        table.advance_row();
868
869        let result = table.get_value_by_idx(1).unwrap();
870        assert!(result.is_some());
871    }
872
873    #[test]
874    fn test_get_value_by_idx_int() {
875        let bs = get_value_test_bytes();
876        let mut b = ByteBuffer::from_bytes(&bs);
877        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
878        let mut table = new_volt_table(&mut b, info).unwrap();
879        table.advance_row();
880
881        let result = table.get_value_by_idx(2).unwrap();
882        assert!(result.is_some());
883    }
884
885    #[test]
886    fn test_get_value_by_idx_long() {
887        let bs = get_value_test_bytes();
888        let mut b = ByteBuffer::from_bytes(&bs);
889        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
890        let mut table = new_volt_table(&mut b, info).unwrap();
891        table.advance_row();
892
893        let result = table.get_value_by_idx(3).unwrap();
894        assert!(result.is_some());
895    }
896
897    #[test]
898    fn test_get_value_by_idx_float() {
899        let bs = get_value_test_bytes();
900        let mut b = ByteBuffer::from_bytes(&bs);
901        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
902        let mut table = new_volt_table(&mut b, info).unwrap();
903        table.advance_row();
904
905        let result = table.get_value_by_idx(4).unwrap();
906        assert!(result.is_some());
907    }
908
909    #[test]
910    fn test_get_value_by_idx_string() {
911        let bs = get_value_test_bytes();
912        let mut b = ByteBuffer::from_bytes(&bs);
913        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
914        let mut table = new_volt_table(&mut b, info).unwrap();
915        table.advance_row();
916
917        let result = table.get_value_by_idx(6).unwrap();
918        assert!(result.is_some());
919    }
920
921    #[test]
922    fn test_get_value_by_idx_timestamp() {
923        let bs = get_value_test_bytes();
924        let mut b = ByteBuffer::from_bytes(&bs);
925        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
926        let mut table = new_volt_table(&mut b, info).unwrap();
927        table.advance_row();
928
929        let result = table.get_value_by_idx(8).unwrap();
930        assert!(result.is_some());
931    }
932
933    #[test]
934    fn test_advance_to_row() {
935        let bs = get_value_test_bytes();
936        let mut b = ByteBuffer::from_bytes(&bs);
937        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
938        let mut table = new_volt_table(&mut b, info).unwrap();
939
940        // Start at row -1
941        assert!(table.advance_row()); // Move to row 0
942        assert!(!table.advance_row()); // No more rows
943
944        // Reset to row 0
945        assert!(table.advance_to_row(0));
946        assert!(!table.advance_to_row(1)); // Only 1 row, so row 1 doesn't exist
947    }
948
949    #[test]
950    fn test_fetch() {
951        let bs = get_value_test_bytes();
952        let mut b = ByteBuffer::from_bytes(&bs);
953        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
954        let mut table = new_volt_table(&mut b, info).unwrap();
955        table.advance_row();
956
957        let result: i32 = table.fetch("T3").unwrap();
958        assert_eq!(result, 256);
959    }
960
961    #[test]
962    fn test_take() {
963        let bs = get_value_test_bytes();
964        let mut b = ByteBuffer::from_bytes(&bs);
965        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
966        let mut table = new_volt_table(&mut b, info).unwrap();
967        table.advance_row();
968
969        let result: i32 = table.take(2).unwrap();
970        assert_eq!(result, 256);
971    }
972
973    #[test]
974    fn test_columns() {
975        let bs = get_value_test_bytes();
976        let mut b = ByteBuffer::from_bytes(&bs);
977        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
978        let table = new_volt_table(&mut b, info).unwrap();
979
980        let columns = table.columns();
981        assert_eq!(columns.len(), 9);
982        assert_eq!(columns[0].header_name, "T1");
983        assert_eq!(columns[0].header_type, TINYINT_COLUMN);
984    }
985
986    #[test]
987    fn test_columns_count() {
988        let bs = get_value_test_bytes();
989        let mut b = ByteBuffer::from_bytes(&bs);
990        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
991        let table = new_volt_table(&mut b, info).unwrap();
992
993        // Check column count via columns() method
994        assert_eq!(table.columns().len(), 9);
995    }
996
997    #[test]
998    fn test_get_column_by_index() {
999        let bs = get_value_test_bytes();
1000        let mut b = ByteBuffer::from_bytes(&bs);
1001        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
1002        let table = new_volt_table(&mut b, info).unwrap();
1003
1004        let col = table.get_column_by_index(0).unwrap();
1005        assert_eq!(col.header_name, "T1");
1006        assert_eq!(col.header_type, TINYINT_COLUMN);
1007
1008        // Test non-existent column
1009        let err = table.get_column_by_index(100);
1010        assert!(err.is_err());
1011    }
1012
1013    #[test]
1014    fn test_get_column_index_not_found() {
1015        let bs = get_value_test_bytes();
1016        let mut b = ByteBuffer::from_bytes(&bs);
1017        let info = VoltResponseInfo::new(&mut b, 1).unwrap();
1018        let mut table = new_volt_table(&mut b, info).unwrap();
1019        table.advance_row();
1020
1021        let result = table.get_column_index("NONEXISTENT");
1022        assert!(result.is_err());
1023    }
1024
1025    #[test]
1026    fn test_volt_table_to_value_string() {
1027        let header = vec!["ID".to_string()];
1028        let tp = vec![LONG_COLUMN];
1029        let table = VoltTable::new_table(tp, header);
1030
1031        assert_eq!(table.to_value_string(), "table");
1032    }
1033
1034    #[test]
1035    fn test_volt_table_get_write_length() {
1036        let header = vec!["ID".to_string()];
1037        let tp = vec![LONG_COLUMN];
1038        let table = VoltTable::new_table(tp, header);
1039
1040        // header_size = 1 + column_info_bytes.len()
1041        // column_info_bytes: 2 bytes for count + 1 byte for type + 4 + 2 bytes for string
1042        // total_size = header_size + 8
1043        // get_write_length = total_size + 5
1044        assert!(table.get_write_length() > 0);
1045    }
1046
1047    #[test]
1048    fn test_new_voltdb_table() {
1049        let columns = vec![
1050            Column {
1051                header_name: "COL1".to_string(),
1052                header_type: INT_COLUMN,
1053            },
1054            Column {
1055                header_name: "COL2".to_string(),
1056                header_type: STRING_COLUMN,
1057            },
1058        ];
1059        let table = VoltTable::new_voltdb_table(columns);
1060
1061        assert_eq!(table.columns().len(), 2);
1062    }
1063}