clickhouse_native_client/column/
nullable.rs1use super::{
19 numeric::ColumnUInt8,
20 Column,
21 ColumnRef,
22};
23use crate::{
24 types::Type,
25 Error,
26 Result,
27};
28use bytes::BytesMut;
29use std::{
30 marker::PhantomData,
31 sync::Arc,
32};
33
34pub struct ColumnNullable {
48 type_: Type,
49 nested: ColumnRef,
50 nulls: ColumnRef, }
52
53impl ColumnNullable {
54 pub fn new(type_: Type) -> Self {
56 let nested = match &type_ {
58 Type::Nullable { nested_type } => {
59 crate::io::block_stream::create_column(nested_type)
60 .expect("Failed to create nested column")
61 }
62 _ => panic!("ColumnNullable requires Nullable type"),
63 };
64
65 let nulls = Arc::new(ColumnUInt8::new());
66 Self { type_, nested, nulls }
67 }
68
69 pub fn with_nested(nested: ColumnRef) -> Self {
71 let nested_type = nested.column_type().clone();
72 let nulls = Arc::new(ColumnUInt8::new());
73 Self { type_: Type::nullable(nested_type), nested, nulls }
74 }
75
76 pub fn from_parts(nested: ColumnRef, nulls: ColumnRef) -> Result<Self> {
78 if nulls.column_type().name() != "UInt8" {
80 return Err(Error::InvalidArgument(
81 "nulls column must be UInt8".to_string(),
82 ));
83 }
84
85 if nested.size() != nulls.size() {
87 return Err(Error::InvalidArgument(format!(
88 "nested and nulls must have same size: nested={}, nulls={}",
89 nested.size(),
90 nulls.size()
91 )));
92 }
93
94 let nested_type = nested.column_type().clone();
95 Ok(Self { type_: Type::nullable(nested_type), nested, nulls })
96 }
97
98 pub fn with_capacity(type_: Type, capacity: usize) -> Self {
100 let nested = match &type_ {
101 Type::Nullable { nested_type } => {
102 crate::io::block_stream::create_column(nested_type)
103 .expect("Failed to create nested column")
104 }
105 _ => panic!("ColumnNullable requires Nullable type"),
106 };
107
108 let mut nulls = ColumnUInt8::new();
109 nulls.reserve(capacity);
110 Self { type_, nested, nulls: Arc::new(nulls) }
111 }
112
113 pub fn append(&mut self, isnull: bool) {
115 let nulls_mut = Arc::get_mut(&mut self.nulls)
116 .expect("Cannot append to shared nulls column")
117 .as_any_mut()
118 .downcast_mut::<ColumnUInt8>()
119 .expect("nulls must be ColumnUInt8");
120 nulls_mut.append(if isnull { 1 } else { 0 });
121 }
122
123 pub fn append_null(&mut self) {
125 self.append(true);
126 }
127
128 pub fn append_non_null(&mut self) {
131 self.append(false);
132 }
133
134 pub fn is_null(&self, index: usize) -> bool {
136 if index >= self.nulls.size() {
137 return false;
138 }
139 let nulls_col = self
140 .nulls
141 .as_any()
142 .downcast_ref::<ColumnUInt8>()
143 .expect("nulls must be ColumnUInt8");
144 nulls_col.at(index) != 0
145 }
146
147 pub fn nested<T: Column + 'static>(&self) -> &T {
155 self.nested
156 .as_any()
157 .downcast_ref::<T>()
158 .expect("Failed to downcast nested column to requested type")
159 }
160
161 pub fn nested_mut<T: Column + 'static>(&mut self) -> &mut T {
169 Arc::get_mut(&mut self.nested)
170 .expect("Cannot get mutable reference to shared nested column")
171 .as_any_mut()
172 .downcast_mut::<T>()
173 .expect("Failed to downcast nested column to requested type")
174 }
175
176 pub fn nested_ref(&self) -> ColumnRef {
178 self.nested.clone()
179 }
180
181 pub fn nested_ref_mut(&mut self) -> &mut ColumnRef {
187 &mut self.nested
188 }
189
190 pub fn nulls(&self) -> ColumnRef {
192 self.nulls.clone()
193 }
194
195 pub fn append_nullable(&mut self, value: Option<u32>) {
197 use crate::column::numeric::ColumnUInt32;
198
199 match value {
200 None => {
201 self.append_null();
202 let nested_mut = Arc::get_mut(&mut self.nested)
205 .expect("Cannot append to shared nullable column - column has multiple references");
206 let col = nested_mut
207 .as_any_mut()
208 .downcast_mut::<ColumnUInt32>()
209 .expect("Nullable nested column is not UInt32");
210 col.append(0); }
212 Some(val) => {
213 self.append_non_null();
214 let nested_mut = Arc::get_mut(&mut self.nested)
215 .expect("Cannot append to shared nullable column - column has multiple references");
216 let col = nested_mut
217 .as_any_mut()
218 .downcast_mut::<ColumnUInt32>()
219 .expect("Nullable nested column is not UInt32");
220 col.append(val);
221 }
222 }
223 }
224
225 pub fn is_null_at(&self, index: usize) -> bool {
227 self.is_null(index)
228 }
229
230 pub fn at(&self, _index: usize) -> ColumnRef {
234 self.nested_ref()
235 }
236
237 pub fn len(&self) -> usize {
239 self.nulls.size()
240 }
241
242 pub fn is_empty(&self) -> bool {
244 self.nulls.size() == 0
245 }
246}
247
248impl Column for ColumnNullable {
249 fn column_type(&self) -> &Type {
250 &self.type_
251 }
252
253 fn size(&self) -> usize {
254 self.nulls.size()
255 }
256
257 fn clear(&mut self) {
258 let nulls_mut = Arc::get_mut(&mut self.nulls)
260 .expect("Cannot clear shared nulls column");
261 nulls_mut.clear();
262
263 let nested_mut = Arc::get_mut(&mut self.nested)
264 .expect("Cannot clear shared nested column");
265 nested_mut.clear();
266 }
267
268 fn reserve(&mut self, new_cap: usize) {
269 let nulls_mut = Arc::get_mut(&mut self.nulls)
270 .expect("Cannot reserve in shared nulls column");
271 nulls_mut.reserve(new_cap);
272
273 let nested_mut = Arc::get_mut(&mut self.nested)
274 .expect("Cannot reserve in shared nested column");
275 nested_mut.reserve(new_cap);
276 }
277
278 fn append_column(&mut self, other: ColumnRef) -> Result<()> {
279 let other = other
280 .as_any()
281 .downcast_ref::<ColumnNullable>()
282 .ok_or_else(|| Error::TypeMismatch {
283 expected: self.type_.name(),
284 actual: other.column_type().name(),
285 })?;
286
287 if self.nested.column_type().name()
289 != other.nested.column_type().name()
290 {
291 return Err(Error::TypeMismatch {
292 expected: self.nested.column_type().name(),
293 actual: other.nested.column_type().name(),
294 });
295 }
296
297 let nulls_mut = Arc::get_mut(&mut self.nulls).ok_or_else(|| {
299 Error::Protocol("Cannot append to shared nulls column".to_string())
300 })?;
301 nulls_mut.append_column(other.nulls.clone())?;
302
303 let nested_mut = Arc::get_mut(&mut self.nested).ok_or_else(|| {
305 Error::Protocol(
306 "Cannot append to shared nested column".to_string(),
307 )
308 })?;
309 nested_mut.append_column(other.nested.clone())?;
310
311 Ok(())
312 }
313
314 fn load_from_buffer(
315 &mut self,
316 buffer: &mut &[u8],
317 rows: usize,
318 ) -> Result<()> {
319 if rows > 0 {
321 let nulls_mut =
322 Arc::get_mut(&mut self.nulls).ok_or_else(|| {
323 Error::Protocol(
324 "Cannot load into shared nulls column".to_string(),
325 )
326 })?;
327 nulls_mut.load_from_buffer(buffer, rows)?;
328
329 let nested_mut =
331 Arc::get_mut(&mut self.nested).ok_or_else(|| {
332 Error::Protocol(
333 "Cannot load into shared nested column".to_string(),
334 )
335 })?;
336 nested_mut.load_from_buffer(buffer, rows)?;
337 }
338
339 Ok(())
340 }
341
342 fn save_prefix(&self, buffer: &mut BytesMut) -> Result<()> {
343 self.nested.save_prefix(buffer)
345 }
346
347 fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
348 self.nulls.save_to_buffer(buffer)?;
350
351 self.nested.save_to_buffer(buffer)?;
353
354 Ok(())
355 }
356
357 fn clone_empty(&self) -> ColumnRef {
358 Arc::new(
359 ColumnNullable::from_parts(
360 self.nested.clone_empty(),
361 self.nulls.clone_empty(),
362 )
363 .expect("clone_empty should succeed"),
364 )
365 }
366
367 fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
368 if begin + len > self.size() {
369 return Err(Error::InvalidArgument(format!(
370 "Slice out of bounds: begin={}, len={}, size={}",
371 begin,
372 len,
373 self.size()
374 )));
375 }
376
377 let sliced_nulls = self.nulls.slice(begin, len)?;
378 let sliced_nested = self.nested.slice(begin, len)?;
379
380 Ok(Arc::new(
381 ColumnNullable::from_parts(sliced_nested, sliced_nulls)
382 .expect("slice should create valid ColumnNullable"),
383 ))
384 }
385
386 fn as_any(&self) -> &dyn std::any::Any {
387 self
388 }
389
390 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
391 self
392 }
393}
394
395pub struct ColumnNullableT<T: Column> {
400 inner: ColumnNullable,
401 _phantom: PhantomData<T>,
402}
403
404impl<T: Column + 'static> ColumnNullableT<T> {
405 pub fn from_parts(nested: Arc<T>, nulls: ColumnRef) -> Result<Self> {
407 let inner = ColumnNullable::from_parts(nested, nulls)?;
408 Ok(Self { inner, _phantom: PhantomData })
409 }
410
411 pub fn from_nested(nested: Arc<T>) -> Self {
413 let size = nested.size();
414 let mut nulls = ColumnUInt8::new();
415 for _ in 0..size {
416 nulls.append(0);
417 }
418 Self {
419 inner: ColumnNullable::from_parts(nested, Arc::new(nulls))
420 .expect("from_nested should succeed"),
421 _phantom: PhantomData,
422 }
423 }
424
425 pub fn new(type_: Type) -> Self {
427 let inner = ColumnNullable::new(type_);
428 Self { inner, _phantom: PhantomData }
429 }
430
431 pub fn wrap(col: ColumnNullable) -> Self {
433 Self { inner: col, _phantom: PhantomData }
434 }
435
436 pub fn wrap_ref(col: ColumnRef) -> Result<Self> {
438 let nullable = col
439 .as_any()
440 .downcast_ref::<ColumnNullable>()
441 .ok_or_else(|| Error::TypeMismatch {
442 expected: "ColumnNullable".to_string(),
443 actual: "unknown".to_string(),
444 })?;
445
446 Ok(Self::wrap(ColumnNullable::from_parts(
448 nullable.nested_ref(),
449 nullable.nulls(),
450 )?))
451 }
452
453 pub fn typed_nested(&self) -> Result<Arc<T>> {
455 self.inner
456 .nested_ref()
457 .as_any()
458 .downcast_ref::<T>()
459 .map(|_| {
460 unsafe {
463 let ptr = Arc::into_raw(self.inner.nested_ref());
464 let typed_ptr = ptr as *const T;
465 Arc::from_raw(typed_ptr)
466 }
467 })
468 .ok_or_else(|| Error::TypeMismatch {
469 expected: std::any::type_name::<T>().to_string(),
470 actual: "unknown".to_string(),
471 })
472 }
473
474 pub fn is_null(&self, index: usize) -> bool {
476 self.inner.is_null(index)
477 }
478
479 pub fn inner(&self) -> &ColumnNullable {
481 &self.inner
482 }
483
484 pub fn inner_mut(&mut self) -> &mut ColumnNullable {
486 &mut self.inner
487 }
488
489 pub fn len(&self) -> usize {
491 self.inner.len()
492 }
493
494 pub fn is_empty(&self) -> bool {
496 self.inner.is_empty()
497 }
498}
499
500impl<T: Column + 'static> Column for ColumnNullableT<T> {
501 fn column_type(&self) -> &Type {
502 self.inner.column_type()
503 }
504
505 fn size(&self) -> usize {
506 self.inner.size()
507 }
508
509 fn clear(&mut self) {
510 self.inner.clear()
511 }
512
513 fn reserve(&mut self, new_cap: usize) {
514 self.inner.reserve(new_cap)
515 }
516
517 fn append_column(&mut self, other: ColumnRef) -> Result<()> {
518 self.inner.append_column(other)
519 }
520
521 fn load_from_buffer(
522 &mut self,
523 buffer: &mut &[u8],
524 rows: usize,
525 ) -> Result<()> {
526 self.inner.load_from_buffer(buffer, rows)
527 }
528
529 fn save_prefix(&self, buffer: &mut BytesMut) -> Result<()> {
530 self.inner.save_prefix(buffer)
531 }
532
533 fn save_to_buffer(&self, buffer: &mut BytesMut) -> Result<()> {
534 self.inner.save_to_buffer(buffer)
535 }
536
537 fn clone_empty(&self) -> ColumnRef {
538 Arc::new(Self::wrap(
539 self.inner
540 .clone_empty()
541 .as_any()
542 .downcast_ref::<ColumnNullable>()
543 .expect("clone_empty must return ColumnNullable")
544 .clone(),
545 ))
546 }
547
548 fn slice(&self, begin: usize, len: usize) -> Result<ColumnRef> {
549 let sliced = self.inner.slice(begin, len)?;
550 Ok(Arc::new(Self::wrap(
551 sliced
552 .as_any()
553 .downcast_ref::<ColumnNullable>()
554 .expect("slice must return ColumnNullable")
555 .clone(),
556 )))
557 }
558
559 fn as_any(&self) -> &dyn std::any::Any {
560 self
561 }
562
563 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
564 self
565 }
566}
567
568impl Clone for ColumnNullable {
570 fn clone(&self) -> Self {
571 Self {
572 type_: self.type_.clone(),
573 nested: self.nested.clone(),
574 nulls: self.nulls.clone(),
575 }
576 }
577}
578
579#[cfg(test)]
580#[cfg_attr(coverage_nightly, coverage(off))]
581mod tests {
582 use super::*;
583 use crate::{
584 column::{
585 numeric::{
586 ColumnUInt32,
587 ColumnUInt64,
588 },
589 string::ColumnString,
590 },
591 types::Type,
592 };
593
594 #[test]
595 fn test_nullable_creation() {
596 let nested = Arc::new(ColumnUInt64::new());
597 let col = ColumnNullable::with_nested(nested);
598 assert_eq!(col.size(), 0);
599 }
600
601 #[test]
602 fn test_nullable_append() {
603 let nested = Arc::new(ColumnUInt64::new());
604 let mut col = ColumnNullable::with_nested(nested);
605
606 col.append_non_null();
607 col.append_null();
608 col.append_non_null();
609
610 assert_eq!(col.size(), 3);
611 assert!(!col.is_null(0));
612 assert!(col.is_null(1));
613 assert!(!col.is_null(2));
614 }
615
616 #[test]
617 fn test_nullable_nulls_bitmap() {
618 let nested = Arc::new(ColumnUInt64::new());
619 let mut col = ColumnNullable::with_nested(nested);
620
621 col.append_non_null();
622 col.append_null();
623 col.append_null();
624 col.append_non_null();
625
626 let nulls_ref = col.nulls();
627 let nulls_col =
628 nulls_ref.as_any().downcast_ref::<ColumnUInt8>().unwrap();
629 assert_eq!(nulls_col.at(0), 0);
630 assert_eq!(nulls_col.at(1), 1);
631 assert_eq!(nulls_col.at(2), 1);
632 assert_eq!(nulls_col.at(3), 0);
633 }
634
635 #[test]
636 fn test_nullable_save_load() {
637 let mut nested = ColumnUInt64::new();
638 nested.append(10);
639 nested.append(20);
640 nested.append(30);
641
642 let mut col = ColumnNullable::with_nested(Arc::new(nested));
643 col.append_non_null();
644 col.append_null();
645 col.append_non_null();
646
647 let mut buffer = BytesMut::new();
648 col.save_to_buffer(&mut buffer).unwrap();
649
650 let nulls_len = 3; assert!(buffer.len() >= nulls_len);
653 assert_eq!(&buffer[..nulls_len], &[0, 1, 0]);
654 }
655
656 #[test]
657 fn test_nullable_load_null_bitmap() {
658 use bytes::{
659 BufMut,
660 BytesMut,
661 };
662
663 let nested = Arc::new(ColumnUInt64::new());
664 let mut col = ColumnNullable::with_nested(nested);
665
666 let mut data = BytesMut::new();
668 data.extend_from_slice(&[1u8, 0, 1, 0, 1]);
669
670 for i in 0..5u64 {
672 data.put_u64_le(i);
673 }
674
675 let mut reader = &data[..];
676 col.load_from_buffer(&mut reader, 5).unwrap();
677
678 assert_eq!(col.size(), 5);
679 assert!(col.is_null(0));
680 assert!(!col.is_null(1));
681 assert!(col.is_null(2));
682 assert!(!col.is_null(3));
683 assert!(col.is_null(4));
684 }
685
686 #[test]
687 fn test_nullable_slice() {
688 let mut nested = ColumnUInt64::new();
689 for i in 0..10 {
691 nested.append(i);
692 }
693 let mut col = ColumnNullable::with_nested(Arc::new(nested));
694
695 for i in 0..10 {
696 if i % 2 == 0 {
697 col.append_null();
698 } else {
699 col.append_non_null();
700 }
701 }
702
703 let sliced = col.slice(2, 5).unwrap();
704 let sliced_col =
705 sliced.as_any().downcast_ref::<ColumnNullable>().unwrap();
706
707 assert_eq!(sliced_col.size(), 5);
708 assert!(sliced_col.is_null(0)); assert!(!sliced_col.is_null(1)); assert!(sliced_col.is_null(2)); }
712
713 #[test]
714 fn test_nullable_with_string() {
715 let nested = Arc::new(ColumnString::new(Type::string()));
716 let mut col = ColumnNullable::with_nested(nested);
717
718 col.append_non_null();
719 col.append_null();
720 col.append_non_null();
721
722 assert_eq!(col.size(), 3);
723 assert!(!col.is_null(0));
724 assert!(col.is_null(1));
725 assert!(!col.is_null(2));
726 }
727
728 #[test]
729 fn test_nullable_type_mismatch() {
730 let nested1 = Arc::new(ColumnUInt64::new());
731 let mut col1 = ColumnNullable::with_nested(nested1);
732
733 let nested2 = Arc::new(ColumnString::new(Type::string()));
734 let col2 = ColumnNullable::with_nested(nested2);
735
736 let result = col1.append_column(Arc::new(col2));
737 assert!(result.is_err());
738 }
739
740 #[test]
741 fn test_nullable_out_of_bounds() {
742 let nested = Arc::new(ColumnUInt64::new());
743 let mut col = ColumnNullable::with_nested(nested);
744
745 col.append_null();
746 col.append_non_null();
747
748 assert!(!col.is_null(100));
750 }
751
752 #[test]
753 fn test_nullable_append_column() {
754 let mut col1 =
756 ColumnNullable::with_nested(Arc::new(ColumnUInt32::new()));
757 col1.append_nullable(Some(1));
758 col1.append_nullable(None);
759 col1.append_nullable(Some(3));
760
761 let mut col2 =
763 ColumnNullable::with_nested(Arc::new(ColumnUInt32::new()));
764 col2.append_nullable(None);
765 col2.append_nullable(Some(5));
766
767 col1.append_column(Arc::new(col2))
769 .expect("append_column should succeed");
770
771 assert_eq!(col1.size(), 5, "Should have 5 elements after append");
773
774 assert!(!col1.is_null(0), "Element 0 should not be null (value=1)");
776 assert!(col1.is_null(1), "Element 1 should be null");
777 assert!(!col1.is_null(2), "Element 2 should not be null (value=3)");
778 assert!(col1.is_null(3), "Element 3 should be null");
779 assert!(!col1.is_null(4), "Element 4 should not be null (value=5)");
780
781 let nested: &ColumnUInt32 = col1.nested();
783 assert_eq!(
784 nested.size(),
785 5,
786 "Nested column should have 5 total elements"
787 );
788 }
789
790 #[test]
791 #[should_panic(expected = "Cannot clear shared nulls column")]
792 fn test_nullable_clear_panics_on_shared_nulls() {
793 use crate::column::numeric::ColumnUInt32;
794
795 let mut col =
797 ColumnNullable::with_nested(Arc::new(ColumnUInt32::new()));
798 col.append_nullable(Some(1));
799 col.append_nullable(None);
800 col.append_nullable(Some(3));
801
802 let _shared_ref = col.nulls();
804
805 col.clear();
807 }
808
809 #[test]
810 fn test_nullable_roundtrip_nested_data() {
811 use bytes::BytesMut;
812
813 let mut col =
815 ColumnNullable::with_nested(Arc::new(ColumnUInt32::new()));
816 col.append_nullable(Some(1));
817 col.append_nullable(None);
818 col.append_nullable(Some(3));
819
820 assert_eq!(col.size(), 3, "Original should have 3 elements");
821
822 let mut buffer = BytesMut::new();
824 col.save_to_buffer(&mut buffer).expect("save should succeed");
825
826 let nested_empty = Arc::new(ColumnUInt32::new());
828 let mut col_loaded = ColumnNullable::with_nested(nested_empty);
829
830 let mut buf_slice = &buffer[..];
831 col_loaded
832 .load_from_buffer(&mut buf_slice, 3)
833 .expect("load should succeed");
834
835 assert_eq!(col_loaded.size(), 3, "Loaded should have 3 elements");
837
838 assert!(!col_loaded.is_null(0), "Element 0 should not be null");
840 assert!(col_loaded.is_null(1), "Element 1 should be null");
841 assert!(!col_loaded.is_null(2), "Element 2 should not be null");
842
843 let nested_loaded: &ColumnUInt32 = col_loaded.nested();
845 assert_eq!(
846 nested_loaded.size(),
847 3,
848 "Nested should have 3 elements after load"
849 );
850 }
851
852 #[test]
853 fn test_nullable_t_creation() {
854 let nested = Arc::new(ColumnUInt64::new());
855 let col = ColumnNullableT::<ColumnUInt64>::from_nested(nested);
856 assert_eq!(col.size(), 0);
857 }
858
859 #[test]
860 fn test_nullable_t_wrap() {
861 let nested = Arc::new(ColumnUInt64::new());
862 let nullable = ColumnNullable::with_nested(nested);
863 let col_t = ColumnNullableT::<ColumnUInt64>::wrap(nullable);
864 assert_eq!(col_t.size(), 0);
865 }
866
867 #[test]
868 fn test_nullable_t_typed_nested() {
869 let mut nested = ColumnUInt64::new();
870 nested.append(42);
871 let col =
872 ColumnNullableT::<ColumnUInt64>::from_nested(Arc::new(nested));
873
874 let typed = col.typed_nested().unwrap();
875 assert_eq!(typed.size(), 1);
876 assert_eq!(typed.at(0), 42);
877 }
878}