uqa-execution 0.4.5

Volcano physical operators with row-batch pipelines
//
// Unified Query Algebra
//
// Copyright (c) 2023-2026 Cognica, Inc.
//

//! Shared relation rename publication and role-transfer authorization boundaries.
use crate::catalog::security::roles::{
    locking::{RoleBinding, RoleLockContext},
    RoleCatalogGuards,
};
use crate::catalog::security::table_inquiry::TablePrivilegeContext;
use crate::row_locks::shared_objects::SharedObjectLockSession;
use std::collections::BTreeMap;
use uqa_core::RelationIdentity;
use uqa_sql::catalog::roles::RoleReference;
use uqa_sql::{
    catalog::roles::{self, RoleReferenceNames},
    catalog::security::ownership::RelationOwnerSchemas,
    SQLError,
};
use uqa_storage::{StorageBackendError, StorageBackendResult};

pub fn validate_relation_alter_authority(
    owners: &TablePrivilegeContext<'_>,
    namespaces: &super::namespaces::relations::RelationCreationContext<'_>,
    relation: &RelationIdentity,
    kind: &str,
    rename: bool,
) -> Result<(), SQLError> {
    owners.ensure_relation_owner(relation, kind)?;
    uqa_sql::catalog::security::ownership::reject_system_relation_alter(relation)?;
    if rename {
        namespaces.ensure_namespace_create(&relation.schema)?;
    }
    Ok(())
}

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: &RoleReference) -> Result<(), SQLError>;
}

pub struct RoleTransferContext<'a> {
    pub roles: &'a dyn RoleCatalogGuards,
    pub session: &'a dyn RoleReferenceNames,
    pub schemas: &'a dyn RelationOwnerSchemas,
    pub locks: &'a dyn SharedObjectLockSession,
}

impl<'a> RoleTransferContext<'a> {
    pub fn lock_context(&self) -> RoleLockContext<'a> {
        RoleLockContext {
            roles: self.roles,
            session: self.locks,
        }
    }

    pub fn bind(
        &self,
        requested: &uqa_sql::ast::RoleSpecification,
    ) -> Result<RoleBinding, SQLError> {
        self.lock_context()
            .bind(&roles::resolve_role_specification(self.session, requested))
    }
}