ALTER ROLE SET INHERIT
(
state: &SharedState,
identity: &AuthenticatedIdentity,
parts: &[&str],
)
| 75 | |
| 76 | /// ALTER ROLE <name> SET INHERIT <parent> |
| 77 | pub fn alter_role( |
| 78 | state: &SharedState, |
| 79 | identity: &AuthenticatedIdentity, |
| 80 | parts: &[&str], |
| 81 | ) -> PgWireResult<Vec<Response>> { |
| 82 | require_tenant_admin(identity, "alter roles")?; |
| 83 | |
| 84 | // ALTER ROLE <name> SET INHERIT <parent> |
| 85 | if parts.len() < 6 { |
| 86 | return Err(sqlstate_error( |
| 87 | "42601", |
| 88 | "syntax: ALTER ROLE <name> SET INHERIT <parent>", |
| 89 | )); |
| 90 | } |
| 91 | |
| 92 | let name = parts[2]; |
| 93 | if !parts[3].eq_ignore_ascii_case("SET") || !parts[4].eq_ignore_ascii_case("INHERIT") { |
| 94 | return Err(sqlstate_error( |
| 95 | "42601", |
| 96 | "expected SET INHERIT after role name", |
| 97 | )); |
| 98 | } |
| 99 | let parent = parts[5]; |
| 100 | |
| 101 | // Validate parent exists (built-in or custom) and the role itself exists. |
| 102 | let old_role = state |
| 103 | .roles |
| 104 | .get_role(name) |
| 105 | .ok_or_else(|| sqlstate_error("42704", &format!("role '{name}' not found")))?; |
| 106 | let parent_is_builtin = matches!( |
| 107 | parent, |
| 108 | "superuser" | "tenant_admin" | "readwrite" | "readonly" | "monitor" |
| 109 | ); |
| 110 | if !parent_is_builtin && state.roles.get_role(parent).is_none() { |
| 111 | return Err(sqlstate_error( |
| 112 | "42704", |
| 113 | &format!("parent role '{parent}' does not exist"), |
| 114 | )); |
| 115 | } |
| 116 | |
| 117 | let now = std::time::SystemTime::now() |
| 118 | .duration_since(std::time::UNIX_EPOCH) |
| 119 | .unwrap_or_default() |
| 120 | .as_secs(); |
| 121 | let stored = crate::control::security::catalog::StoredRole { |
| 122 | name: name.to_string(), |
| 123 | tenant_id: old_role.tenant_id.as_u64(), |
| 124 | parent: parent.to_string(), |
| 125 | created_at: now, |
| 126 | }; |
| 127 | |
| 128 | let entry = crate::control::catalog_entry::CatalogEntry::PutRole(Box::new(stored.clone())); |
| 129 | let log_index = crate::control::metadata_proposer::propose_catalog_entry(state, &entry) |
| 130 | .map_err(|e| sqlstate_error("XX000", &format!("metadata propose: {e}")))?; |
| 131 | if log_index == 0 |
| 132 | && let Some(catalog) = state.credentials.catalog() |
| 133 | { |
| 134 | catalog |
no test coverage detected