nested loop

main
Ziyang Hu 2 years ago
parent 0fe284fe8d
commit 06f93e8259

@ -2,9 +2,6 @@ mod bridge;
mod options; mod options;
mod status; mod status;
use bridge::*;
pub use options::*;
pub use bridge::BridgeStatus; pub use bridge::BridgeStatus;
pub use bridge::PinnableSlice; pub use bridge::PinnableSlice;
pub use bridge::Slice; pub use bridge::Slice;
@ -12,8 +9,10 @@ pub use bridge::StatusBridgeCode;
pub use bridge::StatusCode; pub use bridge::StatusCode;
pub use bridge::StatusSeverity; pub use bridge::StatusSeverity;
pub use bridge::StatusSubCode; pub use bridge::StatusSubCode;
use bridge::*;
use cxx::let_cxx_string; use cxx::let_cxx_string;
pub use cxx::{SharedPtr, UniquePtr}; pub use cxx::{SharedPtr, UniquePtr};
pub use options::*;
pub use status::BridgeError; pub use status::BridgeError;
use status::Result; use status::Result;
use std::ops::Deref; use std::ops::Deref;
@ -142,6 +141,42 @@ impl<'a> Deref for IteratorPtr {
} }
} }
pub struct PrefixIterator<P: AsRef<[u8]>> {
iter: IteratorPtr,
started: bool,
prefix: P,
}
impl<P: AsRef<[u8]>> PrefixIterator<P> {
#[inline]
pub fn reset_prefix(&mut self, prefix: P) {
self.prefix = prefix;
self.iter.seek(self.prefix.as_ref());
self.started = false;
}
}
impl<P: AsRef<[u8]>> Iterator for PrefixIterator<P> {
type Item = (SlicePtr, SlicePtr);
fn next(&mut self) -> Option<Self::Item> {
if self.started {
self.iter.next()
} else {
self.started = true
}
match self.iter.pair() {
None => None,
Some((k, v)) => {
if k.as_ref().starts_with(self.prefix.as_ref()) {
Some((k, v))
} else {
None
}
}
}
}
}
impl IteratorPtr { impl IteratorPtr {
#[inline] #[inline]
pub fn to_first(&self) { pub fn to_first(&self) {
@ -168,6 +203,15 @@ impl IteratorPtr {
IteratorBridge::do_seek_for_prev(self, key.as_ref()) IteratorBridge::do_seek_for_prev(self, key.as_ref())
} }
#[inline] #[inline]
pub fn iter_prefix<T: AsRef<[u8]>>(self, prefix: T) -> PrefixIterator<T> {
self.seek(prefix.as_ref());
PrefixIterator {
iter: self,
started: false,
prefix,
}
}
#[inline]
pub fn refresh(&self) -> Result<()> { pub fn refresh(&self) -> Result<()> {
let mut status = BridgeStatus::default(); let mut status = BridgeStatus::default();
IteratorBridge::refresh(self, &mut status); IteratorBridge::refresh(self, &mut status);

@ -15,13 +15,14 @@ mod cartesian;
mod filter; mod filter;
mod from; mod from;
mod group; mod group;
mod hop;
mod insert; mod insert;
mod limit; mod limit;
mod nested_loop;
mod scan; mod scan;
mod select; mod select;
mod tagged; mod tagged;
mod values; mod values;
mod nested_loop;
use crate::data::expr::Expr; use crate::data::expr::Expr;
use crate::data::tuple::{DataKind, OwnTuple, Tuple}; use crate::data::tuple::{DataKind, OwnTuple, Tuple};
@ -32,13 +33,20 @@ pub(crate) use cartesian::*;
pub(crate) use filter::*; pub(crate) use filter::*;
pub(crate) use from::*; pub(crate) use from::*;
pub(crate) use group::*; pub(crate) use group::*;
pub(crate) use hop::*;
pub(crate) use insert::*; pub(crate) use insert::*;
pub(crate) use limit::*; pub(crate) use limit::*;
pub(crate) use nested_loop::*;
pub(crate) use scan::*; pub(crate) use scan::*;
pub(crate) use select::*; pub(crate) use select::*;
pub(crate) use tagged::*; pub(crate) use tagged::*;
pub(crate) use values::*; pub(crate) use values::*;
pub(crate) use nested_loop::*;
#[derive(thiserror::Error, Debug)]
pub(crate) enum QueryError {
#[error("Data corruption")]
Corruption,
}
pub(crate) trait InterpretContext: PartialEvalContext { pub(crate) trait InterpretContext: PartialEvalContext {
fn resolve_table(&self, name: &str) -> Option<TableId>; fn resolve_table(&self, name: &str) -> Option<TableId>;

@ -42,7 +42,7 @@ impl<'a> WhereFilter<'a> {
let arg = arg.into_inner().next().unwrap(); let arg = arg.into_inner().next().unwrap();
assert_rule(&arg, Rule::expr, NAME_WHERE, 1)?; assert_rule(&arg, Rule::expr, NAME_WHERE, 1)?;
let cond = Expr::try_from(arg)?; let cond = Expr::try_from(arg)?;
conds.push(cond.to_static()); conds.push(cond.into_static());
} }
let condition = Expr::Apply(Arc::new(OpAnd), conds); let condition = Expr::Apply(Arc::new(OpAnd), conds);
Ok(Self { Ok(Self {
@ -76,7 +76,7 @@ impl<'b> RelationalAlgebra for WhereFilter<'b> {
.condition .condition
.clone() .clone()
.partial_eval(&binding_ctx)? .partial_eval(&binding_ctx)?
.to_static(); .into_static();
let txn = self.ctx.txn.clone(); let txn = self.ctx.txn.clone();
let temp_db = self.ctx.sess.temp.clone(); let temp_db = self.ctx.sess.temp.clone();
let w_opts = default_write_options(); let w_opts = default_write_options();

@ -1,11 +1,12 @@
use crate::algebra::op::{ use crate::algebra::op::{
CartesianJoin, InterpretContext, RelationalAlgebra, TableScan, WhereFilter, CartesianJoin, InterpretContext, NestedLoopLeft, RelationalAlgebra, TableScan, WhereFilter,
}; };
use crate::algebra::parser::{assert_rule, AlgebraParseError, RaBox}; use crate::algebra::parser::{assert_rule, AlgebraParseError, RaBox};
use crate::context::TempDbContext; use crate::context::TempDbContext;
use crate::data::expr::{Expr, StaticExpr}; use crate::data::expr::{Expr, StaticExpr};
use crate::data::op::{OpAnd, OpEq}; use crate::data::op::{OpAnd, OpEq};
use crate::data::uuid::random_uuid_v1; use crate::data::uuid::random_uuid_v1;
use crate::data::value::Value;
use crate::parser::text_identifier::build_name_in_def; use crate::parser::text_identifier::build_name_in_def;
use crate::parser::{Pair, Pairs, Rule}; use crate::parser::{Pair, Pairs, Rule};
use anyhow::Result; use anyhow::Result;
@ -49,26 +50,117 @@ pub(crate) fn build_chain<'a>(ctx: &'a TempDbContext<'a>, arg: Pair) -> Result<R
let chain = arg.into_inner().next().ok_or_else(not_enough_args)?; let chain = arg.into_inner().next().ok_or_else(not_enough_args)?;
let chain = parse_chain(chain)?; let chain = parse_chain(chain)?;
if chain.is_empty() {
return Err(not_enough_args().into());
}
let mut seen_bindings = HashSet::new(); let mut seen_bindings = HashSet::new();
let scans = chain let first_el = chain.first().unwrap();
.iter() let mut ret = TableScan::build(ctx, first_el, true)?;
.map(|el| -> Result<RaBox> {
let ts = TableScan::build(ctx, el, true)?;
if !seen_bindings.insert(el.binding.to_string()) { if !seen_bindings.insert(first_el.binding.to_string()) {
return Err(AlgebraParseError::DuplicateBinding(el.binding.to_string()).into()); return Err(AlgebraParseError::DuplicateBinding(first_el.binding.to_string()).into());
} }
Ok(ts) if chain.len() == 1 {
}) return Ok(ret);
.collect::<Result<Vec<_>>>()?;
if scans.is_empty() {
return Err(not_enough_args().into());
} }
if scans.len() == 1 {
return Ok(scans.into_iter().next().unwrap()); let mut prev_el = first_el;
let mut prev_tid = ctx
.resolve_table(&prev_el.target)
.ok_or_else(|| AlgebraParseError::TableNotFound(prev_el.target.clone()))?;
let mut prev_info = ctx.get_table_info(prev_tid)?;
for cur_el in chain.iter().skip(1) {
match cur_el.part {
ChainPart::Node => {
// Edge to node
let node_id = ctx
.resolve_table(&cur_el.target)
.ok_or_else(|| AlgebraParseError::TableNotFound(cur_el.target.clone()))?;
let table_info = ctx.get_table_info(node_id)?;
let (prev_dir, prev_join) = match prev_el.part {
ChainPart::Node => unreachable!(),
ChainPart::Edge { dir, join } => (dir, join),
};
let join_key_prefix = match prev_dir {
ChainPartEdgeDir::Fwd => "_dst_",
ChainPartEdgeDir::Bwd => "_src_",
ChainPartEdgeDir::Bidi => todo!(),
};
let left_join_keys: Vec<StaticExpr> = table_info
.as_node()?
.keys
.iter()
.map(|col| {
Expr::FieldAcc(
join_key_prefix.to_string() + &col.name,
Expr::Variable(prev_el.binding.clone()).into(),
)
})
.collect();
ret = RaBox::NestedLoopLeft(Box::new(NestedLoopLeft {
ctx,
left: ret,
right: table_info.clone(),
right_binding: cur_el.binding.clone(),
left_outer_join: false,
join_key_extracter: left_join_keys,
key_is_prefix: false,
}));
prev_info = table_info;
prev_tid = node_id;
}
ChainPart::Edge { dir, join } => {
// Node to edge join
let edge_id = ctx
.resolve_table(&cur_el.target)
.ok_or_else(|| AlgebraParseError::TableNotFound(cur_el.target.clone()))?;
let table_info = ctx.get_table_info(edge_id)?;
let mut left_join_keys: Vec<StaticExpr> =
vec![Expr::Const(Value::from(prev_tid.int_for_storage()))];
for key in prev_info.as_node()?.keys.iter() {
left_join_keys.push(Expr::FieldAcc(
key.name.to_string(),
Expr::Variable(prev_el.binding.clone()).into(),
))
}
match dir {
ChainPartEdgeDir::Fwd => {
left_join_keys.push(Expr::Const(true.into()));
}
ChainPartEdgeDir::Bwd => {
left_join_keys.push(Expr::Const(false.into()));
}
ChainPartEdgeDir::Bidi => {
todo!()
}
}
ret = RaBox::NestedLoopLeft(Box::new(NestedLoopLeft {
ctx,
left: ret,
right: table_info.clone(),
right_binding: cur_el.binding.clone(),
left_outer_join: match join {
JoinType::Inner => false,
JoinType::Left => true,
JoinType::Right => todo!(),
},
join_key_extracter: left_join_keys,
key_is_prefix: true,
}));
prev_info = table_info;
prev_tid = edge_id;
}
}
prev_el = cur_el;
} }
todo!() Ok(ret)
} }
fn build_join_conditions( fn build_join_conditions(

@ -0,0 +1,20 @@
use crate::algebra::parser::RaBox;
use crate::ddl::reify::{EdgeInfo, NodeInfo};
pub(crate) const NAME_NODE_HOP: &str = "NodeHop";
pub(crate) struct NodeToNodeHop<'a> {
source: RaBox<'a>,
edge_info: EdgeInfo,
target_info: NodeInfo,
edge_binding: String,
target_binding: String,
left_outer: bool,
right_outer: bool,
}
pub(crate) struct EdgeToEdgeHop<'a> {
source: RaBox<'a>,
target_info: EdgeInfo,
target_binding: String,
}

@ -62,7 +62,7 @@ impl<'a> Insertion<'a> {
AlgebraParseError::Parse("Cannot have keyed map in Insert".to_string()).into(), AlgebraParseError::Parse("Cannot have keyed map in Insert".to_string()).into(),
); );
} }
let extract_map = extract_map.to_static(); let extract_map = extract_map.into_static();
let target_id = ctx let target_id = ctx
.resolve_table(&table_name) .resolve_table(&table_name)

@ -1,9 +1,18 @@
use crate::algebra::op::{build_binding_map_from_info, RelationalAlgebra}; use crate::algebra::op::{build_binding_map_from_info, QueryError, RelationalAlgebra};
use crate::algebra::parser::RaBox; use crate::algebra::parser::RaBox;
use crate::context::TempDbContext; use crate::context::TempDbContext;
use crate::data::tuple_set::{shift_merge_binding_map, BindingMap, TupleSet}; use crate::data::expr::StaticExpr;
use crate::data::tuple::{DataKind, OwnTuple, ReifiedTuple, Tuple};
use crate::data::tuple_set::{
shift_merge_binding_map, BindingMap, BindingMapEvalContext, TableId, TupleSet,
TupleSetEvalContext,
};
use crate::ddl::reify::TableInfo; use crate::ddl::reify::TableInfo;
use crate::runtime::options::{default_read_options, default_write_options};
use anyhow::Result; use anyhow::Result;
use cozorocks::{
DbPtr, IteratorPtr, PrefixIterator, ReadOptionsPtr, TransactionPtr, WriteOptionsPtr,
};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
pub(crate) const NAME_NESTED_LOOP_LEFT: &str = "NestedLoop"; pub(crate) const NAME_NESTED_LOOP_LEFT: &str = "NestedLoop";
@ -14,6 +23,8 @@ pub(crate) struct NestedLoopLeft<'a> {
pub(crate) right: TableInfo, pub(crate) right: TableInfo,
pub(crate) right_binding: String, pub(crate) right_binding: String,
pub(crate) left_outer_join: bool, pub(crate) left_outer_join: bool,
pub(crate) join_key_extracter: Vec<StaticExpr>,
pub(crate) key_is_prefix: bool,
} }
fn nested_binding(left: &RaBox, binding: &str) -> Result<BTreeSet<String>> { fn nested_binding(left: &RaBox, binding: &str) -> Result<BTreeSet<String>> {
@ -49,7 +60,96 @@ impl<'b> RelationalAlgebra for NestedLoopLeft<'b> {
} }
fn iter<'a>(&'a self) -> Result<Box<dyn Iterator<Item = Result<TupleSet>> + 'a>> { fn iter<'a>(&'a self) -> Result<Box<dyn Iterator<Item = Result<TupleSet>> + 'a>> {
todo!() let source_map = self.left.binding_map()?;
let binding_ctx = BindingMapEvalContext {
map: &source_map,
parent: self.ctx,
};
let key_extractors = self
.join_key_extracter
.iter()
.map(|ex| {
ex.clone()
.partial_eval(&binding_ctx)
.map(|ex| ex.into_static())
})
.collect::<Result<Vec<_>>>()?;
let table_id = self.right.table_id();
let mut key_tuple = OwnTuple::with_prefix(table_id.id);
let txn = self.ctx.txn.clone();
let temp_db = self.ctx.sess.temp.clone();
let w_opts = default_write_options();
let r_opts = default_read_options();
let left_join = self.left_outer_join;
if self.key_is_prefix {
let left_iter = self.left.iter()?;
let right_iter = if table_id.in_root {
txn.iterator(&r_opts)
} else {
temp_db.iterator(&r_opts)
};
let right_iter = right_iter.iter_prefix(OwnTuple::empty_tuple());
Ok(Box::new(NestLoopLeftPrefixIter {
left_join,
left_iter,
right_iter,
right_table_id: self.right.table_id(),
key_extractors,
left_cache: None,
left_cache_used: false,
txn,
temp_db,
w_opts,
r_opts,
started: false,
}))
} else {
let iter = self
.left
.iter()?
.map(move |tset| -> Result<Option<TupleSet>> {
let mut tset = tset?;
let eval_ctx = TupleSetEvalContext {
tuple_set: &tset,
txn: &txn,
temp_db: &temp_db,
write_options: &w_opts,
};
key_tuple.truncate_all();
for extractor in &key_extractors {
let value = extractor.row_eval(&eval_ctx)?;
key_tuple.push_value(&value)
}
let result = if table_id.in_root {
txn.get_owned(&r_opts, &key_tuple)?
} else {
temp_db.get_owned(&r_opts, &key_tuple)?
};
match result {
None => {
if left_join {
tset.push_key(key_tuple.clone().into());
tset.push_val(Tuple::empty_tuple().into());
Ok(Some(tset))
} else {
Ok(None)
}
}
Some(tuple) => {
tset.push_key(key_tuple.clone().into());
tset.push_val(Tuple::new(tuple).into());
Ok(Some(tset))
}
}
})
.filter_map(|rs| match rs {
Ok(None) => None,
Ok(Some(t)) => Some(Ok(t)),
Err(e) => Some(Err(e)),
});
Ok(Box::new(iter))
}
} }
fn identity(&self) -> Option<TableInfo> { fn identity(&self) -> Option<TableInfo> {
@ -57,34 +157,108 @@ impl<'b> RelationalAlgebra for NestedLoopLeft<'b> {
} }
} }
pub(crate) const NAME_NESTED_LOOP_RIGHT: &str = "NestedLoopRight"; pub(crate) struct NestLoopLeftPrefixIter<'a> {
left_join: bool,
pub(crate) struct NestedLoopRight<'a> { left_iter: Box<dyn Iterator<Item = Result<TupleSet>> + 'a>,
pub(crate) ctx: &'a TempDbContext<'a>, right_iter: PrefixIterator<OwnTuple>,
pub(crate) left: RaBox<'a>, right_table_id: TableId,
pub(crate) right: TableInfo, key_extractors: Vec<StaticExpr>,
pub(crate) right_binding: String, left_cache: Option<TupleSet>,
left_cache_used: bool,
txn: TransactionPtr,
temp_db: DbPtr,
w_opts: WriteOptionsPtr,
r_opts: ReadOptionsPtr,
started: bool,
} }
impl<'b> RelationalAlgebra for NestedLoopRight<'b> { impl<'a> NestLoopLeftPrefixIter<'a> {
fn name(&self) -> &str { fn make_key_tuple(&self, tset: &TupleSet) -> Result<OwnTuple> {
NAME_NESTED_LOOP_RIGHT let mut key_tuple = OwnTuple::with_prefix(self.right_table_id.id);
} let eval_ctx = TupleSetEvalContext {
tuple_set: tset,
txn: &self.txn,
temp_db: &self.temp_db,
write_options: &self.w_opts,
};
fn bindings(&self) -> Result<BTreeSet<String>> { for extractor in &self.key_extractors {
nested_binding(&self.left, &self.right_binding) let value = extractor.row_eval(&eval_ctx)?;
key_tuple.push_value(&value)
}
Ok(key_tuple)
} }
fn next_inner(&mut self) -> Result<Option<TupleSet>> {
loop {
match &self.left_cache {
None => {
match self.left_iter.next() {
None => return Ok(None),
Some(tset) => {
let tset = tset?;
let key_tuple = self.make_key_tuple(&tset)?;
self.right_iter.reset_prefix(key_tuple);
self.left_cache = Some(tset);
self.left_cache_used = false;
}
};
}
fn binding_map(&self) -> Result<BindingMap> { Some(left_tset) => match self.right_iter.next() {
nested_binding_map(self.ctx, &self.left, &self.right, &self.right_binding) None => {
if self.left_join && !self.left_cache_used {
let mut left_tset = self.left_cache.take().unwrap();
self.started = false;
left_tset.push_key(OwnTuple::empty_tuple().into());
left_tset.push_val(OwnTuple::empty_tuple().into());
dbg!(&left_tset);
return Ok(Some(left_tset));
} else {
self.left_cache.take();
}
}
Some((rk, rv)) => {
let mut left_tset = left_tset.clone();
let mut key: ReifiedTuple = Tuple::new(rk).into();
let mut val: ReifiedTuple = Tuple::new(rv).into();
if !matches!(val.data_kind(), Ok(DataKind::Data)) {
key = val;
val = if self.right_table_id.in_root {
Tuple::new(
self.txn
.get_owned(&self.r_opts, &key)?
.ok_or(QueryError::Corruption)?,
)
.into()
} else {
Tuple::new(
self.temp_db
.get_owned(&self.r_opts, &key)?
.ok_or(QueryError::Corruption)?,
)
.into()
}
}
left_tset.push_key(key);
left_tset.push_val(val);
self.left_cache_used = true;
return Ok(Some(left_tset));
}
},
}
}
} }
}
fn iter<'a>(&'a self) -> Result<Box<dyn Iterator<Item = Result<TupleSet>> + 'a>> { impl Iterator for NestLoopLeftPrefixIter<'_> {
todo!() type Item = Result<TupleSet>;
}
fn identity(&self) -> Option<TableInfo> { fn next(&mut self) -> Option<Self::Item> {
None match self.next_inner() {
Ok(None) => None,
Ok(Some(t)) => Some(Ok(t)),
Err(e) => Some(Err(e)),
}
} }
} }

@ -56,7 +56,7 @@ impl<'a> SelectOp<'a> {
AlgebraParseError::Parse("Cannot have keyed map in Select".to_string()).into(), AlgebraParseError::Parse("Cannot have keyed map in Select".to_string()).into(),
); );
} }
let extract_map = extract_map.to_static(); let extract_map = extract_map.into_static();
Ok(Self { Ok(Self {
ctx, ctx,
source, source,
@ -116,7 +116,7 @@ impl<'b> RelationalAlgebra for SelectOp<'b> {
) )
}) })
.collect::<BTreeMap<_, _>>(), .collect::<BTreeMap<_, _>>(),
ex => return Err(SelectOpError::NeedsDict(ex.to_static()).into()), ex => return Err(SelectOpError::NeedsDict(ex.into_static()).into()),
}; };
Ok(BTreeMap::from([(self.binding.clone(), extract_map)])) Ok(BTreeMap::from([(self.binding.clone(), extract_map)]))
} }
@ -131,14 +131,14 @@ impl<'b> RelationalAlgebra for SelectOp<'b> {
.extract_map .extract_map
.clone() .clone()
.partial_eval(&binding_ctx)? .partial_eval(&binding_ctx)?
.to_static() .into_static()
{ {
Expr::Dict(d) => d.values().cloned().collect::<Vec<_>>(), Expr::Dict(d) => d.values().cloned().collect::<Vec<_>>(),
Expr::Const(Value::Dict(d)) => d Expr::Const(Value::Dict(d)) => d
.values() .values()
.map(|v| Expr::Const(v.clone())) .map(|v| Expr::Const(v.clone()))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
ex => return Err(SelectOpError::NeedsDict(ex.to_static()).into()), ex => return Err(SelectOpError::NeedsDict(ex.into_static()).into()),
}; };
let txn = self.ctx.txn.clone(); let txn = self.ctx.txn.clone();

@ -1,4 +1,9 @@
use crate::algebra::op::{build_from_clause, AssocOp, CartesianJoin, Insertion, LimitOp, RelationFromValues, RelationalAlgebra, SelectOp, TableScan, TaggedInsertion, WhereFilter, NAME_FROM, NAME_INSERTION, NAME_RELATION_FROM_VALUES, NAME_SELECT, NAME_SKIP, NAME_TAGGED_INSERTION, NAME_TAGGED_UPSERT, NAME_TAKE, NAME_UPSERT, NAME_WHERE, NestedLoopLeft, NestedLoopRight, NestedLoopOuter}; use crate::algebra::op::{
build_from_clause, AssocOp, CartesianJoin, Insertion, LimitOp, NestedLoopLeft,
RelationFromValues, RelationalAlgebra, SelectOp, TableScan, TaggedInsertion, WhereFilter,
NAME_FROM, NAME_INSERTION, NAME_RELATION_FROM_VALUES, NAME_SELECT, NAME_SKIP,
NAME_TAGGED_INSERTION, NAME_TAGGED_UPSERT, NAME_TAKE, NAME_UPSERT, NAME_WHERE,
};
use crate::context::TempDbContext; use crate::context::TempDbContext;
use crate::data::tuple::OwnTuple; use crate::data::tuple::OwnTuple;
use crate::data::tuple_set::{BindingMap, TableId, TupleSet}; use crate::data::tuple_set::{BindingMap, TableId, TupleSet};
@ -70,8 +75,6 @@ pub(crate) enum RaBox<'a> {
LimitOp(Box<LimitOp<'a>>), LimitOp(Box<LimitOp<'a>>),
Cartesian(Box<CartesianJoin<'a>>), Cartesian(Box<CartesianJoin<'a>>),
NestedLoopLeft(Box<NestedLoopLeft<'a>>), NestedLoopLeft(Box<NestedLoopLeft<'a>>),
NestedLoopRight(Box<NestedLoopRight<'a>>),
NestedLoopOuter(Box<NestedLoopOuter<'a>>)
} }
impl<'a> RaBox<'a> { impl<'a> RaBox<'a> {
@ -87,8 +90,6 @@ impl<'a> RaBox<'a> {
RaBox::LimitOp(inner) => vec![&inner.source], RaBox::LimitOp(inner) => vec![&inner.source],
RaBox::Cartesian(inner) => vec![&inner.left, &inner.right], RaBox::Cartesian(inner) => vec![&inner.left, &inner.right],
RaBox::NestedLoopLeft(inner) => vec![&inner.left], RaBox::NestedLoopLeft(inner) => vec![&inner.left],
RaBox::NestedLoopRight(inner) => vec![&inner.left],
RaBox::NestedLoopOuter(inner) => vec![&inner.left],
} }
} }
} }
@ -116,8 +117,6 @@ impl<'b> RelationalAlgebra for RaBox<'b> {
RaBox::LimitOp(inner) => inner.name(), RaBox::LimitOp(inner) => inner.name(),
RaBox::Cartesian(inner) => inner.name(), RaBox::Cartesian(inner) => inner.name(),
RaBox::NestedLoopLeft(inner) => inner.name(), RaBox::NestedLoopLeft(inner) => inner.name(),
RaBox::NestedLoopRight(inner) => inner.name(),
RaBox::NestedLoopOuter(inner) => inner.name(),
} }
} }
@ -133,8 +132,6 @@ impl<'b> RelationalAlgebra for RaBox<'b> {
RaBox::LimitOp(inner) => inner.bindings(), RaBox::LimitOp(inner) => inner.bindings(),
RaBox::Cartesian(inner) => inner.bindings(), RaBox::Cartesian(inner) => inner.bindings(),
RaBox::NestedLoopLeft(inner) => inner.bindings(), RaBox::NestedLoopLeft(inner) => inner.bindings(),
RaBox::NestedLoopRight(inner) => inner.bindings(),
RaBox::NestedLoopOuter(inner) => inner.bindings(),
} }
} }
@ -150,8 +147,6 @@ impl<'b> RelationalAlgebra for RaBox<'b> {
RaBox::LimitOp(inner) => inner.binding_map(), RaBox::LimitOp(inner) => inner.binding_map(),
RaBox::Cartesian(inner) => inner.binding_map(), RaBox::Cartesian(inner) => inner.binding_map(),
RaBox::NestedLoopLeft(inner) => inner.binding_map(), RaBox::NestedLoopLeft(inner) => inner.binding_map(),
RaBox::NestedLoopRight(inner) => inner.binding_map(),
RaBox::NestedLoopOuter(inner) => inner.binding_map(),
} }
} }
@ -167,8 +162,6 @@ impl<'b> RelationalAlgebra for RaBox<'b> {
RaBox::LimitOp(inner) => inner.iter(), RaBox::LimitOp(inner) => inner.iter(),
RaBox::Cartesian(inner) => inner.iter(), RaBox::Cartesian(inner) => inner.iter(),
RaBox::NestedLoopLeft(inner) => inner.iter(), RaBox::NestedLoopLeft(inner) => inner.iter(),
RaBox::NestedLoopRight(inner) => inner.iter(),
RaBox::NestedLoopOuter(inner) => inner.iter(),
} }
} }
@ -184,8 +177,6 @@ impl<'b> RelationalAlgebra for RaBox<'b> {
RaBox::LimitOp(inner) => inner.identity(), RaBox::LimitOp(inner) => inner.identity(),
RaBox::Cartesian(inner) => inner.identity(), RaBox::Cartesian(inner) => inner.identity(),
RaBox::NestedLoopLeft(inner) => inner.identity(), RaBox::NestedLoopLeft(inner) => inner.identity(),
RaBox::NestedLoopRight(inner) => inner.identity(),
RaBox::NestedLoopOuter(inner) => inner.identity(),
} }
} }
} }
@ -304,7 +295,7 @@ pub(crate) mod tests {
ctx.txn.commit().unwrap(); ctx.txn.commit().unwrap();
} }
let duration = start.elapsed(); let duration_insert = start.elapsed();
let start = Instant::now(); let start = Instant::now();
{ {
let ctx = sess.temp_ctx(true); let ctx = sess.temp_ctx(true);
@ -326,7 +317,47 @@ pub(crate) mod tests {
dbg!(&ra); dbg!(&ra);
dbg!(ra.get_values()?); dbg!(ra.get_values()?);
} }
let duration2 = start.elapsed(); let duration_scan = start.elapsed();
let start = Instant::now();
{
let ctx = sess.temp_ctx(true);
let s = r#"
From(e:Employee-[hj:HasJob]->?j:Job)
.Where(e.id >= 122, e.id < 130)
.Select({...e, title: j.title, salary: hj.salary})
"#;
let ra = build_relational_expr(
&ctx,
CozoParser::parse(Rule::ra_expr_all, s)
.unwrap()
.into_iter()
.next()
.unwrap(),
)?;
dbg!(&ra);
dbg!(ra.get_values()?);
}
let duration_join = start.elapsed();
let start = Instant::now();
{
let ctx = sess.temp_ctx(true);
let s = r#"
From(j:Job<-[hj:HasJob]-?e:Employee)
.Where(e.id >= 122, e.id < 130)
.Select({...e, title: j.title, salary: hj.salary})
"#;
let ra = build_relational_expr(
&ctx,
CozoParser::parse(Rule::ra_expr_all, s)
.unwrap()
.into_iter()
.next()
.unwrap(),
)?;
dbg!(&ra);
dbg!(ra.get_values()?);
}
let duration_join_back = start.elapsed();
let start = Instant::now(); let start = Instant::now();
let mut r_opts = default_read_options(); let mut r_opts = default_read_options();
r_opts.set_total_order_seek(true); r_opts.set_total_order_seek(true);
@ -343,8 +374,15 @@ pub(crate) mod tests {
} }
it.next(); it.next();
} }
let duration3 = start.elapsed(); let duration_list = start.elapsed();
dbg!(duration, duration2, duration3, n); dbg!(
duration_insert,
duration_scan,
duration_join,
duration_join_back,
duration_list,
n
);
Ok(()) Ok(())
} }
} }

@ -165,7 +165,7 @@ impl<'a> Expr<'a> {
Expr::Dict(mut d) => { Expr::Dict(mut d) => {
d.remove(&f as &str).unwrap_or(Expr::Const(Value::Null)) d.remove(&f as &str).unwrap_or(Expr::Const(Value::Null))
} }
v => return Err(EvalError::FieldAccess(f, v.to_static()).into()), v => return Err(EvalError::FieldAccess(f, v.into_static()).into()),
}, },
} }
} }
@ -199,7 +199,7 @@ impl<'a> Expr<'a> {
| Expr::FieldAcc(_, _) | Expr::FieldAcc(_, _)
| Expr::Apply(_, _) | Expr::Apply(_, _)
| Expr::ApplyAgg(_, _, _)) => Expr::IdxAcc(i, v.into()), | Expr::ApplyAgg(_, _, _)) => Expr::IdxAcc(i, v.into()),
v => return Err(EvalError::IndexAccess(i, v.to_static()).into()), v => return Err(EvalError::IndexAccess(i, v.into_static()).into()),
}, },
} }
} }

@ -73,99 +73,99 @@ impl<'a> Expr<'a> {
_ => None, _ => None,
} }
} }
pub(crate) fn to_static(self) -> StaticExpr { pub(crate) fn into_static(self) -> StaticExpr {
match self { match self {
Expr::Const(v) => Expr::Const(v.into_static()), Expr::Const(v) => Expr::Const(v.into_static()),
Expr::List(l) => Expr::List(l.into_iter().map(|v| v.to_static()).collect()), Expr::List(l) => Expr::List(l.into_iter().map(|v| v.into_static()).collect()),
Expr::Dict(d) => Expr::Dict(d.into_iter().map(|(k, v)| (k, v.to_static())).collect()), Expr::Dict(d) => Expr::Dict(d.into_iter().map(|(k, v)| (k, v.into_static())).collect()),
Expr::Variable(v) => Expr::Variable(v), Expr::Variable(v) => Expr::Variable(v),
Expr::TupleSetIdx(idx) => Expr::TupleSetIdx(idx), Expr::TupleSetIdx(idx) => Expr::TupleSetIdx(idx),
Expr::Apply(op, args) => { Expr::Apply(op, args) => {
Expr::Apply(op, args.into_iter().map(|v| v.to_static()).collect()) Expr::Apply(op, args.into_iter().map(|v| v.into_static()).collect())
} }
Expr::ApplyAgg(op, a_args, args) => Expr::ApplyAgg( Expr::ApplyAgg(op, a_args, args) => Expr::ApplyAgg(
op, op,
a_args.into_iter().map(|v| v.to_static()).collect(), a_args.into_iter().map(|v| v.into_static()).collect(),
args.into_iter().map(|v| v.to_static()).collect(), args.into_iter().map(|v| v.into_static()).collect(),
), ),
Expr::FieldAcc(f, arg) => Expr::FieldAcc(f, arg.to_static().into()), Expr::FieldAcc(f, arg) => Expr::FieldAcc(f, arg.into_static().into()),
Expr::IdxAcc(i, arg) => Expr::IdxAcc(i, arg.to_static().into()), Expr::IdxAcc(i, arg) => Expr::IdxAcc(i, arg.into_static().into()),
Expr::IfExpr(args) => { Expr::IfExpr(args) => {
let (a, b, c) = *args; let (a, b, c) = *args;
Expr::IfExpr((a.to_static(), b.to_static(), c.to_static()).into()) Expr::IfExpr((a.into_static(), b.into_static(), c.into_static()).into())
} }
Expr::SwitchExpr(args) => Expr::SwitchExpr( Expr::SwitchExpr(args) => Expr::SwitchExpr(
args.into_iter() args.into_iter()
.map(|(a, b)| (a.to_static(), b.to_static())) .map(|(a, b)| (a.into_static(), b.into_static()))
.collect(), .collect(),
), ),
Expr::Add(args) => { Expr::Add(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Add((a.to_static(), b.to_static()).into()) Expr::Add((a.into_static(), b.into_static()).into())
} }
Expr::Sub(args) => { Expr::Sub(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Sub((a.to_static(), b.to_static()).into()) Expr::Sub((a.into_static(), b.into_static()).into())
} }
Expr::Mul(args) => { Expr::Mul(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Mul((a.to_static(), b.to_static()).into()) Expr::Mul((a.into_static(), b.into_static()).into())
} }
Expr::Div(args) => { Expr::Div(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Div((a.to_static(), b.to_static()).into()) Expr::Div((a.into_static(), b.into_static()).into())
} }
Expr::Pow(args) => { Expr::Pow(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Pow((a.to_static(), b.to_static()).into()) Expr::Pow((a.into_static(), b.into_static()).into())
} }
Expr::Mod(args) => { Expr::Mod(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Mod((a.to_static(), b.to_static()).into()) Expr::Mod((a.into_static(), b.into_static()).into())
} }
Expr::StrCat(args) => { Expr::StrCat(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::StrCat((a.to_static(), b.to_static()).into()) Expr::StrCat((a.into_static(), b.into_static()).into())
} }
Expr::Eq(args) => { Expr::Eq(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Eq((a.to_static(), b.to_static()).into()) Expr::Eq((a.into_static(), b.into_static()).into())
} }
Expr::Ne(args) => { Expr::Ne(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Ne((a.to_static(), b.to_static()).into()) Expr::Ne((a.into_static(), b.into_static()).into())
} }
Expr::Gt(args) => { Expr::Gt(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Gt((a.to_static(), b.to_static()).into()) Expr::Gt((a.into_static(), b.into_static()).into())
} }
Expr::Ge(args) => { Expr::Ge(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Ge((a.to_static(), b.to_static()).into()) Expr::Ge((a.into_static(), b.into_static()).into())
} }
Expr::Lt(args) => { Expr::Lt(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Lt((a.to_static(), b.to_static()).into()) Expr::Lt((a.into_static(), b.into_static()).into())
} }
Expr::Le(args) => { Expr::Le(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Le((a.to_static(), b.to_static()).into()) Expr::Le((a.into_static(), b.into_static()).into())
} }
Expr::Not(arg) => Expr::Not(arg.to_static().into()), Expr::Not(arg) => Expr::Not(arg.into_static().into()),
Expr::Minus(arg) => Expr::Minus(arg.to_static().into()), Expr::Minus(arg) => Expr::Minus(arg.into_static().into()),
Expr::IsNull(arg) => Expr::IsNull(arg.to_static().into()), Expr::IsNull(arg) => Expr::IsNull(arg.into_static().into()),
Expr::NotNull(arg) => Expr::NotNull(arg.to_static().into()), Expr::NotNull(arg) => Expr::NotNull(arg.into_static().into()),
Expr::Coalesce(args) => { Expr::Coalesce(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Coalesce((a.to_static(), b.to_static()).into()) Expr::Coalesce((a.into_static(), b.into_static()).into())
} }
Expr::Or(args) => { Expr::Or(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::Or((a.to_static(), b.to_static()).into()) Expr::Or((a.into_static(), b.into_static()).into())
} }
Expr::And(args) => { Expr::And(args) => {
let (a, b) = *args; let (a, b) = *args;
Expr::And((a.to_static(), b.to_static()).into()) Expr::And((a.into_static(), b.into_static()).into())
} }
} }
} }

@ -1,6 +1,6 @@
use crate::data::eval::{PartialEvalContext, RowEvalContext}; use crate::data::eval::{PartialEvalContext, RowEvalContext};
use crate::data::expr::Expr; use crate::data::expr::Expr;
use crate::data::tuple::{OwnTuple, ReifiedTuple}; use crate::data::tuple::{DataKind, OwnTuple, ReifiedTuple};
use crate::data::typing::Typing; use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value}; use crate::data::value::{StaticValue, Value};
use anyhow::Result; use anyhow::Result;
@ -186,8 +186,12 @@ impl TupleSet {
match tuple { match tuple {
None => Ok(Value::Null), None => Ok(Value::Null),
Some(tuple) => { Some(tuple) => {
let res = tuple.get(*col_idx)?; if matches!(tuple.data_kind(), Ok(DataKind::Empty)) {
Ok(res) Ok(Value::Null)
} else {
let res = tuple.get(*col_idx)?;
Ok(res)
}
} }
} }
} }

@ -31,7 +31,7 @@ impl ColSchema {
.get(&self.name) .get(&self.name)
.cloned() .cloned()
.unwrap_or(Expr::Const(Value::Null)) .unwrap_or(Expr::Const(Value::Null))
.to_static(); .into_static();
let typing = self.typing.clone(); let typing = self.typing.clone();
(extractor, typing) (extractor, typing)
} }
@ -201,7 +201,7 @@ impl<'a> TryFrom<Pair<'a>> for IndexSchema {
for pair in pairs { for pair in pairs {
match pair.as_rule() { match pair.as_rule() {
Rule::name_in_def => associate_names.push(build_name_in_def(pair, false)?), Rule::name_in_def => associate_names.push(build_name_in_def(pair, false)?),
_ => indices.push(Expr::try_from(pair)?.to_static()), _ => indices.push(Expr::try_from(pair)?.into_static()),
} }
} }
if indices.is_empty() { if indices.is_empty() {
@ -242,7 +242,7 @@ fn parse_col_entry(pair: Pair) -> Result<(bool, ColSchema)> {
let typing = Typing::try_from(pairs.next().unwrap())?; let typing = Typing::try_from(pairs.next().unwrap())?;
let default = match pairs.next() { let default = match pairs.next() {
None => Expr::Const(Value::Null), None => Expr::Const(Value::Null),
Some(pair) => Expr::try_from(pair)?.to_static(), Some(pair) => Expr::try_from(pair)?.into_static(),
}; };
Ok(( Ok((
is_key, is_key,

@ -419,7 +419,7 @@ impl<'a> TryFrom<Value<'a>> for IndexCol {
fn try_from(value: Value<'a>) -> Result<Self> { fn try_from(value: Value<'a>) -> Result<Self> {
Ok(match Expr::try_from(value)? { Ok(match Expr::try_from(value)? {
Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx), Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx),
expr => IndexCol::Expr(expr.to_static()), expr => IndexCol::Expr(expr.into_static()),
}) })
} }
} }
@ -573,7 +573,7 @@ pub(crate) trait DdlContext {
.map(|ex| { .map(|ex| {
ex.partial_eval(&ctx).map(|ex| match ex { ex.partial_eval(&ctx).map(|ex| match ex {
Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx), Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx),
ex => IndexCol::Expr(ex.to_static()), ex => IndexCol::Expr(ex.into_static()),
}) })
}) })
.collect::<result::Result<Vec<_>, _>>()? .collect::<result::Result<Vec<_>, _>>()?
@ -602,7 +602,7 @@ pub(crate) trait DdlContext {
.map(|ex| { .map(|ex| {
ex.partial_eval(&ctx).map(|ex| match ex { ex.partial_eval(&ctx).map(|ex| match ex {
Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx), Expr::TupleSetIdx(tidx) => IndexCol::Col(tidx),
ex => IndexCol::Expr(ex.to_static()), ex => IndexCol::Expr(ex.into_static()),
}) })
}) })
.collect::<result::Result<Vec<_>, _>>()? .collect::<result::Result<Vec<_>, _>>()?

Loading…
Cancel
Save