1use std::collections::BTreeSet;
16
17use itertools::Itertools;
18use mz_sql_parser::ast::display::AstDisplay;
19
20use crate::ast::{Ident, UnresolvedDatabaseName};
21use crate::catalog::{
22 DefaultPrivilegeAclItem, DefaultPrivilegeObject, ErrorMessageObjectDescription, ObjectType,
23 SystemObjectType,
24};
25use crate::names::{
26 Aug, ObjectId, ResolvedDatabaseSpecifier, ResolvedRoleName, SchemaSpecifier, SystemObjectId,
27};
28use crate::plan::error::PlanError;
29use crate::plan::statement::ddl::{
30 resolve_cluster, resolve_database, resolve_item_or_type, resolve_network_policy, resolve_schema,
31};
32use crate::plan::statement::{StatementContext, StatementDesc};
33use crate::plan::{
34 AlterDefaultPrivilegesPlan, AlterNoopPlan, AlterOwnerPlan, GrantPrivilegesPlan, GrantRolePlan,
35 Plan, PlanNotice, ReassignOwnedPlan, RevokePrivilegesPlan, RevokeRolePlan, UpdatePrivilege,
36};
37use crate::session::user::SYSTEM_USER;
38use mz_ore::str::StrExt;
39use mz_repr::adt::mz_acl_item::AclMode;
40use mz_repr::role_id::RoleId;
41use mz_sql_parser::ast::{
42 AbbreviatedGrantOrRevokeStatement, AlterDefaultPrivilegesStatement, AlterOwnerStatement,
43 GrantPrivilegesStatement, GrantRoleStatement, GrantTargetAllSpecification,
44 GrantTargetSpecification, GrantTargetSpecificationInner, Privilege, PrivilegeSpecification,
45 ReassignOwnedStatement, RevokePrivilegesStatement, RevokeRoleStatement,
46 TargetRoleSpecification, UnresolvedItemName, UnresolvedObjectName, UnresolvedSchemaName,
47};
48
49pub fn describe_alter_owner(
50 _: &StatementContext,
51 _: AlterOwnerStatement<Aug>,
52) -> Result<StatementDesc, PlanError> {
53 Ok(StatementDesc::new(None))
54}
55
56pub fn plan_alter_owner(
57 scx: &StatementContext,
58 AlterOwnerStatement {
59 object_type,
60 if_exists,
61 name,
62 new_owner,
63 }: AlterOwnerStatement<Aug>,
64) -> Result<Plan, PlanError> {
65 let object_type = object_type.into();
66 match (object_type, name) {
67 (ObjectType::Cluster, UnresolvedObjectName::Cluster(name)) => {
68 plan_alter_cluster_owner(scx, if_exists, name, new_owner.id)
69 }
70 (ObjectType::ClusterReplica, UnresolvedObjectName::ClusterReplica(_)) => {
71 bail_never_supported!("altering the owner of a cluster replica");
72 }
73 (ObjectType::Database, UnresolvedObjectName::Database(name)) => {
74 plan_alter_database_owner(scx, if_exists, name, new_owner.id)
75 }
76 (ObjectType::Schema, UnresolvedObjectName::Schema(name)) => {
77 plan_alter_schema_owner(scx, if_exists, name, new_owner.id)
78 }
79 (ObjectType::NetworkPolicy, UnresolvedObjectName::NetworkPolicy(name)) => {
80 plan_alter_network_policy_owner(scx, if_exists, name, new_owner.id)
81 }
82 (ObjectType::Role, UnresolvedObjectName::Role(_)) => {
84 bail_internal!("cannot ALTER OWNER of a role")
85 }
86 (
87 object_type @ ObjectType::Cluster
88 | object_type @ ObjectType::ClusterReplica
89 | object_type @ ObjectType::Database
90 | object_type @ ObjectType::Schema
91 | object_type @ ObjectType::Role,
92 name,
93 )
94 | (
95 object_type,
96 name @ UnresolvedObjectName::Cluster(_)
97 | name @ UnresolvedObjectName::ClusterReplica(_)
98 | name @ UnresolvedObjectName::Database(_)
99 | name @ UnresolvedObjectName::Schema(_)
100 | name @ UnresolvedObjectName::NetworkPolicy(_)
101 | name @ UnresolvedObjectName::Role(_),
102 ) => {
103 bail_internal!("invalid object type '{object_type}' for ALTER OWNER with name {name}")
105 }
106 (object_type, UnresolvedObjectName::Item(name)) => {
107 plan_alter_item_owner(scx, object_type, if_exists, name, new_owner.id)
108 }
109 }
110}
111
112fn plan_alter_cluster_owner(
113 scx: &StatementContext,
114 if_exists: bool,
115 name: Ident,
116 new_owner: RoleId,
117) -> Result<Plan, PlanError> {
118 match resolve_cluster(scx, &name, if_exists)? {
119 Some(cluster) => Ok(Plan::AlterOwner(AlterOwnerPlan {
120 id: ObjectId::Cluster(cluster.id()),
121 object_type: ObjectType::Cluster,
122 new_owner,
123 })),
124 None => {
125 scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist {
126 name: name.to_ast_string_simple(),
127 object_type: ObjectType::Cluster,
128 });
129 Ok(Plan::AlterNoop(AlterNoopPlan {
130 object_type: ObjectType::Cluster,
131 }))
132 }
133 }
134}
135
136fn plan_alter_database_owner(
137 scx: &StatementContext,
138 if_exists: bool,
139 name: UnresolvedDatabaseName,
140 new_owner: RoleId,
141) -> Result<Plan, PlanError> {
142 match resolve_database(scx, &name, if_exists)? {
143 Some(database) => Ok(Plan::AlterOwner(AlterOwnerPlan {
144 id: ObjectId::Database(database.id()),
145 object_type: ObjectType::Database,
146 new_owner,
147 })),
148 None => {
149 scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist {
150 name: name.to_ast_string_simple(),
151 object_type: ObjectType::Database,
152 });
153
154 Ok(Plan::AlterNoop(AlterNoopPlan {
155 object_type: ObjectType::Database,
156 }))
157 }
158 }
159}
160
161fn plan_alter_schema_owner(
162 scx: &StatementContext,
163 if_exists: bool,
164 name: UnresolvedSchemaName,
165 new_owner: RoleId,
166) -> Result<Plan, PlanError> {
167 let normalized = crate::normalize::unresolved_schema_name(name.clone())?;
171 if normalized.database.is_none() && normalized.schema == mz_repr::namespaces::MZ_TEMP_SCHEMA {
172 sql_bail!("cannot alter schema {name} because it is a temporary schema",)
173 }
174
175 match resolve_schema(scx, name.clone(), if_exists)? {
176 Some((database_spec, schema_spec)) => {
177 if let ResolvedDatabaseSpecifier::Ambient = database_spec {
178 sql_bail!(
179 "cannot alter schema {name} because it is required by the database system",
180 );
181 }
182 if let SchemaSpecifier::Temporary = schema_spec {
183 sql_bail!("cannot alter schema {name} because it is a temporary schema",)
184 }
185 Ok(Plan::AlterOwner(AlterOwnerPlan {
186 id: ObjectId::Schema((database_spec, schema_spec)),
187 object_type: ObjectType::Schema,
188 new_owner,
189 }))
190 }
191 None => {
192 scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist {
193 name: name.to_ast_string_simple(),
194 object_type: ObjectType::Schema,
195 });
196
197 Ok(Plan::AlterNoop(AlterNoopPlan {
198 object_type: ObjectType::Schema,
199 }))
200 }
201 }
202}
203
204fn plan_alter_item_owner(
205 scx: &StatementContext,
206 object_type: ObjectType,
207 if_exists: bool,
208 name: UnresolvedItemName,
209 new_owner: RoleId,
210) -> Result<Plan, PlanError> {
211 let resolved = match resolve_item_or_type(scx, object_type, name.clone(), if_exists) {
212 Ok(r) => r,
213 Err(PlanError::MismatchedObjectType {
215 name,
216 is_type: ObjectType::MaterializedView,
217 expected_type: ObjectType::View,
218 }) => {
219 return Err(PlanError::AlterViewOnMaterializedView(name.to_string()));
220 }
221 e => e?,
222 };
223
224 match resolved {
225 Some(item) => {
226 if item.id().is_system() {
227 sql_bail!(
228 "cannot alter item {} because it is required by the database system",
229 scx.catalog.resolve_full_name(item.name()),
230 );
231 }
232
233 Ok(Plan::AlterOwner(AlterOwnerPlan {
234 id: ObjectId::Item(item.id()),
235 object_type,
236 new_owner,
237 }))
238 }
239 None => {
240 scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist {
241 name: name.to_ast_string_simple(),
242 object_type,
243 });
244
245 Ok(Plan::AlterNoop(AlterNoopPlan { object_type }))
246 }
247 }
248}
249
250fn plan_alter_network_policy_owner(
251 scx: &StatementContext,
252 if_exists: bool,
253 name: Ident,
254 new_owner: RoleId,
255) -> Result<Plan, PlanError> {
256 match resolve_network_policy(scx, name.clone(), if_exists)? {
257 Some(policy_id) => Ok(Plan::AlterOwner(AlterOwnerPlan {
258 id: ObjectId::NetworkPolicy(policy_id.id),
259 object_type: ObjectType::NetworkPolicy,
260 new_owner,
261 })),
262 None => {
263 scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist {
264 name: name.to_ast_string_simple(),
265 object_type: ObjectType::NetworkPolicy,
266 });
267
268 Ok(Plan::AlterNoop(AlterNoopPlan {
269 object_type: ObjectType::NetworkPolicy,
270 }))
271 }
272 }
273}
274
275pub fn describe_grant_role(
276 _: &StatementContext,
277 _: GrantRoleStatement<Aug>,
278) -> Result<StatementDesc, PlanError> {
279 Ok(StatementDesc::new(None))
280}
281
282pub fn plan_grant_role(
283 scx: &StatementContext,
284 GrantRoleStatement {
285 role_names,
286 member_names,
287 }: GrantRoleStatement<Aug>,
288) -> Result<Plan, PlanError> {
289 let grantor_id = scx
295 .catalog
296 .resolve_role(&SYSTEM_USER.name)
297 .expect("system user must exist")
298 .id();
299 Ok(Plan::GrantRole(GrantRolePlan {
300 role_ids: role_names
301 .into_iter()
302 .map(|role_name| role_name.id)
303 .collect(),
304 member_ids: member_names
305 .into_iter()
306 .map(|member_name| member_name.id)
307 .collect(),
308 grantor_id,
309 }))
310}
311
312pub fn describe_revoke_role(
313 _: &StatementContext,
314 _: RevokeRoleStatement<Aug>,
315) -> Result<StatementDesc, PlanError> {
316 Ok(StatementDesc::new(None))
317}
318
319pub fn plan_revoke_role(
320 scx: &StatementContext,
321 RevokeRoleStatement {
322 role_names,
323 member_names,
324 }: RevokeRoleStatement<Aug>,
325) -> Result<Plan, PlanError> {
326 let grantor_id = scx
334 .catalog
335 .resolve_role(&SYSTEM_USER.name)
336 .expect("system user must exist")
337 .id();
338 Ok(Plan::RevokeRole(RevokeRolePlan {
339 role_ids: role_names
340 .into_iter()
341 .map(|role_name| role_name.id)
342 .collect(),
343 member_ids: member_names
344 .into_iter()
345 .map(|member_name| member_name.id)
346 .collect(),
347 grantor_id,
348 }))
349}
350
351pub fn describe_grant_privileges(
352 _: &StatementContext,
353 _: GrantPrivilegesStatement<Aug>,
354) -> Result<StatementDesc, PlanError> {
355 Ok(StatementDesc::new(None))
356}
357
358pub fn plan_grant_privileges(
359 scx: &StatementContext,
360 GrantPrivilegesStatement {
361 privileges,
362 target,
363 roles,
364 }: GrantPrivilegesStatement<Aug>,
365) -> Result<Plan, PlanError> {
366 let plan = plan_update_privilege(scx, privileges, target, roles)?;
367 Ok(Plan::GrantPrivileges(plan.into()))
368}
369
370pub fn describe_revoke_privileges(
371 _: &StatementContext,
372 _: RevokePrivilegesStatement<Aug>,
373) -> Result<StatementDesc, PlanError> {
374 Ok(StatementDesc::new(None))
375}
376
377pub fn plan_revoke_privileges(
378 scx: &StatementContext,
379 RevokePrivilegesStatement {
380 privileges,
381 target,
382 roles,
383 }: RevokePrivilegesStatement<Aug>,
384) -> Result<Plan, PlanError> {
385 let plan = plan_update_privilege(scx, privileges, target, roles)?;
386 Ok(Plan::RevokePrivileges(plan.into()))
387}
388
389struct UpdatePrivilegesPlan {
390 update_privileges: Vec<UpdatePrivilege>,
391 grantees: Vec<RoleId>,
392}
393
394impl From<UpdatePrivilegesPlan> for GrantPrivilegesPlan {
395 fn from(
396 UpdatePrivilegesPlan {
397 update_privileges,
398 grantees,
399 }: UpdatePrivilegesPlan,
400 ) -> GrantPrivilegesPlan {
401 GrantPrivilegesPlan {
402 update_privileges,
403 grantees,
404 }
405 }
406}
407
408impl From<UpdatePrivilegesPlan> for RevokePrivilegesPlan {
409 fn from(
410 UpdatePrivilegesPlan {
411 update_privileges,
412 grantees,
413 }: UpdatePrivilegesPlan,
414 ) -> RevokePrivilegesPlan {
415 RevokePrivilegesPlan {
416 update_privileges,
417 revokees: grantees,
418 }
419 }
420}
421
422fn plan_update_privilege(
423 scx: &StatementContext,
424 privileges: PrivilegeSpecification,
425 target: GrantTargetSpecification<Aug>,
426 roles: Vec<ResolvedRoleName>,
427) -> Result<UpdatePrivilegesPlan, PlanError> {
428 let (object_type, target_ids) = match target {
429 GrantTargetSpecification::Object {
430 object_type,
431 object_spec_inner,
432 } => {
433 fn object_type_filter(
434 object_id: &ObjectId,
435 object_type: &ObjectType,
436 scx: &StatementContext,
437 ) -> bool {
438 if object_type == &ObjectType::Table {
439 scx.get_object_type(object_id).is_relation()
440 } else {
441 object_type == &scx.get_object_type(object_id)
442 }
443 }
444 let object_type = object_type.into();
445 let object_ids: Vec<ObjectId> = match object_spec_inner {
446 GrantTargetSpecificationInner::All(GrantTargetAllSpecification::All) => {
447 let cluster_ids = scx
448 .catalog
449 .get_clusters()
450 .into_iter()
451 .map(|cluster| cluster.id().into());
452 let database_ids = scx
453 .catalog
454 .get_databases()
455 .into_iter()
456 .map(|database| database.id().into());
457 let schema_ids = scx
458 .catalog
459 .get_schemas()
460 .into_iter()
461 .filter(|schema| !schema.id().is_temporary())
462 .map(|schema| (schema.database().clone(), schema.id().clone()).into());
463 let item_ids = scx
464 .catalog
465 .get_items()
466 .into_iter()
467 .map(|item| item.id().into());
468 let network_policy_ids = scx
469 .catalog
470 .get_network_policies()
471 .into_iter()
472 .map(|network_policy| ObjectId::NetworkPolicy(network_policy.id()));
473 cluster_ids
474 .chain(database_ids)
475 .chain(schema_ids)
476 .chain(item_ids)
477 .chain(network_policy_ids)
478 .filter(|object_id| object_type_filter(object_id, &object_type, scx))
479 .filter(|object_id| object_id.is_user())
480 .collect()
481 }
482 GrantTargetSpecificationInner::All(GrantTargetAllSpecification::AllDatabases {
483 databases,
484 }) => {
485 let schema_ids = databases
486 .iter()
487 .map(|database| scx.get_database(database.database_id()))
488 .flat_map(|database| database.schemas().into_iter())
489 .filter(|schema| !schema.id().is_temporary())
490 .map(|schema| (schema.database().clone(), schema.id().clone()).into());
491
492 let item_ids = databases
493 .iter()
494 .map(|database| scx.get_database(database.database_id()))
495 .flat_map(|database| database.schemas().into_iter())
496 .flat_map(|schema| schema.item_ids())
497 .map(|item_id| item_id.into());
498
499 item_ids
500 .chain(schema_ids)
501 .filter(|object_id| object_type_filter(object_id, &object_type, scx))
502 .collect()
503 }
504 GrantTargetSpecificationInner::All(GrantTargetAllSpecification::AllSchemas {
505 schemas,
506 }) => schemas
507 .into_iter()
508 .map(|schema| scx.get_schema(schema.database_spec(), schema.schema_spec()))
509 .flat_map(|schema| schema.item_ids())
510 .map(|item_id| item_id.into())
511 .filter(|object_id| object_type_filter(object_id, &object_type, scx))
512 .collect(),
513 GrantTargetSpecificationInner::Objects { names } => {
514 let mut ids = Vec::with_capacity(names.len());
515 for name in names {
516 ids.push(
517 name.try_into()
519 .map_err(|e| internal_err!("invalid object name: {}", e))?,
520 );
521 }
522 ids
523 }
524 };
525 let target_ids = object_ids.into_iter().map(|id| id.into()).collect();
526 (SystemObjectType::Object(object_type), target_ids)
527 }
528 GrantTargetSpecification::System => {
529 (SystemObjectType::System, vec![SystemObjectId::System])
530 }
531 };
532
533 let mut update_privileges = Vec::with_capacity(target_ids.len());
534
535 for target_id in target_ids {
536 if let SystemObjectId::Object(ObjectId::Schema((_, SchemaSpecifier::Temporary))) =
540 &target_id
541 {
542 sql_bail!(
543 "cannot grant or revoke privileges on schema {} because it is a temporary schema",
544 mz_repr::namespaces::MZ_TEMP_SCHEMA
545 );
546 }
547
548 let actual_object_type = scx.get_system_object_type(&target_id);
550 let mut reference_object_type = actual_object_type.clone();
553
554 if let SystemObjectId::Object(ObjectId::Item(id)) = &target_id {
555 let item = scx.get_item(id);
556 let item_type: ObjectType = item.item_type().into();
557 if (item_type == ObjectType::View
558 || item_type == ObjectType::MaterializedView
559 || item_type == ObjectType::Source)
560 && object_type == SystemObjectType::Object(ObjectType::Table)
561 {
562 reference_object_type = SystemObjectType::Object(ObjectType::Table);
564 } else if SystemObjectType::Object(item_type) != object_type {
565 let object_name = scx.catalog.resolve_full_name(item.name()).to_string();
566 return Err(PlanError::InvalidObjectType {
567 expected_type: object_type,
568 actual_type: actual_object_type,
569 object_name,
570 });
571 }
572 }
573
574 let acl_mode = privilege_spec_to_acl_mode(scx, &privileges, reference_object_type);
579 let acl_from_all = matches!(privileges, PrivilegeSpecification::All);
580
581 let all_object_privileges = scx.catalog.all_object_privileges(reference_object_type);
582 let invalid_privileges = acl_mode.difference(all_object_privileges);
583 if !invalid_privileges.is_empty() {
584 let object_description =
585 ErrorMessageObjectDescription::from_sys_id(&target_id, scx.catalog);
586 return Err(PlanError::InvalidPrivilegeTypes {
587 invalid_privileges,
588 object_description,
589 });
590 }
591
592 let grantor = match &target_id {
599 SystemObjectId::Object(object_id) => scx
600 .catalog
601 .get_owner_id(object_id)
602 .ok_or_else(|| sql_err!("cannot revoke privileges on objects without owners"))?,
603 SystemObjectId::System => scx.catalog.mz_system_role_id(),
604 };
605
606 update_privileges.push(UpdatePrivilege {
607 acl_mode,
608 target_id,
609 grantor,
610 acl_from_all,
611 });
612 }
613
614 let grantees = roles.into_iter().map(|role| role.id).collect();
615
616 Ok(UpdatePrivilegesPlan {
617 update_privileges,
618 grantees,
619 })
620}
621
622fn privilege_spec_to_acl_mode(
623 scx: &StatementContext,
624 privilege_spec: &PrivilegeSpecification,
625 object_type: SystemObjectType,
626) -> AclMode {
627 match privilege_spec {
628 PrivilegeSpecification::All => scx.catalog.all_object_privileges(object_type),
629 PrivilegeSpecification::Privileges(privileges) => privileges
630 .into_iter()
631 .map(|privilege| privilege_to_acl_mode(privilege.clone()))
632 .fold(AclMode::empty(), |accum, acl_mode| accum.union(acl_mode)),
634 }
635}
636
637fn privilege_to_acl_mode(privilege: Privilege) -> AclMode {
638 match privilege {
639 Privilege::SELECT => AclMode::SELECT,
640 Privilege::INSERT => AclMode::INSERT,
641 Privilege::UPDATE => AclMode::UPDATE,
642 Privilege::DELETE => AclMode::DELETE,
643 Privilege::USAGE => AclMode::USAGE,
644 Privilege::CREATE => AclMode::CREATE,
645 Privilege::CREATEROLE => AclMode::CREATE_ROLE,
646 Privilege::CREATEDB => AclMode::CREATE_DB,
647 Privilege::CREATECLUSTER => AclMode::CREATE_CLUSTER,
648 Privilege::CREATENETWORKPOLICY => AclMode::CREATE_NETWORK_POLICY,
649 }
650}
651
652pub fn describe_alter_default_privileges(
653 _: &StatementContext,
654 _: AlterDefaultPrivilegesStatement<Aug>,
655) -> Result<StatementDesc, PlanError> {
656 Ok(StatementDesc::new(None))
657}
658
659pub fn plan_alter_default_privileges(
660 scx: &StatementContext,
661 AlterDefaultPrivilegesStatement {
662 target_roles,
663 target_objects,
664 grant_or_revoke,
665 }: AlterDefaultPrivilegesStatement<Aug>,
666) -> Result<Plan, PlanError> {
667 let object_type: ObjectType = (*grant_or_revoke.object_type()).into();
668 match object_type {
669 ObjectType::View | ObjectType::MaterializedView | ObjectType::Source => sql_bail!(
670 "{object_type}S is not valid for ALTER DEFAULT PRIVILEGES, use TABLES instead"
671 ),
672 ObjectType::Sink | ObjectType::ClusterReplica | ObjectType::Role | ObjectType::Func => {
673 sql_bail!("{object_type}S do not have privileges")
674 }
675 ObjectType::Cluster | ObjectType::Database
676 if matches!(
677 target_objects,
678 GrantTargetAllSpecification::AllDatabases { .. }
679 ) =>
680 {
681 sql_bail!("cannot specify {object_type}S and IN DATABASE")
682 }
683
684 ObjectType::Cluster | ObjectType::Database | ObjectType::Schema
685 if matches!(
686 target_objects,
687 GrantTargetAllSpecification::AllSchemas { .. }
688 ) =>
689 {
690 sql_bail!("cannot specify {object_type}S and IN SCHEMA")
691 }
692 ObjectType::Table
693 | ObjectType::Index
694 | ObjectType::Type
695 | ObjectType::Secret
696 | ObjectType::Connection
697 | ObjectType::Cluster
698 | ObjectType::Database
699 | ObjectType::Schema
700 | ObjectType::NetworkPolicy => {}
701 }
702
703 let acl_mode = privilege_spec_to_acl_mode(
704 scx,
705 grant_or_revoke.privileges(),
706 SystemObjectType::Object(object_type),
707 );
708 let all_object_privileges = scx
709 .catalog
710 .all_object_privileges(SystemObjectType::Object(object_type));
711 let invalid_privileges = acl_mode.difference(all_object_privileges);
712 if !invalid_privileges.is_empty() {
713 let object_description =
714 ErrorMessageObjectDescription::from_object_type(SystemObjectType::Object(object_type));
715 return Err(PlanError::InvalidPrivilegeTypes {
716 invalid_privileges,
717 object_description,
718 });
719 }
720
721 let target_roles = match target_roles {
722 TargetRoleSpecification::Roles(roles) => roles.into_iter().map(|role| role.id).collect(),
723 TargetRoleSpecification::AllRoles => vec![RoleId::Public],
724 };
725 let mut privilege_objects = Vec::with_capacity(target_roles.len() * target_objects.len());
726 for target_role in target_roles {
727 match &target_objects {
728 GrantTargetAllSpecification::All => privilege_objects.push(DefaultPrivilegeObject {
729 role_id: target_role,
730 database_id: None,
731 schema_id: None,
732 object_type,
733 }),
734 GrantTargetAllSpecification::AllDatabases { databases } => {
735 for database in databases {
736 privilege_objects.push(DefaultPrivilegeObject {
737 role_id: target_role,
738 database_id: Some(*database.database_id()),
739 schema_id: None,
740 object_type,
741 });
742 }
743 }
744 GrantTargetAllSpecification::AllSchemas { schemas } => {
745 for schema in schemas {
746 privilege_objects.push(DefaultPrivilegeObject {
747 role_id: target_role,
748 database_id: schema.database_spec().id(),
749 schema_id: Some(schema.schema_spec().into()),
750 object_type,
751 });
752 }
753 }
754 }
755 }
756
757 let privilege_acl_items = grant_or_revoke
758 .roles()
759 .into_iter()
760 .map(|grantee| DefaultPrivilegeAclItem {
761 grantee: grantee.id,
762 acl_mode,
763 })
764 .collect();
765
766 let is_grant = match grant_or_revoke {
767 AbbreviatedGrantOrRevokeStatement::Grant(_) => true,
768 AbbreviatedGrantOrRevokeStatement::Revoke(_) => false,
769 };
770
771 Ok(Plan::AlterDefaultPrivileges(AlterDefaultPrivilegesPlan {
772 privilege_objects,
773 privilege_acl_items,
774 is_grant,
775 }))
776}
777
778pub fn describe_reassign_owned(
779 _: &StatementContext,
780 _: ReassignOwnedStatement<Aug>,
781) -> Result<StatementDesc, PlanError> {
782 Ok(StatementDesc::new(None))
783}
784
785pub fn plan_reassign_owned(
786 scx: &StatementContext,
787 ReassignOwnedStatement {
788 old_roles,
789 new_role,
790 }: ReassignOwnedStatement<Aug>,
791) -> Result<Plan, PlanError> {
792 let old_roles: BTreeSet<_> = old_roles.into_iter().map(|role| role.id).collect();
793 let mut reassign_ids: Vec<ObjectId> = Vec::new();
794
795 for replica in scx.catalog.get_cluster_replicas() {
797 if old_roles.contains(&replica.owner_id()) {
798 reassign_ids.push((replica.cluster_id(), replica.replica_id()).into());
799 }
800 }
801 for cluster in scx.catalog.get_clusters() {
803 if old_roles.contains(&cluster.owner_id()) {
804 reassign_ids.push(cluster.id().into());
805 }
806 }
807 for item in scx.catalog.get_items() {
809 if old_roles.contains(&item.owner_id()) {
810 reassign_ids.push(item.id().into());
811 }
812 }
813 for schema in scx.catalog.get_schemas() {
815 if !schema.id().is_temporary() {
816 if old_roles.contains(&schema.owner_id()) {
817 reassign_ids.push((*schema.database(), *schema.id()).into())
818 }
819 }
820 }
821 for database in scx.catalog.get_databases() {
823 if old_roles.contains(&database.owner_id()) {
824 reassign_ids.push(database.id().into());
825 }
826 }
827 for network_policy in scx.catalog.get_network_policies() {
829 if old_roles.contains(&network_policy.owner_id()) {
830 reassign_ids.push(ObjectId::NetworkPolicy(network_policy.id()));
831 }
832 }
833
834 let system_ids: Vec<_> = reassign_ids.iter().filter(|id| id.is_system()).collect();
835 if !system_ids.is_empty() {
836 let mut owners = system_ids
837 .into_iter()
838 .filter_map(|object_id| scx.catalog.get_owner_id(object_id))
839 .collect::<BTreeSet<_>>()
840 .into_iter()
841 .map(|role_id| scx.catalog.get_role(&role_id).name().quoted());
842 sql_bail!(
843 "cannot reassign objects owned by role {} because they are required by the database system",
844 owners.join(", "),
845 );
846 }
847
848 Ok(Plan::ReassignOwned(ReassignOwnedPlan {
849 old_roles: old_roles.into_iter().collect(),
850 new_role: new_role.id,
851 reassign_ids,
852 }))
853}