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
10 changes: 5 additions & 5 deletions doc/user/content/sql/system-catalog/mz_internal.md
Original file line number Diff line number Diff line change
Expand Up @@ -1374,10 +1374,10 @@ The `mz_webhook_sources` table contains a row for each webhook source in the sys
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.mz_objects_id_namespace_types -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.mz_console_cluster_utilization_overview -->


<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_class_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_type_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_namespace_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_description_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_attrdef_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_attribute_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_authid_core -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_class_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_description_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_namespace_all_databases -->
<!-- RELATION_SPEC_UNDOCUMENTED mz_internal.pg_type_all_databases -->
89 changes: 81 additions & 8 deletions src/catalog/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10564,17 +10564,17 @@ WHERE false",
access: vec![PUBLIC_SELECT],
});

pub static PG_AUTHID: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
name: "pg_authid",
schema: PG_CATALOG_SCHEMA,
oid: oid::VIEW_PG_AUTHID_OID,
/// Peeled version of `PG_AUTHID`: Excludes the columns rolcreaterole and rolcreatedb, to make this
/// view indexable.
pub static PG_AUTHID_CORE: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
name: "pg_authid_core",
schema: MZ_INTERNAL_SCHEMA,
oid: oid::VIEW_PG_AUTHID_CORE_OID,
desc: RelationDesc::builder()
.with_column("oid", SqlScalarType::Oid.nullable(false))
.with_column("rolname", SqlScalarType::String.nullable(false))
.with_column("rolsuper", SqlScalarType::Bool.nullable(true))
.with_column("rolinherit", SqlScalarType::Bool.nullable(false))
.with_column("rolcreaterole", SqlScalarType::Bool.nullable(true))
.with_column("rolcreatedb", SqlScalarType::Bool.nullable(true))
.with_column("rolcanlogin", SqlScalarType::Bool.nullable(false))
.with_column("rolreplication", SqlScalarType::Bool.nullable(false))
.with_column("rolbypassrls", SqlScalarType::Bool.nullable(false))
Expand All @@ -10592,8 +10592,6 @@ SELECT
r.name AS rolname,
rolsuper,
inherit AS rolinherit,
mz_catalog.has_system_privilege(r.oid, 'CREATEROLE') AS rolcreaterole,
mz_catalog.has_system_privilege(r.oid, 'CREATEDB') AS rolcreatedb,
COALESCE(r.rolcanlogin, false) AS rolcanlogin,
-- MZ doesn't support replication in the same way Postgres does
false AS rolreplication,
Expand All @@ -10608,6 +10606,79 @@ LEFT JOIN mz_catalog.mz_role_auth a ON r.oid = a.role_oid"#,
access: vec![rbac::owner_privilege(ObjectType::Table, MZ_SYSTEM_ROLE_ID)],
});

pub const PG_AUTHID_CORE_IND: BuiltinIndex = BuiltinIndex {
name: "pg_authid_core_ind",
schema: MZ_INTERNAL_SCHEMA,
oid: oid::INDEX_PG_AUTHID_CORE_IND_OID,
sql: "IN CLUSTER mz_catalog_server
ON mz_internal.pg_authid_core (rolname)",
is_retained_metrics_object: false,
};

pub static PG_AUTHID: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
name: "pg_authid",
schema: PG_CATALOG_SCHEMA,
oid: oid::VIEW_PG_AUTHID_OID,
desc: RelationDesc::builder()
.with_column("oid", SqlScalarType::Oid.nullable(false))
.with_column("rolname", SqlScalarType::String.nullable(false))
.with_column("rolsuper", SqlScalarType::Bool.nullable(true))
.with_column("rolinherit", SqlScalarType::Bool.nullable(false))
.with_column("rolcreaterole", SqlScalarType::Bool.nullable(true))
.with_column("rolcreatedb", SqlScalarType::Bool.nullable(true))
.with_column("rolcanlogin", SqlScalarType::Bool.nullable(false))
.with_column("rolreplication", SqlScalarType::Bool.nullable(false))
.with_column("rolbypassrls", SqlScalarType::Bool.nullable(false))
.with_column("rolconnlimit", SqlScalarType::Int32.nullable(false))
.with_column("rolpassword", SqlScalarType::String.nullable(true))
.with_column(
"rolvaliduntil",
SqlScalarType::TimestampTz { precision: None }.nullable(true),
)
.finish(),
column_comments: BTreeMap::new(),
// The `has_system_privilege` invocations for `rolcreaterole` and `rolcreatedb` get expanded
// into very complex subqueries. If we put them into the SELECT clause directly, decorrelation
// produces a very complex plan that the optimizer has a hard time dealing with. In particular,
// the optimizer fails to reduce a query like `SELECT oid FROM pg_authid` to a simple lookup on
// the `pg_authid_core` index and instead produces a large plan that contains a bunch of
// expensive joins and arrangements.
//
// The proper fix is likely to implement `has_system_privileges` in Rust, but for now we work
// around the issue by manually decorrelating `rolcreaterole` and `rolcreatedb`. Note that to
// get the desired behavior we need to make sure that the join with `extra` doesn't change the
// cardinality of `pg_authid_core` (otherwise it can never be optimized away). We ensure this
// by:
// * using a `LEFT JOIN`, so the optimizer knows that left elements are never filtered
// * applying a `DISTINCT ON` to the CTE, so the optimizer knows that left elements are never
// duplicated
sql: r#"
WITH extra AS (
SELECT
DISTINCT ON (oid)
oid,
mz_catalog.has_system_privilege(oid, 'CREATEROLE') AS rolcreaterole,
mz_catalog.has_system_privilege(oid, 'CREATEDB') AS rolcreatedb
FROM mz_internal.pg_authid_core
)
SELECT
oid,
rolname,
rolsuper,
rolinherit,
extra.rolcreaterole,
extra.rolcreatedb,
rolcanlogin,
rolreplication,
rolbypassrls,
rolconnlimit,
rolpassword,
rolvaliduntil
FROM mz_internal.pg_authid_core
LEFT JOIN extra USING (oid)"#,
Copy link
Contributor

@SangJunBak SangJunBak Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a left join on extra and not just a single FROM with additional columns/projections for rolcreaterole and rolcreatedb?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a comment now that explains this, but it's necessary to go from the bad EXPLAIN plan I posted above to the good EXPLAIN plan I also posted above. See also this thread.

access: vec![rbac::owner_privilege(ObjectType::Table, MZ_SYSTEM_ROLE_ID)],
});

pub static PG_AGGREGATE: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
name: "pg_aggregate",
schema: PG_CATALOG_SCHEMA,
Expand Down Expand Up @@ -13967,6 +14038,8 @@ pub static BUILTINS_STATIC: LazyLock<Vec<Builtin<NameReference>>> = LazyLock::ne
Builtin::View(&PG_TABLESPACE),
Builtin::View(&PG_ACCESS_METHODS),
Builtin::View(&PG_LOCKS),
Builtin::View(&PG_AUTHID_CORE),
Builtin::Index(&PG_AUTHID_CORE_IND),
Builtin::View(&PG_AUTHID),
Builtin::View(&PG_ROLES),
Builtin::View(&PG_USER),
Expand Down
4 changes: 2 additions & 2 deletions src/environmentd/tests/testdata/http/ws

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/pgrepr-consts/src/oid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,3 +783,5 @@ pub const TABLE_MZ_ROLE_AUTH_OID: u32 = 17059;
pub const TABLE_MZ_ICEBERG_SINKS_OID: u32 = 17060;
pub const VIEW_MZ_OBJECT_GLOBAL_IDS_OID: u32 = 17061;
pub const TABLE_MZ_REPLACEMENTS_OID: u32 = 17062;
pub const VIEW_PG_AUTHID_CORE_OID: u32 = 17063;
pub const INDEX_PG_AUTHID_CORE_IND_OID: u32 = 17064;
1 change: 1 addition & 0 deletions test/sqllogictest/autogenerated/mz_internal.slt
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,7 @@ mz_wallclock_lag_history
mz_webhook_sources
pg_attrdef_all_databases
pg_attribute_all_databases
pg_authid_core
pg_class_all_databases
pg_description_all_databases
pg_namespace_all_databases
Expand Down
4 changes: 2 additions & 2 deletions test/sqllogictest/cluster.slt
Original file line number Diff line number Diff line change
Expand Up @@ -417,15 +417,15 @@ CREATE CLUSTER test REPLICAS (foo (SIZE 'scale=1,workers=1'));
query I
SELECT COUNT(name) FROM mz_indexes;
----
295
296

statement ok
DROP CLUSTER test CASCADE

query T
SELECT COUNT(name) FROM mz_indexes;
----
263
264

simple conn=mz_system,user=mz_system
ALTER CLUSTER quickstart OWNER TO materialize
Expand Down
11 changes: 7 additions & 4 deletions test/sqllogictest/distinct_arrangements.slt
Original file line number Diff line number Diff line change
Expand Up @@ -1019,12 +1019,13 @@ ArrangeBy[[Column(0,␠"objoid"),␠Column(1,␠"classoid"),␠Column(2,␠"objs
ArrangeBy[[Column(0,␠"objoid"),␠Column(1,␠"classoid"),␠Column(2,␠"objsubid"),␠Column(3,␠"description"),␠Column(4,␠"oid_database_name"),␠Column(5,␠"class_database_name")]]-errors 1
ArrangeBy[[Column(0,␠"oid"),␠Column(1,␠"adrelid"),␠Column(2,␠"adnum"),␠Column(3,␠"adbin"),␠Column(4,␠"adsrc")]] 1
ArrangeBy[[Column(0,␠"oid"),␠Column(1,␠"adrelid"),␠Column(2,␠"adnum"),␠Column(3,␠"adbin"),␠Column(4,␠"adsrc")]]-errors 1
ArrangeBy[[Column(0,␠"oid")]] 2
ArrangeBy[[Column(0,␠"oid")]] 3
ArrangeBy[[Column(0,␠"oid")]]-errors 1
ArrangeBy[[Column(0,␠"replica_id"),␠Column(3,␠"bucket_start")]] 5
ArrangeBy[[Column(0,␠"replica_id"),␠Column(4,␠"bucket_start")]] 1
ArrangeBy[[Column(0,␠"replica_id")]] 12
ArrangeBy[[Column(0,␠"replica_id")]]-errors 5
ArrangeBy[[Column(0,␠"role_oid")]] 1
ArrangeBy[[Column(0,␠"schema_id")]] 6
ArrangeBy[[Column(0,␠"schema_id")]]-errors 6
ArrangeBy[[Column(0,␠"self")]] 1
Expand Down Expand Up @@ -1059,6 +1060,8 @@ ArrangeBy[[Column(1,␠"referenced_object_id")]] 2
ArrangeBy[[Column(1,␠"relname")]] 1
ArrangeBy[[Column(1,␠"relname")]]-errors 1
ArrangeBy[[Column(1,␠"replica_id")]] 1
ArrangeBy[[Column(1,␠"rolname")]] 1
ArrangeBy[[Column(1,␠"rolname")]]-errors 1
ArrangeBy[[Column(1,␠"session_id")]] 1
ArrangeBy[[Column(1,␠"shard_id"),␠Column(2,␠"collection_timestamp")]] 1
ArrangeBy[[Column(1,␠"shard_id")]] 1
Expand Down Expand Up @@ -1103,13 +1106,13 @@ ArrangeBy[[Column(6,␠"schema_id")]]-errors 1
ArrangeBy[[Column(7,␠"database_id")]] 1
ArrangeBy[[Column(9,␠"database_id")]] 1
ArrangeBy[[]] 11
Arranged␠DistinctBy 49
Arranged␠DistinctBy 50
Arranged␠MinsMaxesHierarchical␠input 14
Arranged␠ReduceInaccumulable 3
Arranged␠TopK␠input 111
Distinct␠recursive␠err 3
DistinctBy 49
DistinctByErrorCheck 49
DistinctBy 50
DistinctByErrorCheck 50
ReduceAccumulable 11
ReduceInaccumulable 3
ReduceInaccumulable␠Error␠Check 3
Expand Down
4 changes: 4 additions & 0 deletions test/sqllogictest/information_schema_tables.slt
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,10 @@ pg_attribute_all_databases
VIEW
materialize
mz_internal
pg_authid_core
VIEW
materialize
mz_internal
pg_class_all_databases
VIEW
materialize
Expand Down
Loading
Loading