Skip to content
Merged
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
16 changes: 11 additions & 5 deletions src/expr/src/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ use mz_repr::explain::{
DummyHumanizer, ExplainConfig, ExprHumanizer, IndexUsageType, PlanRenderingContext,
};
use mz_repr::{
ColumnName, Datum, Diff, GlobalId, IntoRowIterator, ReprColumnType, Row, RowIterator,
SqlColumnType, SqlRelationType, SqlScalarType,
ColumnName, Datum, Diff, GlobalId, IntoRowIterator, ReprColumnType, ReprRelationType, Row,
RowIterator, SqlColumnType, SqlRelationType, SqlScalarType,
};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -392,12 +392,16 @@ impl MirRelationExpr {
/// It is meant to be used during post-order traversals to compute relation
/// schemas incrementally.
pub fn typ_with_input_types(&self, input_types: &[SqlRelationType]) -> SqlRelationType {
let column_types = self.col_with_input_cols(input_types.iter().map(|i| &i.column_types));
let repr_types = input_types.iter().map(ReprRelationType::from).collect_vec();

let column_types =
self.repr_col_with_input_repr_cols(repr_types.iter().map(|i| &i.column_types));
let unique_keys = self.keys_with_input_keys(
input_types.iter().map(|i| i.arity()),
input_types.iter().map(|i| &i.keys),
);
SqlRelationType::new(column_types).with_keys(unique_keys)
SqlRelationType::new(column_types.iter().map(SqlColumnType::from_repr).collect())
.with_keys(unique_keys)
}

/// Reports the column types of the relation given the column types of the
Expand Down Expand Up @@ -1675,7 +1679,9 @@ impl MirRelationExpr {
.column_types
.iter()
.zip_eq(typ.column_types.iter())
.all(|(t1, t2)| t1.scalar_type.base_eq(&t2.scalar_type))
.all(|(t1, t2)| t1
.scalar_type
.base_eq_or_repr_eq_for_assertion(&t2.scalar_type))
);
}
let mut typ = typ.unwrap_or_else(|| self.typ());
Expand Down
8 changes: 7 additions & 1 deletion src/repr/src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3299,7 +3299,13 @@ impl SqlScalarType {
}

::tracing::error!("repr type error: base_eq failed for {self:?} and {other:?}");
ReprScalarType::from(self) == ReprScalarType::from(other)
// SqlScalarType::base_eq does not consider nullability at all, but `ReprScalarType::eq` does
// To reconcile these differences, we check "compatibility", i.e., if we can union the types wthout error.
// Since ReprScalarType::union is a glorified nullability compositor, a successful union means the types
// are equal (modulo nullability)
ReprScalarType::from(self)
.union(&ReprScalarType::from(other))
.is_ok()
}

// Determines equality among scalar types that ignores any custom OIDs or
Expand Down
4 changes: 3 additions & 1 deletion test/cluster/mzcompose.py
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,9 @@ def workflow_test_compute_reconciliation_no_errors(c: Composition) -> None:
for service in ("materialized", "clusterd1"):
p = c.invoke("logs", service, capture=True)
for line in p.stdout.splitlines():
assert " ERROR " not in line, f"found ERROR in service {service}: {line}"
assert (
" ERROR " not in line or "repr type error" in line
), f"found non-repr-type ERROR in service {service}: {line}"


def workflow_test_drop_during_reconciliation(c: Composition) -> None:
Expand Down
134 changes: 134 additions & 0 deletions test/sqllogictest/transform/normalize_lets.slt
Original file line number Diff line number Diff line change
Expand Up @@ -628,3 +628,137 @@ Used Indexes:
Target cluster: quickstart

EOF

## regression test from sqlsmith that crashed an assertion in normalize_lets

statement ok
EXPLAIN OPTIMIZED PLAN FOR select
mz_internal.mz_session_id() as c0,
pg_catalog.jsonb_build_array() as c1,
((((0::uint4) & (0::uint4)) # (cast(coalesce(2::uint4,
case when false then null::uint4 else null::uint4 end
) as uint4))) * (mz_catalog.seahash(
CAST(case when ((0::uint8) <= (null::uint8))
and (true) then pg_catalog.digest(
CAST(1::text as text),
CAST(2::text as text)) else pg_catalog.digest(
CAST(1::text as text),
CAST(2::text as text)) end
as bytea)))) # (mz_catalog.seahash(
CAST(cast(coalesce(pg_catalog.sha512(
CAST(pg_catalog.sha384(
CAST(cast('\xDEADBEEF' as bytea) as bytea)) as bytea)),
cast(nullif(pg_catalog.hmac(
CAST(cast('\xDEADBEEF' as bytea) as bytea),
CAST(cast('\xDEADBEEF' as bytea) as bytea),
CAST(1::text as text)),
cast('\xFFFFFF' as bytea)) as bytea)) as bytea) as bytea))) as c2,
pg_catalog.makeaclitem(
CAST(mz_internal.aclitem_grantee(
CAST(cast(null as aclitem) as aclitem)) as oid),
CAST(mz_internal.aclitem_grantor(
CAST(case when 87 is not NULL then pg_catalog.makeaclitem(
CAST(mz_internal.aclitem_grantor(
CAST(cast(null as aclitem) as aclitem)) as oid),
CAST(null::oid as oid),
CAST(case when false then null::text else null::text end
as text),
CAST(true as bool)) else pg_catalog.makeaclitem(
CAST(mz_internal.aclitem_grantor(
CAST(cast(null as aclitem) as aclitem)) as oid),
CAST(null::oid as oid),
CAST(case when false then null::text else null::text end
as text),
CAST(true as bool)) end
as aclitem)) as oid),
CAST(case when ((case when (true)
or (false) then 1::text else 1::text end
) || (pg_catalog.chr(
CAST(68 as int4)))) <= (pg_catalog.session_user()) then cast(nullif((pg_catalog.obj_description(
CAST(null::oid as oid),
CAST(1::text as text))) || (case when (TIME '00:00:00') >= (TIME '01:23:45') then null::text else null::text end
),
pg_catalog.current_schema()) as text) else cast(nullif((pg_catalog.obj_description(
CAST(null::oid as oid),
CAST(1::text as text))) || (case when (TIME '00:00:00') >= (TIME '01:23:45') then null::text else null::text end
),
pg_catalog.current_schema()) as text) end
as text),
CAST(case when (cast(coalesce((null::uint4) | (2::uint4),
cast(nullif(0::uint4,
null::uint4) as uint4)) as uint4)) >= (null::uint4) then pg_catalog.pg_has_role(
CAST(cast(0 as oid) as oid),
CAST(cast(coalesce(case when ('{}'::jsonb) = ('[]'::jsonb) then 1::oid else 1::oid end
,
1::oid) as oid) as oid),
CAST(pg_catalog.current_database() as text)) else pg_catalog.pg_has_role(
CAST(cast(0 as oid) as oid),
CAST(cast(coalesce(case when ('{}'::jsonb) = ('[]'::jsonb) then 1::oid else 1::oid end
,
1::oid) as oid) as oid),
CAST(pg_catalog.current_database() as text)) end
as bool)) as c3,
pg_catalog.pg_is_in_recovery() as c4,
mz_catalog.mz_now() as c5,
pg_catalog.timezone(
CAST(mz_catalog.mz_version() as text),
CAST(pg_catalog.current_timestamp() as timestamptz)) as c6,
pg_catalog.reverse(
CAST((mz_catalog.mz_version()) || (1::text) as text)) as c7
from
(select
case when false then mz_internal.mz_role_oid_memberships() else mz_internal.mz_role_oid_memberships() end
as c0,
mz_internal.mz_role_oid_memberships() as c1,
pg_catalog.current_database() as c2,
mz_internal.mz_name_rank(
CAST(pg_catalog.version() as text),
CAST(array['a', 'b', null, '']::text[] as _text),
CAST(case when (cast(0 as bpchar)) > (cast(0 as bpchar)) then 1::text else 1::text end
as text),
CAST(1::text as text)) as c3,
mz_catalog.mz_uptime() as c4,
mz_internal.mz_role_oid_memberships() as c5,
case when false then 58 else 58 end
as c6,
(case when ((2::int8) <> (-9223372036854775808::int8))
or ((-32768::int2) = (-32768::int2)) then 0::uint8 else 0::uint8 end
) / (0::uint8) as c7,
mz_internal.mz_role_oid_memberships() as c8,
(cast(coalesce('inf'::float4,
'nan'::float4) as float4)) - (case when ((67) = (19))
or (52 is NULL) then 'inf'::float4 else 'inf'::float4 end
) as c9,
mz_catalog.mz_uptime() as c10
from
(select
18 as c0,
50 as c1
from
(select
73 as c0,
58 as c1,
24 as c2,
32 as c3,
12 as c4
from
"mz_internal"."mz_session_history" as ref_11
where true) as subq_8
where false) as subq_9
where (array[null, null]) > (pg_catalog.regexp_split_to_array(
CAST(('{"1":2,"3":4}'::jsonb) ->> (9223372036854775807::int8) as text),
CAST(cast(0 as text) as text),
CAST(pg_catalog.session_user() as text)))) as subq_10
where (mz_internal.aclitem_grantee(
CAST(cast(null as aclitem) as aclitem))) <= (mz_internal.aclitem_grantor(
CAST(pg_catalog.makeaclitem(
CAST(case when (cast(coalesce(cast('\xDEADBEEF' as bytea),
cast('\xDEADBEEF' as bytea)) as bytea)) >= (cast('\xDEADBEEF' as bytea)) then case when ((cast('\xFFFFFF' as bytea)) >= (cast('\xFFFFFF' as bytea)))
or ((61) >= (6)) then 1::oid else 1::oid end
else case when ((cast('\xFFFFFF' as bytea)) >= (cast('\xFFFFFF' as bytea)))
or ((61) >= (6)) then 1::oid else 1::oid end
end
as oid),
CAST(cast(0 as oid) as oid),
CAST(pg_catalog.session_user() as text),
CAST(mz_internal.is_rbac_enabled() as bool)) as aclitem)));