Skip to content

Commit

Permalink
Add PartiQL Shape (#464)
Browse files Browse the repository at this point in the history
Refactors `partiql-types` by adding `PartiqlShape`; with this model, `PartiqlShape`
is one of `Dynamic` (ex. `Any`), `AnyOf`, `Static`, or `Undefined`. `nullability` is
 defined as part of `StaticType`.

The large diff is as a result of the `PartiqlType` refactoring.
  • Loading branch information
am357 authored Jun 19, 2024
1 parent 2e9e4cd commit ee13dee
Show file tree
Hide file tree
Showing 8 changed files with 503 additions and 313 deletions.
12 changes: 6 additions & 6 deletions partiql-catalog/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::call_defs::CallDef;

use partiql_types::PartiqlType;
use partiql_types::PartiqlShape;
use partiql_value::Value;
use std::borrow::Cow;

Expand Down Expand Up @@ -128,12 +128,12 @@ pub trait Catalog: Debug {
pub struct TypeEnvEntry<'a> {
name: UniCase<String>,
aliases: Vec<&'a str>,
ty: PartiqlType,
ty: PartiqlShape,
}

impl<'a> TypeEnvEntry<'a> {
#[must_use]
pub fn new(name: &str, aliases: &[&'a str], ty: PartiqlType) -> Self {
pub fn new(name: &str, aliases: &[&'a str], ty: PartiqlShape) -> Self {
TypeEnvEntry {
name: UniCase::from(name.to_string()),
aliases: aliases.to_vec(),
Expand All @@ -145,7 +145,7 @@ impl<'a> TypeEnvEntry<'a> {
#[derive(Debug, Clone)]
pub struct TypeEntry {
id: ObjectId,
ty: PartiqlType,
ty: PartiqlShape,
}

impl TypeEntry {
Expand All @@ -155,7 +155,7 @@ impl TypeEntry {
}

#[must_use]
pub fn ty(&self) -> &PartiqlType {
pub fn ty(&self) -> &PartiqlShape {
&self.ty
}
}
Expand Down Expand Up @@ -197,7 +197,7 @@ impl<'a> FunctionEntry<'a> {
#[derive(Debug)]
pub struct PartiqlCatalog {
functions: CatalogEntrySet<FunctionEntryFunction>,
types: CatalogEntrySet<PartiqlType>,
types: CatalogEntrySet<PartiqlShape>,
id: CatalogId,
}

Expand Down
109 changes: 58 additions & 51 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::{PartiqlType, TypeKind, TYPE_ANY};
use partiql_types::{PartiqlShape, StaticTypeVariant, TYPE_DYNAMIC};
use partiql_value::Value::{Missing, Null};
use partiql_value::{Tuple, Value};

Expand All @@ -18,36 +18,47 @@ use std::ops::ControlFlow;

// TODO replace with type system's subsumption once it is in place
#[inline]
pub(crate) fn subsumes(typ: &PartiqlType, value: &Value) -> bool {
match (typ.kind(), value) {
pub(crate) fn subsumes(typ: &PartiqlShape, value: &Value) -> bool {
match (typ, value) {
(_, Value::Null) => true,
(_, Value::Missing) => true,
(TypeKind::Any, _) => true,
(TypeKind::AnyOf(anyof), val) => anyof.types().any(|typ| subsumes(typ, val)),
(
TypeKind::Int | TypeKind::Int8 | TypeKind::Int16 | TypeKind::Int32 | TypeKind::Int64,
Value::Integer(_),
) => true,
(TypeKind::Bool, Value::Boolean(_)) => true,
(TypeKind::Decimal | TypeKind::DecimalP(_, _), Value::Decimal(_)) => true,
(TypeKind::Float32 | TypeKind::Float64, Value::Real(_)) => true,
(
TypeKind::String | TypeKind::StringFixed(_) | TypeKind::StringVarying(_),
Value::String(_),
) => true,
(TypeKind::Struct(_), Value::Tuple(_)) => true,
(TypeKind::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))
}
(TypeKind::DateTime, Value::DateTime(_)) => true,
(PartiqlShape::Dynamic, _) => true,
(PartiqlShape::AnyOf(anyof), val) => anyof.types().any(|typ| subsumes(typ, val)),
(PartiqlShape::Static(s), val) => match (s.ty(), val) {
(
StaticTypeVariant::Int
| StaticTypeVariant::Int8
| StaticTypeVariant::Int16
| StaticTypeVariant::Int32
| StaticTypeVariant::Int64,
Value::Integer(_),
) => true,
(StaticTypeVariant::Bool, Value::Boolean(_)) => true,
(StaticTypeVariant::Decimal | StaticTypeVariant::DecimalP(_, _), Value::Decimal(_)) => {
true
}
(StaticTypeVariant::Float32 | StaticTypeVariant::Float64, Value::Real(_)) => true,
(
StaticTypeVariant::String
| StaticTypeVariant::StringFixed(_)
| StaticTypeVariant::StringVarying(_),
Value::String(_),
) => true,
(StaticTypeVariant::Struct(_), Value::Tuple(_)) => true,
(StaticTypeVariant::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))
}
(StaticTypeVariant::DateTime, Value::DateTime(_)) => true,

(TypeKind::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))
}
(StaticTypeVariant::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))
}
_ => false,
},
_ => false,
}
}
Expand Down Expand Up @@ -95,7 +106,7 @@ pub(crate) enum ArgCheckControlFlow<B, C, R = B> {
pub(crate) trait ArgChecker: Debug {
/// Check an argument against an expected type.
fn arg_check<'a>(
typ: &PartiqlType,
typ: &PartiqlShape,
arg: Cow<'a, Value>,
) -> ArgCheckControlFlow<Value, Cow<'a, Value>>;
}
Expand Down Expand Up @@ -158,7 +169,7 @@ impl<const STRICT: bool, OnMissing: ArgShortCircuit> ArgChecker
for DefaultArgChecker<STRICT, OnMissing>
{
fn arg_check<'a>(
typ: &PartiqlType,
typ: &PartiqlShape,
arg: Cow<'a, Value>,
) -> ArgCheckControlFlow<Value, Cow<'a, Value>> {
let err = || {
Expand Down Expand Up @@ -189,7 +200,7 @@ pub(crate) struct NullArgChecker {}

impl ArgChecker for NullArgChecker {
fn arg_check<'a>(
_typ: &PartiqlType,
_typ: &PartiqlShape,
arg: Cow<'a, Value>,
) -> ArgCheckControlFlow<Value, Cow<'a, Value>> {
ArgCheckControlFlow::Continue(arg)
Expand All @@ -209,7 +220,7 @@ pub(crate) struct ArgCheckEvalExpr<
ArgC: ArgChecker,
> {
/// The expected type of expression's positional arguments
pub(crate) types: [PartiqlType; N],
pub(crate) types: [PartiqlShape; N],
/// The expression's positional arguments
pub(crate) args: [Box<dyn EvalExpr>; N],
/// the expression
Expand Down Expand Up @@ -237,7 +248,7 @@ impl<const STRICT: bool, const N: usize, E: ExecuteEvalExpr<N>, ArgC: ArgChecker
impl<const STRICT: bool, const N: usize, E: ExecuteEvalExpr<N>, ArgC: ArgChecker>
ArgCheckEvalExpr<STRICT, N, E, ArgC>
{
pub fn new(types: [PartiqlType; N], args: [Box<dyn EvalExpr>; N], expr: E) -> Self {
pub fn new(types: [PartiqlShape; N], args: [Box<dyn EvalExpr>; N], expr: E) -> Self {
Self {
types,
args,
Expand Down Expand Up @@ -298,11 +309,7 @@ impl<const STRICT: bool, const N: usize, E: ExecuteEvalExpr<N>, ArgC: ArgChecker
ArgCheckControlFlow::ShortCircuit(v) => return ControlFlow::Break(v),
ArgCheckControlFlow::ErrorOrShortCircuit(v) => {
if STRICT {
let signature = self
.types
.iter()
.map(|typ| format!("{}", typ.kind()))
.join(",");
let signature = self.types.iter().map(|typ| format!("{}", typ)).join(",");
let before = (0..i).map(|_| "_");
let arg = "MISSING"; // TODO display actual argument?
let after = (i + 1..N).map(|_| "_");
Expand Down Expand Up @@ -368,7 +375,7 @@ impl<E: 'static, F: 'static> EvalExprWrapper<E, F> {
#[inline]
pub(crate) fn create_checked<const STRICT: bool, const N: usize, ArgC: 'static + ArgChecker>(
ident: E,
types: [PartiqlType; N],
types: [PartiqlShape; N],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand Down Expand Up @@ -414,13 +421,13 @@ impl UnaryValueExpr {
where
F: 'static + Fn(&Value) -> Value,
{
Self::create_typed::<STRICT, F>([TYPE_ANY; 1], args, f)
Self::create_typed::<STRICT, F>([TYPE_DYNAMIC; 1], args, f)
}

#[allow(dead_code)]
#[inline]
pub(crate) fn create_typed<const STRICT: bool, F>(
types: [PartiqlType; 1],
types: [PartiqlShape; 1],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand All @@ -434,7 +441,7 @@ impl UnaryValueExpr {
#[allow(dead_code)]
#[inline]
pub(crate) fn create_checked<const STRICT: bool, ArgC, F>(
types: [PartiqlType; 1],
types: [PartiqlShape; 1],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand Down Expand Up @@ -478,13 +485,13 @@ impl BinaryValueExpr {
where
F: 'static + Fn(&Value, &Value) -> Value,
{
Self::create_typed::<STRICT, F>([TYPE_ANY; 2], args, f)
Self::create_typed::<STRICT, F>([TYPE_DYNAMIC; 2], args, f)
}

#[allow(dead_code)]
#[inline]
pub(crate) fn create_typed<const STRICT: bool, F>(
types: [PartiqlType; 2],
types: [PartiqlShape; 2],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand All @@ -498,7 +505,7 @@ impl BinaryValueExpr {
#[allow(dead_code)]
#[inline]
pub(crate) fn create_checked<const STRICT: bool, ArgC, F>(
types: [PartiqlType; 2],
types: [PartiqlShape; 2],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand Down Expand Up @@ -542,13 +549,13 @@ impl TernaryValueExpr {
where
F: 'static + Fn(&Value, &Value, &Value) -> Value,
{
Self::create_typed::<STRICT, F>([TYPE_ANY; 3], args, f)
Self::create_typed::<STRICT, F>([TYPE_DYNAMIC; 3], args, f)
}

#[allow(dead_code)]
#[inline]
pub(crate) fn create_typed<const STRICT: bool, F>(
types: [PartiqlType; 3],
types: [PartiqlShape; 3],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand All @@ -562,7 +569,7 @@ impl TernaryValueExpr {
#[allow(dead_code)]
#[inline]
pub(crate) fn create_checked<const STRICT: bool, ArgC, F>(
types: [PartiqlType; 3],
types: [PartiqlShape; 3],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand Down Expand Up @@ -611,13 +618,13 @@ impl QuaternaryValueExpr {
where
F: 'static + Fn(&Value, &Value, &Value, &Value) -> Value,
{
Self::create_typed::<STRICT, F>([TYPE_ANY; 4], args, f)
Self::create_typed::<STRICT, F>([TYPE_DYNAMIC; 4], args, f)
}

#[allow(dead_code)]
#[inline]
pub(crate) fn create_typed<const STRICT: bool, F>(
types: [PartiqlType; 4],
types: [PartiqlShape; 4],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand All @@ -631,7 +638,7 @@ impl QuaternaryValueExpr {
#[allow(dead_code)]
#[inline]
pub(crate) fn create_checked<const STRICT: bool, ArgC, F>(
types: [PartiqlType; 4],
types: [PartiqlShape; 4],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand Down
32 changes: 18 additions & 14 deletions partiql-eval/src/eval/expr/coll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::eval::expr::{BindError, BindEvalExpr, EvalExpr};

use itertools::{Itertools, Unique};

use partiql_types::{ArrayType, BagType, PartiqlType, TypeKind, TYPE_BOOL, TYPE_NUMERIC_TYPES};
use partiql_types::{
ArrayType, BagType, PartiqlShape, StaticTypeVariant, TYPE_BOOL, TYPE_NUMERIC_TYPES,
};
use partiql_value::Value::{Missing, Null};
use partiql_value::{BinaryAnd, BinaryOr, Value, ValueIter};

Expand Down Expand Up @@ -38,7 +40,7 @@ impl BindEvalExpr for EvalCollFn {
args: Vec<Box<dyn EvalExpr>>,
) -> Result<Box<dyn EvalExpr>, BindError> {
fn create<const STRICT: bool, F>(
types: [PartiqlType; 1],
types: [PartiqlShape; 1],
args: Vec<Box<dyn EvalExpr>>,
f: F,
) -> Result<Box<dyn EvalExpr>, BindError>
Expand All @@ -49,21 +51,23 @@ impl BindEvalExpr for EvalCollFn {
value.sequence_iter().map_or(Missing, &f)
})
}
let boolean_elems = [PartiqlType::any_of([
PartiqlType::new(TypeKind::Array(ArrayType::new(Box::new(TYPE_BOOL)))),
PartiqlType::new(TypeKind::Bag(BagType::new(Box::new(TYPE_BOOL)))),
let boolean_elems = [PartiqlShape::any_of([
PartiqlShape::new(StaticTypeVariant::Array(ArrayType::new(Box::new(
TYPE_BOOL,
)))),
PartiqlShape::new(StaticTypeVariant::Bag(BagType::new(Box::new(TYPE_BOOL)))),
])];
let numeric_elems = [PartiqlType::any_of([
PartiqlType::new(TypeKind::Array(ArrayType::new(Box::new(
PartiqlType::any_of(TYPE_NUMERIC_TYPES),
let numeric_elems = [PartiqlShape::any_of([
PartiqlShape::new(StaticTypeVariant::Array(ArrayType::new(Box::new(
PartiqlShape::any_of(TYPE_NUMERIC_TYPES),
)))),
PartiqlShape::new(StaticTypeVariant::Bag(BagType::new(Box::new(
PartiqlShape::any_of(TYPE_NUMERIC_TYPES),
)))),
PartiqlType::new(TypeKind::Bag(BagType::new(Box::new(PartiqlType::any_of(
TYPE_NUMERIC_TYPES,
))))),
])];
let any_elems = [PartiqlType::any_of([
PartiqlType::new(TypeKind::Array(ArrayType::new_any())),
PartiqlType::new(TypeKind::Bag(BagType::new_any())),
let any_elems = [PartiqlShape::any_of([
PartiqlShape::new(StaticTypeVariant::Array(ArrayType::new_any())),
PartiqlShape::new(StaticTypeVariant::Bag(BagType::new_any())),
])];

match *self {
Expand Down
Loading

1 comment on commit ee13dee

@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: ee13dee Previous: 2e9e4cd Ratio
arith_agg-avg 767717 ns/iter (± 11268) 774533 ns/iter (± 16563) 0.99
arith_agg-avg_distinct 851108 ns/iter (± 1835) 861350 ns/iter (± 3171) 0.99
arith_agg-count 813150 ns/iter (± 19464) 820254 ns/iter (± 13998) 0.99
arith_agg-count_distinct 843925 ns/iter (± 32715) 853809 ns/iter (± 3987) 0.99
arith_agg-min 817304 ns/iter (± 7430) 825050 ns/iter (± 4414) 0.99
arith_agg-min_distinct 846594 ns/iter (± 2351) 860652 ns/iter (± 2366) 0.98
arith_agg-max 826997 ns/iter (± 4265) 831514 ns/iter (± 3169) 0.99
arith_agg-max_distinct 858037 ns/iter (± 4935) 867419 ns/iter (± 3058) 0.99
arith_agg-sum 814499 ns/iter (± 2444) 825232 ns/iter (± 5604) 0.99
arith_agg-sum_distinct 848180 ns/iter (± 2724) 858983 ns/iter (± 2008) 0.99
arith_agg-avg-count-min-max-sum 956398 ns/iter (± 2582) 970126 ns/iter (± 3363) 0.99
arith_agg-avg-count-min-max-sum-group_by 1235065 ns/iter (± 18090) 1220538 ns/iter (± 11818) 1.01
arith_agg-avg-count-min-max-sum-group_by-group_as 1869138 ns/iter (± 19298) 1813863 ns/iter (± 8587) 1.03
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct 1181105 ns/iter (± 9480) 1252766 ns/iter (± 7657) 0.94
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by 1527971 ns/iter (± 8624) 1536893 ns/iter (± 33050) 0.99
arith_agg-avg_distinct-count_distinct-min_distinct-max_distinct-sum_distinct-group_by-group_as 2155595 ns/iter (± 9589) 2129085 ns/iter (± 4630) 1.01
parse-1 4146 ns/iter (± 24) 4294 ns/iter (± 114) 0.97
parse-15 37762 ns/iter (± 118) 39405 ns/iter (± 210) 0.96
parse-30 74801 ns/iter (± 225) 77075 ns/iter (± 258) 0.97
compile-1 4347 ns/iter (± 50) 4320 ns/iter (± 19) 1.01
compile-15 33151 ns/iter (± 182) 33899 ns/iter (± 143) 0.98
compile-30 67895 ns/iter (± 278) 68765 ns/iter (± 227) 0.99
plan-1 67680 ns/iter (± 766) 69407 ns/iter (± 261) 0.98
plan-15 1047469 ns/iter (± 8010) 1086664 ns/iter (± 89435) 0.96
plan-30 2100142 ns/iter (± 9448) 2167995 ns/iter (± 15109) 0.97
eval-1 12798017 ns/iter (± 187554) 13411922 ns/iter (± 115353) 0.95
eval-15 88444199 ns/iter (± 1061763) 85882750 ns/iter (± 298670) 1.03
eval-30 168749431 ns/iter (± 536572) 166363476 ns/iter (± 587071) 1.01
join 10111 ns/iter (± 38) 9746 ns/iter (± 104) 1.04
simple 2522 ns/iter (± 15) 2457 ns/iter (± 7) 1.03
simple-no 437 ns/iter (± 1) 426 ns/iter (± 1) 1.03
numbers 57 ns/iter (± 0) 57 ns/iter (± 0) 1
parse-simple 571 ns/iter (± 33) 565 ns/iter (± 8) 1.01
parse-ion 1764 ns/iter (± 7) 1777 ns/iter (± 3) 0.99
parse-group 5764 ns/iter (± 21) 5797 ns/iter (± 13) 0.99
parse-complex 14759 ns/iter (± 159) 14900 ns/iter (± 72) 0.99
parse-complex-fexpr 21149 ns/iter (± 92) 21947 ns/iter (± 95) 0.96

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

Please sign in to comment.