diff --git a/src/db/iterator.rs b/src/db/iterator.rs index 7e25023a..58b1f86f 100644 --- a/src/db/iterator.rs +++ b/src/db/iterator.rs @@ -31,7 +31,9 @@ pub enum TableRowGetter { impl Debug for TableRowGetter { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { TableRowGetter::Dummy => write!(f, "DummyRowGetter") } + match self { + TableRowGetter::Dummy => write!(f, "DummyRowGetter"), + } } } @@ -55,7 +57,7 @@ pub enum ChainJoinKind { NodeToFwdEdge, NodeToBwdEdge, FwdEdgeToNode, - BwdEdgeToNode + BwdEdgeToNode, } #[derive(Debug)] @@ -87,7 +89,7 @@ pub enum ExecPlan<'a> { right_info: TableInfo, kind: ChainJoinKind, left_outer: bool, - right_outer: bool + right_outer: bool, }, // IndexIt {it: ..} KeySortedWithAssocItPlan { @@ -163,12 +165,8 @@ impl<'a> ExecPlan<'a> { } ExecPlan::KeyedUnionItPlan { left, .. } => left.tuple_widths(), ExecPlan::KeyedDifferenceItPlan { left, .. } => left.tuple_widths(), - ExecPlan::FilterItPlan { source, .. } => { - source.tuple_widths() - } - ExecPlan::EvalItPlan { source, .. } => { - source.tuple_widths() - } + ExecPlan::FilterItPlan { source, .. } => source.tuple_widths(), + ExecPlan::EvalItPlan { source, .. } => source.tuple_widths(), ExecPlan::BagsUnionIt { bags } => { if bags.is_empty() { (0, 0) @@ -202,7 +200,7 @@ impl<'a> OutputItPlan<'a> { } impl<'a> ExecPlan<'a> { - pub fn iter(&'a self) -> Result> + 'a>> { + pub fn iter(&'a self) -> Result> + 'a>> { match self { ExecPlan::NodeItPlan { it, info, .. } => { let it = it.try_get()?; @@ -217,7 +215,11 @@ impl<'a> ExecPlan<'a> { prefix_tuple.push_int(info.src_table_id.id); it.seek(prefix_tuple); - Ok(Box::new(EdgeIterator { it, started: false, src_table_id: info.src_table_id.id })) + Ok(Box::new(EdgeIterator { + it, + started: false, + src_table_id: info.src_table_id.id, + })) } ExecPlan::EdgeKeyOnlyBwdItPlan { it, info, .. } => { let it = it.try_get()?; @@ -225,7 +227,11 @@ impl<'a> ExecPlan<'a> { prefix_tuple.push_int(info.dst_table_id.id); it.seek(prefix_tuple); - Ok(Box::new(EdgeKeyOnlyBwdIterator { it, started: false, dst_table_id: info.dst_table_id.id })) + Ok(Box::new(EdgeKeyOnlyBwdIterator { + it, + started: false, + dst_table_id: info.dst_table_id.id, + })) } ExecPlan::KeySortedWithAssocItPlan { main, associates } => { let buffer = iter::repeat_with(|| None).take(associates.len()).collect(); @@ -259,7 +265,7 @@ impl<'a> ExecPlan<'a> { ExecPlan::EvalItPlan { source: it, keys, - vals + vals, } => Ok(Box::new(EvalIterator { it: it.iter()?, keys, @@ -303,12 +309,14 @@ impl<'a> ExecPlan<'a> { left: left.iter()?, right: right.iter()?, })), - ExecPlan::KeyedDifferenceItPlan { left, right } => Ok(Box::new(KeyedDifferenceIterator { - left: left.iter()?, - right: right.iter()?, - right_cache: None, - started: false, - })), + ExecPlan::KeyedDifferenceItPlan { left, right } => { + Ok(Box::new(KeyedDifferenceIterator { + left: left.iter()?, + right: right.iter()?, + right_cache: None, + started: false, + })) + } ExecPlan::BagsUnionIt { bags } => { let bags = bags.iter().map(|i| i.iter()).collect::>>()?; Ok(Box::new(BagsUnionIterator { bags, current: 0 })) @@ -324,8 +332,8 @@ impl<'a> ExecPlan<'a> { } pub struct KeyedUnionIterator<'a> { - left: Box> + 'a>, - right: Box> + 'a>, + left: Box> + 'a>, + right: Box> + 'a>, } impl<'a> Iterator for KeyedUnionIterator<'a> { @@ -376,8 +384,8 @@ impl<'a> Iterator for KeyedUnionIterator<'a> { } pub struct KeyedDifferenceIterator<'a> { - left: Box> + 'a>, - right: Box> + 'a>, + left: Box> + 'a>, + right: Box> + 'a>, right_cache: Option, started: bool, } @@ -445,7 +453,7 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> { } pub struct BagsUnionIterator<'a> { - bags: Vec> + 'a>>, + bags: Vec> + 'a>>, current: usize, } @@ -568,7 +576,7 @@ impl<'a> Iterator for EdgeKeyOnlyBwdIterator<'a> { } pub struct KeySortedWithAssocIterator<'a> { - main: Box> + 'a>, + main: Box> + 'a>, associates: Vec>, buffer: Vec>, } @@ -588,7 +596,8 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> { }; let l = self.associates.len(); // initialize vector for associate values - let mut assoc_vals: Vec> = iter::repeat_with(|| None).take(l).collect(); + let mut assoc_vals: Vec> = + iter::repeat_with(|| None).take(l).collect(); // let l = assoc_vals.len(); #[allow(clippy::needless_range_loop)] for i in 0..l { @@ -651,8 +660,8 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> { } pub struct OuterMergeJoinIterator<'a> { - left: Box> + 'a>, - right: Box> + 'a>, + left: Box> + 'a>, + right: Box> + 'a>, left_outer: bool, right_outer: bool, left_keys: &'a [(TableId, ColId)], @@ -800,8 +809,8 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> { } pub struct MergeJoinIterator<'a> { - left: Box> + 'a>, - right: Box> + 'a>, + left: Box> + 'a>, + right: Box> + 'a>, left_keys: &'a [(TableId, ColId)], right_keys: &'a [(TableId, ColId)], } @@ -861,10 +870,10 @@ impl<'a> Iterator for MergeJoinIterator<'a> { } pub struct CartesianProdIterator<'a> { - left: Box> + 'a>, + left: Box> + 'a>, left_cache: MegaTuple, right_source: &'a ExecPlan<'a>, - right: Box> + 'a>, + right: Box> + 'a>, } impl<'a> Iterator for CartesianProdIterator<'a> { @@ -907,7 +916,7 @@ impl<'a> Iterator for CartesianProdIterator<'a> { } pub struct FilterIterator<'a> { - it: Box> + 'a>, + it: Box> + 'a>, filter: &'a Value<'a>, } @@ -935,7 +944,7 @@ impl<'a> Iterator for FilterIterator<'a> { } pub struct OutputIterator<'a> { - it: Box> + 'a>, + it: Box> + 'a>, transform: &'a Value<'a>, } @@ -961,7 +970,7 @@ impl<'a> Iterator for OutputIterator<'a> { } pub struct EvalIterator<'a> { - it: Box> + 'a>, + it: Box> + 'a>, keys: &'a [(String, Value<'a>)], vals: &'a [(String, Value<'a>)], } @@ -1072,11 +1081,14 @@ mod tests { .next() .unwrap(); let sel_pat = sess.parse_select_pattern(p).unwrap(); - let sel_vals = Value::Dict(sel_pat.vals.into_iter().map(|(k, v)| (k.into(), v)).collect()); - let amap = sess.node_accessor_map( - &from_pat.binding, - &from_pat.info, + let sel_vals = Value::Dict( + sel_pat + .vals + .into_iter() + .map(|(k, v)| (k.into(), v)) + .collect(), ); + let amap = sess.node_accessor_map(&from_pat.binding, &from_pat.info); let (_, vals) = sess .partial_eval(sel_vals, &Default::default(), &amap) .unwrap(); @@ -1211,7 +1223,6 @@ mod tests { let duration = start.elapsed(); println!("Time elapsed {:?}", duration); - let s = r##"from (e:Employee)-[hj:HasJob]->(j:Job) where e.id == 110 select { fname: e.first_name, salary: hj.salary, job: j.title }"##; diff --git a/src/db/plan.rs b/src/db/plan.rs index d1558123..8520d462 100644 --- a/src/db/plan.rs +++ b/src/db/plan.rs @@ -1,16 +1,16 @@ -use std::collections::btree_map::Entry; use crate::db::engine::Session; use crate::db::iterator::{ChainJoinKind, ExecPlan, IteratorSlot, OutputItPlan, TableRowGetter}; use crate::db::query::{EdgeOrNodeEl, EdgeOrNodeKind, FromEl, Selection}; use crate::db::table::{ColId, TableId, TableInfo}; +use crate::error::CozoError::LogicError; use crate::error::Result; use crate::parser::Rule; +use crate::relation::data::DataKind; use crate::relation::value::{StaticValue, Value}; use cozorocks::IteratorPtr; use pest::iterators::Pair; +use std::collections::btree_map::Entry; use std::collections::BTreeMap; -use crate::error::CozoError::LogicError; -use crate::relation::data::DataKind; #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum OuterJoinType { @@ -40,20 +40,43 @@ fn merge_accessor_map(mut left: AccessorMap, right: AccessorMap) -> AccessorMap fn convert_to_relative_accessor_map(amap: AccessorMap) -> AccessorMap { // TODO this only handles the simplest case - fn convert_inner(inner: BTreeMap) -> BTreeMap { - inner.into_iter().map(|(k, (_tid, cid))| { - (k, (TableId::new(false, 0), cid)) - }).collect() + fn convert_inner( + inner: BTreeMap, + ) -> BTreeMap { + inner + .into_iter() + .map(|(k, (_tid, cid))| (k, (TableId::new(false, 0), cid))) + .collect() } - amap.into_iter().map(|(k, v)| (k, convert_inner(v))).collect() + amap.into_iter() + .map(|(k, v)| (k, convert_inner(v))) + .collect() } fn shift_accessor_map(amap: AccessorMap, (keyshift, valshift): (usize, usize)) -> AccessorMap { - let shift_inner = |inner: BTreeMap| -> BTreeMap { - inner.into_iter().map(|(k, (tid, cid))| { - (k, (TableId::new(tid.in_root, tid.id + if cid.is_key { keyshift as i64 } else { valshift as i64 }), cid)) - }).collect() - }; + let shift_inner = + |inner: BTreeMap| -> BTreeMap { + inner + .into_iter() + .map(|(k, (tid, cid))| { + ( + k, + ( + TableId::new( + tid.in_root, + tid.id + + if cid.is_key { + keyshift as i64 + } else { + valshift as i64 + }, + ), + cid, + ), + ) + }) + .collect() + }; amap.into_iter().map(|(k, v)| (k, shift_inner(v))).collect() } @@ -64,7 +87,10 @@ impl<'a> Session<'a> { v.0 }) } - fn do_reify_intermediate_plan(&'a self, plan: ExecPlan<'a>) -> Result<(ExecPlan<'a>, AccessorMap)> { + fn do_reify_intermediate_plan( + &'a self, + plan: ExecPlan<'a>, + ) -> Result<(ExecPlan<'a>, AccessorMap)> { let res = match plan { ExecPlan::NodeItPlan { info, binding, .. } => { let amap = match &binding { @@ -80,11 +106,7 @@ impl<'a> Session<'a> { self.txn.iterator(true, &self.temp_cf) }; let it = IteratorSlot::Reified(it); - let plan = ExecPlan::NodeItPlan { - it, - info, - binding, - }; + let plan = ExecPlan::NodeItPlan { it, info, binding }; (plan, amap) } ExecPlan::EdgeItPlan { info, binding, .. } => { @@ -101,11 +123,7 @@ impl<'a> Session<'a> { self.txn.iterator(true, &self.temp_cf) }; let it = IteratorSlot::Reified(it); - let plan = ExecPlan::EdgeItPlan { - it, - info, - binding, - }; + let plan = ExecPlan::EdgeItPlan { it, info, binding }; (plan, amap) } ExecPlan::EdgeBwdItPlan { .. } => { @@ -136,16 +154,26 @@ impl<'a> Session<'a> { }; (plan, amap) } - ExecPlan::EvalItPlan { source: it, keys, vals } => { + ExecPlan::EvalItPlan { + source: it, + keys, + vals, + } => { let (inner, amap) = self.do_reify_intermediate_plan(*it)?; - let keys = keys.into_iter().map(|(k, v)| -> Result<_> { - let (_, v) = self.partial_eval(v, &Default::default(), &amap)?; - Ok((k, v)) - }).collect::>>()?; - let vals = vals.into_iter().map(|(k, v)| -> Result<_> { - let (_, v) = self.partial_eval(v, &Default::default(), &amap)?; - Ok((k, v)) - }).collect::>>()?; + let keys = keys + .into_iter() + .map(|(k, v)| -> Result<_> { + let (_, v) = self.partial_eval(v, &Default::default(), &amap)?; + Ok((k, v)) + }) + .collect::>>()?; + let vals = vals + .into_iter() + .map(|(k, v)| -> Result<_> { + let (_, v) = self.partial_eval(v, &Default::default(), &amap)?; + Ok((k, v)) + }) + .collect::>>()?; let plan = ExecPlan::EvalItPlan { source: inner.into(), keys, @@ -154,7 +182,14 @@ impl<'a> Session<'a> { (plan, amap) } ExecPlan::BagsUnionIt { .. } => todo!(), - ExecPlan::ChainJoinItPlan { .. } => { + ExecPlan::ChainJoinItPlan { + left, + right, + right_info, + kind, + left_outer, + right_outer, + } => { todo!() } }; @@ -163,7 +198,11 @@ impl<'a> Session<'a> { pub fn reify_output_plan(&'a self, plan: ExecPlan<'a>) -> Result> { let plan = self.reify_intermediate_plan(plan)?; let plan = match plan { - ExecPlan::EvalItPlan { source: it, mut keys, vals } => { + ExecPlan::EvalItPlan { + source: it, + mut keys, + vals, + } => { keys.extend(vals); let filter = Value::Dict(keys.into_iter().map(|(k, v)| (k.into(), v)).collect()); OutputItPlan { @@ -195,82 +234,80 @@ impl<'a> Session<'a> { self.convert_select_data_to_plan(plan, select_data) } fn convert_from_data_to_plan(&self, from_data: Vec) -> Result { - let convert_el = |el| - match el { - FromEl::Simple(el) => { - match el.info.kind { - DataKind::Node => { - Ok(ExecPlan::NodeItPlan { - it: IteratorSlot::Dummy, - info: el.info, - binding: Some(el.binding), - }) - } - DataKind::Edge => { - Ok(ExecPlan::EdgeItPlan { - it: IteratorSlot::Dummy, - info: el.info, - binding: Some(el.binding), - }) - } - _ => Err(LogicError("Wrong type for table binding".to_string())) - } - } - FromEl::Chain(ch) => { - let mut it = ch.into_iter(); - let nxt = it.next().ok_or_else(|| LogicError("Empty chain not allowed".to_string()))?; - let mut prev_kind = nxt.kind; - let mut prev_left_outer = nxt.left_outer_marker; - let mut plan = match prev_kind { - EdgeOrNodeKind::Node => { - ExecPlan::NodeItPlan { - it: IteratorSlot::Dummy, - info: nxt.info, - binding: nxt.binding, + let convert_el = |el| match el { + FromEl::Simple(el) => match el.info.kind { + DataKind::Node => Ok(ExecPlan::NodeItPlan { + it: IteratorSlot::Dummy, + info: el.info, + binding: Some(el.binding), + }), + DataKind::Edge => Ok(ExecPlan::EdgeItPlan { + it: IteratorSlot::Dummy, + info: el.info, + binding: Some(el.binding), + }), + _ => Err(LogicError("Wrong type for table binding".to_string())), + }, + FromEl::Chain(ch) => { + let mut it = ch.into_iter(); + let nxt = it + .next() + .ok_or_else(|| LogicError("Empty chain not allowed".to_string()))?; + let mut prev_kind = nxt.kind; + let mut prev_left_outer = nxt.left_outer_marker; + let mut plan = match prev_kind { + EdgeOrNodeKind::Node => ExecPlan::NodeItPlan { + it: IteratorSlot::Dummy, + info: nxt.info, + binding: nxt.binding, + }, + EdgeOrNodeKind::FwdEdge => ExecPlan::EdgeItPlan { + it: IteratorSlot::Dummy, + info: nxt.info, + binding: nxt.binding, + }, + EdgeOrNodeKind::BwdEdge => ExecPlan::EdgeBwdItPlan { + it: IteratorSlot::Dummy, + info: nxt.info, + binding: nxt.binding, + getter: TableRowGetter::Dummy, + }, + }; + for el in it { + plan = ExecPlan::ChainJoinItPlan { + left: plan.into(), + right: TableRowGetter::Dummy, + right_info: el.info, + kind: match (prev_kind, el.kind) { + (EdgeOrNodeKind::Node, EdgeOrNodeKind::FwdEdge) => { + ChainJoinKind::NodeToFwdEdge + } + (EdgeOrNodeKind::Node, EdgeOrNodeKind::BwdEdge) => { + ChainJoinKind::NodeToBwdEdge } - } - EdgeOrNodeKind::FwdEdge => { - ExecPlan::EdgeItPlan { - it: IteratorSlot::Dummy, - info: nxt.info, - binding: nxt.binding, + (EdgeOrNodeKind::FwdEdge, EdgeOrNodeKind::Node) => { + ChainJoinKind::FwdEdgeToNode } - } - EdgeOrNodeKind::BwdEdge => { - ExecPlan::EdgeBwdItPlan { - it: IteratorSlot::Dummy, - info: nxt.info, - binding: nxt.binding, - getter: TableRowGetter::Dummy + (EdgeOrNodeKind::BwdEdge, EdgeOrNodeKind::Node) => { + ChainJoinKind::BwdEdgeToNode } - } + _ => unreachable!(), + }, + left_outer: prev_left_outer, + right_outer: el.right_outer_marker, }; - for el in it { - plan = ExecPlan::ChainJoinItPlan { - left: plan.into(), - right: TableRowGetter::Dummy, - right_info: el.info, - kind: match (prev_kind, el.kind) { - (EdgeOrNodeKind::Node, EdgeOrNodeKind::FwdEdge) => ChainJoinKind::NodeToFwdEdge, - (EdgeOrNodeKind::Node, EdgeOrNodeKind::BwdEdge) => ChainJoinKind::NodeToBwdEdge, - (EdgeOrNodeKind::FwdEdge, EdgeOrNodeKind::Node) => ChainJoinKind::FwdEdgeToNode, - (EdgeOrNodeKind::BwdEdge, EdgeOrNodeKind::Node) => ChainJoinKind::BwdEdgeToNode, - _ => unreachable!() - }, - left_outer: prev_left_outer, - right_outer: el.right_outer_marker - }; - prev_kind = el.kind; - prev_left_outer = el.left_outer_marker; - } - println!("{:#?}", plan); - Ok(plan) + prev_kind = el.kind; + prev_left_outer = el.left_outer_marker; } - }; + println!("{:#?}", plan); + Ok(plan) + } + }; let mut from_data = from_data.into_iter(); - let fst = from_data.next().ok_or_else(|| - LogicError("Empty from clause".to_string()))?; + let fst = from_data + .next() + .ok_or_else(|| LogicError("Empty from clause".to_string()))?; let mut res = convert_el(fst)?; for nxt in from_data { let nxt = convert_el(nxt)?; @@ -281,11 +318,7 @@ impl<'a> Session<'a> { } Ok(res) } - pub(crate) fn node_accessor_map( - &self, - binding: &str, - info: &TableInfo, - ) -> AccessorMap { + pub(crate) fn node_accessor_map(&self, binding: &str, info: &TableInfo) -> AccessorMap { let mut ret = BTreeMap::new(); for (i, (k, _)) in info.key_typing.iter().enumerate() { ret.insert(k.into(), (info.table_id, (true, i).into())); @@ -303,22 +336,30 @@ impl<'a> Session<'a> { } BTreeMap::from([(binding.to_string(), ret)]) } - pub(crate) fn edge_accessor_map( - &self, - binding: &str, - info: &TableInfo, - ) -> AccessorMap { + pub(crate) fn edge_accessor_map(&self, binding: &str, info: &TableInfo) -> AccessorMap { let mut ret = BTreeMap::new(); let src_key_len = info.src_key_typing.len(); let dst_key_len = info.dst_key_typing.len(); for (i, (k, _)) in info.src_key_typing.iter().enumerate() { - ret.insert("_src_".to_string() + k, (info.table_id, (true, 1 + i).into())); + ret.insert( + "_src_".to_string() + k, + (info.table_id, (true, 1 + i).into()), + ); } for (i, (k, _)) in info.dst_key_typing.iter().enumerate() { - ret.insert("_dst_".to_string() + k, (info.table_id, (true, 2 + src_key_len + i).into())); + ret.insert( + "_dst_".to_string() + k, + (info.table_id, (true, 2 + src_key_len + i).into()), + ); } for (i, (k, _)) in info.key_typing.iter().enumerate() { - ret.insert(k.into(), (info.table_id, (true, 2 + src_key_len + dst_key_len + i).into())); + ret.insert( + k.into(), + ( + info.table_id, + (true, 2 + src_key_len + dst_key_len + i).into(), + ), + ); } for (i, (k, _)) in info.val_typing.iter().enumerate() { ret.insert(k.into(), (info.table_id, (false, i).into())); @@ -341,12 +382,10 @@ impl<'a> Session<'a> { let where_data = self.partial_eval(where_data, &Default::default(), &Default::default()); let plan = match where_data?.1 { Value::Bool(true) => plan, - v => { - ExecPlan::FilterItPlan { - source: Box::new(plan), - filter: v, - } - } + v => ExecPlan::FilterItPlan { + source: Box::new(plan), + filter: v, + }, }; Ok(plan) } @@ -396,4 +435,4 @@ impl<'a> Session<'a> { mod tests { #[test] fn from_data() {} -} \ No newline at end of file +} diff --git a/src/db/query.rs b/src/db/query.rs index 98dcaffd..50339022 100644 --- a/src/db/query.rs +++ b/src/db/query.rs @@ -248,7 +248,10 @@ impl<'a> Session<'a> { } let vals = if merged.is_empty() { - collected_vals.into_iter().map(|(k, v)| (k.to_string(), v.to_static())).collect::>() + collected_vals + .into_iter() + .map(|(k, v)| (k.to_string(), v.to_static())) + .collect::>() } else { // construct it with help of partial eval todo!()