Skip to content

Commit

Permalink
Type Simple SFW queries using current LogicalPlan as an IR (#399)
Browse files Browse the repository at this point in the history
Relates to: https://github.com/partiql/partiql-spec/issues/49

Adds the code for typing a query using the current `LogicalPlan` as an `IR`. This PR includes the changes to enable simple SFW queries as the following in both `Strict` and `Permissive` typing modes with `Open` and `Closed` schemas.

#### Closed schema with `Strict` typing mode.
```SQL
-- customers: <<{'id': INT, 'name': STRING, age: ANY}>>
SELECT customers.id, customers.name FROM customers;

-- Output schema: <<{'id': INT, 'name': STRING}>>
```

#### Open schema with `Strict` typing mode and `age` non-existent projection.
```SQL

-- customers: <<{'id': INT, 'name': STRING}>>
SELECT customers.id, customers.name, customers.age FROM customers;

-- Output schema: <<{'id': INT, 'name': STRING, 'age': ANY}>>
```

#### Closed Schema with `Permissive` typing mode and `age` non-existent projection.
```SQL
-- customers: <<{'id': INT, 'name': STRING>>
SELECT customers.id, customers.name, customers.age FROM customers;


-- Output schema: <<{'id': INT, 'name': STRING, 'age': NULL}>>
```

See: partiql/partiql-spec#64

#### Open Schema with `Strict` typing mode and `age` in nested attribute.
```SQL
-- customers: <<{'id': INT, 'name': STRING, 'details': {'age': INT}}>>
SELECT customers.id, customers.name, customers.details.age FROM customers;


-- Output schema: <<{'id': INT, 'name': STRING, 'age': INT}>>
```

#### Open Schema (`customers and details`) with `Strict` typing mode.
```SQL
-- customers: <<{'id': INT, 'name': STRING, 'details': {'age': INT}}>>
SELECT customers.id, customers.name, customers.details.age, customers.details.foo.bar FROM customers;


-- Output schema: <<{'id': INT, 'name': STRING, 'age': INT, 'bar': ANY}>>
```

#### Open Schema (`customers and details`)  with `Strict` typing mode and `age` in nested attribute with Path in `FROM` with alias.
```SQL
-- customers: <<{'id': INT, 'name': STRING, 'details': {'age': INT}}>>
SELECT d.age FROM customers.details AS d;


-- Output schema: <<{'age': INT}>>
```

See: partiql/partiql-spec#65

#### Closed Schema with `Strict` typing mode with `FROM` and `Projection` aliases.
```SQL
-- customers: <<{'id': INT, 'name': STRING, 'age': ANY}>>
SELECT c.id AS my_id, customers.name AS my_name FROM customers AS c;


-- Output schema: <<{'my_id': INT, 'my_name': STRING}>>
```

In addition:
- fixes some issues with the current `partiql_types` macros, changes the model for some of the types, and adds some helper methods to `PartiqlType`.
- moves constraints to set
- uses ` BTreeSet` for constraints and `AnyOf` to be able to support ordering on the these types; since we're not expecting large number of elements for these types the performance hit seems negligible. 

Upon merging this commit we need to add:
- Support for operators (E.g., unary, binary).
- Support for the rest of the Binding Operators (E.g., `Filter`, `OrderBy`).
- Support for functions.
- Related Conformance Tests.
  • Loading branch information
am357 authored Sep 14, 2023
1 parent 14f6e01 commit fbaac0f
Show file tree
Hide file tree
Showing 9 changed files with 1,101 additions and 87 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add `partiql_ast_passes::static_typer` for type annotating the AST.
- Add ability to parse `ORDER BY`, `LIMIT`, `OFFSET` in children of set operators
- Add `OUTER` bag operator (`OUTER UNION`, `OUTER INTERSECT`, `OUTER EXCEPT`) implementation
- Add experimental `partiql_logical_planner::typer` for typing PartiQL queries with the initial support for simple SFW queries with `SELECT` and `FROM` clauses only with no operators, JOINs, etc.
- Add `NullSortedValue` to specify ordering null or missing values `partiql_value::Value`s before or after all other values
- Implements the aggregation functions `ANY`, `SOME`, `EVERY` and their `COLL_` versions
- Add `COUNT(*)` implementation
Expand Down
1 change: 1 addition & 0 deletions partiql-ast-passes/src/name_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ enum EnclosingClause {
/// AST and collecting variable references. Also partially infers alias if no `AS` alias
/// was provided in the query.
#[derive(Debug)]
#[allow(dead_code)]
pub struct NameResolver<'c> {
// environment stack tracking
id_path_to_root: Vec<ast::NodeId>,
Expand Down
13 changes: 12 additions & 1 deletion partiql-catalog/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,24 @@ impl<'a> TypeEnvEntry<'a> {
}
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct TypeEntry {
id: ObjectId,
ty: PartiqlType,
}

impl TypeEntry {
pub fn id(&self) -> &ObjectId {
&self.id
}

pub fn ty(&self) -> &PartiqlType {
&self.ty
}
}

#[derive(Debug)]
#[allow(dead_code)]
pub struct FunctionEntry<'a> {
id: ObjectId,
function: &'a FunctionEntryFunction,
Expand Down
4 changes: 2 additions & 2 deletions partiql-eval/src/eval/eval_expr_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ pub(crate) fn subsumes(typ: &PartiqlType, value: &Value) -> bool {
) => true,
(TypeKind::Struct(_), Value::Tuple(_)) => true,
(TypeKind::Bag(b_type), Value::Bag(b_values)) => {
let bag_element_type = b_type.element_type.as_ref();
let bag_element_type = b_type.element_type();
let mut b_values = b_values.iter();
b_values.all(|b_value| subsumes(bag_element_type, b_value))
}
(TypeKind::DateTime, Value::DateTime(_)) => true,

(TypeKind::Array(a_type), Value::List(l_values)) => {
let array_element_type = a_type.element_type.as_ref();
let array_element_type = a_type.element_type();
let mut l_values = l_values.iter();
l_values.all(|l_value| subsumes(array_element_type, l_value))
}
Expand Down
1 change: 1 addition & 0 deletions partiql-logical-planner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ partiql-ast = { path = "../partiql-ast", version = "0.5.*" }
partiql-parser = { path = "../partiql-parser", version = "0.5.*" }
partiql-catalog = { path = "../partiql-catalog", version = "0.5.*" }
partiql-ast-passes = { path = "../partiql-ast-passes", version = "0.5.*" }
partiql-types = { path = "../partiql-types", version = "0.5.*" }

ion-rs = "0.18"
ordered-float = "3.*"
Expand Down
1 change: 1 addition & 0 deletions partiql-logical-planner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use partiql_catalog::{Catalog, PartiqlCatalog};

mod builtins;
mod lower;
mod typer;

pub struct LogicalPlanner<'c> {
catalog: &'c dyn Catalog,
Expand Down
14 changes: 8 additions & 6 deletions partiql-logical-planner/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,14 @@ impl<'a> AstToLogical<'a> {
for id in self.id_stack.iter().rev() {
if let Some(key_schema) = self.key_registry.schema.get(id) {
let key_schema: &name_resolver::KeySchema = key_schema;

let name_ref: &name_resolver::NameRef = key_schema
.consume
.iter()
.find(|name_ref| name_ref.sym == varref.name)
.expect("NameRef");

let var_binding = symprim_to_binding(&name_ref.sym);

let mut lookups = vec![];
for lookup in &name_ref.lookup {
match lookup {
Expand All @@ -330,20 +330,21 @@ impl<'a> AstToLogical<'a> {
.filter_map(|scope_id| self.key_registry.schema.get(scope_id))
.collect();

let mut exact = scopes.iter().filter(|&scope| {
scope.produce.contains(&name_resolver::Symbol::Known(
let mut exact = scopes.iter().filter(|key_schema| {
key_schema.produce.contains(&name_resolver::Symbol::Known(
name_ref.sym.clone(),
))
});

if let Some(_matching) = exact.next() {
let var_ref_expr =
ValueExpr::VarRef(var_binding.clone(), VarRefType::Local);
lookups.push(var_ref_expr);
continue;
}

for scope in scopes {
for produce in &scope.produce {
for schema in scopes {
for produce in &schema.produce {
if let name_resolver::Symbol::Known(sym) = produce {
if (sym == &varref.name)
|| (sym.value.to_lowercase()
Expand All @@ -360,6 +361,7 @@ impl<'a> AstToLogical<'a> {
if !lookups.contains(&expr) {
lookups.push(expr);
}

continue;
} else if let Some(_type_entry) = self
.catalog
Expand Down Expand Up @@ -1280,7 +1282,7 @@ impl<'a, 'ast> Visitor<'ast> for AstToLogical<'a> {
}
}
};
self.aggregate_exprs.push(agg_expr.clone());
self.aggregate_exprs.push(agg_expr);
Traverse::Continue
}

Expand Down
Loading

1 comment on commit fbaac0f

@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: fbaac0f Previous: 14f6e01 Ratio
arith_agg-avg 1212926 ns/iter (± 19035) 1213220 ns/iter (± 12508) 1.00
arith_agg-avg_distinct 1582179 ns/iter (± 27164) 1572893 ns/iter (± 16767) 1.01
arith_agg-count 1511903 ns/iter (± 14718) 1522868 ns/iter (± 23537) 0.99
arith_agg-count_distinct 1533225 ns/iter (± 31524) 1559692 ns/iter (± 22208) 0.98
arith_agg-min 1488384 ns/iter (± 19863) 1521911 ns/iter (± 21203) 0.98
arith_agg-min_distinct 1553106 ns/iter (± 17910) 1579583 ns/iter (± 17113) 0.98
arith_agg-max 1524643 ns/iter (± 56117) 1550883 ns/iter (± 8125) 0.98
arith_agg-max_distinct 1560447 ns/iter (± 21059) 1578388 ns/iter (± 16666) 0.99
arith_agg-sum 1523670 ns/iter (± 12597) 1517316 ns/iter (± 24189) 1.00
arith_agg-sum_distinct 1576659 ns/iter (± 13738) 1557248 ns/iter (± 31386) 1.01
arith_agg-avg-count-min-max-sum 1851634 ns/iter (± 8243) 1851214 ns/iter (± 26914) 1.00
arith_agg-avg-count-min-max-sum-group_by 2244821 ns/iter (± 29424) 2214797 ns/iter (± 57988) 1.01
arith_agg-avg-count-min-max-sum-group_by-group_as 3273668 ns/iter (± 36373) 3307202 ns/iter (± 158680) 0.99
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct 2096917 ns/iter (± 21530) 2092775 ns/iter (± 81306) 1.00
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by 2501800 ns/iter (± 30606) 2505991 ns/iter (± 37844) 1.00
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by-group_as 3480626 ns/iter (± 39961) 3488942 ns/iter (± 42833) 1.00
parse-1 6232 ns/iter (± 117) 6871 ns/iter (± 532) 0.91
parse-15 59143 ns/iter (± 912) 65207 ns/iter (± 33597) 0.91
parse-30 118572 ns/iter (± 1759) 122542 ns/iter (± 4017) 0.97
compile-1 6634 ns/iter (± 98) 6536 ns/iter (± 206) 1.01
compile-15 50958 ns/iter (± 392) 51136 ns/iter (± 1518) 1.00
compile-30 103772 ns/iter (± 924) 110807 ns/iter (± 7807) 0.94
plan-1 79923 ns/iter (± 1133) 77594 ns/iter (± 1283) 1.03
plan-15 1281174 ns/iter (± 23005) 1238399 ns/iter (± 60424) 1.03
plan-30 2552074 ns/iter (± 36714) 2444791 ns/iter (± 68665) 1.04
eval-1 23547100 ns/iter (± 629248) 23777220 ns/iter (± 782446) 0.99
eval-15 128954574 ns/iter (± 1564430) 132054690 ns/iter (± 948550) 0.98
eval-30 245984294 ns/iter (± 3999203) 247631799 ns/iter (± 4043217) 0.99
join 15317 ns/iter (± 283) 15542 ns/iter (± 392) 0.99
simple 4070 ns/iter (± 77) 4204 ns/iter (± 129) 0.97
simple-no 685 ns/iter (± 14) 682 ns/iter (± 28) 1.00
numbers 62 ns/iter (± 0) 52 ns/iter (± 1) 1.19
parse-simple 937 ns/iter (± 7) 920 ns/iter (± 125) 1.02
parse-ion 2832 ns/iter (± 23) 2630 ns/iter (± 34) 1.08
parse-group 8551 ns/iter (± 127) 8681 ns/iter (± 539) 0.99
parse-complex 23275 ns/iter (± 464) 23262 ns/iter (± 466) 1.00
parse-complex-fexpr 34548 ns/iter (± 779) 33925 ns/iter (± 968) 1.02

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

Please sign in to comment.