Skip to main content

uqa_sql/semantics/privileges/
columns.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Base columns referenced by an executable query block, including aliases and joined output names.
8
9use super::{
10    analyze_query_block, BTreeMap, BTreeSet, CteScope, QueryBlockPlan, SQLError, SourceLineage,
11};
12
13pub fn required(
14    block: &QueryBlockPlan,
15    scope: &CteScope<'_>,
16) -> Result<BTreeMap<String, BTreeSet<String>>, SQLError> {
17    let mut scope = scope.clone();
18    scope.include_authorization_only_columns = false;
19    let mut universe = SourceLineage::default();
20    let mut required = BTreeSet::new();
21    analyze_query_block(
22        block,
23        block.from.as_ref(),
24        &scope,
25        &[],
26        &mut universe,
27        &mut required,
28    )?;
29    Ok(by_relation(required))
30}
31
32fn by_relation(required: BTreeSet<super::BaseColumn>) -> BTreeMap<String, BTreeSet<String>> {
33    let mut result: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
34    for column in required {
35        result
36            .entry(column.table)
37            .or_default()
38            .insert(column.column);
39    }
40    result
41}
42
43/// Columns read through a mutation's additional sources, using the same aliases as SELECT privilege analysis.
44pub fn for_source_expressions(
45    source: &crate::plan::SourcePlan,
46    expressions: &[&crate::ScalarExpr],
47    scope: &CteScope<'_>,
48) -> Result<BTreeMap<String, BTreeSet<String>>, SQLError> {
49    let mut scope = scope.clone();
50    scope.include_authorization_only_columns = false;
51    let (_, required) = super::source_expression_dependencies(source, expressions, &scope)?;
52    Ok(by_relation(required))
53}
54
55/// Columns read from a mutation target, including RETURNING's OLD/NEW aliases and correlated subqueries.
56pub fn for_target_expressions(
57    table: &str,
58    qualifiers: &BTreeSet<String>,
59    expressions: &[&crate::ScalarExpr],
60    scope: &CteScope<'_>,
61) -> Result<BTreeMap<String, BTreeSet<String>>, SQLError> {
62    let mut scope = scope.clone();
63    scope.include_authorization_only_columns = false;
64    let (_, required) = super::table_expression_dependencies(
65        table,
66        qualifiers,
67        expressions,
68        &scope.scalar_subqueries,
69        &[],
70        &scope,
71    )?;
72    Ok(by_relation(required))
73}