Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/expr/src/scalar/func/variadic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use mz_repr::adt::range::{InvalidRangeError, Range, RangeBound, parse_range_boun
use mz_repr::adt::system::Oid;
use mz_repr::adt::timestamp::CheckedTimestamp;
use mz_repr::role_id::RoleId;
use mz_repr::{ColumnName, Datum, Row, RowArena, SqlColumnType, SqlScalarType};
use mz_repr::{ColumnName, Datum, ReprScalarType, Row, RowArena, SqlColumnType, SqlScalarType};
use serde::{Deserialize, Serialize};
use sha1::Sha1;
use sha2::{Sha224, Sha256, Sha384, Sha512};
Expand Down Expand Up @@ -1321,8 +1321,11 @@ impl VariadicFunc {
.nullable(true),
ArrayCreate { elem_type } => {
debug_assert!(
input_types.iter().all(|t| t.scalar_type.base_eq(elem_type)),
"Args to ArrayCreate should have types that are compatible with the elem_type"
input_types
.iter()
.all(|t| ReprScalarType::from(&t.scalar_type)
== ReprScalarType::from(elem_type)),
"Args to ArrayCreate should have types that are repr-compatible with the elem_type"
);
match elem_type {
SqlScalarType::Array(_) => elem_type.clone().nullable(false),
Expand Down
14 changes: 13 additions & 1 deletion src/repr/src/explain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use crate::explain::dot::{DisplayDot, dot_string};
use crate::explain::json::{DisplayJson, json_string};
use crate::explain::text::{DisplayText, text_string};
use crate::optimize::OptimizerFeatureOverrides;
use crate::{GlobalId, SqlColumnType, SqlScalarType};
use crate::{GlobalId, ReprColumnType, ReprScalarType, SqlColumnType, SqlScalarType};

pub mod dot;
pub mod json;
Expand Down Expand Up @@ -444,6 +444,12 @@ pub trait ExprHumanizer: fmt::Debug {
/// compatibility is more important.
fn humanize_scalar_type(&self, ty: &SqlScalarType, postgres_compat: bool) -> String;

/// Returns a human-readable name for the specified scalar type.
/// Calls `humanize_scalar_type` with the `SqlScalarType` representation of the specified type.
fn humanize_scalar_type_repr(&self, typ: &ReprScalarType, postgres_compat: bool) -> String {
self.humanize_scalar_type(&SqlScalarType::from_repr(typ), postgres_compat)
}

/// Returns a human-readable name for the specified column type.
/// Used in, e.g., EXPLAIN and error msgs, in which case exact Postgres compatibility is less
/// important than showing as much detail as possible. Also used in `pg_typeof`, where Postgres
Expand All @@ -456,6 +462,12 @@ pub trait ExprHumanizer: fmt::Debug {
)
}

/// Returns a human-readable name for the specified column type.
/// Calls `humanize_column_type` with the `SqlColumnType` representation of the specified type.
fn humanize_column_type_repr(&self, typ: &ReprColumnType, postgres_compat: bool) -> String {
self.humanize_column_type(&SqlColumnType::from_repr(typ), postgres_compat)
}

/// Returns a vector of column names for the relation identified by `id`.
fn column_names_for_id(&self, id: GlobalId) -> Option<Vec<String>>;

Expand Down
8 changes: 4 additions & 4 deletions src/repr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ pub use crate::global_id::GlobalId;
pub use crate::relation::{
ColumnIndex, ColumnName, NotNullViolation, PropRelationDescDiff, ProtoColumnName,
ProtoColumnType, ProtoRelationDesc, ProtoRelationType, RelationDesc, RelationDescBuilder,
RelationVersion, RelationVersionSelector, ReprColumnType, SqlColumnType, SqlRelationType,
UNKNOWN_COLUMN_NAME, VersionedRelationDesc, arb_relation_desc_diff,
RelationVersion, RelationVersionSelector, ReprColumnType, ReprRelationType, SqlColumnType,
SqlRelationType, UNKNOWN_COLUMN_NAME, VersionedRelationDesc, arb_relation_desc_diff,
arb_relation_desc_projection, arb_row_for_relation,
};
pub use crate::row::encode::{RowColumnarDecoder, RowColumnarEncoder, preserves_order};
Expand All @@ -66,7 +66,7 @@ pub use crate::row::{
};
pub use crate::scalar::{
ArrayRustType, AsColumnType, Datum, DatumType, PropArray, PropDatum, PropDict, PropList,
ProtoScalarType, ReprScalarType, ScalarBaseType, SqlScalarType, arb_datum,
arb_datum_for_column, arb_datum_for_scalar, arb_range_type,
ProtoScalarType, ReprScalarBaseType, ReprScalarType, SqlScalarBaseType, SqlScalarType,
arb_datum, arb_datum_for_column, arb_datum_for_scalar, arb_range_type,
};
pub use crate::timestamp::{Timestamp, TimestampManipulation};
95 changes: 95 additions & 0 deletions src/repr/src/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ impl SqlColumnType {
);
};

if fields.len() != other_fields.len() {
bail!(
"Can't union types: {:?} and {:?}",
self.scalar_type,
other.scalar_type
);
}
let mut union_fields = Vec::with_capacity(fields.len());
for ((name, typ), (other_name, other_typ)) in
fields.iter().zip_eq(other_fields.iter())
Expand Down Expand Up @@ -259,6 +266,94 @@ impl RustType<ProtoKey> for Vec<usize> {
}
}

/// The type of a relation.
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
pub struct ReprRelationType {
/// The type for each column, in order.
pub column_types: Vec<ReprColumnType>,
/// Sets of indices that are "keys" for the collection.
///
/// Each element in this list is a set of column indices, each with the
/// property that the collection contains at most one record with each
/// distinct set of values for each column. Alternately, for a specific set
/// of values assigned to the these columns there is at most one record.
///
/// A collection can contain multiple sets of keys, although it is common to
/// have either zero or one sets of key indices.
#[serde(default)]
pub keys: Vec<Vec<usize>>,
}

impl ReprRelationType {
/// Constructs a `ReprRelationType` representing the relation with no columns and
/// no keys.
pub fn empty() -> Self {
ReprRelationType::new(vec![])
}

/// Constructs a new `ReprRelationType` from specified column types.
///
/// The `ReprRelationType` will have no keys.
pub fn new(column_types: Vec<ReprColumnType>) -> Self {
ReprRelationType {
column_types,
keys: Vec::new(),
}
}

/// Adds a new key for the relation.
pub fn with_key(mut self, mut indices: Vec<usize>) -> Self {
indices.sort_unstable();
if !self.keys.contains(&indices) {
self.keys.push(indices);
}
self
}

pub fn with_keys(mut self, keys: Vec<Vec<usize>>) -> Self {
for key in keys {
self = self.with_key(key)
}
self
}

/// Computes the number of columns in the relation.
pub fn arity(&self) -> usize {
self.column_types.len()
}

/// Gets the index of the columns used when creating a default index.
pub fn default_key(&self) -> Vec<usize> {
if let Some(key) = self.keys.first() {
if key.is_empty() {
(0..self.column_types.len()).collect()
} else {
key.clone()
}
} else {
(0..self.column_types.len()).collect()
}
}

/// Returns all the column types in order, for this relation.
pub fn columns(&self) -> &[ReprColumnType] {
&self.column_types
}
}

impl From<&SqlRelationType> for ReprRelationType {
fn from(sql_relation_type: &SqlRelationType) -> Self {
ReprRelationType {
column_types: sql_relation_type
.column_types
.iter()
.map(ReprColumnType::from)
.collect(),
keys: sql_relation_type.keys.clone(),
}
}
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, MzReflect)]
pub struct ReprColumnType {
/// The underlying representation scalar type (e.g., Int32 or String) of this column.
Expand Down
78 changes: 33 additions & 45 deletions src/repr/src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,7 @@ impl fmt::Display for Datum<'_> {
#[derive(
Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd, Hash, EnumKind, MzReflect,
)]
#[enum_kind(ScalarBaseType, derive(PartialOrd, Ord, Hash))]
#[enum_kind(SqlScalarBaseType, derive(PartialOrd, Ord, Hash))]
pub enum SqlScalarType {
/// The type of [`Datum::True`] and [`Datum::False`].
Bool,
Expand Down Expand Up @@ -3212,7 +3212,7 @@ impl SqlScalarType {
&& a.1.scalar_type.eq_inner(&b.1.scalar_type, structure_only)
})
}
(s, o) => ScalarBaseType::from(s) == ScalarBaseType::from(o),
(s, o) => SqlScalarBaseType::from(s) == SqlScalarBaseType::from(o),
}
}

Expand Down Expand Up @@ -3968,12 +3968,8 @@ impl Arbitrary for ReprScalarType {
Just(ReprScalarType::Numeric).boxed(),
Just(ReprScalarType::Date).boxed(),
Just(ReprScalarType::Time).boxed(),
any::<Option<TimestampPrecision>>()
.prop_map(|precision| ReprScalarType::Timestamp { precision })
.boxed(),
any::<Option<TimestampPrecision>>()
.prop_map(|precision| ReprScalarType::TimestampTz { precision })
.boxed(),
Just(ReprScalarType::Timestamp).boxed(),
Just(ReprScalarType::TimestampTz).boxed(),
Just(ReprScalarType::MzTimestamp).boxed(),
Just(ReprScalarType::Interval).boxed(),
Just(ReprScalarType::Bytes).boxed(),
Expand All @@ -3995,12 +3991,8 @@ impl Arbitrary for ReprScalarType {
Just(ReprScalarType::Int64).boxed(),
Just(ReprScalarType::Date).boxed(),
Just(ReprScalarType::Numeric).boxed(),
any::<Option<TimestampPrecision>>()
.prop_map(|precision| ReprScalarType::Timestamp { precision })
.boxed(),
any::<Option<TimestampPrecision>>()
.prop_map(|precision| ReprScalarType::TimestampTz { precision })
.boxed(),
Just(ReprScalarType::Timestamp).boxed(),
Just(ReprScalarType::TimestampTz).boxed(),
]);
let range = range_leaf
.prop_map(|inner_type| ReprScalarType::Range {
Expand Down Expand Up @@ -4068,7 +4060,10 @@ impl Arbitrary for ReprScalarType {
/// There is a direct correspondence between `Datum` variants and `ReprScalarType`
/// variants: every `Datum` variant corresponds to exactly one `ReprScalarType` variant
/// (with an exception for `Datum::Array`, which could be both an `Int2Vector` and an `Array`).
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd, Hash, MzReflect)]
#[derive(
Clone, Debug, EnumKind, PartialEq, Eq, Serialize, Deserialize, Ord, PartialOrd, Hash, MzReflect,
)]
#[enum_kind(ReprScalarBaseType, derive(PartialOrd, Ord, Hash))]
pub enum ReprScalarType {
Bool,
Int16,
Expand All @@ -4083,12 +4078,8 @@ pub enum ReprScalarType {
Numeric,
Date,
Time,
Timestamp {
precision: Option<TimestampPrecision>,
},
TimestampTz {
precision: Option<TimestampPrecision>,
},
Timestamp,
TimestampTz,
MzTimestamp,
Interval,
Bytes,
Expand All @@ -4097,18 +4088,10 @@ pub enum ReprScalarType {
Uuid,
Array(Box<ReprScalarType>),
Int2Vector, // differs from Array enough to stick around
List {
element_type: Box<ReprScalarType>,
},
Record {
fields: Box<[ReprColumnType]>,
},
Map {
value_type: Box<ReprScalarType>,
},
Range {
element_type: Box<ReprScalarType>,
},
List { element_type: Box<ReprScalarType> },
Record { fields: Box<[ReprColumnType]> },
Map { value_type: Box<ReprScalarType> },
Range { element_type: Box<ReprScalarType> },
MzAclItem,
AclItem,
}
Expand All @@ -4128,12 +4111,8 @@ impl From<&SqlScalarType> for ReprScalarType {
SqlScalarType::Numeric { max_scale: _ } => ReprScalarType::Numeric,
SqlScalarType::Date => ReprScalarType::Date,
SqlScalarType::Time => ReprScalarType::Time,
SqlScalarType::Timestamp { precision } => ReprScalarType::Timestamp {
precision: *precision,
},
SqlScalarType::TimestampTz { precision } => ReprScalarType::TimestampTz {
precision: *precision,
},
SqlScalarType::Timestamp { precision: _ } => ReprScalarType::Timestamp,
SqlScalarType::TimestampTz { precision: _ } => ReprScalarType::TimestampTz,
SqlScalarType::Interval => ReprScalarType::Interval,
SqlScalarType::PgLegacyChar => ReprScalarType::UInt8,
SqlScalarType::PgLegacyName => ReprScalarType::String,
Expand Down Expand Up @@ -4214,12 +4193,8 @@ impl SqlScalarType {
ReprScalarType::Numeric => SqlScalarType::Numeric { max_scale: None },
ReprScalarType::Date => SqlScalarType::Date,
ReprScalarType::Time => SqlScalarType::Time,
ReprScalarType::Timestamp { precision } => SqlScalarType::Timestamp {
precision: *precision,
},
ReprScalarType::TimestampTz { precision } => SqlScalarType::TimestampTz {
precision: *precision,
},
ReprScalarType::Timestamp => SqlScalarType::Timestamp { precision: None },
ReprScalarType::TimestampTz => SqlScalarType::TimestampTz { precision: None },
ReprScalarType::MzTimestamp => SqlScalarType::MzTimestamp,
ReprScalarType::Interval => SqlScalarType::Interval,
ReprScalarType::Bytes => SqlScalarType::Bytes,
Expand Down Expand Up @@ -5006,6 +4981,19 @@ mod tests {
}
}

proptest! {
#![proptest_config(ProptestConfig::with_cases(10000))]
#[mz_ore::test]
#[cfg_attr(miri, ignore)]
fn sql_type_base_eq_implies_repr_type_eq(sql_type1 in any::<SqlScalarType>(), sql_type2 in any::<SqlScalarType>()) {
let repr_type1 = ReprScalarType::from(&sql_type1);
let repr_type2 = ReprScalarType::from(&sql_type2);
if sql_type1.base_eq(&sql_type2) {
assert_eq!(repr_type1, repr_type2);
}
}
}

proptest! {
#[mz_ore::test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `decContextDefault` on OS `linux`
Expand Down
Loading