1use std::{
8 any::Any,
9 marker::PhantomData,
10 ops::{Deref, DerefMut},
11};
12
13use crate::numeric_id::{DenseIdMap, NumericId, define_id};
14use smallvec::SmallVec;
15
16use crate::{
17 QueryEntry, TableId, Variable,
18 action::{
19 Bindings, ExecutionState,
20 mask::{Mask, MaskIter, ValueSource},
21 },
22 common::Value,
23 hash_index::{IndexBase, TupleIndex},
24 offsets::{RowId, Subset, SubsetRef},
25 pool::{PoolSet, Pooled, with_pool_set},
26 row_buffer::{RowBuffer, RowSink, TaggedRowBuffer},
27};
28
29define_id!(pub ColumnId, u32, "a particular column in a table", pretty "Col");
30define_id!(
31 pub Generation,
32 u64,
33 "the current version of a table -- used to invalidate any existing RowIds"
34);
35define_id!(
36 pub Offset,
37 u64,
38 "an opaque offset token -- used to encode iterations over a table (within a generation). These always start at 0."
39);
40
41#[derive(Clone, Debug, PartialEq, Eq)]
43pub struct TableVersion {
44 pub major: Generation,
46 pub minor: Offset,
50 }
52
53#[derive(Clone)]
54pub struct TableSpec {
55 pub n_keys: usize,
57
58 pub n_vals: usize,
62
63 pub uncacheable_columns: DenseIdMap<ColumnId, bool>,
68
69 pub allows_delete: bool,
74}
75
76impl TableSpec {
77 pub fn arity(&self) -> usize {
79 self.n_keys + self.n_vals
80 }
81}
82
83#[derive(Eq, PartialEq, Copy, Clone)]
85pub struct TableChange {
86 pub added: bool,
88 pub removed: bool,
90}
91
92#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
94pub enum Constraint {
95 Eq { l_col: ColumnId, r_col: ColumnId },
96 EqConst { col: ColumnId, val: Value },
97 LtConst { col: ColumnId, val: Value },
98 GtConst { col: ColumnId, val: Value },
99 LeConst { col: ColumnId, val: Value },
100 GeConst { col: ColumnId, val: Value },
101}
102
103pub trait ValueRebuilder: Send + Sync {
107 fn rebuild_val(&self, val: Value) -> Value;
109 fn rebuild_slice(&self, vals: &mut [Value]) -> bool {
114 let mut changed = false;
115 for val in vals.iter_mut() {
116 let new = self.rebuild_val(*val);
117 if new != *val {
118 *val = new;
119 changed = true;
120 }
121 }
122 changed
123 }
124}
125
126pub trait Rebuilder: ValueRebuilder {
137 fn hint_col(&self) -> Option<ColumnId>;
140 fn rebuild_buf(
142 &self,
143 buf: &RowBuffer,
144 start: RowId,
145 end: RowId,
146 out: &mut TaggedRowBuffer,
147 exec_state: &mut ExecutionState,
148 );
149 fn rebuild_subset(
151 &self,
152 other: WrappedTableRef,
153 subset: SubsetRef,
154 out: &mut TaggedRowBuffer,
155 exec_state: &mut ExecutionState,
156 );
157}
158
159pub struct Row {
161 pub id: RowId,
163 pub vals: Pooled<Vec<Value>>,
165}
166
167pub trait Table: Any + Send + Sync {
169 fn dyn_clone(&self) -> Box<dyn Table>;
172
173 fn rebuilder<'a>(&'a self, _cols: &[ColumnId]) -> Option<Box<dyn Rebuilder + 'a>> {
175 None
176 }
177
178 fn apply_rebuild(
187 &mut self,
188 _table_id: TableId,
189 _table: &WrappedTable,
190 _next_ts: Value,
191 _exec_state: &mut ExecutionState,
192 ) -> bool {
193 false
195 }
196
197 fn refresh_rows_for_values(&mut self, _dirty_ids: &[Value], _next_ts: Value) -> bool {
210 false
211 }
212
213 fn as_any(&self) -> &dyn Any;
218
219 fn spec(&self) -> TableSpec;
224
225 fn clear(&mut self);
228
229 fn all(&self) -> Subset;
233
234 fn len(&self) -> usize;
240
241 fn is_empty(&self) -> bool {
243 self.len() == 0
244 }
245
246 fn version(&self) -> TableVersion;
249
250 fn updates_since(&self, offset: Offset) -> Subset;
252
253 fn scan_generic_bounded(
266 &self,
267 subset: SubsetRef,
268 start: Offset,
269 n: usize,
270 cs: &[Constraint],
271 f: impl FnMut(RowId, &[Value]),
272 ) -> Option<Offset>
273 where
274 Self: Sized;
275
276 fn scan_generic(&self, subset: SubsetRef, mut f: impl FnMut(RowId, &[Value]))
281 where
282 Self: Sized,
283 {
284 let mut cur = Offset::new(0);
285 while let Some(next) = self.scan_generic_bounded(subset, cur, usize::MAX, &[], |id, row| {
286 f(id, row);
287 }) {
288 cur = next;
289 }
290 }
291
292 fn has_stale_rows(&self) -> bool {
296 true
297 }
298
299 fn refine_live(&self, subset: Subset) -> Subset {
301 self.refine_one(
303 subset,
304 &Constraint::LtConst {
305 col: ColumnId::new_const(0),
306 val: Value::stale(),
307 },
308 )
309 }
310
311 fn refine_one(&self, subset: Subset, c: &Constraint) -> Subset {
315 self.refine(subset, std::slice::from_ref(c))
316 }
317
318 fn refine(&self, subset: Subset, cs: &[Constraint]) -> Subset {
322 cs.iter()
323 .fold(subset, |subset, c| self.refine_one(subset, c))
324 }
325
326 fn refine_ref(&self, subset: SubsetRef, cs: &[Constraint], check_live: bool) -> Subset {
332 let mut owned = subset.to_owned(&with_pool_set(|ps| ps.get_pool()));
333 if check_live {
334 owned = self.refine_live(owned);
335 }
336 if cs.is_empty() {
337 owned
338 } else {
339 self.refine(owned, cs)
340 }
341 }
342
343 fn fast_subset(&self, _: &Constraint) -> Option<Subset> {
350 None
351 }
352
353 fn split_fast_slow(
357 &self,
358 cs: &[Constraint],
359 ) -> (
360 Subset, Pooled<Vec<Constraint>>, Pooled<Vec<Constraint>>, ) {
364 with_pool_set(|ps| {
365 let mut fast = ps.get::<Vec<Constraint>>();
366 let mut slow = ps.get::<Vec<Constraint>>();
367 let mut subset = self.all();
368 for c in cs {
369 if let Some(sub) = self.fast_subset(c) {
370 subset.intersect(sub.as_ref(), &ps.get_pool());
371 fast.push(c.clone());
372 } else {
373 slow.push(c.clone());
374 }
375 }
376 (subset, fast, slow)
377 })
378 }
379
380 fn get_row(&self, key: &[Value]) -> Option<Row>;
387
388 fn get_row_column(&self, key: &[Value], col: ColumnId) -> Option<Value> {
394 self.get_row(key).map(|row| row.vals[col.index()])
395 }
396
397 fn merge(&mut self, exec_state: &mut ExecutionState) -> TableChange;
400
401 fn new_buffer(&self) -> Box<dyn MutationBuffer>;
405}
406
407pub trait MutationBuffer: Any + Send + Sync {
413 fn stage_insert(&mut self, row: &[Value]);
417
418 fn stage_remove(&mut self, key: &[Value]);
422
423 fn fresh_handle(&self) -> Box<dyn MutationBuffer>;
425}
426
427struct WrapperImpl<T>(PhantomData<T>);
428
429pub(crate) fn wrapper<T: Table>() -> Box<dyn TableWrapper> {
430 Box::new(WrapperImpl::<T>(PhantomData))
431}
432
433impl<T: Table> TableWrapper for WrapperImpl<T> {
434 fn dyn_clone(&self) -> Box<dyn TableWrapper> {
435 Box::new(Self(PhantomData))
436 }
437 fn scan_bounded(
438 &self,
439 table: &dyn Table,
440 subset: SubsetRef,
441 start: Offset,
442 n: usize,
443 out: &mut TaggedRowBuffer,
444 ) -> Option<Offset> {
445 let table = table.as_any().downcast_ref::<T>().unwrap();
446 table.scan_generic_bounded(subset, start, n, &[], |row_id, row| {
447 out.add_row(row_id, row);
448 })
449 }
450 fn group_by_key(&self, table: &dyn Table, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex {
451 let table = table.as_any().downcast_ref::<T>().unwrap();
452 let mut res = TupleIndex::new(cols.len());
453 match cols {
454 [] => {}
455 [col] => table.scan_generic(subset, |row_id, row| {
456 res.add_row(&[row[col.index()]], row_id);
457 }),
458 [x, y] => table.scan_generic(subset, |row_id, row| {
459 res.add_row(&[row[x.index()], row[y.index()]], row_id);
460 }),
461 [x, y, z] => table.scan_generic(subset, |row_id, row| {
462 res.add_row(&[row[x.index()], row[y.index()], row[z.index()]], row_id);
463 }),
464 _ => {
465 let mut scratch = SmallVec::<[Value; 8]>::new();
466 table.scan_generic(subset, |row_id, row| {
467 for col in cols {
468 scratch.push(row[col.index()]);
469 }
470 res.add_row(&scratch, row_id);
471 scratch.clear();
472 });
473 }
474 }
475 res
476 }
477 fn for_each_col(
478 &self,
479 table: &dyn Table,
480 subset: SubsetRef,
481 col: ColumnId,
482 f: &mut dyn FnMut(RowId, Value),
483 ) {
484 let table = table.as_any().downcast_ref::<T>().unwrap();
485 let col_idx = col.index();
486 table.scan_generic(subset, |row_id, row| {
487 f(row_id, row[col_idx]);
488 });
489 }
490
491 fn collect_col_pairs(
492 &self,
493 table: &dyn Table,
494 subset: SubsetRef,
495 col: ColumnId,
496 out: &mut Vec<(Value, RowId)>,
497 ) {
498 let table = table.as_any().downcast_ref::<T>().unwrap();
499 let col_idx = col.index();
500 out.reserve(subset.size());
501 table.scan_generic(subset, |row_id, row| {
502 out.push((row[col_idx], row_id));
503 });
504 }
505
506 fn scan_project(
507 &self,
508 table: &dyn Table,
509 subset: SubsetRef,
510 cols: &[ColumnId],
511 start: Offset,
512 n: usize,
513 cs: &[Constraint],
514 out: &mut dyn RowSink,
515 ) -> Option<Offset> {
516 let table = table.as_any().downcast_ref::<T>().unwrap();
517 match cols {
518 [] => None,
519 [col] => table.scan_generic_bounded(subset, start, n, cs, |id, row| {
520 out.add_row(id, &[row[col.index()]]);
521 }),
522 [x, y] => table.scan_generic_bounded(subset, start, n, cs, |id, row| {
523 out.add_row(id, &[row[x.index()], row[y.index()]]);
524 }),
525 [x, y, z] => table.scan_generic_bounded(subset, start, n, cs, |id, row| {
526 out.add_row(id, &[row[x.index()], row[y.index()], row[z.index()]]);
527 }),
528 _ => {
529 let mut scratch = SmallVec::<[Value; 8]>::with_capacity(cols.len());
530 table.scan_generic_bounded(subset, start, n, cs, |id, row| {
531 for col in cols {
532 scratch.push(row[col.index()]);
533 }
534 out.add_row(id, &scratch);
535 scratch.clear();
536 })
537 }
538 }
539 }
540
541 fn lookup_row_vectorized(
542 &self,
543 table: &dyn Table,
544 mask: &mut Mask,
545 bindings: &mut Bindings,
546 args: &[QueryEntry],
547 col: ColumnId,
548 out_var: Variable,
549 ) {
550 let table = table.as_any().downcast_ref::<T>().unwrap();
551 let mut out = with_pool_set(PoolSet::get::<Vec<Value>>);
552 for_each_binding_with_mask!(mask, args, bindings, |iter| {
553 iter.fill_vec(&mut out, Value::stale, |_, args| {
554 table.get_row_column(args.as_slice(), col)
555 })
556 });
557 bindings.insert(out_var, &out);
558 }
559
560 fn lookup_with_default_vectorized(
561 &self,
562 table: &dyn Table,
563 mask: &mut Mask,
564 bindings: &mut Bindings,
565 args: &[QueryEntry],
566 col: ColumnId,
567 default: QueryEntry,
568 out_var: Variable,
569 ) {
570 let table = table.as_any().downcast_ref::<T>().unwrap();
571 let mut out = with_pool_set(|ps| ps.get::<Vec<Value>>());
572 for_each_binding_with_mask!(mask, args, bindings, |iter| {
573 match default {
574 QueryEntry::Var(default) => iter.zip(&bindings[default]).fill_vec(
575 &mut out,
576 Value::stale,
577 |_, (args, default)| {
578 Some(
579 table
580 .get_row_column(args.as_slice(), col)
581 .unwrap_or(*default),
582 )
583 },
584 ),
585 QueryEntry::Const(default) => iter.fill_vec(&mut out, Value::stale, |_, args| {
586 Some(
587 table
588 .get_row_column(args.as_slice(), col)
589 .unwrap_or(default),
590 )
591 }),
592 }
593 });
594 bindings.insert(out_var, &out);
595 }
596}
597
598pub struct WrappedTable {
606 inner: Box<dyn Table>,
607 wrapper: Box<dyn TableWrapper>,
608}
609
610impl WrappedTable {
611 pub(crate) fn new<T: Table>(inner: T) -> Self {
612 let wrapper = wrapper::<T>();
613 let inner = Box::new(inner);
614 Self { inner, wrapper }
615 }
616
617 pub fn dyn_clone(&self) -> Self {
619 WrappedTable {
620 inner: self.inner.dyn_clone(),
621 wrapper: self.wrapper.dyn_clone(),
622 }
623 }
624
625 pub(crate) fn as_ref(&self) -> WrappedTableRef<'_> {
626 WrappedTableRef {
627 inner: &*self.inner,
628 wrapper: &*self.wrapper,
629 }
630 }
631
632 pub fn scan_bounded(
638 &self,
639 subset: SubsetRef,
640 start: Offset,
641 n: usize,
642 out: &mut TaggedRowBuffer,
643 ) -> Option<Offset> {
644 self.as_ref().scan_bounded(subset, start, n, out)
645 }
646
647 pub(crate) fn group_by_key(&self, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex {
649 self.as_ref().group_by_key(subset, cols)
650 }
651
652 pub fn scan_project(
657 &self,
658 subset: SubsetRef,
659 cols: &[ColumnId],
660 start: Offset,
661 n: usize,
662 cs: &[Constraint],
663 out: &mut dyn RowSink,
664 ) -> Option<Offset> {
665 self.as_ref().scan_project(subset, cols, start, n, cs, out)
666 }
667
668 pub fn scan(&self, subset: SubsetRef) -> TaggedRowBuffer {
670 self.as_ref().scan(subset)
671 }
672
673 pub fn len(&self) -> usize {
675 self.inner.len()
676 }
677
678 pub fn is_empty(&self) -> bool {
680 self.inner.is_empty()
681 }
682
683 pub(crate) fn lookup_row_vectorized(
684 &self,
685 mask: &mut Mask,
686 bindings: &mut Bindings,
687 args: &[QueryEntry],
688 col: ColumnId,
689 out_var: Variable,
690 ) {
691 self.as_ref()
692 .lookup_row_vectorized(mask, bindings, args, col, out_var)
693 }
694
695 #[allow(clippy::too_many_arguments)]
696 pub(crate) fn lookup_with_default_vectorized(
697 &self,
698 mask: &mut Mask,
699 bindings: &mut Bindings,
700 args: &[QueryEntry],
701 col: ColumnId,
702 default: QueryEntry,
703 out_var: Variable,
704 ) {
705 self.as_ref()
706 .lookup_with_default_vectorized(mask, bindings, args, col, default, out_var)
707 }
708}
709
710impl Deref for WrappedTable {
711 type Target = dyn Table;
712
713 fn deref(&self) -> &Self::Target {
714 &*self.inner
715 }
716}
717
718impl DerefMut for WrappedTable {
719 fn deref_mut(&mut self) -> &mut Self::Target {
720 &mut *self.inner
721 }
722}
723
724pub(crate) trait TableWrapper: Send + Sync {
725 fn dyn_clone(&self) -> Box<dyn TableWrapper>;
726 fn scan_bounded(
727 &self,
728 table: &dyn Table,
729 subset: SubsetRef,
730 start: Offset,
731 n: usize,
732 out: &mut TaggedRowBuffer,
733 ) -> Option<Offset>;
734 fn group_by_key(&self, table: &dyn Table, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex;
735
736 fn for_each_col(
740 &self,
741 table: &dyn Table,
742 subset: SubsetRef,
743 col: ColumnId,
744 f: &mut dyn FnMut(RowId, Value),
745 );
746
747 fn collect_col_pairs(
752 &self,
753 table: &dyn Table,
754 subset: SubsetRef,
755 col: ColumnId,
756 out: &mut Vec<(Value, RowId)>,
757 );
758
759 #[allow(clippy::too_many_arguments)]
760 fn scan_project(
761 &self,
762 table: &dyn Table,
763 subset: SubsetRef,
764 cols: &[ColumnId],
765 start: Offset,
766 n: usize,
767 cs: &[Constraint],
768 out: &mut dyn RowSink,
769 ) -> Option<Offset>;
770
771 fn scan(&self, table: &dyn Table, subset: SubsetRef) -> TaggedRowBuffer {
772 let arity = table.spec().arity();
773 let mut buf = TaggedRowBuffer::new(arity);
774 assert!(
775 self.scan_bounded(table, subset, Offset::new(0), usize::MAX, &mut buf)
776 .is_none()
777 );
778 buf
779 }
780
781 #[allow(clippy::too_many_arguments)]
782 fn lookup_row_vectorized(
783 &self,
784 table: &dyn Table,
785 mask: &mut Mask,
786 bindings: &mut Bindings,
787 args: &[QueryEntry],
788 col: ColumnId,
789 out_var: Variable,
790 );
791
792 #[allow(clippy::too_many_arguments)]
793 fn lookup_with_default_vectorized(
794 &self,
795 table: &dyn Table,
796 mask: &mut Mask,
797 bindings: &mut Bindings,
798 args: &[QueryEntry],
799 col: ColumnId,
800 default: QueryEntry,
801 out_var: Variable,
802 );
803}
804
805#[derive(Clone, Copy)]
809pub struct WrappedTableRef<'a> {
810 inner: &'a dyn Table,
811 wrapper: &'a dyn TableWrapper,
812}
813
814impl WrappedTableRef<'_> {
815 pub(crate) fn with_wrapper<T: Table, R>(
816 inner: &T,
817 f: impl for<'a> FnOnce(WrappedTableRef<'a>) -> R,
818 ) -> R {
819 let wrapper = WrapperImpl::<T>(PhantomData);
820 f(WrappedTableRef {
821 inner,
822 wrapper: &wrapper,
823 })
824 }
825
826 pub fn scan_bounded(
830 &self,
831 subset: SubsetRef,
832 start: Offset,
833 n: usize,
834 out: &mut TaggedRowBuffer,
835 ) -> Option<Offset> {
836 self.wrapper.scan_bounded(self.inner, subset, start, n, out)
837 }
838
839 pub(crate) fn group_by_key(&self, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex {
841 self.wrapper.group_by_key(self.inner, subset, cols)
842 }
843
844 pub(crate) fn for_each_col(
848 &self,
849 subset: SubsetRef,
850 col: ColumnId,
851 f: &mut dyn FnMut(RowId, Value),
852 ) {
853 self.wrapper.for_each_col(self.inner, subset, col, f);
854 }
855
856 pub(crate) fn collect_col_pairs(
859 &self,
860 subset: SubsetRef,
861 col: ColumnId,
862 out: &mut Vec<(Value, RowId)>,
863 ) {
864 self.wrapper.collect_col_pairs(self.inner, subset, col, out);
865 }
866
867 pub fn scan_project(
870 &self,
871 subset: SubsetRef,
872 cols: &[ColumnId],
873 start: Offset,
874 n: usize,
875 cs: &[Constraint],
876 out: &mut dyn RowSink,
877 ) -> Option<Offset> {
878 self.wrapper
879 .scan_project(self.inner, subset, cols, start, n, cs, out)
880 }
881
882 pub fn scan(&self, subset: SubsetRef) -> TaggedRowBuffer {
884 self.wrapper.scan(self.inner, subset)
885 }
886
887 pub fn len(&self) -> usize {
889 self.inner.len()
890 }
891
892 pub(crate) fn lookup_row_vectorized(
893 &self,
894 mask: &mut Mask,
895 bindings: &mut Bindings,
896 args: &[QueryEntry],
897 col: ColumnId,
898 out_var: Variable,
899 ) {
900 self.wrapper
901 .lookup_row_vectorized(self.inner, mask, bindings, args, col, out_var);
902 }
903
904 #[allow(clippy::too_many_arguments)]
905 pub(crate) fn lookup_with_default_vectorized(
906 &self,
907 mask: &mut Mask,
908 bindings: &mut Bindings,
909 args: &[QueryEntry],
910 col: ColumnId,
911 default: QueryEntry,
912 out_var: Variable,
913 ) {
914 self.wrapper.lookup_with_default_vectorized(
915 self.inner, mask, bindings, args, col, default, out_var,
916 );
917 }
918}
919
920impl Deref for WrappedTableRef<'_> {
921 type Target = dyn Table;
922
923 fn deref(&self) -> &Self::Target {
924 self.inner
925 }
926}