From eceab71fcd4501e6e76da7d731f5c31a33fe3ec1 Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Mon, 2 May 2022 16:13:33 +0800 Subject: [PATCH] remove environment nonsense --- src/db/engine.rs | 1 - src/db/eval.rs | 40 +++++++++-------------------- src/db/mutation.rs | 26 +++++++++---------- src/db/plan.rs | 50 ++++++++++++++++++++++++++++-------- src/db/table.rs | 57 ++++++++++++++++++++++++++---------------- src/relation/typing.rs | 5 ++-- 6 files changed, 100 insertions(+), 79 deletions(-) diff --git a/src/db/engine.rs b/src/db/engine.rs index 8f4eaac4..3dbce9e8 100644 --- a/src/db/engine.rs +++ b/src/db/engine.rs @@ -201,7 +201,6 @@ pub enum SessionStatus { #[cfg(test)] mod tests { use std::{fs, thread}; - use crate::db::eval::Environment; use crate::relation::tuple::Tuple; use super::*; diff --git a/src/db/eval.rs b/src/db/eval.rs index fab268cf..339a55f5 100644 --- a/src/db/eval.rs +++ b/src/db/eval.rs @@ -22,21 +22,12 @@ use crate::relation::value; /// `[Null, Int, Text, Int, Text]` inverted index for related tables /// `[True, Int]` table info, value is key -pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized { - fn get_next_storage_id(&mut self, in_root: bool) -> Result; - fn get_stack_depth(&self) -> i32; - fn push_env(&mut self) -> Result<()>; - fn pop_env(&mut self) -> Result<()>; - fn set_param(&mut self, name: &str, val: &'t str); - fn define_variable(&mut self, name: &str, val: &Value, in_root: bool) -> Result<()> { +impl<'s, 't> Session<'s, 't> { + pub fn define_variable(&mut self, name: &str, val: &Value, in_root: bool) -> Result<()> { let mut data = Tuple::with_data_prefix(DataKind::Value); data.push_value(val); self.define_data(name, data, in_root) } - fn table_data(&self, id: i64, in_root: bool) -> Result>>; - fn resolve(&self, name: &str) -> Result>>; - fn resolve_related_tables(&self, name: &str) -> Result)>>; - fn resolve_param(&self, name: &str) -> Result; fn resolve_value(&self, name: &str) -> Result> { if name.starts_with('&') { self.resolve_param(name).map(|v| Some(v.clone())) @@ -54,11 +45,6 @@ pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized { } } } - fn delete_defined(&mut self, name: &str, in_root: bool) -> Result<()>; - fn define_data(&mut self, name: &str, data: OwnTuple, in_root: bool) -> Result<()>; - fn key_exists(&self, key: &OwnTuple, in_root: bool) -> Result; - fn del_key(&self, key: &OwnTuple, in_root: bool) -> Result<()>; - fn define_raw_key(&self, key: &OwnTuple, value: Option<&OwnTuple>, in_root: bool) -> Result<()>; fn encode_definable_key(&self, name: &str, in_root: bool) -> OwnTuple { let depth_code = if in_root { 0 } else { self.get_stack_depth() as i64 }; let mut tuple = Tuple::with_null_prefix(); @@ -231,7 +217,7 @@ pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized { Ok((name, tuple, index_data)) } - fn extract_table_id(src_tbl: Tuple) -> Result<(DataKind, bool, i64)> { + fn extract_table_id>(src_tbl: Tuple) -> Result<(DataKind, bool, i64)> { let kind = src_tbl.data_kind()?; match kind { DataKind::Data | DataKind::Value | DataKind::Type => return Err(CozoError::UnexpectedDataKind(kind)), @@ -252,7 +238,7 @@ pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized { tuple.push_null(); // TODO default values for cols Ok((name, tuple, vec![])) } - fn run_definition(&mut self, pair: Pair) -> Result<()> { + pub fn run_definition(&mut self, pair: Pair) -> Result<()> { let in_root = match pair.as_rule() { Rule::global_def => true, Rule::local_def => false, @@ -276,7 +262,7 @@ pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized { } self.define_data(&name, tuple, in_root) } - fn partial_eval<'a>(&self, value: Value<'a>) -> Result<(bool, Value<'a>)> { + pub fn partial_eval<'a>(&self, value: Value<'a>) -> Result<(bool, Value<'a>)> { match value { v @ (Value::Null | Value::Bool(_) | @@ -722,10 +708,8 @@ pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized { Err(Err(e)) => Err(e) } } -} -impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { fn get_next_storage_id(&mut self, in_root: bool) -> Result { // TODO: deal with wrapping problem let mut key_entry = Tuple::with_null_prefix(); @@ -756,7 +740,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { self.stack_depth } - fn push_env(&mut self) -> Result<()> { + pub fn push_env(&mut self) -> Result<()> { if self.stack_depth <= -1024 { return Err(CozoError::LogicError("Stack overflow in env".to_string())); } @@ -764,7 +748,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { Ok(()) } - fn pop_env(&mut self) -> Result<()> { + pub fn pop_env(&mut self) -> Result<()> { // Remove all stuff starting with the stack depth from the temp session let mut prefix = Tuple::with_null_prefix(); prefix.push_int(self.stack_depth as i64); @@ -845,7 +829,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { self.params.insert(name.to_string(), val); } - fn table_data(&self, id: i64, in_root: bool) -> Result>> { + pub fn table_data(&self, id: i64, in_root: bool) -> Result>> { let mut key = Tuple::with_null_prefix(); key.push_bool(true); key.push_int(id); @@ -858,7 +842,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { } } - fn resolve(&self, name: &str) -> Result>> { + pub fn resolve(&self, name: &str) -> Result>> { let mut tuple = Tuple::with_null_prefix(); tuple.push_str(name); let it = self.txn.iterator(false, &self.temp_cf); @@ -874,7 +858,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { Ok(res) } - fn resolve_related_tables(&self, name: &str) -> Result)>> { + pub fn resolve_related_tables(&self, name: &str) -> Result)>> { let mut prefix = Tuple::with_prefix(0); prefix.push_null(); prefix.push_str(name); @@ -956,7 +940,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { Ok(()) } - fn key_exists(&self, key: &OwnTuple, in_root: bool) -> Result { + pub fn key_exists(&self, key: &OwnTuple, in_root: bool) -> Result { let res = self.txn.get(in_root, if in_root { &self.perm_cf } else { &self.temp_cf }, key)?; Ok(res.is_some()) } @@ -966,7 +950,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> { Ok(()) } - fn define_raw_key(&self, key: &OwnTuple, value: Option<&OwnTuple>, in_root: bool) -> Result<()> { + pub fn define_raw_key(&self, key: &OwnTuple, value: Option<&OwnTuple>, in_root: bool) -> Result<()> { if in_root { match value { None => { diff --git a/src/db/mutation.rs b/src/db/mutation.rs index b8971361..afb6c49c 100644 --- a/src/db/mutation.rs +++ b/src/db/mutation.rs @@ -4,7 +4,6 @@ use std::collections::{BTreeMap, HashSet}; use std::rc::Rc; use pest::iterators::Pair; use crate::db::engine::Session; -use crate::db::eval::Environment; use crate::db::table::TableInfo; use crate::error::CozoError::LogicError; use crate::error::{CozoError, Result}; @@ -117,7 +116,7 @@ impl<'a, 'b, 't> MutationManager<'a, 'b, 't> { match table_info.kind { DataKind::Node => { - key_tuple = Tuple::with_prefix(table_info.table_id as u32); + key_tuple = Tuple::with_prefix(table_info.table_id.id as u32); for (k, v) in &table_info.key_typing { let raw = val_map.remove(k.as_str()).unwrap_or(Value::Null); let processed = v.coerce(raw)?; @@ -130,17 +129,17 @@ impl<'a, 'b, 't> MutationManager<'a, 'b, 't> { let processed = v.coerce(raw)?; val_tuple.push_value(&processed); } - if error_on_existing && self.sess.key_exists(&key_tuple, table_info.in_root)? { + if error_on_existing && self.sess.key_exists(&key_tuple, table_info.table_id.in_root)? { return Err(CozoError::KeyConflict(key_tuple)); } - self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.in_root)?; + self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.table_id.in_root)?; } DataKind::Edge => { - key_tuple = Tuple::with_prefix(table_info.table_id as u32); - key_tuple.push_int(table_info.src_table_id); + key_tuple = Tuple::with_prefix(table_info.table_id.id as u32); + key_tuple.push_int(table_info.src_table_id.id); - let mut ikey_tuple = Tuple::with_prefix(table_info.table_id as u32); - ikey_tuple.push_int(table_info.dst_table_id); + let mut ikey_tuple = Tuple::with_prefix(table_info.table_id.id as u32); + ikey_tuple.push_int(table_info.dst_table_id.id); let mut val_tuple = Tuple::with_data_prefix(DataKind::Data); @@ -196,11 +195,11 @@ impl<'a, 'b, 't> MutationManager<'a, 'b, 't> { let processed = v.coerce(raw)?; val_tuple.push_value(&processed); } - if error_on_existing && self.sess.key_exists(&key_tuple, table_info.in_root)? { + if error_on_existing && self.sess.key_exists(&key_tuple, table_info.table_id.in_root)? { return Err(CozoError::KeyConflict(key_tuple)); } - self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.in_root)?; - self.sess.define_raw_key(&ikey_tuple, Some(&key_tuple), table_info.in_root)?; + self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.table_id.in_root)?; + self.sess.define_raw_key(&ikey_tuple, Some(&key_tuple), table_info.table_id.in_root)?; } _ => unreachable!() } @@ -215,8 +214,8 @@ impl<'a, 'b, 't> MutationManager<'a, 'b, 't> { let processed = v.coerce(raw)?; val_tuple.push_value(&processed); } - key_tuple.overwrite_prefix(assoc.table_id as u32); - self.sess.define_raw_key(&key_tuple, Some(&val_tuple), assoc.in_root)?; + key_tuple.overwrite_prefix(assoc.table_id.id as u32); + self.sess.define_raw_key(&key_tuple, Some(&val_tuple), assoc.table_id.in_root)?; } } Ok(()) @@ -229,7 +228,6 @@ mod tests { use std::time::Instant; use pest::Parser as PestParser; use crate::db::engine::Engine; - use crate::db::eval::Environment; use crate::parser::{Parser, Rule}; use crate::relation::tuple::Tuple; diff --git a/src/db/plan.rs b/src/db/plan.rs index f79d2ebd..64f0a280 100644 --- a/src/db/plan.rs +++ b/src/db/plan.rs @@ -41,7 +41,7 @@ use crate::db::engine::Session; use crate::db::table::TableInfo; use crate::error::CozoError::LogicError; use crate::parser::Rule; -use crate::error::Result; +use crate::error::{CozoError, Result}; use crate::parser::text_identifier::build_name_in_def; use crate::relation::data::DataKind; @@ -74,7 +74,7 @@ pub struct EdgeOrNodeEl { } impl<'a, 't> Session<'a, 't> { - pub fn parse_from_pattern(&self, pair: Pair) -> Result<()> { + pub fn parse_from_pattern(&self, pair: Pair) -> Result> { let res: Result> = pair.into_inner().map(|p| { match p.as_rule() { Rule::simple_from_pattern => self.parse_simple_from_pattern(p), @@ -82,10 +82,10 @@ impl<'a, 't> Session<'a, 't> { _ => unreachable!() } }).collect(); - Ok(()) + res } - fn parse_simple_from_pattern(&self, pair: Pair) -> Result<()> { + fn parse_simple_from_pattern(&self, pair: Pair) -> Result { let mut pairs = pair.into_inner(); let name = pairs.next().unwrap().as_str(); if name.starts_with('_') { @@ -94,11 +94,10 @@ impl<'a, 't> Session<'a, 't> { let table_name = build_name_in_def(pairs.next().unwrap(), true)?; let table_info = self.get_table_info(&table_name)?; let ret = FromEl::Simple(Box::new(SimpleFromEl { binding: name.to_string(), table: table_name, info: table_info })); - println!("{:#?}", ret); - Ok(()) + Ok(ret) } - fn parse_node_edge_pattern(&self, pair: Pair) -> Result<()> { + fn parse_node_edge_pattern(&self, pair: Pair) -> Result { let res: Result> = pair.into_inner().map(|p| { match p.as_rule() { Rule::node_pattern => self.parse_node_pattern(p), @@ -107,9 +106,30 @@ impl<'a, 't> Session<'a, 't> { _ => unreachable!() } }).collect(); - // TODO check the chain connects! - println!("{:#?}", res); - Ok(()) + let res = res?; + let connects = res.windows(2).all(|v| { + let left = &v[0]; + let right = &v[1]; + match (&left.kind, &right.kind) { + (EdgeOrNodeKind::FwdEdge, EdgeOrNodeKind::Node) => { + left.info.dst_table_id == right.info.table_id + } + (EdgeOrNodeKind::BwdEdge, EdgeOrNodeKind::Node) => { + left.info.src_table_id == right.info.table_id + } + (EdgeOrNodeKind::Node, EdgeOrNodeKind::FwdEdge) => { + left.info.table_id == right.info.src_table_id + } + (EdgeOrNodeKind::Node, EdgeOrNodeKind::BwdEdge) => { + left.info.table_id == right.info.dst_table_id + } + _ => unreachable!() + } + }); + if !connects { + return Err(CozoError::LogicError("Chain does not connect".to_string())); + } + Ok(FromEl::Chain(res)) } fn parse_node_pattern(&self, pair: Pair) -> Result { @@ -164,7 +184,6 @@ mod tests { use crate::parser::{Parser, Rule}; use pest::Parser as PestParser; use crate::db::engine::Engine; - use crate::db::eval::Environment; #[test] fn parse_patterns() { @@ -184,6 +203,10 @@ mod tests { relation: ?Text } + create node Z { + *id: Text + } + create assoc WorkInfo : Person { work_id: Int } @@ -205,6 +228,11 @@ mod tests { let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap(); assert_eq!(parsed.as_rule(), Rule::from_pattern); sess.parse_from_pattern(parsed).unwrap(); + + let s = "from a:Friend, (b:Person)-[:Friend]->(c:Z), x:Person"; + let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap(); + assert_eq!(parsed.as_rule(), Rule::from_pattern); + assert!(sess.parse_from_pattern(parsed).is_err()); } drop(engine); let _ = fs::remove_dir_all(db_path); diff --git a/src/db/table.rs b/src/db/table.rs index 6cc68dfc..b9c87a88 100644 --- a/src/db/table.rs +++ b/src/db/table.rs @@ -1,20 +1,37 @@ use std::collections::HashSet; use crate::db::engine::Session; -use crate::db::eval::Environment; use crate::error::{CozoError, Result}; use crate::error::CozoError::LogicError; use crate::relation::data::DataKind; use crate::relation::typing::Typing; +#[derive(Eq, PartialEq, Debug, Clone, Copy)] +pub struct TableId { + pub in_root: bool, + pub id: i64, +} + +impl TableId { + pub fn new(in_root: bool, id: i64) -> Self { + TableId { in_root, id } + } + pub fn is_valid(&self) -> bool { + self.id >= 0 + } +} + +impl Default for TableId { + fn default() -> Self { + TableId { in_root: false, id: -1 } + } +} + #[derive(Eq, PartialEq, Debug, Clone)] pub struct TableInfo { pub kind: DataKind, - pub table_id: i64, - pub src_table_id: i64, - pub dst_table_id: i64, - pub src_in_root: bool, - pub dst_in_root: bool, - pub in_root: bool, + pub table_id: TableId, + pub src_table_id: TableId, + pub dst_table_id: TableId, pub data_keys: HashSet, pub key_typing: Vec<(String, Typing)>, pub val_typing: Vec<(String, Typing)>, @@ -38,21 +55,19 @@ impl<'a, 't> Session<'a, 't> { .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; + let table_id = TableId::new(in_root, table_id); TableInfo { kind: DataKind::Node, table_id, - in_root, - src_table_id: -1, - dst_table_id: -1, - src_in_root: false, + src_table_id: Default::default(), + dst_table_id: Default::default(), data_keys: val_extractor.iter().map(|(k, _)| k.clone()).collect(), key_typing: key_extractor, val_typing: val_extractor, src_key_typing: vec![], dst_key_typing: vec![], associates: vec![], - dst_in_root: false } } DataKind::Edge => { @@ -66,10 +81,12 @@ impl<'a, 't> Session<'a, 't> { .ok_or_else(|| CozoError::LogicError("Src in root extraction failed".to_string()))?; let src_id = tpl.get_int(3) .ok_or_else(|| CozoError::LogicError("Src id extraction failed".to_string()))?; + let src_table_id = TableId::new(src_in_root, src_id); let dst_in_root = tpl.get_bool(4) .ok_or_else(|| CozoError::LogicError("Dst in root extraction failed".to_string()))?; let dst_id = tpl.get_int(5) .ok_or_else(|| CozoError::LogicError("Dst id extraction failed".to_string()))?; + let dst_table_id = TableId::new(dst_in_root, dst_id); let src = self.table_data(src_id, src_in_root)? .ok_or_else(|| CozoError::LogicError("Getting src failed".to_string()))?; let src_key = Typing::try_from(src.get_text(2) @@ -86,21 +103,19 @@ impl<'a, 't> Session<'a, 't> { let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; + let table_id = TableId::new(in_root, table_id); TableInfo { kind: DataKind::Edge, table_id, - in_root, - src_table_id: src_id, - dst_table_id: dst_id, - src_in_root, + src_table_id, + dst_table_id, data_keys: val_extractor.iter().map(|(k, _)| k.clone()).collect(), key_typing: other_key_extractor, val_typing: val_extractor, src_key_typing, dst_key_typing, associates: vec![], - dst_in_root } } _ => return Err(LogicError("Cannot insert into non-tables".to_string())) @@ -113,21 +128,19 @@ impl<'a, 't> Session<'a, 't> { .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; let in_root = d.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; let table_id = d.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; + let table_id = TableId::new(in_root, table_id); let coercer = TableInfo { kind: DataKind::Assoc, table_id, - in_root, - src_table_id: -1, - dst_table_id: -1, - src_in_root: false, + src_table_id: Default::default(), + dst_table_id: Default::default(), data_keys: t.iter().map(|(k, _)| k.clone()).collect(), key_typing: vec![], val_typing: t, src_key_typing: vec![], dst_key_typing: vec![], associates: vec![], - dst_in_root: false }; main_coercer.associates.push(coercer); diff --git a/src/relation/typing.rs b/src/relation/typing.rs index 4ec49f28..ac86cdc3 100644 --- a/src/relation/typing.rs +++ b/src/relation/typing.rs @@ -5,7 +5,6 @@ use crate::relation::value::Value; use pest::Parser as PestParser; use cozorocks::SlicePtr; use crate::db::engine::Session; -use crate::db::eval::{Environment}; use crate::parser::Parser; use crate::parser::Rule; use crate::parser::text_identifier::build_name_in_def; @@ -66,7 +65,7 @@ impl Typing { } impl Typing { - pub fn from_pair<'t, T: AsRef<[u8]>, E: Environment<'t, T>>(pair: Pair, env: Option<&E>) -> Result { + pub fn from_pair<'a, 't>(pair: Pair, env: Option<&Session<'a, 't>>) -> Result { Ok(match pair.as_rule() { Rule::simple_type => match pair.as_str() { "Any" => Typing::Any, @@ -194,7 +193,7 @@ impl TryFrom<&str> for Typing { fn try_from(value: &str) -> Result { let pair = Parser::parse(Rule::typing, value)?.next().unwrap(); - Typing::from_pair::(pair, None) + Typing::from_pair(pair, None) } }