Skip to main content

uqa_sql/catalog/roles/
inquiry.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Role privilege inquiry with ordered session and retained catalog reads.
8
9use super::{
10    guards::RoleCatalogGuards,
11    memberships::{
12        parse_pg_has_role_privileges, pg_has_role_privilege, resolve_pg_has_role_identifier,
13        role_privilege_text,
14    },
15    RoleReferenceNames,
16};
17use crate::catalog::roles::RoleReference;
18use crate::SQLError;
19use uqa_core::Value;
20
21pub fn pg_has_role_value(
22    names: &dyn RoleReferenceNames,
23    catalog: &dyn RoleCatalogGuards,
24    arguments: &[Value],
25) -> Result<Value, SQLError> {
26    if arguments.iter().any(|argument| argument == &Value::Null) {
27        return Ok(Value::Null);
28    }
29    let (subject_value, target_value, privilege_value) = match arguments {
30        [target, privilege] => (None, target, privilege),
31        [subject, target, privilege] => (Some(subject), target, privilege),
32        _ => {
33            return Err(SQLError::BadArity {
34                name: "pg_has_role".into(),
35                expected: "2 or 3".into(),
36                actual: arguments.len(),
37            });
38        }
39    };
40    let current_user = subject_value.is_none().then(|| names.current_role());
41    let roles = catalog.role_definitions();
42    let subject = subject_value.map_or_else(
43        || Ok(current_user),
44        |value| {
45            resolve_pg_has_role_identifier(value, &roles).map(|role| role.map(RoleReference::from))
46        },
47    )?;
48    let target = resolve_pg_has_role_identifier(target_value, &roles)?;
49    let privileges = parse_pg_has_role_privileges(role_privilege_text(privilege_value)?)?;
50    let memberships = catalog.role_memberships();
51    let allowed = privileges.into_iter().any(|privilege| {
52        pg_has_role_privilege(
53            &roles,
54            &memberships,
55            subject.as_ref(),
56            target.as_deref(),
57            privilege,
58        )
59    });
60    Ok(Value::Bool(allowed))
61}