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::BoundTableSecurity;
8use std::ops::{Deref, DerefMut};
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)]
12pub struct StoredView {
13    /// Security is loaded independently from the durable catalog row.
14    #[serde(skip)]
15    pub security: BoundTableSecurity,
16    #[serde(flatten)]
17    pub definition: StoredViewDefinition,
18}
19
20/// Query-definition JSON carries no authorization state. Restoration supplies validated security before publishing a view.
21#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
22pub struct StoredViewDefinition {
23    /// Stable logical relation identity. Renames and replacement preserve it; a zero value marks a legacy catalog row upgraded during initial open.
24    #[serde(default)]
25    pub object_id: [u8; 16],
26    pub query: crate::plan::QueryPlan,
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub output_columns: Option<Vec<String>>,
29    #[serde(default)]
30    pub persistence: crate::ast::RelationPersistence,
31    #[serde(default, skip_serializing_if = "Vec::is_empty")]
32    pub options: Vec<(String, String)>,
33    #[serde(default)]
34    pub kind: StoredViewKind,
35    #[serde(default, skip_serializing_if = "Vec::is_empty")]
36    pub materialized_rows: Vec<crate::ResultRow>,
37    #[serde(default, skip_serializing_if = "Vec::is_empty")]
38    pub materialized_column_types: Vec<Option<crate::ast::ColumnType>>,
39    #[serde(default = "default_view_populated")]
40    pub populated: bool,
41}
42
43use super::view::StoredViewKind;
44
45const fn default_view_populated() -> bool {
46    true
47}
48
49impl Deref for StoredView {
50    type Target = StoredViewDefinition;
51    fn deref(&self) -> &Self::Target {
52        &self.definition
53    }
54}
55
56impl DerefMut for StoredView {
57    fn deref_mut(&mut self) -> &mut Self::Target {
58        &mut self.definition
59    }
60}
61
62impl StoredView {
63    pub fn security(&self) -> BoundTableSecurity {
64        self.security.clone()
65    }
66
67    pub fn set_security(&mut self, security: BoundTableSecurity) {
68        self.security = security;
69    }
70
71    pub fn security_invoker(&self) -> bool {
72        self.options.iter().any(|(name, value)| {
73            name == "security_invoker" && matches!(value.as_str(), "true" | "on" | "yes" | "1")
74        })
75    }
76}
77
78impl StoredView {
79    pub fn rewrite_definition(&self) -> crate::catalog::view::ViewRewriteDefinition {
80        crate::catalog::view::ViewRewriteDefinition {
81            query: self.query.clone(),
82            output_columns: self.output_columns.clone(),
83            options: self.options.clone(),
84            kind: self.kind,
85            materialized_column_types: self.materialized_column_types.clone(),
86        }
87    }
88    pub fn row_schema(
89        &self,
90        routines: &dyn crate::routines::RoutineResolution,
91        catalog: super::analysis::CatalogReadView,
92        resolution: super::resolution::RelationNameResolution,
93    ) -> Result<crate::RowSchema, crate::SQLError> {
94        self.rewrite_definition()
95            .row_schema(routines, catalog, resolution)
96    }
97}
98
99pub mod dependencies;
100
101pub mod restoration;
102
103pub mod references;
104pub mod removal;