explain op; fix inefficient filter plans

main
Ziyang Hu 2 years ago
parent 1ab10a1ab5
commit 4d0160c85c

@ -13,7 +13,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct BetweennessCentrality;
@ -23,8 +23,8 @@ impl AlgoImpl for BetweennessCentrality {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;
@ -84,8 +84,8 @@ impl AlgoImpl for ClosenessCentrality {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -11,7 +11,7 @@ use crate::data::program::{MagicAlgoApply, MagicAlgoRuleArg, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct ShortestPathAStar;
@ -21,8 +21,8 @@ impl AlgoImpl for ShortestPathAStar {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation_with_min_len(0, 3, tx, stores)?;
@ -72,7 +72,7 @@ fn astar(
nodes: &MagicAlgoRuleArg,
heuristic: &Expr,
tx: &SessionTx,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
poison: Poison,
) -> Result<(f64, Vec<DataValue>)> {
let start_node = &starting.0[0];

@ -7,7 +7,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct Bfs;
@ -17,8 +17,8 @@ impl AlgoImpl for Bfs {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation_with_min_len(0, 2, tx, stores)?;

@ -12,7 +12,7 @@ use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::parse_type;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct CsvReader;
@ -22,8 +22,8 @@ impl AlgoImpl for CsvReader {
&mut self,
_tx: &SessionTx,
algo: &MagicAlgoApply,
_stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
_stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
_poison: Poison,
) -> Result<()> {
let delimiter = algo.string_option("delimiter", Some(","))?;

@ -7,7 +7,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct DegreeCentrality;
@ -17,8 +17,8 @@ impl AlgoImpl for DegreeCentrality {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let it = algo

@ -7,7 +7,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct Dfs;
@ -17,8 +17,8 @@ impl AlgoImpl for Dfs {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation_with_min_len(0, 2, tx, stores)?;

@ -14,7 +14,7 @@ use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct JsonReader;
@ -24,8 +24,8 @@ impl AlgoImpl for JsonReader {
&mut self,
_tx: &SessionTx,
algo: &MagicAlgoApply,
_stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
_stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
_poison: Poison,
) -> Result<()> {
let url = algo.string_option("url", None)?;

@ -11,7 +11,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct MinimumSpanningForestKruskal;
@ -21,8 +21,8 @@ impl AlgoImpl for MinimumSpanningForestKruskal {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -9,7 +9,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct LabelPropagation;
@ -19,8 +19,8 @@ impl AlgoImpl for LabelPropagation {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -9,7 +9,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct CommunityDetectionLouvain;
@ -19,8 +19,8 @@ impl AlgoImpl for CommunityDetectionLouvain {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -34,7 +34,7 @@ use crate::data::tuple::{Tuple, TupleIter};
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) mod all_pairs_shortest_path;
@ -62,8 +62,8 @@ pub(crate) trait AlgoImpl {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()>;
}
@ -291,7 +291,7 @@ impl MagicAlgoRuleArg {
undirected: bool,
allow_negative_edges: bool,
tx: &SessionTx,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
) -> Result<(
Vec<Vec<(usize, f64)>>,
Vec<DataValue>,
@ -375,7 +375,7 @@ impl MagicAlgoRuleArg {
&self,
undirected: bool,
tx: &SessionTx,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
) -> Result<(Vec<Vec<usize>>, Vec<DataValue>, BTreeMap<DataValue, usize>)> {
let mut graph: Vec<Vec<usize>> = vec![];
let mut indices: Vec<DataValue> = vec![];
@ -415,7 +415,7 @@ impl MagicAlgoRuleArg {
&'a self,
prefix: &DataValue,
tx: &'a SessionTx,
stores: &'a BTreeMap<MagicSymbol, StoredRelation>,
stores: &'a BTreeMap<MagicSymbol, InMemRelation>,
) -> Result<TupleIter<'a>> {
Ok(match self {
MagicAlgoRuleArg::InMem { name, .. } => {
@ -435,7 +435,7 @@ impl MagicAlgoRuleArg {
pub(crate) fn arity(
&self,
tx: &SessionTx,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
) -> Result<usize> {
Ok(match self {
MagicAlgoRuleArg::InMem { name, .. } => {
@ -453,7 +453,7 @@ impl MagicAlgoRuleArg {
pub(crate) fn iter<'a>(
&'a self,
tx: &'a SessionTx,
stores: &'a BTreeMap<MagicSymbol, StoredRelation>,
stores: &'a BTreeMap<MagicSymbol, InMemRelation>,
) -> Result<TupleIter<'a>> {
Ok(match self {
MagicAlgoRuleArg::InMem { name, .. } => {

@ -10,7 +10,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct PageRank;
@ -20,8 +20,8 @@ impl AlgoImpl for PageRank {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -13,7 +13,7 @@ use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct MinimumSpanningTreePrim;
@ -23,8 +23,8 @@ impl AlgoImpl for MinimumSpanningTreePrim {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -10,7 +10,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct RandomWalk;
@ -20,8 +20,8 @@ impl AlgoImpl for RandomWalk {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation_with_min_len(0, 2, tx, stores)?;

@ -11,7 +11,7 @@ use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct ReorderSort;
@ -21,8 +21,8 @@ impl AlgoImpl for ReorderSort {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let in_rel = algo.relation(0)?;

@ -14,7 +14,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct ShortestPathDijkstra;
@ -24,8 +24,8 @@ impl AlgoImpl for ShortestPathDijkstra {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -9,7 +9,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct StronglyConnectedComponent {
@ -27,8 +27,8 @@ impl AlgoImpl for StronglyConnectedComponent {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -7,7 +7,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct TopSort;
@ -17,8 +17,8 @@ impl AlgoImpl for TopSort {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -8,7 +8,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct ClusteringCoefficients;
@ -18,8 +18,8 @@ impl AlgoImpl for ClusteringCoefficients {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -10,7 +10,7 @@ use crate::data::program::{MagicAlgoApply, MagicSymbol};
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct KShortestPathYen;
@ -20,8 +20,8 @@ impl AlgoImpl for KShortestPathYen {
&mut self,
tx: &SessionTx,
algo: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
out: &StoredRelation,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
out: &InMemRelation,
poison: Poison,
) -> Result<()> {
let edges = algo.relation(0)?;

@ -3,11 +3,12 @@ query_script = {SOI ~ (option | rule | const_rule | algo_rule)+ ~ EOI}
query_script_inner = {"{" ~ (option | rule | const_rule | algo_rule)+ ~ "}"}
multi_script = {SOI ~ query_script_inner+ ~ EOI}
sys_script = {SOI ~ "::" ~ (compact_op | list_relations_op | list_relation_op | remove_relations_op | trigger_relation_op |
trigger_relation_show_op | rename_relations_op | running_op | kill_op) ~ EOI}
trigger_relation_show_op | rename_relations_op | running_op | kill_op | explain_op) ~ EOI}
compact_op = {"compact"}
running_op = {"running"}
kill_op = {"kill" ~ int}
explain_op = {"explain" ~ query_script_inner}
list_relations_op = {"relations"}
list_relation_op = {"relation" ~ "columns" ~ compound_ident}
remove_relations_op = {"relation" ~ "remove" ~ (compound_ident ~ ",")* ~ compound_ident }

@ -312,15 +312,17 @@ impl Expr {
}
Some(i) => {
#[derive(Error, Diagnostic, Debug)]
#[error("The tuple bound by variable '{0}' is too short")]
#[error("The tuple bound by variable '{0}' is too short: index is {1}, length is {2}")]
#[diagnostic(help("This is definitely a bug. Please report it."))]
#[diagnostic(code(eval::unbound))]
struct TupleTooShortError(String, #[label] SourceSpan);
struct TupleTooShortError(String, usize, usize, #[label] SourceSpan);
Ok(bindings
.0
.get(*i)
.ok_or_else(|| TupleTooShortError(var.name.to_string(), var.span))?
.ok_or_else(|| {
TupleTooShortError(var.name.to_string(), *i, bindings.0.len(), var.span)
})?
.clone())
}
},

@ -17,7 +17,7 @@ use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::relation::InputRelationHandle;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) type ConstRules = BTreeMap<MagicSymbol, ConstRule>;
@ -270,7 +270,7 @@ impl MagicAlgoApply {
idx: usize,
len: usize,
tx: &SessionTx,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
) -> Result<&MagicAlgoRuleArg> {
#[derive(Error, Diagnostic, Debug)]
#[error("Input relation to algorithm has insufficient arity")]
@ -940,6 +940,12 @@ impl MagicSymbol {
}
}
impl Display for MagicSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl Debug for MagicSymbol {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {

@ -121,7 +121,7 @@ pub(crate) fn parse_script(
}
CozoScript::Multi(qs)
}
Rule::sys_script => CozoScript::Sys(parse_sys(parsed.into_inner())?),
Rule::sys_script => CozoScript::Sys(parse_sys(parsed.into_inner(), param_pool)?),
_ => unreachable!(),
})
}

@ -1,18 +1,22 @@
use std::collections::BTreeMap;
use itertools::Itertools;
use miette::{Diagnostic, Result};
use thiserror::Error;
use crate::data::program::InputProgram;
use crate::data::symb::Symbol;
use crate::data::value::DataValue;
use crate::parse::query::parse_query;
use crate::parse::{ExtractSpan, Pairs, Rule, SourceSpan};
#[derive(serde_derive::Serialize, serde_derive::Deserialize)]
pub(crate) enum SysOp {
Compact,
ListRelation(Symbol),
ListRelations,
ListRunning,
KillRunning(u64),
Explain(InputProgram),
RemoveRelation(Vec<Symbol>),
RenameRelation(Vec<(Symbol, Symbol)>),
ShowTrigger(Symbol),
@ -24,7 +28,10 @@ pub(crate) enum SysOp {
#[diagnostic(code(parser::not_proc_id))]
struct ProcessIdError(String, #[label] SourceSpan);
pub(crate) fn parse_sys(mut src: Pairs<'_>) -> Result<SysOp> {
pub(crate) fn parse_sys(
mut src: Pairs<'_>,
param_pool: &BTreeMap<String, DataValue>,
) -> Result<SysOp> {
let inner = src.next().unwrap();
Ok(match inner.as_rule() {
Rule::compact_op => SysOp::Compact,
@ -35,6 +42,10 @@ pub(crate) fn parse_sys(mut src: Pairs<'_>) -> Result<SysOp> {
.map_err(|_| ProcessIdError(i_str.as_str().to_string(), i_str.extract_span()))?;
SysOp::KillRunning(i)
}
Rule::explain_op => {
let prog = parse_query(inner.into_inner().next().unwrap().into_inner(), param_pool)?;
SysOp::Explain(prog)
}
Rule::list_relations_op => SysOp::ListRelations,
Rule::remove_relations_op => {
let rel = inner
@ -90,6 +101,6 @@ pub(crate) fn parse_sys(mut src: Pairs<'_>) -> Result<SysOp> {
}
SysOp::SetTriggers(rel, puts, rms, replaces)
}
_ => unreachable!(),
rule => unreachable!("{:?}", rule),
})
}

@ -1,7 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};
use itertools::Itertools;
use miette::{Context, Diagnostic, ensure, Result};
use miette::{ensure, Context, Diagnostic, Result};
use thiserror::Error;
use crate::data::aggr::Aggregation;
@ -14,7 +14,7 @@ use crate::data::symb::Symbol;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::query::relation::RelAlgebra;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) type CompiledProgram = BTreeMap<MagicSymbol, CompiledRuleSet>;
@ -85,8 +85,8 @@ impl SessionTx {
&mut self,
prog: &StratifiedMagicProgram,
const_rules: &ConstRules,
) -> Result<(Vec<CompiledProgram>, BTreeMap<MagicSymbol, StoredRelation>)> {
let mut stores: BTreeMap<MagicSymbol, StoredRelation> = Default::default();
) -> Result<(Vec<CompiledProgram>, BTreeMap<MagicSymbol, InMemRelation>)> {
let mut stores: BTreeMap<MagicSymbol, InMemRelation> = Default::default();
for (name, ConstRule { data, bindings, .. }) in const_rules {
let arity = if bindings.is_empty() {
@ -105,10 +105,7 @@ impl SessionTx {
for (name, ruleset) in &stratum.prog {
stores.insert(
name.clone(),
self.new_rule_store(
name.clone(),
ruleset.arity()?,
),
self.new_rule_store(name.clone(), ruleset.arity()?),
);
}
}
@ -129,7 +126,7 @@ impl SessionTx {
let header = &rule.head;
let mut relation =
self.compile_magic_rule_body(rule, k, &stores, header)?;
relation.fill_normal_binding_indices().with_context(|| {
relation.fill_binding_indices().with_context(|| {
format!(
"error encountered when filling binding indices for {:#?}",
relation
@ -158,7 +155,7 @@ impl SessionTx {
&mut self,
rule: &MagicRule,
rule_name: &MagicSymbol,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
ret_vars: &[Symbol],
) -> Result<RelAlgebra> {
let mut ret = RelAlgebra::unit(rule_name.symbol().span);
@ -318,11 +315,7 @@ impl SessionTx {
);
}
MagicAtom::Predicate(p) => {
if let Some(fs) = ret.get_filters() {
fs.extend(p.to_conjunction());
} else {
ret = ret.filter(p.clone());
}
ret = ret.filter(p.clone());
}
MagicAtom::Unification(u) => {
if seen_variables.contains(&u.binding) {
@ -349,11 +342,7 @@ impl SessionTx {
u.span,
)
};
if let Some(fs) = ret.get_filters() {
fs.push(expr);
} else {
ret = ret.filter(expr);
}
ret = ret.filter(expr);
} else {
seen_variables.insert(u.binding.clone());
ret = ret.unify(u.binding.clone(), u.expr.clone(), u.one_many_unif, u.span);
@ -376,7 +365,7 @@ impl SessionTx {
#[error("Symbol '{0}' in rule head is unbound")]
#[diagnostic(code(eval::unbound_symb_in_head))]
#[diagnostic(help(
"Note that symbols occurring only in negated positions are not considered bound"
"Note that symbols occurring only in negated positions are not considered bound"
))]
struct UnboundSymbolInRuleHead(String, #[label] SourceSpan);

@ -1,7 +1,7 @@
use std::collections::{BTreeMap, BTreeSet};
use std::mem;
use log::{debug, Level, log_enabled, trace};
use log::{debug, trace};
use miette::Result;
use crate::data::program::{MagicAlgoApply, MagicSymbol, NoEntryError};
@ -9,7 +9,7 @@ use crate::data::symb::{PROG_ENTRY, Symbol};
use crate::parse::SourceSpan;
use crate::query::compile::{AggrKind, CompiledProgram, CompiledRule, CompiledRuleSet};
use crate::runtime::db::Poison;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
pub(crate) struct QueryLimiter {
@ -32,10 +32,10 @@ impl SessionTx {
pub(crate) fn stratified_magic_evaluate(
&self,
strata: &[CompiledProgram],
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
num_to_take: Option<usize>,
poison: Poison,
) -> Result<StoredRelation> {
) -> Result<InMemRelation> {
let ret_area = stores
.get(&MagicSymbol::Muggle {
inner: Symbol::new(PROG_ENTRY, SourceSpan(0, 0)),
@ -52,25 +52,10 @@ impl SessionTx {
fn semi_naive_magic_evaluate(
&self,
prog: &CompiledProgram,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
num_to_take: Option<usize>,
poison: Poison,
) -> Result<()> {
if log_enabled!(Level::Debug) {
for (k, vs) in prog.iter() {
match vs {
CompiledRuleSet::Rules(vs) => {
for (i, compiled) in vs.iter().enumerate() {
debug!("{:?}.{} {:#?}", k, i, compiled)
}
}
CompiledRuleSet::Algo(algo_apply) => {
debug!("{:?} {:?}", k, algo_apply)
}
}
}
}
let mut changed: BTreeMap<_, _> = prog.keys().map(|k| (k, false)).collect();
let mut prev_changed = changed.clone();
let mut limiter = QueryLimiter {
@ -141,7 +126,7 @@ impl SessionTx {
&self,
rule_symb: &MagicSymbol,
algo_apply: &MagicAlgoApply,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
poison: Poison,
) -> Result<()> {
let mut algo_impl = algo_apply.algo.get_impl()?;
@ -153,7 +138,7 @@ impl SessionTx {
rule_symb: &MagicSymbol,
ruleset: &[CompiledRule],
aggr_kind: AggrKind,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
changed: &mut BTreeMap<&MagicSymbol, bool>,
limiter: &mut QueryLimiter,
poison: Poison,
@ -230,7 +215,7 @@ impl SessionTx {
ruleset: &[CompiledRule],
epoch: u32,
is_meet_aggr: bool,
stores: &BTreeMap<MagicSymbol, StoredRelation>,
stores: &BTreeMap<MagicSymbol, InMemRelation>,
prev_changed: &BTreeMap<&MagicSymbol, bool>,
changed: &mut BTreeMap<&MagicSymbol, bool>,
limiter: &mut QueryLimiter,

@ -4,10 +4,8 @@ use std::iter;
use either::{Left, Right};
use itertools::Itertools;
use log::error;
use log::{debug, error};
use miette::{Diagnostic, Result};
use serde_json::json;
use sqlx::types::JsonValue;
use thiserror::Error;
use crate::data::expr::{compute_bounds, Expr};
@ -15,13 +13,14 @@ use crate::data::symb::Symbol;
use crate::data::tuple::{Tuple, TupleIter};
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::in_mem::{InMemRelation, StoredRelationId};
use crate::runtime::relation::RelationHandle;
use crate::runtime::stored::{StoredRelation, StoredRelationId};
use crate::runtime::transact::SessionTx;
use crate::utils::swap_option_result;
pub(crate) enum RelAlgebra {
Fixed(InlineFixedRA),
Stored(StoredRelationRA),
InMem(InMemRelationRA),
Relation(RelationRA),
Join(Box<InnerJoin>),
NegJoin(Box<NegJoin>),
@ -30,57 +29,11 @@ pub(crate) enum RelAlgebra {
Unification(UnificationRA),
}
impl RelAlgebra {
pub(crate) fn flatten_display(&self, idx: usize) -> (Vec<Vec<JsonValue>>, usize) {
let bindings_before = self.bindings_before_eliminate();
let bindings_after = self.bindings_after_eliminate();
let (new_idx, rel_type, mut flattened): (usize, &str, Vec<Vec<JsonValue>>) = match self {
RelAlgebra::Fixed(_) => (idx + 1, "Fixed", vec![]),
RelAlgebra::Stored(_) => (idx + 1, "Stored", vec![]),
RelAlgebra::Relation(_) => (idx + 1, "Rule", vec![]),
RelAlgebra::Join(inner) => {
let InnerJoin {
left,
right,
joiner,
to_eliminate,
span,
} = inner.as_ref();
let (mut left_prev, left_idx) = left.flatten_display(idx);
let (right_prev, right_idx) = right.flatten_display(left_idx);
left_prev.extend(right_prev);
(right_idx + 1, "Join", left_prev)
}
RelAlgebra::NegJoin(_) => (todo!(), "Negation", todo!()),
RelAlgebra::Reorder(_) => (todo!(), "Reorder", todo!()),
RelAlgebra::Filter(_) => (todo!(), "Filter", todo!()),
RelAlgebra::Unification(UnificationRA {
parent,
binding,
expr,
is_multi,
to_eliminate,
span,
}) => {
let rel_type = if *is_multi { "MultiUnify" } else { "Unify" };
let (prev, prev_idx) = parent.flatten_display(idx);
(prev_idx + 1, rel_type, prev)
}
};
flattened.push(vec![
json!(rel_type),
json!(bindings_before),
json!(bindings_after),
]);
(flattened, new_idx)
}
}
impl RelAlgebra {
pub(crate) fn span(&self) -> SourceSpan {
match self {
RelAlgebra::Fixed(i) => i.span,
RelAlgebra::Stored(i) => i.span,
RelAlgebra::InMem(i) => i.span,
RelAlgebra::Relation(i) => i.span,
RelAlgebra::Join(i) => i.span,
RelAlgebra::NegJoin(i) => i.span,
@ -92,12 +45,12 @@ impl RelAlgebra {
}
pub(crate) struct UnificationRA {
parent: Box<RelAlgebra>,
binding: Symbol,
expr: Expr,
is_multi: bool,
pub(crate) parent: Box<RelAlgebra>,
pub(crate) binding: Symbol,
pub(crate) expr: Expr,
pub(crate) is_multi: bool,
pub(crate) to_eliminate: BTreeSet<Symbol>,
span: SourceSpan,
pub(crate) span: SourceSpan,
}
#[derive(Debug, Error, Diagnostic)]
@ -203,8 +156,8 @@ impl UnificationRA {
}
pub(crate) struct FilteredRA {
parent: Box<RelAlgebra>,
pred: Vec<Expr>,
pub(crate) parent: Box<RelAlgebra>,
pub(crate) pred: Vec<Expr>,
pub(crate) to_eliminate: BTreeSet<Symbol>,
pub(crate) span: SourceSpan,
}
@ -294,7 +247,7 @@ impl Debug for RelAlgebra {
.finish()
}
}
RelAlgebra::Stored(r) => f
RelAlgebra::InMem(r) => f
.debug_tuple("Derived")
.field(&bindings)
.field(&r.storage.rule_name)
@ -348,56 +301,32 @@ impl Debug for RelAlgebra {
}
impl RelAlgebra {
pub(crate) fn get_filters(&mut self) -> Option<&mut Vec<Expr>> {
match self {
RelAlgebra::Stored(d) => Some(&mut d.filters),
RelAlgebra::Join(j) => j.right.get_filters(),
RelAlgebra::Filter(f) => Some(&mut f.pred),
_ => None,
}
}
pub(crate) fn fill_normal_binding_indices(&mut self) -> Result<()> {
pub(crate) fn fill_binding_indices(&mut self) -> Result<()> {
match self {
RelAlgebra::Fixed(_) => {}
RelAlgebra::Stored(d) => {
RelAlgebra::InMem(d) => {
d.fill_binding_indices()?;
}
RelAlgebra::Relation(v) => {
v.fill_binding_indices()?;
}
RelAlgebra::Reorder(r) => {
r.relation.fill_normal_binding_indices()?;
r.relation.fill_binding_indices()?;
}
RelAlgebra::Filter(f) => {
f.parent.fill_normal_binding_indices()?;
f.parent.fill_binding_indices()?;
f.fill_binding_indices()?
}
RelAlgebra::NegJoin(r) => {
r.left.fill_normal_binding_indices()?;
r.left.fill_binding_indices()?;
}
RelAlgebra::Unification(u) => {
u.parent.fill_normal_binding_indices()?;
u.parent.fill_binding_indices()?;
u.fill_binding_indices()?
}
RelAlgebra::Join(r) => {
r.left.fill_normal_binding_indices()?;
}
}
if matches!(self, RelAlgebra::Join(_)) {
let bindings = self.bindings_before_eliminate();
if let RelAlgebra::Join(r) = self {
r.right.fill_join_binding_indices(bindings)?;
}
}
Ok(())
}
pub(crate) fn fill_join_binding_indices(&mut self, bindings: Vec<Symbol>) -> Result<()> {
match self {
RelAlgebra::Stored(d) => {
d.fill_join_binding_indices(&bindings)?;
}
r => {
r.fill_normal_binding_indices()?;
r.left.fill_binding_indices()?;
r.right.fill_binding_indices()?;
}
}
Ok(())
@ -415,12 +344,8 @@ impl RelAlgebra {
pub(crate) fn cartesian_join(self, right: RelAlgebra, span: SourceSpan) -> Self {
self.join(right, vec![], vec![], span)
}
pub(crate) fn derived(
bindings: Vec<Symbol>,
storage: StoredRelation,
span: SourceSpan,
) -> Self {
Self::Stored(StoredRelationRA {
pub(crate) fn derived(bindings: Vec<Symbol>, storage: InMemRelation, span: SourceSpan) -> Self {
Self::InMem(InMemRelationRA {
bindings,
storage,
filters: vec![],
@ -446,13 +371,106 @@ impl RelAlgebra {
})
}
pub(crate) fn filter(self, filter: Expr) -> Self {
let span = filter.span();
RelAlgebra::Filter(FilteredRA {
parent: Box::new(self),
pred: vec![filter],
to_eliminate: Default::default(),
span,
})
match self {
s @ (RelAlgebra::Fixed(_)
| RelAlgebra::Reorder(_)
| RelAlgebra::NegJoin(_)
| RelAlgebra::Unification(_)) => {
let span = filter.span();
RelAlgebra::Filter(FilteredRA {
parent: Box::new(s),
pred: vec![filter],
to_eliminate: Default::default(),
span,
})
}
RelAlgebra::Filter(FilteredRA {
parent,
mut pred,
to_eliminate,
span,
}) => {
pred.push(filter);
RelAlgebra::Filter(FilteredRA {
parent,
pred,
to_eliminate,
span,
})
}
RelAlgebra::InMem(InMemRelationRA {
bindings,
storage,
mut filters,
span,
}) => {
filters.push(filter);
RelAlgebra::InMem(InMemRelationRA {
bindings,
storage,
filters,
span,
})
}
RelAlgebra::Relation(RelationRA {
bindings,
storage,
mut filters,
span,
}) => {
filters.push(filter);
RelAlgebra::Relation(RelationRA {
bindings,
storage,
filters,
span,
})
}
RelAlgebra::Join(inner) => {
let filters = filter.to_conjunction();
let left_bindings: BTreeSet<Symbol> =
inner.left.bindings_before_eliminate().into_iter().collect();
let right_bindings: BTreeSet<Symbol> = inner
.right
.bindings_before_eliminate()
.into_iter()
.collect();
let mut remaining = vec![];
let InnerJoin {
mut left,
mut right,
joiner,
to_eliminate,
span,
} = *inner;
for filter in filters {
let f_bindings = filter.bindings();
if f_bindings.is_subset(&left_bindings) {
left = left.filter(filter);
} else if f_bindings.is_subset(&right_bindings) {
right = right.filter(filter);
} else {
remaining.push(filter);
}
}
let mut joined = RelAlgebra::Join(Box::new(InnerJoin {
left,
right,
joiner,
to_eliminate,
span,
}));
if !remaining.is_empty() {
joined = RelAlgebra::Filter(FilteredRA {
parent: Box::new(joined),
pred: remaining,
to_eliminate: Default::default(),
span,
});
}
joined
}
}
}
pub(crate) fn unify(
self,
@ -580,6 +598,15 @@ impl InlineFixedRA {
}
impl InlineFixedRA {
pub(crate) fn join_type(&self) -> &str {
if self.data.is_empty() {
"null_join"
} else if self.data.len() == 1 {
"singleton_join"
} else {
"fixed_join"
}
}
pub(crate) fn join<'a>(
&'a self,
left_iter: TupleIter<'a>,
@ -666,7 +693,10 @@ fn filter_iter(
for p in filters.iter() {
match p.eval_pred(&t) {
Ok(false) => return None,
Err(e) => return Some(Err(e)),
Err(e) => {
debug!("{:?}", t);
return Some(Err(e));
}
Ok(true) => {}
}
}
@ -735,6 +765,7 @@ impl RelationRA {
.map(|i| tuple.0[*i].clone())
.collect_vec(),
);
let filters = self.filters.clone();
if !skip_range_check && !self.filters.is_empty() {
let other_bindings = &self.bindings[right_join_indices.len()..];
@ -748,12 +779,19 @@ impl RelationRA {
return Left(
self.storage
.scan_bounded_prefix(tx, &prefix, &l_bound, &u_bound)
.filter_map_ok(move |found| {
// dbg!("filter", &tuple, &prefix, &found);
.map(move |res_found| -> Result<Option<Tuple>> {
let found = res_found?;
for p in filters.iter() {
if !p.eval_pred(&found)? {
return Ok(None);
}
}
let mut ret = tuple.0.clone();
ret.extend(found.0);
Some(Tuple(ret))
}),
Ok(Some(Tuple(ret)))
})
.map(swap_option_result)
.flatten(),
);
}
}
@ -761,29 +799,28 @@ impl RelationRA {
Right(
self.storage
.scan_prefix(tx, &prefix)
.filter_map_ok(move |found| {
// dbg!("filter", &tuple, &prefix, &found);
.map(move |res_found| -> Result<Option<Tuple>> {
let found = res_found?;
for p in filters.iter() {
if !p.eval_pred(&found)? {
return Ok(None);
}
}
let mut ret = tuple.0.clone();
ret.extend(found.0);
Some(Tuple(ret))
}),
Ok(Some(Tuple(ret)))
})
.map(swap_option_result)
.flatten(),
)
})
.flatten_ok()
.map(flatten_err);
Ok(
match (self.filters.is_empty(), eliminate_indices.is_empty()) {
(true, true) => Box::new(it),
(true, false) => {
Box::new(it.map_ok(move |t| eliminate_from_tuple(t, &eliminate_indices)))
}
(false, true) => Box::new(filter_iter(self.filters.clone(), it)),
(false, false) => Box::new(
filter_iter(self.filters.clone(), it)
.map_ok(move |t| eliminate_from_tuple(t, &eliminate_indices)),
),
},
)
Ok(if eliminate_indices.is_empty() {
Box::new(it)
} else {
Box::new(it.map_ok(move |t| eliminate_from_tuple(t, &eliminate_indices)))
})
}
fn neg_join<'a>(
@ -914,14 +951,14 @@ fn join_is_prefix(right_join_indices: &[usize]) -> bool {
}
#[derive(Debug)]
pub(crate) struct StoredRelationRA {
pub(crate) struct InMemRelationRA {
pub(crate) bindings: Vec<Symbol>,
pub(crate) storage: StoredRelation,
pub(crate) storage: InMemRelation,
pub(crate) filters: Vec<Expr>,
pub(crate) span: SourceSpan,
}
impl StoredRelationRA {
impl InMemRelationRA {
fn fill_binding_indices(&mut self) -> Result<()> {
let bindings: BTreeMap<_, _> = self
.bindings
@ -936,19 +973,6 @@ impl StoredRelationRA {
Ok(())
}
fn fill_join_binding_indices(&mut self, bindings: &[Symbol]) -> Result<()> {
let bindings: BTreeMap<_, _> = bindings
.iter()
.cloned()
.enumerate()
.map(|(a, b)| (b, a))
.collect();
for e in self.filters.iter_mut() {
e.fill_binding_indices(&bindings)?;
}
Ok(())
}
fn iter(
&self,
epoch: Option<u32>,
@ -1118,6 +1142,8 @@ impl StoredRelationRA {
.collect_vec(),
);
let filters = self.filters.clone();
if !skip_range_check && !self.filters.is_empty() {
let other_bindings = &self.bindings[right_join_indices.len()..];
let (l_bound, u_bound) = match compute_bounds(&self.filters, other_bindings) {
@ -1132,12 +1158,19 @@ impl StoredRelationRA {
.scan_bounded_prefix_for_epoch(
&prefix, &l_bound, &u_bound, scan_epoch,
)
.filter_map_ok(move |found| {
// dbg!("filter", &tuple, &prefix, &found);
.map(move |res_found| -> Result<Option<Tuple>> {
let found = res_found?;
for p in filters.iter() {
if !p.eval_pred(&found)? {
return Ok(None);
}
}
let mut ret = tuple.0.clone();
ret.extend(found.0);
Some(Tuple(ret))
}),
Ok(Some(Tuple(ret)))
})
.map(swap_option_result)
.flatten(),
);
}
}
@ -1145,29 +1178,28 @@ impl StoredRelationRA {
Right(
self.storage
.scan_prefix_for_epoch(&prefix, scan_epoch)
.filter_map_ok(move |found| {
// dbg!("filter", &tuple, &prefix, &found);
.map(move |res_found| -> Result<Option<Tuple>> {
let found = res_found?;
for p in filters.iter() {
if !p.eval_pred(&found)? {
return Ok(None);
}
}
let mut ret = tuple.0.clone();
ret.extend(found.0);
Some(Tuple(ret))
}),
Ok(Some(Tuple(ret)))
})
.map(swap_option_result)
.flatten(),
)
})
.flatten_ok()
.map(flatten_err);
Ok(
match (self.filters.is_empty(), eliminate_indices.is_empty()) {
(true, true) => Box::new(it),
(true, false) => {
Box::new(it.map_ok(move |t| eliminate_from_tuple(t, &eliminate_indices)))
}
(false, true) => Box::new(filter_iter(self.filters.clone(), it)),
(false, false) => Box::new(
filter_iter(self.filters.clone(), it)
.map_ok(move |t| eliminate_from_tuple(t, &eliminate_indices)),
),
},
)
Ok(if eliminate_indices.is_empty() {
Box::new(it)
} else {
Box::new(it.map_ok(move |t| eliminate_from_tuple(t, &eliminate_indices)))
})
}
}
@ -1186,6 +1218,13 @@ impl Debug for Joiner {
}
impl Joiner {
pub(crate) fn as_map(&self) -> BTreeMap<&str, &str> {
self.left_keys
.iter()
.zip(self.right_keys.iter())
.map(|(l, r)| (&l.name as &str, &r.name as &str))
.collect()
}
pub(crate) fn join_indices(
&self,
left_bindings: &[Symbol],
@ -1217,7 +1256,7 @@ impl RelAlgebra {
pub(crate) fn eliminate_temp_vars(&mut self, used: &BTreeSet<Symbol>) -> Result<()> {
match self {
RelAlgebra::Fixed(r) => r.do_eliminate_temp_vars(used),
RelAlgebra::Stored(_r) => Ok(()),
RelAlgebra::InMem(_r) => Ok(()),
RelAlgebra::Relation(_v) => Ok(()),
RelAlgebra::Join(r) => r.do_eliminate_temp_vars(used),
RelAlgebra::Reorder(r) => r.relation.eliminate_temp_vars(used),
@ -1230,7 +1269,7 @@ impl RelAlgebra {
fn eliminate_set(&self) -> Option<&BTreeSet<Symbol>> {
match self {
RelAlgebra::Fixed(r) => Some(&r.to_eliminate),
RelAlgebra::Stored(_) => None,
RelAlgebra::InMem(_) => None,
RelAlgebra::Relation(_) => None,
RelAlgebra::Join(r) => Some(&r.to_eliminate),
RelAlgebra::Reorder(_) => None,
@ -1254,7 +1293,7 @@ impl RelAlgebra {
fn bindings_before_eliminate(&self) -> Vec<Symbol> {
match self {
RelAlgebra::Fixed(f) => f.bindings.clone(),
RelAlgebra::Stored(d) => d.bindings.clone(),
RelAlgebra::InMem(d) => d.bindings.clone(),
RelAlgebra::Relation(v) => v.bindings.clone(),
RelAlgebra::Join(j) => j.bindings(),
RelAlgebra::Reorder(r) => r.bindings(),
@ -1275,7 +1314,7 @@ impl RelAlgebra {
) -> Result<TupleIter<'a>> {
match self {
RelAlgebra::Fixed(f) => Ok(Box::new(f.data.iter().map(|t| Ok(Tuple(t.clone()))))),
RelAlgebra::Stored(r) => r.iter(epoch, use_delta),
RelAlgebra::InMem(r) => r.iter(epoch, use_delta),
RelAlgebra::Relation(v) => v.iter(tx),
RelAlgebra::Join(j) => j.iter(tx, epoch, use_delta),
RelAlgebra::Reorder(r) => r.iter(tx, epoch, use_delta),
@ -1309,6 +1348,42 @@ impl NegJoin {
Ok(())
}
pub(crate) fn join_type(&self) -> &str {
match &self.right {
RelAlgebra::InMem(_) => {
let join_indices = self
.joiner
.join_indices(
&self.left.bindings_after_eliminate(),
&self.right.bindings_after_eliminate(),
)
.unwrap();
if join_is_prefix(&join_indices.1) {
"mem_neg_prefix_join"
} else {
"mem_neg_mat_join"
}
}
RelAlgebra::Relation(_) => {
let join_indices = self
.joiner
.join_indices(
&self.left.bindings_after_eliminate(),
&self.right.bindings_after_eliminate(),
)
.unwrap();
if join_is_prefix(&join_indices.1) {
"stored_neg_prefix_join"
} else {
"stored_neg_mat_join"
}
}
_ => {
unreachable!()
}
}
}
pub(crate) fn iter<'a>(
&'a self,
tx: &'a SessionTx,
@ -1318,7 +1393,7 @@ impl NegJoin {
let bindings = self.left.bindings_after_eliminate();
let eliminate_indices = get_eliminate_indices(&bindings, &self.to_eliminate);
match &self.right {
RelAlgebra::Stored(r) => {
RelAlgebra::InMem(r) => {
let join_indices = self
.joiner
.join_indices(
@ -1373,7 +1448,7 @@ impl InnerJoin {
let mut left = used.clone();
left.extend(self.joiner.left_keys.clone());
if let Some(filters) = match &self.right {
RelAlgebra::Stored(r) => Some(&r.filters),
RelAlgebra::InMem(r) => Some(&r.filters),
_ => None,
} {
for filter in filters {
@ -1393,6 +1468,48 @@ impl InnerJoin {
debug_assert_eq!(ret.len(), ret.iter().collect::<BTreeSet<_>>().len());
ret
}
pub(crate) fn join_type(&self) -> &str {
match &self.right {
RelAlgebra::Fixed(f) => f.join_type(),
RelAlgebra::InMem(_) => {
let join_indices = self
.joiner
.join_indices(
&self.left.bindings_after_eliminate(),
&self.right.bindings_after_eliminate(),
)
.unwrap();
if join_is_prefix(&join_indices.1) {
"mem_prefix_join"
} else {
"mem_mat_join"
}
}
RelAlgebra::Relation(_) => {
let join_indices = self
.joiner
.join_indices(
&self.left.bindings_after_eliminate(),
&self.right.bindings_after_eliminate(),
)
.unwrap();
if join_is_prefix(&join_indices.1) {
"stored_prefix_join"
} else {
"stored_mat_join"
}
}
RelAlgebra::Join(_) | RelAlgebra::Filter(_) | RelAlgebra::Unification(_) => {
"generic_mat_join"
}
RelAlgebra::Reorder(_) => {
panic!("joining on reordered")
}
RelAlgebra::NegJoin(_) => {
panic!("joining on NegJoin")
}
}
}
pub(crate) fn iter<'a>(
&'a self,
tx: &'a SessionTx,
@ -1416,7 +1533,7 @@ impl InnerJoin {
eliminate_indices,
)
}
RelAlgebra::Stored(r) => {
RelAlgebra::InMem(r) => {
let join_indices = self
.joiner
.join_indices(

@ -8,16 +8,16 @@ use crate::data::program::SortDir;
use crate::data::symb::Symbol;
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::runtime::stored::StoredRelation;
use crate::runtime::in_mem::InMemRelation;
use crate::runtime::transact::SessionTx;
impl SessionTx {
pub(crate) fn sort_and_collect(
&mut self,
original: StoredRelation,
original: InMemRelation,
sorters: &[(Symbol, SortDir)],
head: &[Symbol],
) -> Result<StoredRelation> {
) -> Result<InMemRelation> {
let head_indices: BTreeMap<_, _> = head.iter().enumerate().map(|(i, k)| (k, i)).collect();
let idx_sorters = sorters
.iter()

@ -9,7 +9,6 @@ use std::{fs, thread};
use either::{Left, Right};
use itertools::Itertools;
use log::debug;
use miette::{bail, ensure, Diagnostic, Result, WrapErr};
use serde_json::json;
use smartstring::SmartString;
@ -26,6 +25,11 @@ use crate::data::tuple::{
use crate::data::value::{DataValue, LARGEST_UTF_CHAR};
use crate::parse::sys::SysOp;
use crate::parse::{parse_script, CozoScript, SourceSpan};
use crate::query::compile::{CompiledProgram, CompiledRule, CompiledRuleSet};
use crate::query::relation::{
FilteredRA, InMemRelationRA, InnerJoin, NegJoin, RelAlgebra, RelationRA, ReorderRA,
UnificationRA,
};
use crate::runtime::relation::{RelationHandle, RelationId};
use crate::runtime::transact::SessionTx;
use crate::utils::swap_option_result;
@ -230,8 +234,194 @@ impl Db {
CozoScript::Sys(op) => self.run_sys_op(op),
}
}
fn explain_compiled(&self, strata: &[CompiledProgram]) -> Result<JsonValue> {
let mut ret: Vec<JsonValue> = vec![];
const STRATUM: &str = "stratum";
const ATOM_IDX: &str = "atom_idx";
const OP: &str = "op";
const RULE_IDX: &str = "rule_idx";
const RULE_NAME: &str = "rule";
const REF_NAME: &str = "ref";
const OUT_BINDINGS: &str = "out_relation";
const JOINS_ON: &str = "joins_on";
const FILTERS: &str = "filters/expr";
let headers = [
STRATUM,
RULE_IDX,
RULE_NAME,
ATOM_IDX,
OP,
REF_NAME,
JOINS_ON,
FILTERS,
OUT_BINDINGS,
];
for (stratum, p) in strata.iter().enumerate() {
let mut clause_idx = -1;
for (rule_name, v) in p {
match v {
CompiledRuleSet::Rules(rules) => {
for CompiledRule { aggr, relation, .. } in rules.iter() {
clause_idx += 1;
let mut ret_for_relation = vec![];
let mut rel_stack = vec![relation];
let mut idx = 0;
let mut atom_type = "out";
for (a, _) in aggr.iter().flatten() {
if a.is_meet {
if atom_type == "out" {
atom_type = "meet_aggr_out";
}
} else {
atom_type = "aggr_out";
}
}
ret_for_relation.push(json!({
STRATUM: stratum,
ATOM_IDX: idx,
OP: atom_type,
RULE_IDX: clause_idx,
RULE_NAME: rule_name.to_string(),
OUT_BINDINGS: relation.bindings_after_eliminate().into_iter().map(|v| v.to_string()).collect_vec()
}));
idx += 1;
while let Some(rel) = rel_stack.pop() {
let (atom_type, ref_name, joins_on, filters) = match rel {
r @ RelAlgebra::Fixed(..) => {
if r.is_unit() {
continue;
}
("fixed", json!(null), json!(null), json!(null))
}
RelAlgebra::InMem(InMemRelationRA {
storage, filters, ..
}) => (
"load_mem",
json!(storage.rule_name.to_string()),
json!(null),
json!(filters.iter().map(|f| f.to_string()).collect_vec()),
),
RelAlgebra::Relation(RelationRA {
storage, filters, ..
}) => (
"load_stored",
json!(format!(":{}", storage.name)),
json!(null),
json!(filters.iter().map(|f| f.to_string()).collect_vec()),
),
RelAlgebra::Join(inner) => {
if inner.left.is_unit() {
rel_stack.push(&inner.right);
continue;
}
let t = inner.join_type();
let InnerJoin {
left,
right,
joiner,
..
} = inner.as_ref();
rel_stack.push(left);
rel_stack.push(right);
(t, json!(null), json!(joiner.as_map()), json!(null))
}
RelAlgebra::NegJoin(inner) => {
let t = inner.join_type();
let NegJoin {
left,
right,
joiner,
..
} = inner.as_ref();
rel_stack.push(left);
rel_stack.push(right);
(t, json!(null), json!(joiner.as_map()), json!(null))
}
RelAlgebra::Reorder(ReorderRA { relation, .. }) => {
rel_stack.push(relation);
("reorder", json!(null), json!(null), json!(null))
}
RelAlgebra::Filter(FilteredRA { parent, pred, .. }) => {
rel_stack.push(parent);
(
"filter",
json!(null),
json!(null),
json!(pred.iter().map(|f| f.to_string()).collect_vec()),
)
}
RelAlgebra::Unification(UnificationRA {
parent,
binding,
expr,
is_multi,
..
}) => {
rel_stack.push(parent);
(
if *is_multi { "multi-unify" } else { "unify" },
json!(binding.name),
json!(null),
json!(expr.to_string()),
)
}
};
ret_for_relation.push(json!({
STRATUM: stratum,
ATOM_IDX: idx,
OP: atom_type,
RULE_IDX: clause_idx,
RULE_NAME: rule_name.to_string(),
REF_NAME: ref_name,
OUT_BINDINGS: rel.bindings_after_eliminate().into_iter().map(|v| v.to_string()).collect_vec(),
JOINS_ON: joins_on,
FILTERS: filters,
}));
idx += 1;
}
ret_for_relation.reverse();
ret.extend(ret_for_relation)
}
}
CompiledRuleSet::Algo(_) => ret.push(json!({
STRATUM: stratum,
ATOM_IDX: 0,
OP: "algo",
RULE_IDX: 0,
RULE_NAME: rule_name.to_string(),
})),
}
}
}
let ret = ret
.into_iter()
.map(|m| {
headers
.iter()
.map(|i| m.get(*i).unwrap_or(&JsonValue::Null).clone())
.collect_vec()
})
.collect_vec();
Ok(json!({"headers": headers, "rows": ret}))
}
fn run_sys_op(&self, op: SysOp) -> Result<JsonValue> {
match op {
SysOp::Explain(prog) => {
let mut tx = self.transact()?;
let program = prog
.to_normalized_program(&tx)?
.stratify()?
.magic_sets_rewrite(&tx)?;
let (compiled, _) = tx.stratified_magic_compile(&program, &prog.const_rules)?;
self.explain_compiled(&compiled)
}
SysOp::Compact => {
self.compact_relation()?;
Ok(json!({"headers": ["status"], "rows": [["OK"]]}))
@ -295,7 +485,6 @@ impl Db {
tx: &mut SessionTx,
input_program: InputProgram,
) -> Result<(JsonValue, Vec<(Vec<u8>, Vec<u8>)>)> {
debug!("{}", input_program);
let mut clean_ups = vec![];
if let Some((meta, op)) = &input_program.out_opts.store_relation {
if *op == RelationOp::Create {
@ -328,7 +517,6 @@ impl Db {
.to_normalized_program(tx)?
.stratify()?
.magic_sets_rewrite(tx)?;
debug!("{:#?}", program);
let (compiled, stores) =
tx.stratified_magic_compile(&program, &input_program.const_rules)?;

@ -29,7 +29,7 @@ impl Debug for StoredRelationId {
}
#[derive(Clone)]
pub(crate) struct StoredRelation {
pub(crate) struct InMemRelation {
mem_db: Arc<RwLock<Vec<Arc<RwLock<BTreeMap<Tuple, Tuple>>>>>>,
epoch_size: Arc<AtomicU32>,
pub(crate) id: StoredRelationId,
@ -37,18 +37,18 @@ pub(crate) struct StoredRelation {
pub(crate) arity: usize,
}
impl Debug for StoredRelation {
impl Debug for InMemRelation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "TempStore<{}>", self.id.0)
}
}
impl StoredRelation {
impl InMemRelation {
pub(crate) fn new(
id: StoredRelationId,
rule_name: MagicSymbol,
arity: usize,
) -> StoredRelation {
) -> InMemRelation {
Self {
epoch_size: Default::default(),
mem_db: Default::default(),
@ -177,7 +177,7 @@ impl StoredRelation {
pub(crate) fn normal_aggr_scan_and_put(
&self,
aggrs: &[Option<(Aggregation, Vec<DataValue>)>],
store: &StoredRelation,
store: &InMemRelation,
mut limiter: Option<&mut QueryLimiter>,
poison: Poison,
) -> Result<bool> {

@ -1,4 +1,4 @@
pub(crate) mod db;
pub(crate) mod transact;
pub(crate) mod stored;
pub(crate) mod in_mem;
pub(crate) mod relation;

@ -10,7 +10,7 @@ use crate::data::symb::Symbol;
use crate::data::tuple::Tuple;
use crate::data::value::DataValue;
use crate::parse::SourceSpan;
use crate::runtime::stored::{StoredRelation, StoredRelationId};
use crate::runtime::in_mem::{InMemRelation, StoredRelationId};
use crate::runtime::relation::RelationId;
pub struct SessionTx {
@ -20,16 +20,16 @@ pub struct SessionTx {
}
impl SessionTx {
pub(crate) fn new_rule_store(&self, rule_name: MagicSymbol, arity: usize) -> StoredRelation {
pub(crate) fn new_rule_store(&self, rule_name: MagicSymbol, arity: usize) -> InMemRelation {
let old_count = self.mem_store_id.fetch_add(1, Ordering::AcqRel);
let old_count = old_count & 0x00ff_ffffu32;
StoredRelation::new(StoredRelationId(old_count), rule_name, arity)
InMemRelation::new(StoredRelationId(old_count), rule_name, arity)
}
pub(crate) fn new_temp_store(&self, span: SourceSpan) -> StoredRelation {
pub(crate) fn new_temp_store(&self, span: SourceSpan) -> InMemRelation {
let old_count = self.mem_store_id.fetch_add(1, Ordering::AcqRel);
let old_count = old_count & 0x00ff_ffffu32;
StoredRelation::new(
InMemRelation::new(
StoredRelationId(old_count),
MagicSymbol::Muggle {
inner: Symbol::new("", span),

Loading…
Cancel
Save