|
|
@ -5,12 +5,13 @@ use crate::error::CozoError::LogicError;
|
|
|
|
use crate::error::Result;
|
|
|
|
use crate::error::Result;
|
|
|
|
use crate::relation::data::{DataKind, EMPTY_DATA};
|
|
|
|
use crate::relation::data::{DataKind, EMPTY_DATA};
|
|
|
|
use crate::relation::table::MegaTuple;
|
|
|
|
use crate::relation::table::MegaTuple;
|
|
|
|
use crate::relation::tuple::{CowSlice, CowTuple, OwnTuple, Tuple};
|
|
|
|
use crate::relation::tuple::{CowSlice, CowTuple, OwnTuple, SliceTuple, Tuple};
|
|
|
|
use crate::relation::value::Value;
|
|
|
|
use crate::relation::value::Value;
|
|
|
|
use cozorocks::IteratorPtr;
|
|
|
|
use cozorocks::IteratorPtr;
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
use std::fmt::{Debug, Formatter};
|
|
|
|
use std::fmt::{Debug, Formatter};
|
|
|
|
use std::{iter, mem};
|
|
|
|
use std::{iter, mem};
|
|
|
|
|
|
|
|
use std::ops::Range;
|
|
|
|
|
|
|
|
|
|
|
|
pub enum IteratorSlot<'a> {
|
|
|
|
pub enum IteratorSlot<'a> {
|
|
|
|
Dummy,
|
|
|
|
Dummy,
|
|
|
@ -26,20 +27,39 @@ impl<'a> Debug for IteratorSlot<'a> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub enum TableRowGetter<'a> {
|
|
|
|
pub enum TableRowGetterSlot<'a> {
|
|
|
|
Dummy,
|
|
|
|
Dummy,
|
|
|
|
Reified {
|
|
|
|
Reified(TableRowGetter<'a>),
|
|
|
|
sess: &'a Session<'a>,
|
|
|
|
}
|
|
|
|
key_cache: OwnTuple,
|
|
|
|
|
|
|
|
in_root: bool,
|
|
|
|
#[derive(Clone)]
|
|
|
|
},
|
|
|
|
pub struct TableRowGetter<'a> {
|
|
|
|
|
|
|
|
pub sess: &'a Session<'a>,
|
|
|
|
|
|
|
|
pub key_cache: OwnTuple,
|
|
|
|
|
|
|
|
pub in_root: bool,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Debug for TableRowGetter<'a> {
|
|
|
|
impl<'a> TableRowGetter<'a> {
|
|
|
|
|
|
|
|
pub fn reset(&mut self) {
|
|
|
|
|
|
|
|
self.key_cache.truncate_all();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get<'b, T: Iterator<Item=Value<'b>>>(&mut self, vals: T) -> Result<Option<SliceTuple>> {
|
|
|
|
|
|
|
|
for val in vals {
|
|
|
|
|
|
|
|
self.key_cache.push_value(&val);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let val = self.sess.txn.get(
|
|
|
|
|
|
|
|
self.in_root,
|
|
|
|
|
|
|
|
if self.in_root { &self.sess.perm_cf } else { &self.sess.temp_cf },
|
|
|
|
|
|
|
|
&self.key_cache)?;
|
|
|
|
|
|
|
|
Ok(val.map(Tuple::new))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Debug for TableRowGetterSlot<'a> {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
match self {
|
|
|
|
TableRowGetter::Dummy => write!(f, "DummyRowGetter"),
|
|
|
|
TableRowGetterSlot::Dummy => write!(f, "DummyRowGetter"),
|
|
|
|
TableRowGetter::Reified { .. } => write!(f, "TableRowGetter"),
|
|
|
|
TableRowGetterSlot::Reified { .. } => write!(f, "TableRowGetter"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -88,16 +108,15 @@ pub enum ExecPlan<'a> {
|
|
|
|
it: IteratorSlot<'a>,
|
|
|
|
it: IteratorSlot<'a>,
|
|
|
|
info: TableInfo,
|
|
|
|
info: TableInfo,
|
|
|
|
binding: Option<String>,
|
|
|
|
binding: Option<String>,
|
|
|
|
getter: TableRowGetter<'a>,
|
|
|
|
getter: TableRowGetterSlot<'a>,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ChainJoinItPlan {
|
|
|
|
ChainJoinItPlan {
|
|
|
|
left: Box<ExecPlan<'a>>,
|
|
|
|
left: Box<ExecPlan<'a>>,
|
|
|
|
right: TableRowGetter<'a>,
|
|
|
|
right: TableRowGetterSlot<'a>,
|
|
|
|
right_info: TableInfo,
|
|
|
|
right_info: TableInfo,
|
|
|
|
right_binding: Option<String>,
|
|
|
|
right_binding: Option<String>,
|
|
|
|
kind: ChainJoinKind,
|
|
|
|
kind: ChainJoinKind,
|
|
|
|
left_outer: bool,
|
|
|
|
left_outer: bool,
|
|
|
|
right_outer: bool,
|
|
|
|
|
|
|
|
},
|
|
|
|
},
|
|
|
|
// IndexIt {it: ..}
|
|
|
|
// IndexIt {it: ..}
|
|
|
|
KeySortedWithAssocItPlan {
|
|
|
|
KeySortedWithAssocItPlan {
|
|
|
@ -186,10 +205,10 @@ impl<'a> ExecPlan<'a> {
|
|
|
|
todo!()
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ExecPlan::ChainJoinItPlan {
|
|
|
|
ExecPlan::ChainJoinItPlan {
|
|
|
|
left, right_info, ..
|
|
|
|
left, ..
|
|
|
|
} => {
|
|
|
|
} => {
|
|
|
|
let (l1, l2) = left.tuple_widths();
|
|
|
|
let (l1, l2) = left.tuple_widths();
|
|
|
|
(l1 + 1, l2 + 1)
|
|
|
|
(l1, l2 + 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -335,10 +354,107 @@ impl<'a> ExecPlan<'a> {
|
|
|
|
ExecPlan::EdgeBwdItPlan { .. } => {
|
|
|
|
ExecPlan::EdgeBwdItPlan { .. } => {
|
|
|
|
todo!()
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ExecPlan::ChainJoinItPlan { .. } => {
|
|
|
|
ExecPlan::ChainJoinItPlan { left, right, left_outer, kind, right_info, .. } => {
|
|
|
|
|
|
|
|
match right {
|
|
|
|
|
|
|
|
TableRowGetterSlot::Dummy => Err(LogicError("Uninitialized chain join".to_string())),
|
|
|
|
|
|
|
|
TableRowGetterSlot::Reified(right) => {
|
|
|
|
|
|
|
|
Ok(match kind {
|
|
|
|
|
|
|
|
ChainJoinKind::NodeToFwdEdge => Box::new(NodeToFwdEdgeChainJoinIterator {
|
|
|
|
|
|
|
|
left: left.iter()?,
|
|
|
|
|
|
|
|
right: right.clone(),
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
ChainJoinKind::NodeToBwdEdge => todo!(),
|
|
|
|
|
|
|
|
ChainJoinKind::FwdEdgeToNode => {
|
|
|
|
|
|
|
|
let key_indices = Range {
|
|
|
|
|
|
|
|
start: 1,
|
|
|
|
|
|
|
|
end: right_info.src_key_typing.len() + 1,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Box::new(EdgeToNodeChainJoinIterator {
|
|
|
|
|
|
|
|
left: left.iter()?,
|
|
|
|
|
|
|
|
right: right.clone(),
|
|
|
|
|
|
|
|
left_outer: *left_outer,
|
|
|
|
|
|
|
|
key_indices,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ChainJoinKind::BwdEdgeToNode => {
|
|
|
|
|
|
|
|
let key_indices = Range {
|
|
|
|
|
|
|
|
start: right_info.src_key_typing.len() + 2,
|
|
|
|
|
|
|
|
end: right_info.src_key_typing.len() + right_info.dst_key_typing.len() + 2,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Box::new(EdgeToNodeChainJoinIterator {
|
|
|
|
|
|
|
|
left: left.iter()?,
|
|
|
|
|
|
|
|
right: right.clone(),
|
|
|
|
|
|
|
|
left_outer: *left_outer,
|
|
|
|
|
|
|
|
key_indices,
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Implementation notice
|
|
|
|
|
|
|
|
// Never define `.next()` recursively for iterators below, otherwise stackoverflow is almost
|
|
|
|
|
|
|
|
// guaranteed (but may not show for test data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct NodeToFwdEdgeChainJoinIterator<'a> {
|
|
|
|
|
|
|
|
left: Box<dyn Iterator<Item=Result<MegaTuple>> + 'a>,
|
|
|
|
|
|
|
|
right: TableRowGetter<'a>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Iterator for NodeToFwdEdgeChainJoinIterator<'a> {
|
|
|
|
|
|
|
|
type Item = Result<MegaTuple>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
todo!()
|
|
|
|
todo!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct EdgeToNodeChainJoinIterator<'a> {
|
|
|
|
|
|
|
|
left: Box<dyn Iterator<Item=Result<MegaTuple>> + 'a>,
|
|
|
|
|
|
|
|
right: TableRowGetter<'a>,
|
|
|
|
|
|
|
|
left_outer: bool,
|
|
|
|
|
|
|
|
key_indices: Range<usize>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a> Iterator for EdgeToNodeChainJoinIterator<'a> {
|
|
|
|
|
|
|
|
type Item = Result<MegaTuple>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
|
|
match self.left.next() {
|
|
|
|
|
|
|
|
None => return None,
|
|
|
|
|
|
|
|
Some(Err(e)) => return Some(Err(e)),
|
|
|
|
|
|
|
|
Some(Ok(mut left_tuple)) => {
|
|
|
|
|
|
|
|
self.right.reset();
|
|
|
|
|
|
|
|
let key_iter = self.key_indices.clone().map(|i|
|
|
|
|
|
|
|
|
left_tuple.keys.last().unwrap().get(i).unwrap()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
match self.right.get(key_iter) {
|
|
|
|
|
|
|
|
Ok(v) => {
|
|
|
|
|
|
|
|
match v {
|
|
|
|
|
|
|
|
None => {
|
|
|
|
|
|
|
|
if self.left_outer {
|
|
|
|
|
|
|
|
left_tuple.vals.push(OwnTuple::empty_tuple().into());
|
|
|
|
|
|
|
|
return Some(Ok(left_tuple));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// else fall through, go to the next iteration
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(right_val) => {
|
|
|
|
|
|
|
|
left_tuple.vals.push(right_val.into());
|
|
|
|
|
|
|
|
return Some(Ok(left_tuple));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(e) => return Some(Err(e))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -472,17 +588,18 @@ impl<'a> Iterator for BagsUnionIterator<'a> {
|
|
|
|
type Item = Result<MegaTuple>;
|
|
|
|
type Item = Result<MegaTuple>;
|
|
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let cur_it = self.bags.get_mut(self.current).unwrap();
|
|
|
|
let cur_it = self.bags.get_mut(self.current).unwrap();
|
|
|
|
match cur_it.next() {
|
|
|
|
match cur_it.next() {
|
|
|
|
None => {
|
|
|
|
None => {
|
|
|
|
if self.current == self.bags.len() - 1 {
|
|
|
|
if self.current == self.bags.len() - 1 {
|
|
|
|
None
|
|
|
|
return None;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
self.current += 1;
|
|
|
|
self.current += 1;
|
|
|
|
self.next()
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
v => v,
|
|
|
|
v => return v,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|