Skip to main content

uqa_sql/catalog/
stored_view.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7use super::security::TableSecurity;
8use std::collections::BTreeMap;
9
10/// One bound view query together with the fixed public column names captured when the view was created. `None` exists only while the catalog-opening migration reads formats written before column metadata was persisted.
11#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
12pub struct StoredView {
13    /// Stable logical relation identity. Renames and replacement preserve it; a zero value marks a legacy catalog row upgraded during initial open.
14    #[serde(default)]
15    pub object_id: [u8; 16],
16    /// Durable SQL-role owner loaded from the typed view catalog row. The query-definition JSON deliberately excludes ownership so catalog definition and authorization state cannot disagree.
17    #[serde(skip)]
18    pub role_owner: String,
19    /// Durable relation-wide ACL loaded from the typed view catalog row.
20    #[serde(skip)]
21    pub acl: Option<Vec<super::security::TableAclEntry>>,
22    /// Durable per-column ACLs loaded from the typed view catalog row.
23    #[serde(skip)]
24    pub column_acls: BTreeMap<String, Vec<super::security::TableAclEntry>>,
25    pub query: crate::plan::QueryPlan,
26    #[serde(default, skip_serializing_if = "Option::is_none")]
27    pub output_columns: Option<Vec<String>>,
28    #[serde(default)]
29    pub persistence: crate::ast::RelationPersistence,
30    #[serde(default, skip_serializing_if = "Vec::is_empty")]
31    pub options: Vec<(String, String)>,
32    #[serde(default)]
33    pub kind: StoredViewKind,
34    #[serde(default, skip_serializing_if = "Vec::is_empty")]
35    pub materialized_rows: Vec<crate::ResultRow>,
36    #[serde(default, skip_serializing_if = "Vec::is_empty")]
37    pub materialized_column_types: Vec<Option<crate::ast::ColumnType>>,
38    #[serde(default = "default_view_populated")]
39    pub populated: bool,
40}
41
42use super::view::StoredViewKind;
43
44const fn default_view_populated() -> bool {
45    true
46}
47
48impl StoredView {
49    pub fn security(&self) -> TableSecurity {
50        TableSecurity {
51            role_owner: self.role_owner.clone(),
52            acl: self.acl.clone(),
53            column_acls: self.column_acls.clone(),
54        }
55    }
56
57    pub fn set_security(&mut self, security: TableSecurity) {
58        self.role_owner = security.role_owner;
59        self.acl = security.acl;
60        self.column_acls = security.column_acls;
61    }
62
63    pub fn security_invoker(&self) -> bool {
64        self.options.iter().any(|(name, value)| {
65            name == "security_invoker" && matches!(value.as_str(), "true" | "on" | "yes" | "1")
66        })
67    }
68}
69
70impl StoredView {
71    pub fn rewrite_definition(&self) -> crate::catalog::view::ViewRewriteDefinition {
72        crate::catalog::view::ViewRewriteDefinition {
73            query: self.query.clone(),
74            output_columns: self.output_columns.clone(),
75            options: self.options.clone(),
76            kind: self.kind,
77            materialized_column_types: self.materialized_column_types.clone(),
78        }
79    }
80    pub fn row_schema(
81        &self,
82        routines: &dyn crate::routines::RoutineResolution,
83        catalog: super::analysis::CatalogReadView,
84        resolution: super::resolution::RelationNameResolution,
85    ) -> Result<crate::RowSchema, crate::SQLError> {
86        self.rewrite_definition()
87            .row_schema(routines, catalog, resolution)
88    }
89}
90
91pub mod dependencies;
92
93pub mod restoration;
94
95pub mod references;
96pub mod removal;