1use crate::{
9 catalog::security::table::TableAclPrivilege,
10 plan::UpdatePlan,
11 semantics::{privileges::TargetSelectPrivilegeRequest, view_privileges::ViewPrivilegeCatalog},
12 SQLError, ScalarExpr,
13};
14pub trait MutationPrivilegeCatalog: ViewPrivilegeCatalog {
15 fn bound_table_column_names(&self, table: &str) -> Result<Vec<String>, SQLError>;
16 fn ensure_table_privilege_for(
17 &self,
18 table: &str,
19 subject: &str,
20 privilege: TableAclPrivilege,
21 ) -> Result<(), SQLError>;
22 fn ensure_column_privilege_for(
23 &self,
24 table: &str,
25 column: &str,
26 subject: &str,
27 privilege: TableAclPrivilege,
28 ) -> Result<(), SQLError>;
29 fn ensure_any_column_privilege_for(
30 &self,
31 table: &str,
32 subject: &str,
33 privilege: TableAclPrivilege,
34 ) -> Result<(), SQLError>;
35}
36pub fn ensure_update_target_privileges<'a>(
37 catalog: &dyn MutationPrivilegeCatalog,
38 statement: &'a UpdatePlan,
39) -> Result<Vec<&'a ScalarExpr>, SQLError> {
40 let privilege_subject = statement
41 .target_privilege_subject
42 .clone()
43 .unwrap_or_else(|| catalog.current_user_name());
44 for assignment in &statement.assignments {
45 catalog.ensure_column_privilege_for(
46 &statement.table,
47 &assignment.column,
48 &privilege_subject,
49 TableAclPrivilege::Update,
50 )?;
51 }
52 let expressions = statement
53 .assignments
54 .iter()
55 .map(|assignment| &assignment.value)
56 .chain(statement.predicate.iter())
57 .chain(
58 statement
59 .returning
60 .iter()
61 .map(|projection| &projection.expr),
62 )
63 .collect::<Vec<_>>();
64 catalog.ensure_target_select(TargetSelectPrivilegeRequest {
65 table: &statement.table,
66 privilege_subject: statement.target_privilege_subject.as_deref(),
67 target_qualifier: &statement.target_qualifier,
68 returning_aliases: &statement.returning_aliases,
69 expressions: &expressions,
70 subqueries: &statement.subqueries,
71 required_columns: &[],
72 })?;
73 Ok(expressions)
74}
75
76pub fn ensure_insert_target_privileges(
78 catalog: &dyn MutationPrivilegeCatalog,
79 stmt: &crate::plan::InsertPlan,
80 conflict_update_columns: Option<&[String]>,
81) -> Result<(), SQLError> {
82 use crate::plan::{ConflictActionPlan, ConflictPlan};
83 let default_values =
84 stmt.source.is_none() && stmt.columns.is_empty() && stmt.rows.iter().all(Vec::is_empty);
85 let privilege_subject = stmt
86 .target_privilege_subject
87 .clone()
88 .unwrap_or_else(|| catalog.current_user_name());
89 if default_values {
90 catalog.ensure_any_column_privilege_for(
91 &stmt.table,
92 &privilege_subject,
93 TableAclPrivilege::Insert,
94 )?;
95 } else {
96 let insert_columns = if stmt.columns.is_empty() {
97 let supplied = stmt.source.as_deref().map_or_else(
98 || stmt.rows.first().map(Vec::len),
99 |source| {
100 crate::semantics::projection::query_plan_output_columns(source)
101 .map(|columns| columns.len())
102 },
103 );
104 let columns = catalog.bound_table_column_names(&stmt.table)?;
105 match supplied {
106 Some(supplied) => columns.into_iter().take(supplied).collect(),
107 None => columns,
108 }
109 } else {
110 stmt.columns.clone()
111 };
112 for column in insert_columns {
113 catalog.ensure_column_privilege_for(
114 &stmt.table,
115 &column,
116 &privilege_subject,
117 TableAclPrivilege::Insert,
118 )?;
119 }
120 }
121 if let Some(columns) = conflict_update_columns {
122 for column in columns {
123 catalog.ensure_column_privilege_for(
124 &stmt.table,
125 column,
126 &privilege_subject,
127 TableAclPrivilege::Update,
128 )?;
129 }
130 }
131 let mut privilege_expressions = stmt
132 .returning
133 .iter()
134 .map(|projection| &projection.expr)
135 .collect::<Vec<_>>();
136 if let Some(conflict) = &stmt.on_conflict {
137 privilege_expressions.extend(conflict.expressions.iter());
138 privilege_expressions.extend(conflict.predicate.iter().map(Box::as_ref));
139 }
140 if let Some(ConflictPlan {
141 action:
142 ConflictActionPlan::Update {
143 assignments,
144 predicate,
145 },
146 ..
147 }) = stmt.on_conflict.as_ref()
148 {
149 privilege_expressions.extend(assignments.iter().map(|assignment| &assignment.value));
150 privilege_expressions.extend(predicate.iter().map(Box::as_ref));
151 }
152 catalog.ensure_target_select(TargetSelectPrivilegeRequest {
153 table: &stmt.table,
154 privilege_subject: stmt.target_privilege_subject.as_deref(),
155 target_qualifier: &stmt.target_qualifier,
156 returning_aliases: &stmt.returning_aliases,
157 expressions: &privilege_expressions,
158 subqueries: &stmt.subqueries,
159 required_columns: stmt
160 .on_conflict
161 .as_ref()
162 .map_or(&[][..], |conflict| conflict.conflict_columns.as_slice()),
163 })?;
164 Ok(())
165}
166
167pub fn inherit_command_privilege_subject(
169 command: &mut crate::plan::CommandPlan,
170 subject: String,
171) -> Result<(), SQLError> {
172 use crate::plan::CommandPlan;
173 let (statement_subject, target_subject) = match command {
174 CommandPlan::Insert(plan) => (
175 &mut plan.statement_privilege_subject,
176 &mut plan.target_privilege_subject,
177 ),
178 CommandPlan::Update(plan) => (
179 &mut plan.statement_privilege_subject,
180 &mut plan.target_privilege_subject,
181 ),
182 CommandPlan::Delete(plan) => (
183 &mut plan.statement_privilege_subject,
184 &mut plan.target_privilege_subject,
185 ),
186 CommandPlan::Merge(plan) => (
187 &mut plan.statement_privilege_subject,
188 &mut plan.target_privilege_subject,
189 ),
190 _ => {
191 return Err(SQLError::Internal(
192 "non-DML command in a WITH definition".into(),
193 ))
194 }
195 };
196 statement_subject.get_or_insert(subject.clone());
197 target_subject.get_or_insert(subject);
198 Ok(())
199}