Skip to main content

clickhouse_native_client/column/
tuple.rs

1//! Tuple column implementation.
2//!
3//! A tuple stores a fixed number of heterogeneous columns (e.g.,
4//! `Tuple(UInt64, String, Float64)`). Each element column has the same
5//! number of rows.
6
7use super::{
8    Column,
9    ColumnRef,
10};
11use crate::{
12    types::Type,
13    Error,
14    Result,
15};
16use bytes::BytesMut;
17use std::sync::Arc;
18
19/// Column for tuple types (fixed number of heterogeneous columns).
20pub struct ColumnTuple {
21    type_: Type,
22    columns: Vec<ColumnRef>,
23}
24
25impl ColumnTuple {
26    /// Create a new tuple column with the given type and element columns.
27    pub fn new(type_: Type, columns: Vec<ColumnRef>) -> Self {
28        Self { type_, columns }
29    }
30
31    /// Get the number of columns in the tuple
32    pub fn column_count(&self) -> usize {
33        self.columns.len()
34    }
35
36    /// Get a reference to a specific column in the tuple
37    pub fn column_at(&self, index: usize) -> ColumnRef {
38        self.columns[index].clone()
39    }
40
41    /// Get mutable reference to a specific column (for appending)
42    pub fn column_at_mut(&mut self, index: usize) -> &mut dyn Column {
43        Arc::get_mut(&mut self.columns[index])
44            .expect("Cannot get mutable reference to shared column")
45    }
46
47    /// Get the number of elements (rows) - all columns should have the same
48    /// size
49    pub fn len(&self) -> usize {
50        if self.columns.is_empty() {
51            0
52        } else {
53            self.columns[0].size()
54        }
55    }
56
57    /// Check if the tuple column is empty
58    pub fn is_empty(&self) -> bool {
59        self.len() == 0
60    }
61}
62
63impl Column for ColumnTuple {
64    fn column_type(&self) -> &Type {
65        &self.type_
66    }
67
68    fn size(&self) -> usize {
69        self.len()
70    }
71
72    fn clear(&mut self) {
73        for col in &mut self.columns {
74            let col_mut = Arc::get_mut(col)
75                .expect("Cannot clear shared tuple column - column has multiple references");
76            col_mut.clear();
77        }
78    }
79
80    fn reserve(&mut self, new_cap: usize) {
81        for col in &mut self.columns {
82            let col_mut = Arc::get_mut(col)
83                .expect("Cannot reserve on shared tuple column - column has multiple references");
84            col_mut.reserve(new_cap);
85        }
86    }
87
88    fn append_column(&mut self, other: ColumnRef) -> Result<()> {
89        let other =
90            other.as_any().downcast_ref::<ColumnTuple>().ok_or_else(|| {
91                Error::TypeMismatch {
92                    expected: self.type_.name(),
93                    actual: other.column_type().name(),
94                }
95            })?;
96
97        if self.columns.len() != other.columns.len() {
98            return Err(Error::TypeMismatch {
99                expected: format!("Tuple with {} columns", self.columns.len()),
100                actual: format!("Tuple with {} columns", other.columns.len()),
101            });
102        }
103
104        for (i, col) in self.columns.iter_mut().enumerate() {
105            let col_mut = Arc::get_mut(col)
106                .ok_or_else(|| Error::Protocol(
107                    "Cannot append to shared tuple column - column has multiple references".to_string()
108                ))?;
109            col_mut.append_column(other.columns[i].clone())?;
110        }
111
112        Ok(())
113    }
114
115    fn load_prefix(&mut self, buffer: &mut &[u8], rows: usize) -> Result<()> {
116        // Call load_prefix on all tuple element columns
117        for col in &mut self.columns {
118            let col_mut = Arc::get_mut(col).ok_or_else(|| {
119                Error::Protocol(
120                    "Cannot load prefix for shared tuple column".to_string(),
121                )
122            })?;
123            col_mut.load_prefix(buffer, rows)?;
124        }
125        Ok(())
126    }
127
128    fn load_from_buffer(
129        &mut self,
130        buffer: &mut &[u8],
131        rows: usize,
132    ) -> Result<()> {
133        for col in &mut self.columns {
134            let col_mut = Arc::get_mut(col)
135                .ok_or_else(|| Error::Protocol(
136                    "Cannot load into shared tuple column - column has multiple references".to_string()
137                ))?;
138            col_mut.load_from_buffer(buffer, rows)?;
139        }
140        Ok(())
141    }
142
143    fn save_prefix(&self, buffer: &mut BytesMut) -> Result<()> {
144        // Call save_prefix on all tuple element columns
145        for col in &self.columns {
146            col.save_prefix(buffer)?;
147        }
148        Ok(())
149    }
150
151    fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
152        for col in &self.columns {
153            col.save_to_buffer(buffer)?;
154        }
155        Ok(())
156    }
157
158    fn clone_empty(&self) -> ColumnRef {
159        let empty_cols: Vec<ColumnRef> =
160            self.columns.iter().map(|c| c.clone_empty()).collect();
161        Arc::new(ColumnTuple::new(self.type_.clone(), empty_cols))
162    }
163
164    fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
165        if begin + len > self.size() {
166            return Err(Error::InvalidArgument(format!(
167                "Slice out of bounds: begin={}, len={}, size={}",
168                begin,
169                len,
170                self.size()
171            )));
172        }
173
174        let sliced_cols: Result<Vec<ColumnRef>> =
175            self.columns.iter().map(|col| col.slice(begin, len)).collect();
176
177        Ok(Arc::new(ColumnTuple::new(self.type_.clone(), sliced_cols?)))
178    }
179
180    fn as_any(&self) -> &dyn std::any::Any {
181        self
182    }
183
184    fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
185        self
186    }
187}
188
189#[cfg(test)]
190#[cfg_attr(coverage_nightly, coverage(off))]
191mod tests {
192    use super::*;
193    use crate::{
194        column::{
195            ColumnString,
196            ColumnUInt64,
197        },
198        types::Type,
199    };
200
201    #[test]
202    fn test_tuple_creation() {
203        let types = vec![Type::uint64(), Type::string()];
204        let tuple_type = Type::tuple(types);
205
206        let col1 = Arc::new(ColumnUInt64::new()) as ColumnRef;
207        let col2 = Arc::new(ColumnString::new(Type::string())) as ColumnRef;
208
209        let tuple = ColumnTuple::new(tuple_type, vec![col1, col2]);
210
211        assert_eq!(tuple.column_count(), 2);
212        assert_eq!(tuple.size(), 0);
213    }
214
215    #[test]
216    fn test_tuple_slice() {
217        let types = vec![Type::uint64(), Type::string()];
218        let tuple_type = Type::tuple(types);
219
220        let mut col1 = ColumnUInt64::new();
221        col1.append(1);
222        col1.append(2);
223        col1.append(3);
224
225        let mut col2 = ColumnString::new(Type::string());
226        col2.append("a");
227        col2.append("b");
228        col2.append("c");
229
230        let tuple = ColumnTuple::new(
231            tuple_type,
232            vec![Arc::new(col1) as ColumnRef, Arc::new(col2) as ColumnRef],
233        );
234
235        let sliced = tuple.slice(1, 2).unwrap();
236        assert_eq!(sliced.size(), 2);
237
238        let sliced_tuple =
239            sliced.as_any().downcast_ref::<ColumnTuple>().unwrap();
240        let col_ref = sliced_tuple.column_at(0);
241        let sliced_col1 =
242            col_ref.as_any().downcast_ref::<ColumnUInt64>().unwrap();
243        assert_eq!(sliced_col1.at(0), 2);
244        assert_eq!(sliced_col1.at(1), 3);
245    }
246}