use crate::catalog::security::roles::RoleCatalogGuards;
use std::collections::BTreeMap;
use uqa_core::RelationIdentity;
use uqa_sql::{
ast::RoleAttribute,
catalog::roles::{self, RoleReferenceNames},
SQLError,
};
use uqa_storage::{StorageBackendError, StorageBackendResult};
pub trait RelationAlterLocks {
fn lock_exclusive(&self, name: &str) -> Result<(), SQLError>;
}
pub trait RelationRenameDependencies {
fn rewrite_views(
&self,
renames: &BTreeMap<RelationIdentity, RelationIdentity>,
) -> StorageBackendResult<()>;
fn rewrite_routines(
&self,
from: &RelationIdentity,
to: &RelationIdentity,
) -> Result<(), String>;
fn rename_events(
&self,
from: &RelationIdentity,
to: &RelationIdentity,
) -> StorageBackendResult<()>;
}
pub fn rewrite_relation_rename_dependents(
dependencies: &dyn RelationRenameDependencies,
from: &RelationIdentity,
to: &RelationIdentity,
) -> StorageBackendResult<()> {
dependencies.rewrite_views(&BTreeMap::from([(from.clone(), to.clone())]))?;
dependencies
.rewrite_routines(from, to)
.map_err(StorageBackendError::Other)?;
dependencies.rename_events(from, to)
}
pub trait RoleTargetSchemaAccess {
fn require_schema_create(&self, schema: &str, role: &str) -> Result<(), SQLError>;
}
pub struct RoleTransferContext<'a> {
pub roles: &'a dyn RoleCatalogGuards,
pub session: &'a dyn RoleReferenceNames,
pub schemas: &'a dyn RoleTargetSchemaAccess,
}
pub fn role_transfer_target(
context: &RoleTransferContext<'_>,
requested_owner: &str,
) -> Result<(String, bool), SQLError> {
let new_owner = roles::resolve_role_reference(context.session, requested_owner);
let current_user_is_superuser;
{
let roles = context.roles.role_definitions();
roles::require_role_exists(&roles, &new_owner)?;
let memberships = context.roles.role_memberships();
let current_user = context.session.current_user_name();
current_user_is_superuser = roles
.get(¤t_user)
.is_some_and(|role| role.has(RoleAttribute::Superuser));
roles::require_set_role(&roles, &memberships, ¤t_user, &new_owner)?;
}
Ok((new_owner, current_user_is_superuser))
}