Skip to content

Commit

Permalink
Add errors from BaseTableExpr's to the evaluator (#447)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpschorr authored Mar 12, 2024
1 parent a177f63 commit 6e16561
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adds quotes to the attributes of PartiQL tuple's debug output so it can be read and transformed using Kotlin `partiql-cli`
- Adds u8, u16, u32, u64, and u128 support to partiql_value::Value::from(type)
- [breaking] Changes the interface to `EvalPlan` to accept an `EvalContext`
- [breaking] Changes `EvaluationError` to not implement `Clone`
- [breaking] Changes the structure of `EvalPlan`

### Added
- Add `partiql-extension-visualize` for visualizing AST and logical plan
- Add a `SessionContext` containing both a system-level and a user-level context object usable by expression evaluation

### Fixed
- Fixed `ORDER BY`'s ability to see into projection aliases
- Fixed errors in `BaseTableExpr`s get added to the evaluation context
- Fixed certain errors surfacing in Permissive evaluation mode, when they should only be present in Strict mode

## [0.6.0] - 2023-10-31
### Changed
Expand Down
1 change: 1 addition & 0 deletions partiql-catalog/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct ObjectId {
}

pub type BaseTableExprResultError = Box<dyn Error>;

pub type BaseTableExprResultValueIter<'a> =
Box<dyn 'a + Iterator<Item = Result<Value, BaseTableExprResultError>>>;
pub type BaseTableExprResult<'a> =
Expand Down
9 changes: 7 additions & 2 deletions partiql-eval/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::eval::evaluable::Evaluable;
use crate::eval::expr::EvalExpr;
use crate::eval::EvalContext;
use partiql_catalog::BaseTableExprResultError;
use partiql_value::{Tuple, Value};
use std::borrow::Cow;
use thiserror::Error;
Expand Down Expand Up @@ -30,7 +31,7 @@ pub struct EvalErr {
}

/// An error that can happen during evaluation.
#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum EvaluationError {
/// Internal error that was not due to user input or API violation.
Expand All @@ -42,9 +43,13 @@ pub enum EvaluationError {
/// Feature has not yet been implemented.
#[error("Not yet implemented: {0}")]
NotYetImplemented(String),

/// Error originating in an extension
#[error("Base Table Expression Error")]
ExtensionResultError(#[from] BaseTableExprResultError),
}

/// Used when an error occurs during the the logical to eval plan conversion. Allows the conversion
/// Used when an error occurs during the logical to eval plan conversion. Allows the conversion
/// to continue in order to report multiple errors.
#[derive(Debug)]
pub(crate) struct ErrorNode {}
Expand Down
8 changes: 4 additions & 4 deletions partiql-eval/src/eval/expr/base_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ impl EvalExpr for EvalFnBaseTableExpr {
let bag: Result<Bag, _> = it.collect();
match bag {
Ok(b) => Value::from(b),
Err(_) => {
// TODO hook into pending eval errors
Err(err) => {
ctx.add_error(err.into());
Missing
}
}
}
Err(_) => {
// TODO hook into pending eval errors
Err(err) => {
ctx.add_error(err.into());
Missing
}
};
Expand Down
23 changes: 15 additions & 8 deletions partiql-eval/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use petgraph::visit::EdgeRef;
use unicase::UniCase;

use crate::eval::evaluable::{EvalType, Evaluable};
use crate::plan::EvaluationMode;

pub(crate) mod eval_expr_wrapper;
pub mod evaluable;
Expand All @@ -31,11 +32,14 @@ pub mod expr;
/// Represents a PartiQL evaluation query plan which is a plan that can be evaluated to produce
/// a result. The plan uses a directed `petgraph::StableGraph`.
#[derive(Debug)]
pub struct EvalPlan(pub StableGraph<Box<dyn Evaluable>, u8, Directed>);
pub struct EvalPlan {
mode: EvaluationMode,
plan_graph: StableGraph<Box<dyn Evaluable>, u8, Directed>,
}

impl Default for EvalPlan {
fn default() -> Self {
Self::new()
Self::new(EvaluationMode::Permissive, Default::default())
}
}

Expand All @@ -48,13 +52,16 @@ fn err_illegal_state(msg: impl AsRef<str>) -> EvalErr {

impl EvalPlan {
/// Creates a new evaluation plan.
fn new() -> Self {
EvalPlan(StableGraph::<Box<dyn Evaluable>, u8, Directed>::new())
pub fn new(
mode: EvaluationMode,
plan_graph: StableGraph<Box<dyn Evaluable>, u8, Directed>,
) -> Self {
EvalPlan { mode, plan_graph }
}

#[inline]
fn plan_graph(&mut self) -> &mut StableGraph<Box<dyn Evaluable>, u8> {
&mut self.0
&mut self.plan_graph
}

#[inline]
Expand All @@ -73,7 +80,7 @@ impl EvalPlan {
// that all v ∈ V \{v0} are reachable from v0. Note that this is the definition of trees
// without the condition |E| = |V | − 1. Hence, all trees are DAGs.
// Reference: https://link.springer.com/article/10.1007/s00450-009-0061-0
let ops = toposort(&self.0, None).map_err(|e| EvalErr {
let ops = toposort(&self.plan_graph, None).map_err(|e| EvalErr {
errors: vec![EvaluationError::InvalidEvaluationPlan(format!(
"Malformed evaluation plan detected: {e:?}"
))],
Expand Down Expand Up @@ -101,7 +108,7 @@ impl EvalPlan {
result = Some(src.evaluate(ctx));

// return on first evaluation error
if ctx.has_errors() {
if ctx.has_errors() && self.mode == EvaluationMode::Strict {
return Err(EvalErr {
errors: ctx.errors(),
});
Expand All @@ -127,7 +134,7 @@ impl EvalPlan {
}

pub fn to_dot_graph(&self) -> String {
format!("{:?}", Dot::with_config(&self.0, &[]))
format!("{:?}", Dot::with_config(&self.plan_graph, &[]))
}
}

Expand Down
19 changes: 12 additions & 7 deletions partiql-eval/src/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ macro_rules! correct_num_args_or_err {
};
}

#[derive(Debug, Eq, PartialEq)]
pub enum EvaluationMode {
Strict,
Permissive,
Expand Down Expand Up @@ -129,22 +130,26 @@ impl<'c> EvaluatorPlanner<'c> {
fn plan_eval<const STRICT: bool>(&mut self, lg: &LogicalPlan<BindingsOp>) -> EvalPlan {
let flows = lg.flows();

let mut graph: StableGraph<_, _> = Default::default();
let mut plan_graph: StableGraph<_, _> = Default::default();
let mut seen = HashMap::new();

for (s, d, branch_num) in flows {
let mut add_node = |op_id: &OpId| {
let logical_op = lg.operator(*op_id).unwrap();
*seen
.entry(*op_id)
.or_insert_with(|| graph.add_node(self.get_eval_node::<{ STRICT }>(logical_op)))
*seen.entry(*op_id).or_insert_with(|| {
plan_graph.add_node(self.get_eval_node::<{ STRICT }>(logical_op))
})
};

let (s, d) = (add_node(s), add_node(d));
graph.add_edge(s, d, *branch_num);
plan_graph.add_edge(s, d, *branch_num);
}

EvalPlan(graph)
let mode = if STRICT {
EvaluationMode::Strict
} else {
EvaluationMode::Permissive
};
EvalPlan::new(mode, plan_graph)
}

fn get_eval_node<const STRICT: bool>(&mut self, be: &BindingsOp) -> Box<dyn Evaluable> {
Expand Down
2 changes: 2 additions & 0 deletions partiql/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ itertools = "0.12"
criterion = "0.5"
rand = "0.8"

assert_matches = "1.5"

[[bench]]
name = "bench_eval_multi_like"
harness = false
Expand Down
Loading

1 comment on commit 6e16561

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PartiQL (rust) Benchmark

Benchmark suite Current: 6e16561 Previous: a177f63 Ratio
arith_agg-avg 747809 ns/iter (± 34356) 746821 ns/iter (± 19100) 1.00
arith_agg-avg_distinct 831777 ns/iter (± 5705) 829264 ns/iter (± 3199) 1.00
arith_agg-count 790076 ns/iter (± 17042) 787844 ns/iter (± 12562) 1.00
arith_agg-count_distinct 823566 ns/iter (± 23775) 826939 ns/iter (± 2530) 1.00
arith_agg-min 797208 ns/iter (± 2083) 793890 ns/iter (± 7999) 1.00
arith_agg-min_distinct 828043 ns/iter (± 1950) 841550 ns/iter (± 4400) 0.98
arith_agg-max 800288 ns/iter (± 8875) 806244 ns/iter (± 5126) 0.99
arith_agg-max_distinct 837043 ns/iter (± 18183) 854146 ns/iter (± 2215) 0.98
arith_agg-sum 796913 ns/iter (± 21548) 802239 ns/iter (± 13457) 0.99
arith_agg-sum_distinct 827024 ns/iter (± 4742) 827343 ns/iter (± 3607) 1.00
arith_agg-avg-count-min-max-sum 939603 ns/iter (± 16643) 934828 ns/iter (± 10031) 1.01
arith_agg-avg-count-min-max-sum-group_by 1205820 ns/iter (± 12994) 1173523 ns/iter (± 15018) 1.03
arith_agg-avg-count-min-max-sum-group_by-group_as 1788912 ns/iter (± 13490) 1760710 ns/iter (± 18886) 1.02
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct 1229401 ns/iter (± 21851) 1247320 ns/iter (± 25380) 0.99
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by 1518219 ns/iter (± 40358) 1504635 ns/iter (± 7476) 1.01
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by-group_as 2117193 ns/iter (± 92643) 2073905 ns/iter (± 10864) 1.02
parse-1 4410 ns/iter (± 17) 4133 ns/iter (± 50) 1.07
parse-15 40403 ns/iter (± 1440) 38969 ns/iter (± 328) 1.04
parse-30 79352 ns/iter (± 554) 76003 ns/iter (± 1038) 1.04
compile-1 4458 ns/iter (± 25) 4404 ns/iter (± 28) 1.01
compile-15 30702 ns/iter (± 128) 31097 ns/iter (± 116) 0.99
compile-30 62489 ns/iter (± 233) 63106 ns/iter (± 325) 0.99
plan-1 66573 ns/iter (± 342) 66885 ns/iter (± 626) 1.00
plan-15 1041907 ns/iter (± 10191) 1043991 ns/iter (± 39924) 1.00
plan-30 2086756 ns/iter (± 11988) 2094529 ns/iter (± 8733) 1.00
eval-1 12654151 ns/iter (± 180220) 12975916 ns/iter (± 267403) 0.98
eval-15 85231512 ns/iter (± 860320) 85761476 ns/iter (± 893565) 0.99
eval-30 163672275 ns/iter (± 4185849) 164584010 ns/iter (± 859013) 0.99
join 9886 ns/iter (± 97) 9758 ns/iter (± 35) 1.01
simple 2496 ns/iter (± 11) 2519 ns/iter (± 7) 0.99
simple-no 443 ns/iter (± 1) 442 ns/iter (± 0) 1.00
numbers 58 ns/iter (± 0) 59 ns/iter (± 0) 0.98
parse-simple 579 ns/iter (± 1) 548 ns/iter (± 2) 1.06
parse-ion 1984 ns/iter (± 49) 1796 ns/iter (± 70) 1.10
parse-group 5956 ns/iter (± 65) 5733 ns/iter (± 22) 1.04
parse-complex 15655 ns/iter (± 33) 14943 ns/iter (± 98) 1.05
parse-complex-fexpr 22266 ns/iter (± 329) 21558 ns/iter (± 80) 1.03

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.