Skip to content

Commit

Permalink
Add category for PartiqlShape (#535)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpschorr authored Jan 14, 2025
1 parent a409335 commit 3647c56
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 39 deletions.
93 changes: 57 additions & 36 deletions partiql-eval/src/eval/eval_expr_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::eval::expr::{BindError, EvalExpr};
use crate::eval::EvalContext;
use itertools::Itertools;

use partiql_types::{PartiqlShape, Static, TYPE_DYNAMIC};
use partiql_types::{PartiqlShape, Static, StaticCategory, TYPE_DYNAMIC};
use partiql_value::Value::{Missing, Null};
use partiql_value::{Tuple, Value};

Expand All @@ -14,44 +14,66 @@ use std::hash::Hash;

use std::marker::PhantomData;

use partiql_value::datum::{DatumCategory, DatumCategoryRef, DatumValueRef};
use std::ops::ControlFlow;

// TODO replace with type system's subsumption once it is in place
#[inline]
pub(crate) fn subsumes(typ: &PartiqlShape, value: &Value) -> bool {
match (typ, value) {
(_, Value::Null) => true,
(_, Value::Missing) => true,
(PartiqlShape::Dynamic, _) => true,
(PartiqlShape::AnyOf(anyof), val) => anyof.types().any(|typ| subsumes(typ, val)),
(PartiqlShape::Static(s), val) => match (s.ty(), val) {
(
Static::Int | Static::Int8 | Static::Int16 | Static::Int32 | Static::Int64,
Value::Integer(_),
) => true,
(Static::Bool, Value::Boolean(_)) => true,
(Static::Decimal | Static::DecimalP(_, _), Value::Decimal(_)) => true,
(Static::Float32 | Static::Float64, Value::Real(_)) => true,
(
Static::String | Static::StringFixed(_) | Static::StringVarying(_),
Value::String(_),
) => true,
(Static::Struct(_), Value::Tuple(_)) => true,
(Static::Bag(b_type), Value::Bag(b_values)) => {
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))
}
(Static::DateTime, Value::DateTime(_)) => true,
/// A Trait that represents the ability to match an expected 'type' judgement against a provided value.
trait TypeSatisfier {
/// Returns true if the provided [`Value`] satisfies this type expectation.
fn satisfies(&self, value: &Value) -> bool;
}

(Static::Array(a_type), Value::List(l_values)) => {
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))
/// Type subsumbtion for [`Static`]
impl TypeSatisfier for Static {
fn satisfies(&self, value: &Value) -> bool {
match (self.category(), value.category()) {
(_, DatumCategoryRef::Null) => true,
(_, DatumCategoryRef::Missing) => true,
(StaticCategory::Scalar(ty), DatumCategoryRef::Scalar(scalar)) => match scalar {
DatumValueRef::Value(scalar) => {
matches!(
(ty, scalar),
(
Static::Int
| Static::Int8
| Static::Int16
| Static::Int32
| Static::Int64,
Value::Integer(_),
) | (Static::Bool, Value::Boolean(_))
| (Static::Decimal | Static::DecimalP(_, _), Value::Decimal(_))
| (Static::Float32 | Static::Float64, Value::Real(_))
| (
Static::String | Static::StringFixed(_) | Static::StringVarying(_),
Value::String(_),
)
| (Static::DateTime, Value::DateTime(_))
)
}
},
(StaticCategory::Sequence(shape), DatumCategoryRef::Sequence(seq)) => match shape {
PartiqlShape::Dynamic | PartiqlShape::Undefined => true,
shape => seq.into_iter().all(|v| shape.satisfies(v)),
},
(StaticCategory::Tuple(), DatumCategoryRef::Tuple(_)) => {
true // TODO when Static typing knows how to type a tuple
}
_ => false,
},
_ => false,
}
}
}

/// Type subsumbtion for [`PartiqlShape`]
impl TypeSatisfier for PartiqlShape {
fn satisfies(&self, value: &Value) -> bool {
match (self, value) {
(_, Value::Null) => true,
(_, Value::Missing) => true,
(PartiqlShape::Dynamic, _) => true,
(PartiqlShape::AnyOf(anyof), val) => anyof.types().any(|typ| typ.satisfies(val)),
(PartiqlShape::Static(s), val) => s.ty().satisfies(val),
_ => false,
}
}
}

Expand Down Expand Up @@ -187,7 +209,7 @@ impl<const STRICT: bool, OnMissing: ArgShortCircuit> ArgChecker
Missing => ArgCheckControlFlow::Propagate(OnMissing::propagate()),
Null => ArgCheckControlFlow::Propagate(Null),
val => {
if subsumes(typ, val) {
if typ.satisfies(val) {
ArgCheckControlFlow::Continue(arg)
} else {
err()
Expand Down Expand Up @@ -322,7 +344,6 @@ where
for (idx, arg) in args.iter().enumerate() {
let typ = types(idx);
let arg = arg.evaluate(bindings, ctx);

match ArgC::arg_check(typ, arg) {
ArgCheckControlFlow::Continue(v) => {
if propagate.is_none() {
Expand Down
15 changes: 15 additions & 0 deletions partiql-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,12 @@ pub enum Static {
// TODO Add BitString, ByteString, Blob, Clob, and Graph types
}

pub enum StaticCategory<'a> {
Tuple(),
Sequence(&'a PartiqlShape),
Scalar(&'a Static),
}

impl Static {
pub fn is_scalar(&self) -> bool {
!matches!(self, Static::Struct(_) | Static::Bag(_) | Static::Array(_))
Expand All @@ -754,6 +760,15 @@ impl Static {
pub fn is_struct(&self) -> bool {
matches!(self, Static::Struct(_))
}

pub fn category(&self) -> StaticCategory<'_> {
match self {
Static::Struct(_) => StaticCategory::Tuple(),
Static::Bag(b) => StaticCategory::Sequence(b.element_type()),
Static::Array(b) => StaticCategory::Sequence(b.element_type()),
_ => StaticCategory::Scalar(self),
}
}
}

// TODO, this should probably be via a prettyprint...
Expand Down
66 changes: 63 additions & 3 deletions partiql-value/src/datum.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::{Bag, BindingsName, List, Tuple, Value};
use crate::{
Bag, BagIntoIterator, BagIter, BindingsName, List, ListIntoIterator, ListIter, Tuple, Value,
};
use std::borrow::Cow;
use std::error::Error;

Expand Down Expand Up @@ -194,11 +196,13 @@ pub trait SequenceDatum {
}
}

pub trait RefSequenceView<'a, DV: DatumValue<DV>>: SequenceDatum {
pub trait RefSequenceView<'a, DV: DatumValue<DV> + 'a>:
SequenceDatum + IntoIterator<Item = &'a DV>
{
fn get_val(&self, k: i64) -> Option<Cow<'a, DV>>;
}

pub trait OwnedSequenceView<D: Datum<D>>: SequenceDatum {
pub trait OwnedSequenceView<D: Datum<D>>: SequenceDatum + IntoIterator<Item = D> {
fn take_val(self, k: i64) -> Option<D>;
fn take_val_boxed(self: Box<Self>, k: i64) -> Option<D>;
}
Expand Down Expand Up @@ -253,3 +257,59 @@ impl OwnedSequenceView<Value> for DatumSeqOwned {
self.take_val(k)
}
}

impl<'a> IntoIterator for DatumSeqRef<'a> {
type Item = &'a Value;
type IntoIter = DatumSeqRefIterator<'a>;

fn into_iter(self) -> Self::IntoIter {
match self {
DatumSeqRef::List(l) => DatumSeqRefIterator::List(l.into_iter()),
DatumSeqRef::Bag(b) => DatumSeqRefIterator::Bag(b.into_iter()),
}
}
}

pub enum DatumSeqRefIterator<'a> {
List(ListIter<'a>),
Bag(BagIter<'a>),
}

impl<'a> Iterator for DatumSeqRefIterator<'a> {
type Item = &'a Value;

fn next(&mut self) -> Option<Self::Item> {
match self {
DatumSeqRefIterator::List(l) => l.next(),
DatumSeqRefIterator::Bag(b) => b.next(),
}
}
}

impl IntoIterator for DatumSeqOwned {
type Item = Value;
type IntoIter = DatumSeqOwnedIterator;

fn into_iter(self) -> Self::IntoIter {
match self {
DatumSeqOwned::List(l) => DatumSeqOwnedIterator::List(l.into_iter()),
DatumSeqOwned::Bag(b) => DatumSeqOwnedIterator::Bag(b.into_iter()),
}
}
}

pub enum DatumSeqOwnedIterator {
List(ListIntoIterator),
Bag(BagIntoIterator),
}

impl Iterator for DatumSeqOwnedIterator {
type Item = Value;

fn next(&mut self) -> Option<Self::Item> {
match self {
DatumSeqOwnedIterator::List(l) => l.next(),
DatumSeqOwnedIterator::Bag(b) => b.next(),
}
}
}

1 comment on commit 3647c56

@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: 3647c56 Previous: a409335 Ratio
arith_agg-avg 778823 ns/iter (± 4235) 772276 ns/iter (± 3437) 1.01
arith_agg-avg_distinct 862469 ns/iter (± 14558) 858566 ns/iter (± 4128) 1.00
arith_agg-count 824616 ns/iter (± 20684) 827877 ns/iter (± 13071) 1.00
arith_agg-count_distinct 862385 ns/iter (± 25442) 852895 ns/iter (± 6794) 1.01
arith_agg-min 829546 ns/iter (± 3251) 828341 ns/iter (± 5418) 1.00
arith_agg-min_distinct 867717 ns/iter (± 9625) 857045 ns/iter (± 2362) 1.01
arith_agg-max 839271 ns/iter (± 3509) 827910 ns/iter (± 3246) 1.01
arith_agg-max_distinct 867308 ns/iter (± 3488) 865956 ns/iter (± 16577) 1.00
arith_agg-sum 829345 ns/iter (± 2584) 824878 ns/iter (± 5881) 1.01
arith_agg-sum_distinct 863063 ns/iter (± 17521) 859240 ns/iter (± 4802) 1.00
arith_agg-avg-count-min-max-sum 1007676 ns/iter (± 6642) 990177 ns/iter (± 17058) 1.02
arith_agg-avg-count-min-max-sum-group_by 1262956 ns/iter (± 28389) 1291903 ns/iter (± 6879) 0.98
arith_agg-avg-count-min-max-sum-group_by-group_as 1895714 ns/iter (± 7046) 1906669 ns/iter (± 8973) 0.99
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct 1204549 ns/iter (± 11239) 1200477 ns/iter (± 18692) 1.00
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by 1483475 ns/iter (± 12157) 1495367 ns/iter (± 31044) 0.99
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by-group_as 2081734 ns/iter (± 8508) 2110307 ns/iter (± 9760) 0.99
parse-1 5605 ns/iter (± 88) 5373 ns/iter (± 24) 1.04
parse-15 47958 ns/iter (± 112) 46819 ns/iter (± 97) 1.02
parse-30 94102 ns/iter (± 428) 89844 ns/iter (± 308) 1.05
compile-1 4242 ns/iter (± 25) 4182 ns/iter (± 23) 1.01
compile-15 30977 ns/iter (± 278) 30764 ns/iter (± 282) 1.01
compile-30 63911 ns/iter (± 219) 63231 ns/iter (± 291) 1.01
plan-1 70381 ns/iter (± 503) 70099 ns/iter (± 1332) 1.00
plan-15 1096120 ns/iter (± 6850) 1088274 ns/iter (± 8357) 1.01
plan-30 2193417 ns/iter (± 17025) 2255612 ns/iter (± 46211) 0.97
eval-1 12444594 ns/iter (± 193410) 12213604 ns/iter (± 145987) 1.02
eval-15 78434654 ns/iter (± 1473407) 78102224 ns/iter (± 491542) 1.00
eval-30 149096079 ns/iter (± 763485) 148626494 ns/iter (± 839657) 1.00
join 9890 ns/iter (± 250) 9902 ns/iter (± 275) 1.00
simple 2498 ns/iter (± 5) 2466 ns/iter (± 9) 1.01
simple-no 460 ns/iter (± 3) 467 ns/iter (± 4) 0.99
numbers 48 ns/iter (± 0) 48 ns/iter (± 0) 1
parse-simple 760 ns/iter (± 9) 755 ns/iter (± 5) 1.01
parse-ion 2271 ns/iter (± 27) 2242 ns/iter (± 42) 1.01
parse-group 7149 ns/iter (± 12) 7039 ns/iter (± 88) 1.02
parse-complex 18629 ns/iter (± 194) 18804 ns/iter (± 43) 0.99
parse-complex-fexpr 25853 ns/iter (± 104) 26127 ns/iter (± 76) 0.99

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

Please sign in to comment.