Skip to content

Commit 337f912

Browse files
authored
PoC interpreting evaluator (#197)
1 parent 17cbcb5 commit 337f912

File tree

14 files changed

+2297
-7
lines changed

14 files changed

+2297
-7
lines changed

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
[workspace.package]
2+
authors = ["PartiQL Team <[email protected]>"]
3+
homepage = "https://github.com/partiql/partiql-lang-rust"
4+
repository = "https://github.com/partiql/partiql-lang-rust"
5+
version = "0.1.0"
6+
edition = "2021"
7+
18
[workspace]
29

310
members = [
@@ -6,12 +13,14 @@ members = [
613
"partiql-conformance-tests",
714
"partiql-conformance-test-generator",
815
"partiql-source-map",
16+
"partiql-logical",
917
"partiql-eval",
1018
"partiql-ir",
1119
"partiql-irgen",
1220
"partiql-parser",
1321
"partiql-rewriter",
1422
"partiql-types",
23+
"partiql-value",
1524
]
1625

1726
exclude = [

partiql-eval/Cargo.toml

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
11
[package]
22
name = "partiql-eval"
3-
authors = ["PartiQL Team <[email protected]>"]
43
description = "PartiQL Expression Evaluator"
5-
homepage = "https://github.com/partiql/partiql-lang-rust"
6-
repository = "https://github.com/partiql/partiql-lang-rust"
4+
authors.workspace = true
5+
homepage.workspace = true
6+
repository.workspace = true
77
license = "Apache-2.0"
88
readme = "../README.md"
99
keywords = ["sql", "parser", "query", "compilers", "interpreters"]
10-
categories = ["database", "compilers", "parser-implementations"]
10+
categories = ["database", "compilers"]
1111
exclude = [
1212
"**/.git/**",
1313
"**/.github/**",
1414
"**/.travis.yml",
1515
"**/.appveyor.yml",
1616
]
17-
edition = "2021"
18-
version = "0.1.0"
17+
version.workspace = true
18+
edition.workspace = true
1919

2020
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
2121

2222
[dependencies]
23+
partiql-logical = { path = "../partiql-logical" }
24+
partiql-value = { path = "../partiql-value" }
25+
ordered-float = "3.*"
26+
itertools = "0.10.*"
27+
unicase = "2.*"
28+
29+
[dev-dependencies]
30+
criterion = "0.4"
31+
32+
[[bench]]
33+
name = "bench_eval"
34+
harness = false

partiql-eval/benches/bench_eval.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
2+
3+
use partiql_eval::env::basic::MapBindings;
4+
use partiql_eval::eval::{
5+
BasicContext, EvalFrom, EvalOutputAccumulator, EvalPath, EvalVarRef, Evaluable, Output,
6+
PathComponent,
7+
};
8+
use partiql_value::{partiql_bag, partiql_list, Bag, BindingsName, List, Tuple, Value};
9+
use std::cell::RefCell;
10+
use std::rc::Rc;
11+
use std::time::Duration;
12+
13+
fn data() -> MapBindings<Value> {
14+
let employees = partiql_bag![
15+
Tuple::from([
16+
("id", 3.into()),
17+
("name", "Bob Smith".into()),
18+
("title", Value::Null),
19+
(
20+
"projects",
21+
partiql_list![
22+
"AWS Redshift Spectrum querying".into(),
23+
"AWS Redshift security".into(),
24+
"AWS Aurora security".into()
25+
]
26+
.into()
27+
),
28+
])
29+
.into(),
30+
Tuple::from([
31+
("id", 4.into()),
32+
("name", "Susan Smith".into()),
33+
("title", "Dev Mgr".into()),
34+
("projects", partiql_list![].into()),
35+
])
36+
.into(),
37+
Tuple::from([
38+
("id", 6.into()),
39+
("name", "Jane Smith".into()),
40+
("title", "Software Eng 2".into()),
41+
(
42+
"projects",
43+
partiql_list!["AWS Redshift security".into()].into()
44+
),
45+
])
46+
.into(),
47+
];
48+
let hr = Tuple::from([("employeesNestScalars", Value::from(employees))]);
49+
50+
let mut p0: MapBindings<Value> = MapBindings::default();
51+
p0.insert("hr", hr.into());
52+
p0
53+
}
54+
55+
fn eval_bench(c: &mut Criterion) {
56+
fn eval(eval: bool) {
57+
let output = Rc::new(RefCell::new(EvalOutputAccumulator::default()));
58+
let eout = Box::new(Output { output });
59+
60+
// eval plan for SELECT * FROM hr.employeesNestScalars
61+
let mut from = EvalFrom::new(
62+
Box::new(EvalPath {
63+
expr: Box::new(EvalVarRef {
64+
name: BindingsName::CaseInsensitive("hr".to_string()),
65+
}),
66+
components: vec![PathComponent::Key("employeesNestScalars".to_string())],
67+
}),
68+
"x",
69+
eout,
70+
);
71+
72+
let ctx = BasicContext::new(data());
73+
if eval {
74+
from.evaluate(&ctx);
75+
}
76+
}
77+
78+
let _dummy = "dummy";
79+
c.bench_function("simple", |b| b.iter(|| eval(black_box(true))));
80+
c.bench_function("simple-no", |b| b.iter(|| eval(black_box(false))));
81+
c.bench_function("numbers", |b| {
82+
b.iter(|| {
83+
black_box(Value::Integer(0));
84+
black_box(Value::Integer(7));
85+
black_box(Value::Integer(29));
86+
black_box(Value::Integer(119));
87+
black_box(Value::Integer(1209));
88+
black_box(Value::Integer(12209));
89+
black_box(Value::Integer(122039));
90+
black_box(Value::Integer(1220339));
91+
black_box(Value::Integer(12203392));
92+
black_box(Value::Integer(122033942));
93+
})
94+
});
95+
}
96+
97+
criterion_group! {
98+
name = eval;
99+
config = Criterion::default().measurement_time(Duration::new(5, 0));
100+
targets = eval_bench
101+
}
102+
103+
criterion_main!(eval);

partiql-eval/src/env.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use std::fmt::Debug;
2+
3+
use partiql_value::{BindingsName, Tuple, Value};
4+
use unicase::UniCase;
5+
6+
pub trait Bindings<T> {
7+
fn get(&self, name: &BindingsName) -> Option<&T>;
8+
}
9+
10+
impl Bindings<Value> for Tuple {
11+
fn get(&self, name: &BindingsName) -> Option<&Value> {
12+
match name {
13+
BindingsName::CaseSensitive(s) => self.0.get(s),
14+
BindingsName::CaseInsensitive(s) => {
15+
//TODO
16+
self.0.get(s)
17+
}
18+
}
19+
}
20+
}
21+
22+
pub mod basic {
23+
use super::*;
24+
use std::collections::HashMap;
25+
26+
#[derive(Debug)]
27+
pub struct MapBindings<T> {
28+
sensitive: HashMap<String, usize>,
29+
insensitive: HashMap<UniCase<String>, usize>,
30+
values: Vec<T>,
31+
}
32+
33+
impl<T> Default for MapBindings<T> {
34+
fn default() -> Self {
35+
MapBindings {
36+
sensitive: HashMap::new(),
37+
insensitive: HashMap::new(),
38+
values: vec![],
39+
}
40+
}
41+
}
42+
43+
impl<T> MapBindings<T> {
44+
pub fn insert(&mut self, name: &str, value: T) {
45+
// TODO error on duplicate insensitive
46+
let idx = self.values.len();
47+
self.values.push(value);
48+
self.sensitive.insert(name.to_string(), idx);
49+
self.insensitive.insert(UniCase::new(name.to_string()), idx);
50+
}
51+
}
52+
53+
impl<T> Bindings<T> for MapBindings<T> {
54+
#[inline]
55+
fn get(&self, name: &BindingsName) -> Option<&T> {
56+
let idx = match name {
57+
BindingsName::CaseSensitive(s) => self.sensitive.get(s),
58+
BindingsName::CaseInsensitive(s) => {
59+
self.insensitive.get(&UniCase::new(s.to_string()))
60+
}
61+
};
62+
idx.and_then(|idx| self.values.get(*idx))
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)