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(
262 &self,
263 subset: SubsetRef,
264 start: Offset,
265 n: usize,
266 cs: &[Constraint],
267 f: impl FnMut(RowId, &[Value]),
268 ) -> Option<Offset>
269 where
270 Self: Sized;
271
272 fn scan_generic(&self, subset: SubsetRef, mut f: impl FnMut(RowId, &[Value]))
277 where
278 Self: Sized,
279 {
280 let mut cur = Offset::new(0);
281 while let Some(next) = self.scan_generic_bounded(subset, cur, usize::MAX, &[], |id, row| {
282 f(id, row);
283 }) {
284 cur = next;
285 }
286 }
287
288 fn has_stale_rows(&self) -> bool {
292 true
293 }
294
295 fn refine_live(&self, subset: Subset) -> Subset {
297 self.refine_one(
299 subset,
300 &Constraint::LtConst {
301 col: ColumnId::new_const(0),
302 val: Value::stale(),
303 },
304 )
305 }
306
307 fn refine_one(&self, subset: Subset, c: &Constraint) -> Subset {
311 self.refine(subset, std::slice::from_ref(c))
312 }
313
314 fn refine(&self, subset: Subset, cs: &[Constraint]) -> Subset {
318 cs.iter()
319 .fold(subset, |subset, c| self.refine_one(subset, c))
320 }
321
322 fn refine_ref(&self, subset: SubsetRef, cs: &[Constraint], check_live: bool) -> Subset {
328 let mut owned = subset.to_owned(&with_pool_set(|ps| ps.get_pool()));
329 if check_live {
330 owned = self.refine_live(owned);
331 }
332 if cs.is_empty() {
333 owned
334 } else {
335 self.refine(owned, cs)
336 }
337 }
338
339 fn fast_subset(&self, _: &Constraint) -> Option<Subset> {
346 None
347 }
348
349 fn split_fast_slow(
353 &self,
354 cs: &[Constraint],
355 ) -> (
356 Subset, Pooled<Vec<Constraint>>, Pooled<Vec<Constraint>>, ) {
360 with_pool_set(|ps| {
361 let mut fast = ps.get::<Vec<Constraint>>();
362 let mut slow = ps.get::<Vec<Constraint>>();
363 let mut subset = self.all();
364 for c in cs {
365 if let Some(sub) = self.fast_subset(c) {
366 subset.intersect(sub.as_ref(), &ps.get_pool());
367 fast.push(c.clone());
368 } else {
369 slow.push(c.clone());
370 }
371 }
372 (subset, fast, slow)
373 })
374 }
375
376 fn get_row(&self, key: &[Value]) -> Option<Row>;
383
384 fn get_row_column(&self, key: &[Value], col: ColumnId) -> Option<Value> {
390 self.get_row(key).map(|row| row.vals[col.index()])
391 }
392
393 fn merge(&mut self, exec_state: &mut ExecutionState) -> TableChange;
396
397 fn new_buffer(&self) -> Box<dyn MutationBuffer>;
401}
402
403pub trait MutationBuffer: Any + Send + Sync {
409 fn stage_insert(&mut self, row: &[Value]);
413
414 fn stage_remove(&mut self, key: &[Value]);
418
419 fn fresh_handle(&self) -> Box<dyn MutationBuffer>;
421}
422
423struct WrapperImpl<T>(PhantomData<T>);
424
425pub(crate) fn wrapper<T: Table>() -> Box<dyn TableWrapper> {
426 Box::new(WrapperImpl::<T>(PhantomData))
427}
428
429impl<T: Table> TableWrapper for WrapperImpl<T> {
430 fn dyn_clone(&self) -> Box<dyn TableWrapper> {
431 Box::new(Self(PhantomData))
432 }
433 fn scan_bounded(
434 &self,
435 table: &dyn Table,
436 subset: SubsetRef,
437 start: Offset,
438 n: usize,
439 out: &mut TaggedRowBuffer,
440 ) -> Option<Offset> {
441 let table = table.as_any().downcast_ref::<T>().unwrap();
442 table.scan_generic_bounded(subset, start, n, &[], |row_id, row| {
443 out.add_row(row_id, row);
444 })
445 }
446 fn group_by_key(&self, table: &dyn Table, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex {
447 let table = table.as_any().downcast_ref::<T>().unwrap();
448 let mut res = TupleIndex::new(cols.len());
449 match cols {
450 [] => {}
451 [col] => table.scan_generic(subset, |row_id, row| {
452 res.add_row(&[row[col.index()]], row_id);
453 }),
454 [x, y] => table.scan_generic(subset, |row_id, row| {
455 res.add_row(&[row[x.index()], row[y.index()]], row_id);
456 }),
457 [x, y, z] => table.scan_generic(subset, |row_id, row| {
458 res.add_row(&[row[x.index()], row[y.index()], row[z.index()]], row_id);
459 }),
460 _ => {
461 let mut scratch = SmallVec::<[Value; 8]>::new();
462 table.scan_generic(subset, |row_id, row| {
463 for col in cols {
464 scratch.push(row[col.index()]);
465 }
466 res.add_row(&scratch, row_id);
467 scratch.clear();
468 });
469 }
470 }
471 res
472 }
473 fn for_each_col(
474 &self,
475 table: &dyn Table,
476 subset: SubsetRef,
477 col: ColumnId,
478 f: &mut dyn FnMut(RowId, Value),
479 ) {
480 let table = table.as_any().downcast_ref::<T>().unwrap();
481 let col_idx = col.index();
482 table.scan_generic(subset, |row_id, row| {
483 f(row_id, row[col_idx]);
484 });
485 }
486
487 fn collect_col_pairs(
488 &self,
489 table: &dyn Table,
490 subset: SubsetRef,
491 col: ColumnId,
492 out: &mut Vec<(Value, RowId)>,
493 ) {
494 let table = table.as_any().downcast_ref::<T>().unwrap();
495 let col_idx = col.index();
496 out.reserve(subset.size());
497 table.scan_generic(subset, |row_id, row| {
498 out.push((row[col_idx], row_id));
499 });
500 }
501
502 fn scan_project(
503 &self,
504 table: &dyn Table,
505 subset: SubsetRef,
506 cols: &[ColumnId],
507 start: Offset,
508 n: usize,
509 cs: &[Constraint],
510 out: &mut dyn RowSink,
511 ) -> Option<Offset> {
512 let table = table.as_any().downcast_ref::<T>().unwrap();
513 match cols {
514 [] => None,
515 [col] => table.scan_generic_bounded(subset, start, n, cs, |id, row| {
516 out.add_row(id, &[row[col.index()]]);
517 }),
518 [x, y] => table.scan_generic_bounded(subset, start, n, cs, |id, row| {
519 out.add_row(id, &[row[x.index()], row[y.index()]]);
520 }),
521 [x, y, z] => table.scan_generic_bounded(subset, start, n, cs, |id, row| {
522 out.add_row(id, &[row[x.index()], row[y.index()], row[z.index()]]);
523 }),
524 _ => {
525 let mut scratch = SmallVec::<[Value; 8]>::with_capacity(cols.len());
526 table.scan_generic_bounded(subset, start, n, cs, |id, row| {
527 for col in cols {
528 scratch.push(row[col.index()]);
529 }
530 out.add_row(id, &scratch);
531 scratch.clear();
532 })
533 }
534 }
535 }
536
537 fn lookup_row_vectorized(
538 &self,
539 table: &dyn Table,
540 mask: &mut Mask,
541 bindings: &mut Bindings,
542 args: &[QueryEntry],
543 col: ColumnId,
544 out_var: Variable,
545 ) {
546 let table = table.as_any().downcast_ref::<T>().unwrap();
547 let mut out = with_pool_set(PoolSet::get::<Vec<Value>>);
548 for_each_binding_with_mask!(mask, args, bindings, |iter| {
549 iter.fill_vec(&mut out, Value::stale, |_, args| {
550 table.get_row_column(args.as_slice(), col)
551 })
552 });
553 bindings.insert(out_var, &out);
554 }
555
556 fn lookup_with_default_vectorized(
557 &self,
558 table: &dyn Table,
559 mask: &mut Mask,
560 bindings: &mut Bindings,
561 args: &[QueryEntry],
562 col: ColumnId,
563 default: QueryEntry,
564 out_var: Variable,
565 ) {
566 let table = table.as_any().downcast_ref::<T>().unwrap();
567 let mut out = with_pool_set(|ps| ps.get::<Vec<Value>>());
568 for_each_binding_with_mask!(mask, args, bindings, |iter| {
569 match default {
570 QueryEntry::Var(default) => iter.zip(&bindings[default]).fill_vec(
571 &mut out,
572 Value::stale,
573 |_, (args, default)| {
574 Some(
575 table
576 .get_row_column(args.as_slice(), col)
577 .unwrap_or(*default),
578 )
579 },
580 ),
581 QueryEntry::Const(default) => iter.fill_vec(&mut out, Value::stale, |_, args| {
582 Some(
583 table
584 .get_row_column(args.as_slice(), col)
585 .unwrap_or(default),
586 )
587 }),
588 }
589 });
590 bindings.insert(out_var, &out);
591 }
592}
593
594pub struct WrappedTable {
602 inner: Box<dyn Table>,
603 wrapper: Box<dyn TableWrapper>,
604}
605
606impl WrappedTable {
607 pub(crate) fn new<T: Table>(inner: T) -> Self {
608 let wrapper = wrapper::<T>();
609 let inner = Box::new(inner);
610 Self { inner, wrapper }
611 }
612
613 pub fn dyn_clone(&self) -> Self {
615 WrappedTable {
616 inner: self.inner.dyn_clone(),
617 wrapper: self.wrapper.dyn_clone(),
618 }
619 }
620
621 pub(crate) fn as_ref(&self) -> WrappedTableRef<'_> {
622 WrappedTableRef {
623 inner: &*self.inner,
624 wrapper: &*self.wrapper,
625 }
626 }
627
628 pub fn scan_bounded(
632 &self,
633 subset: SubsetRef,
634 start: Offset,
635 n: usize,
636 out: &mut TaggedRowBuffer,
637 ) -> Option<Offset> {
638 self.as_ref().scan_bounded(subset, start, n, out)
639 }
640
641 pub(crate) fn group_by_key(&self, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex {
643 self.as_ref().group_by_key(subset, cols)
644 }
645
646 pub fn scan_project(
649 &self,
650 subset: SubsetRef,
651 cols: &[ColumnId],
652 start: Offset,
653 n: usize,
654 cs: &[Constraint],
655 out: &mut dyn RowSink,
656 ) -> Option<Offset> {
657 self.as_ref().scan_project(subset, cols, start, n, cs, out)
658 }
659
660 pub fn scan(&self, subset: SubsetRef) -> TaggedRowBuffer {
662 self.as_ref().scan(subset)
663 }
664
665 pub fn len(&self) -> usize {
667 self.inner.len()
668 }
669
670 pub fn is_empty(&self) -> bool {
672 self.inner.is_empty()
673 }
674
675 pub(crate) fn lookup_row_vectorized(
676 &self,
677 mask: &mut Mask,
678 bindings: &mut Bindings,
679 args: &[QueryEntry],
680 col: ColumnId,
681 out_var: Variable,
682 ) {
683 self.as_ref()
684 .lookup_row_vectorized(mask, bindings, args, col, out_var)
685 }
686
687 #[allow(clippy::too_many_arguments)]
688 pub(crate) fn lookup_with_default_vectorized(
689 &self,
690 mask: &mut Mask,
691 bindings: &mut Bindings,
692 args: &[QueryEntry],
693 col: ColumnId,
694 default: QueryEntry,
695 out_var: Variable,
696 ) {
697 self.as_ref()
698 .lookup_with_default_vectorized(mask, bindings, args, col, default, out_var)
699 }
700}
701
702impl Deref for WrappedTable {
703 type Target = dyn Table;
704
705 fn deref(&self) -> &Self::Target {
706 &*self.inner
707 }
708}
709
710impl DerefMut for WrappedTable {
711 fn deref_mut(&mut self) -> &mut Self::Target {
712 &mut *self.inner
713 }
714}
715
716pub(crate) trait TableWrapper: Send + Sync {
717 fn dyn_clone(&self) -> Box<dyn TableWrapper>;
718 fn scan_bounded(
719 &self,
720 table: &dyn Table,
721 subset: SubsetRef,
722 start: Offset,
723 n: usize,
724 out: &mut TaggedRowBuffer,
725 ) -> Option<Offset>;
726 fn group_by_key(&self, table: &dyn Table, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex;
727
728 fn for_each_col(
732 &self,
733 table: &dyn Table,
734 subset: SubsetRef,
735 col: ColumnId,
736 f: &mut dyn FnMut(RowId, Value),
737 );
738
739 fn collect_col_pairs(
744 &self,
745 table: &dyn Table,
746 subset: SubsetRef,
747 col: ColumnId,
748 out: &mut Vec<(Value, RowId)>,
749 );
750
751 #[allow(clippy::too_many_arguments)]
752 fn scan_project(
753 &self,
754 table: &dyn Table,
755 subset: SubsetRef,
756 cols: &[ColumnId],
757 start: Offset,
758 n: usize,
759 cs: &[Constraint],
760 out: &mut dyn RowSink,
761 ) -> Option<Offset>;
762
763 fn scan(&self, table: &dyn Table, subset: SubsetRef) -> TaggedRowBuffer {
764 let arity = table.spec().arity();
765 let mut buf = TaggedRowBuffer::new(arity);
766 assert!(
767 self.scan_bounded(table, subset, Offset::new(0), usize::MAX, &mut buf)
768 .is_none()
769 );
770 buf
771 }
772
773 #[allow(clippy::too_many_arguments)]
774 fn lookup_row_vectorized(
775 &self,
776 table: &dyn Table,
777 mask: &mut Mask,
778 bindings: &mut Bindings,
779 args: &[QueryEntry],
780 col: ColumnId,
781 out_var: Variable,
782 );
783
784 #[allow(clippy::too_many_arguments)]
785 fn lookup_with_default_vectorized(
786 &self,
787 table: &dyn Table,
788 mask: &mut Mask,
789 bindings: &mut Bindings,
790 args: &[QueryEntry],
791 col: ColumnId,
792 default: QueryEntry,
793 out_var: Variable,
794 );
795}
796
797#[derive(Clone, Copy)]
801pub struct WrappedTableRef<'a> {
802 inner: &'a dyn Table,
803 wrapper: &'a dyn TableWrapper,
804}
805
806impl WrappedTableRef<'_> {
807 pub(crate) fn with_wrapper<T: Table, R>(
808 inner: &T,
809 f: impl for<'a> FnOnce(WrappedTableRef<'a>) -> R,
810 ) -> R {
811 let wrapper = WrapperImpl::<T>(PhantomData);
812 f(WrappedTableRef {
813 inner,
814 wrapper: &wrapper,
815 })
816 }
817
818 pub fn scan_bounded(
822 &self,
823 subset: SubsetRef,
824 start: Offset,
825 n: usize,
826 out: &mut TaggedRowBuffer,
827 ) -> Option<Offset> {
828 self.wrapper.scan_bounded(self.inner, subset, start, n, out)
829 }
830
831 pub(crate) fn group_by_key(&self, subset: SubsetRef, cols: &[ColumnId]) -> TupleIndex {
833 self.wrapper.group_by_key(self.inner, subset, cols)
834 }
835
836 pub(crate) fn for_each_col(
840 &self,
841 subset: SubsetRef,
842 col: ColumnId,
843 f: &mut dyn FnMut(RowId, Value),
844 ) {
845 self.wrapper.for_each_col(self.inner, subset, col, f);
846 }
847
848 pub(crate) fn collect_col_pairs(
851 &self,
852 subset: SubsetRef,
853 col: ColumnId,
854 out: &mut Vec<(Value, RowId)>,
855 ) {
856 self.wrapper.collect_col_pairs(self.inner, subset, col, out);
857 }
858
859 pub fn scan_project(
862 &self,
863 subset: SubsetRef,
864 cols: &[ColumnId],
865 start: Offset,
866 n: usize,
867 cs: &[Constraint],
868 out: &mut dyn RowSink,
869 ) -> Option<Offset> {
870 self.wrapper
871 .scan_project(self.inner, subset, cols, start, n, cs, out)
872 }
873
874 pub fn scan(&self, subset: SubsetRef) -> TaggedRowBuffer {
876 self.wrapper.scan(self.inner, subset)
877 }
878
879 pub fn len(&self) -> usize {
881 self.inner.len()
882 }
883
884 pub(crate) fn lookup_row_vectorized(
885 &self,
886 mask: &mut Mask,
887 bindings: &mut Bindings,
888 args: &[QueryEntry],
889 col: ColumnId,
890 out_var: Variable,
891 ) {
892 self.wrapper
893 .lookup_row_vectorized(self.inner, mask, bindings, args, col, out_var);
894 }
895
896 #[allow(clippy::too_many_arguments)]
897 pub(crate) fn lookup_with_default_vectorized(
898 &self,
899 mask: &mut Mask,
900 bindings: &mut Bindings,
901 args: &[QueryEntry],
902 col: ColumnId,
903 default: QueryEntry,
904 out_var: Variable,
905 ) {
906 self.wrapper.lookup_with_default_vectorized(
907 self.inner, mask, bindings, args, col, default, out_var,
908 );
909 }
910}
911
912impl Deref for WrappedTableRef<'_> {
913 type Target = dyn Table;
914
915 fn deref(&self) -> &Self::Target {
916 self.inner
917 }
918}