Skip to main content

uqa_sql/ast/
routine_security.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Routine security, ownership, configuration, privileges, and role statements.
8
9use std::collections::{BTreeMap, BTreeSet};
10
11use serde::{Deserialize, Serialize};
12
13use super::{FunctionVolatility, RoutineColumnTypeReference};
14
15/// `PARALLEL UNSAFE`, `PARALLEL RESTRICTED`, or `PARALLEL SAFE` routine metadata.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
17pub enum FunctionParallel {
18    #[default]
19    Unsafe,
20    Restricted,
21    Safe,
22}
23
24/// Execution identity and planner leakproofness attached to a routine definition.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
26pub struct RoutineSecurityAttributes {
27    /// `SECURITY DEFINER` when true, otherwise `SECURITY INVOKER`.
28    #[serde(default)]
29    pub security_definer: bool,
30    /// `LEAKPROOF` planner metadata.
31    #[serde(default)]
32    pub leakproof: bool,
33}
34
35/// One explicit `EXECUTE` ACL entry. `None` on `CreateFunction::execute_acl` retains `PostgreSQL`'s default public execution privilege.
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct RoutineAclEntry {
38    pub role: String,
39    /// Grantor for this ACL path. Legacy persisted definitions omit the field and therefore use the routine owner.
40    #[serde(default, skip_serializing_if = "Option::is_none")]
41    pub grantor: Option<String>,
42    pub grant_option: bool,
43}
44
45/// Routine namespace selected by `ALTER FUNCTION`, `ALTER PROCEDURE`, or `ALTER ROUTINE`.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
47pub enum AlterRoutineKind {
48    Function,
49    Procedure,
50    Routine,
51}
52
53/// `ALTER FUNCTION | PROCEDURE | ROUTINE name[(input_types)] ...` with an optional exact declared input identity.
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55pub struct AlterRoutineStmt {
56    pub kind: AlterRoutineKind,
57    pub name: String,
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub arg_types: Option<Vec<String>>,
60    #[serde(default, skip_serializing_if = "Vec::is_empty")]
61    pub arg_type_references: Vec<Option<RoutineColumnTypeReference>>,
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub volatility: Option<FunctionVolatility>,
64    #[serde(default, skip_serializing_if = "Option::is_none")]
65    pub strict: Option<bool>,
66    #[serde(default, skip_serializing_if = "Option::is_none")]
67    pub security_definer: Option<bool>,
68    #[serde(default, skip_serializing_if = "Option::is_none")]
69    pub leakproof: Option<bool>,
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub parallel: Option<FunctionParallel>,
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub support: Option<String>,
74    #[serde(default, skip_serializing_if = "Vec::is_empty")]
75    pub config_actions: Vec<RoutineConfigAction>,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub enum RoutineConfigAction {
80    Set { name: String, value: String },
81    FromCurrent { name: String },
82    Reset { name: String },
83    ResetAll,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct AlterRoutineOwnerStmt {
88    pub kind: AlterRoutineKind,
89    pub name: String,
90    pub arg_types: Option<Vec<String>>,
91    pub arg_type_references: Vec<Option<RoutineColumnTypeReference>>,
92    pub new_owner: String,
93}
94
95/// `ALTER FUNCTION | PROCEDURE | ROUTINE name[(input_types)] RENAME TO new_name`.
96#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
97pub struct RenameRoutineStmt {
98    pub kind: AlterRoutineKind,
99    pub name: String,
100    #[serde(default, skip_serializing_if = "Option::is_none")]
101    pub arg_types: Option<Vec<String>>,
102    #[serde(default, skip_serializing_if = "Vec::is_empty")]
103    pub arg_type_references: Vec<Option<RoutineColumnTypeReference>>,
104    pub new_name: String,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct GrantRoutineItem {
109    pub name: String,
110    pub arg_types: Option<Vec<String>>,
111}
112
113#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
114pub enum RoutineRevokeBehavior {
115    #[default]
116    Restrict,
117    Cascade,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct GrantRoutineStmt {
122    pub kind: AlterRoutineKind,
123    pub is_grant: bool,
124    pub grant_option: bool,
125    pub grant_option_only: bool,
126    pub items: Vec<GrantRoutineItem>,
127    pub grantees: Vec<String>,
128    #[serde(default, skip_serializing_if = "Option::is_none")]
129    pub grantor: Option<String>,
130    #[serde(default)]
131    pub revoke_behavior: RoutineRevokeBehavior,
132}
133
134/// `PostgreSQL` 18 options stored on one role-membership grant.
135#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
136pub struct RoleMembershipOptions {
137    pub admin: Option<bool>,
138    pub inherit: Option<bool>,
139    pub set: Option<bool>,
140}
141
142/// `GRANT role TO member` or `REVOKE role FROM member`.
143#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
144pub struct GrantRoleStmt {
145    pub granted_roles: Vec<String>,
146    pub grantee_roles: Vec<String>,
147    pub is_grant: bool,
148    pub options: RoleMembershipOptions,
149    pub grantor: Option<String>,
150    pub cascade: bool,
151}
152
153#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
154pub enum RoleAttribute {
155    Superuser,
156    Inherit,
157    CreateRole,
158    CreateDb,
159    Login,
160    Replication,
161    BypassRls,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
165pub struct CreateRoleStmt {
166    pub name: String,
167    pub attributes: BTreeSet<RoleAttribute>,
168    pub connection_limit: i32,
169    #[serde(default, skip_serializing_if = "Vec::is_empty")]
170    pub in_roles: Vec<String>,
171    #[serde(default, skip_serializing_if = "Vec::is_empty")]
172    pub role_members: Vec<String>,
173    #[serde(default, skip_serializing_if = "Vec::is_empty")]
174    pub admin_members: Vec<String>,
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
178pub enum RoleMembershipAction {
179    Add,
180    Drop,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
184pub struct AlterRoleStmt {
185    pub name: String,
186    pub attributes: BTreeMap<RoleAttribute, bool>,
187    pub connection_limit: Option<i32>,
188    pub membership_action: Option<RoleMembershipAction>,
189    pub members: Vec<String>,
190}
191
192#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
193pub struct DropRoleStmt {
194    pub names: Vec<String>,
195    pub if_exists: bool,
196}