Skip to content

Commit 7e56972

Browse files
authored
Changes logical plan to eval plan API to return Result type (#363)
1 parent 637fdab commit 7e56972

File tree

10 files changed

+241
-89
lines changed

10 files changed

+241
-89
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- *BREAKING:* removed `from_ion` method on `Value`
1212
- *BREAKING:* partiql-ast: `visit` fn returns a `partiql-ast::Recurse` type to indicate if visitation of children nodes should continue
1313
- *BREAKING:* partiql-logical-planner: modifies `lower(parsed: &Parsed)` to return a Result type of `Result<logical::LogicalPlan<logical::BindingsOp>, LoweringError>` rather than a `logical::LogicalPlan<logical::BindingsOp>`
14+
- *BREAKING:* partiql-eval: modifies `compile(&mut self, plan: &LogicalPlan<BindingsOp>)` to return a Result type of `Result<EvalPlan, PlanErr>` rather than an `EvalPlan`
1415
- This is part of an effort to replace `panic`s with `Result`s
1516
- *BREAKING:* partiql-logical-planner: Adds a `LogicalPlanner` to encapsulate the `lower` method
1617
- *BREAKING:* partiql-eval: Adds a `EvaluatorPlanner` now requires a `Catalog` to be supplied at initialization

extension/partiql-extension-ion-functions/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ mod tests {
183183
logical: partiql_logical::LogicalPlan<partiql_logical::BindingsOp>,
184184
bindings: MapBindings<Value>,
185185
) -> Value {
186-
let planner = partiql_eval::plan::EvaluatorPlanner::new(catalog);
186+
let mut planner = partiql_eval::plan::EvaluatorPlanner::new(catalog);
187187

188-
let mut plan = planner.compile(&logical);
188+
let mut plan = planner.compile(&logical).expect("Expect no plan error");
189189

190190
if let Ok(out) = plan.execute_mut(bindings) {
191191
out.result

partiql-conformance-tests/tests/mod.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use partiql_catalog::{Catalog, PartiqlCatalog};
22
use partiql_eval as eval;
33
use partiql_eval::env::basic::MapBindings;
4+
use partiql_eval::error::PlanErr;
5+
use partiql_eval::eval::{EvalPlan, EvalResult};
46
use partiql_logical as logical;
57
use partiql_logical_planner::error::LoweringError;
68
use partiql_parser::{Parsed, ParserResult};
@@ -34,20 +36,18 @@ pub(crate) fn lower(
3436

3537
#[track_caller]
3638
#[inline]
37-
pub(crate) fn evaluate(
39+
pub(crate) fn compile(
3840
catalog: &dyn Catalog,
3941
logical: logical::LogicalPlan<logical::BindingsOp>,
40-
bindings: MapBindings<Value>,
41-
) -> Value {
42-
let planner = eval::plan::EvaluatorPlanner::new(catalog);
43-
44-
let mut plan = planner.compile(&logical);
42+
) -> Result<EvalPlan, PlanErr> {
43+
let mut planner = eval::plan::EvaluatorPlanner::new(catalog);
44+
planner.compile(&logical)
45+
}
4546

46-
if let Ok(out) = plan.execute_mut(bindings) {
47-
out.result
48-
} else {
49-
Value::Missing
50-
}
47+
#[track_caller]
48+
#[inline]
49+
pub(crate) fn evaluate(mut plan: EvalPlan, bindings: MapBindings<Value>) -> EvalResult {
50+
plan.execute_mut(bindings)
5151
}
5252

5353
#[track_caller]
@@ -111,10 +111,10 @@ pub(crate) fn fail_eval(statement: &str, mode: EvaluationMode, env: &Option<Test
111111
.as_ref()
112112
.map(|e| (&e.value).into())
113113
.unwrap_or_else(MapBindings::default);
114-
let out = evaluate(&catalog, lowered, bindings);
114+
let plan = compile(&catalog, lowered).expect("compile");
115+
let out = evaluate(plan, bindings);
115116

116-
println!("{:?}", &out);
117-
// TODO assert failure
117+
assert!(out.is_err());
118118
}
119119

120120
#[track_caller]
@@ -139,10 +139,13 @@ pub(crate) fn pass_eval(
139139
.as_ref()
140140
.map(|e| (&e.value).into())
141141
.unwrap_or_else(MapBindings::default);
142-
let out = evaluate(&catalog, lowered, bindings);
142+
let plan = compile(&catalog, lowered).expect("compile");
143+
let out = evaluate(plan, bindings);
143144

144-
println!("{:?}", &out);
145-
assert_eq!(out, expected.value);
145+
match out {
146+
Ok(v) => assert_eq!(v.result, expected.value),
147+
Err(err) => panic!("Encountered error: {err:?}"),
148+
}
146149
}
147150

148151
#[allow(dead_code)]

partiql-eval/benches/bench_eval.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,8 @@ fn logical_plan() -> LogicalPlan<BindingsOp> {
122122

123123
fn eval_plan(logical: &LogicalPlan<BindingsOp>) -> EvalPlan {
124124
let catalog = PartiqlCatalog::default();
125-
let planner = plan::EvaluatorPlanner::new(&catalog);
126-
127-
planner.compile(logical)
125+
let mut planner = plan::EvaluatorPlanner::new(&catalog);
126+
planner.compile(logical).expect("Expect no plan error")
128127
}
129128

130129
fn evaluate(mut plan: EvalPlan, bindings: MapBindings<Value>) -> Value {

partiql-eval/src/error.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use crate::eval::evaluable::Evaluable;
2+
use crate::eval::expr::EvalExpr;
3+
use crate::eval::EvalContext;
4+
use partiql_value::{Tuple, Value};
5+
use std::borrow::Cow;
6+
use thiserror::Error;
7+
8+
/// All errors that occurred during [`partiql_logical::LogicalPlan`] to [`eval::EvalPlan`] creation.
9+
#[derive(Debug)]
10+
pub struct PlanErr {
11+
pub errors: Vec<PlanningError>,
12+
}
13+
14+
/// An error that can happen during [`partiql_logical::LogicalPlan`] to [`eval::EvalPlan`] creation.
15+
#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
16+
#[non_exhaustive]
17+
pub enum PlanningError {
18+
/// Feature has not yet been implemented.
19+
#[error("Not yet implemented: {0}")]
20+
NotYetImplemented(String),
21+
/// Internal error that was not due to user input or API violation.
22+
#[error("Illegal State: {0}")]
23+
IllegalState(String),
24+
}
25+
26+
/// All errors that occurred during evaluation.
27+
#[derive(Debug)]
28+
pub struct EvalErr {
29+
pub errors: Vec<EvaluationError>,
30+
}
31+
32+
/// An error that can happen during evaluation.
33+
#[derive(Error, Debug, Clone, PartialEq, Eq, Hash)]
34+
#[non_exhaustive]
35+
pub enum EvaluationError {
36+
/// Malformed evaluation plan with graph containing cycle.
37+
#[error("Evaluation Error: invalid evaluation plan detected `{0}`")]
38+
InvalidEvaluationPlan(String),
39+
}
40+
41+
/// Used when an error occurs during the the logical to eval plan conversion. Allows the conversion
42+
/// to continue in order to report multiple errors.
43+
#[derive(Debug)]
44+
pub(crate) struct ErrorNode {}
45+
46+
impl ErrorNode {
47+
pub(crate) fn new() -> ErrorNode {
48+
ErrorNode {}
49+
}
50+
}
51+
52+
impl Evaluable for ErrorNode {
53+
fn evaluate(&mut self, _ctx: &dyn EvalContext) -> Option<Value> {
54+
panic!("ErrorNode will not be evaluated")
55+
}
56+
57+
fn update_input(&mut self, _input: Value, _branch_num: u8) {
58+
panic!("ErrorNode will not be evaluated")
59+
}
60+
}
61+
62+
impl EvalExpr for ErrorNode {
63+
fn evaluate<'a>(&'a self, _bindings: &'a Tuple, _ctx: &'a dyn EvalContext) -> Cow<'a, Value> {
64+
panic!("ErrorNode will not be evaluated")
65+
}
66+
}

partiql-eval/src/eval/mod.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use itertools::Itertools;
22

33
use std::fmt::Debug;
44

5-
use thiserror::Error;
6-
75
use petgraph::algo::toposort;
86
use petgraph::dot::{Config, Dot};
97
use petgraph::prelude::StableGraph;
@@ -16,6 +14,7 @@ use crate::env::Bindings;
1614

1715
use petgraph::graph::NodeIndex;
1816

17+
use crate::error::{EvalErr, EvaluationError};
1918
use petgraph::visit::EdgeRef;
2019

2120
use crate::eval::evaluable::Evaluable;
@@ -106,16 +105,6 @@ pub struct Evaluated {
106105
pub result: Value,
107106
}
108107

109-
pub struct EvalErr {
110-
pub errors: Vec<EvaluationError>,
111-
}
112-
113-
#[derive(Error, Debug)]
114-
pub enum EvaluationError {
115-
#[error("Evaluation Error: malformed evaluation plan detected `{}`", _0)]
116-
InvalidEvaluationPlan(String),
117-
}
118-
119108
/// Represents an evaluation context that is used during evaluation of a plan.
120109
pub trait EvalContext {
121110
fn bindings(&self) -> &dyn Bindings<Value>;

partiql-eval/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod env;
2+
pub mod error;
23
pub mod eval;
34
pub mod plan;
45

@@ -27,8 +28,8 @@ mod tests {
2728

2829
fn evaluate(logical: LogicalPlan<BindingsOp>, bindings: MapBindings<Value>) -> Value {
2930
let catalog = PartiqlCatalog::default();
30-
let planner = plan::EvaluatorPlanner::new(&catalog);
31-
let mut plan = planner.compile(&logical);
31+
let mut planner = plan::EvaluatorPlanner::new(&catalog);
32+
let mut plan = planner.compile(&logical).expect("Expect no plan error");
3233

3334
if let Ok(out) = plan.execute_mut(bindings) {
3435
out.result

0 commit comments

Comments
 (0)