clickhouse_native_client/column/
uuid.rs1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct Uuid {
22 pub high: u64,
24 pub low: u64,
26}
27
28impl Uuid {
29 pub fn new(high: u64, low: u64) -> Self {
31 Self { high, low }
32 }
33
34 pub fn parse(s: &str) -> Result<Self> {
41 let s = s.replace("-", "");
42 if s.len() != 32 {
43 return Err(Error::Protocol(format!(
44 "Invalid UUID format: {}",
45 s
46 )));
47 }
48
49 let high = u64::from_str_radix(&s[0..16], 16).map_err(|e| {
50 Error::Protocol(format!("Invalid UUID hex: {}", e))
51 })?;
52 let low = u64::from_str_radix(&s[16..32], 16).map_err(|e| {
53 Error::Protocol(format!("Invalid UUID hex: {}", e))
54 })?;
55
56 Ok(Self { high, low })
57 }
58
59 pub fn as_string(&self) -> String {
61 format!(
62 "{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
63 (self.high >> 32) as u32,
64 ((self.high >> 16) & 0xFFFF) as u16,
65 (self.high & 0xFFFF) as u16,
66 (self.low >> 48) as u16,
67 self.low & 0xFFFFFFFFFFFF,
68 )
69 }
70}
71
72impl std::fmt::Display for Uuid {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 write!(f, "{}", self.as_string())
75 }
76}
77
78pub struct ColumnUuid {
80 type_: Type,
81 data: Vec<Uuid>,
82}
83
84impl ColumnUuid {
85 pub fn new(type_: Type) -> Self {
87 Self { type_, data: Vec::new() }
88 }
89
90 pub fn with_data(mut self, data: Vec<Uuid>) -> Self {
92 self.data = data;
93 self
94 }
95
96 pub fn append(&mut self, value: Uuid) {
98 self.data.push(value);
99 }
100
101 pub fn append_from_string(&mut self, s: &str) -> Result<()> {
103 let uuid = Uuid::parse(s)?;
104 self.data.push(uuid);
105 Ok(())
106 }
107
108 pub fn at(&self, index: usize) -> Uuid {
110 self.data[index]
111 }
112
113 pub fn as_string(&self, index: usize) -> String {
115 self.data[index].as_string()
116 }
117
118 pub fn len(&self) -> usize {
120 self.data.len()
121 }
122
123 pub fn is_empty(&self) -> bool {
125 self.data.is_empty()
126 }
127}
128
129impl Column for ColumnUuid {
130 fn column_type(&self) -> &Type {
131 &self.type_
132 }
133
134 fn size(&self) -> usize {
135 self.data.len()
136 }
137
138 fn clear(&mut self) {
139 self.data.clear();
140 }
141
142 fn reserve(&mut self, new_cap: usize) {
143 self.data.reserve(new_cap);
144 }
145
146 fn append_column(&mut self, other: ColumnRef) -> Result<()> {
147 let other =
148 other.as_any().downcast_ref::<ColumnUuid>().ok_or_else(|| {
149 Error::TypeMismatch {
150 expected: self.type_.name(),
151 actual: other.column_type().name(),
152 }
153 })?;
154
155 self.data.extend_from_slice(&other.data);
156 Ok(())
157 }
158
159 fn load_from_buffer(
160 &mut self,
161 buffer: &mut &[u8],
162 rows: usize,
163 ) -> Result<()> {
164 let bytes_needed = rows * 16;
165 if buffer.len() < bytes_needed {
166 return Err(Error::Protocol(format!(
167 "Buffer underflow: need {} bytes for UUID, have {}",
168 bytes_needed,
169 buffer.len()
170 )));
171 }
172
173 self.data.reserve(rows);
177 let current_len = self.data.len();
178 unsafe {
179 self.data.set_len(current_len + rows);
181 let dest_ptr =
182 (self.data.as_mut_ptr() as *mut u8).add(current_len * 16);
183 std::ptr::copy_nonoverlapping(
184 buffer.as_ptr(),
185 dest_ptr,
186 bytes_needed,
187 );
188 }
189
190 use bytes::Buf;
191 buffer.advance(bytes_needed);
192 Ok(())
193 }
194
195 fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
196 if !self.data.is_empty() {
197 let byte_slice = unsafe {
198 std::slice::from_raw_parts(
199 self.data.as_ptr() as *const u8,
200 self.data.len() * 16,
201 )
202 };
203 buffer.extend_from_slice(byte_slice);
204 }
205 Ok(())
206 }
207
208 fn clone_empty(&self) -> ColumnRef {
209 Arc::new(ColumnUuid::new(self.type_.clone()))
210 }
211
212 fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
213 if begin + len > self.data.len() {
214 return Err(Error::InvalidArgument(format!(
215 "Slice out of bounds: begin={}, len={}, size={}",
216 begin,
217 len,
218 self.data.len()
219 )));
220 }
221
222 let sliced_data = self.data[begin..begin + len].to_vec();
223 Ok(Arc::new(
224 ColumnUuid::new(self.type_.clone()).with_data(sliced_data),
225 ))
226 }
227
228 fn as_any(&self) -> &dyn std::any::Any {
229 self
230 }
231
232 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
233 self
234 }
235}
236
237#[cfg(test)]
238#[cfg_attr(coverage_nightly, coverage(off))]
239mod tests {
240 use super::*;
241
242 #[test]
243 fn test_uuid_parse() {
244 let uuid =
245 Uuid::parse("550e8400-e29b-41d4-a716-446655440000").unwrap();
246 assert_eq!(uuid.high, 0x550e8400e29b41d4);
247 assert_eq!(uuid.low, 0xa716446655440000);
248 }
249
250 #[test]
251 fn test_uuid_to_string() {
252 let uuid = Uuid::new(0x550e8400e29b41d4, 0xa716446655440000);
253 assert_eq!(uuid.as_string(), "550e8400-e29b-41d4-a716-446655440000");
254 assert_eq!(
256 format!("{}", uuid),
257 "550e8400-e29b-41d4-a716-446655440000"
258 );
259 }
260
261 #[test]
262 fn test_uuid_column_append() {
263 let mut col = ColumnUuid::new(Type::uuid());
264 col.append(Uuid::new(0x123456789abcdef0, 0xfedcba9876543210));
265 col.append(Uuid::new(0, 0));
266
267 assert_eq!(col.len(), 2);
268 assert_eq!(
269 col.at(0),
270 Uuid::new(0x123456789abcdef0, 0xfedcba9876543210)
271 );
272 assert_eq!(col.at(1), Uuid::new(0, 0));
273 }
274
275 #[test]
276 fn test_uuid_column_from_string() {
277 let mut col = ColumnUuid::new(Type::uuid());
278 col.append_from_string("550e8400-e29b-41d4-a716-446655440000")
279 .unwrap();
280
281 assert_eq!(col.len(), 1);
282 assert_eq!(col.as_string(0), "550e8400-e29b-41d4-a716-446655440000");
283 }
284}