Skip to main content

uqa_sql/semantics/view_rewrite/
context.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Catalog and authorization inputs for automatic view analysis and DML rewriting.
8
9use crate::{
10    ast::{ColumnDef, RuleEvent, TriggerEvent, TriggerTiming},
11    binding::snapshot::BindingSnapshot,
12    catalog::{
13        analysis::CatalogReadView,
14        events::StoredRule,
15        resolution::RelationNameResolution,
16        view::{StoredViewKind, ViewRewriteDefinition},
17    },
18    plan::{QueryPlan, SourcePlan},
19    semantics::sets::SetFunctionCatalog,
20    RowSchema, SQLError, SQLParam,
21};
22use std::collections::BTreeSet;
23
24pub trait ViewRewriteCatalog {
25    fn view_definition(&self, name: &str) -> Result<Option<ViewRewriteDefinition>, SQLError>;
26    fn try_resolve_view_name(&self, name: &str) -> Result<Option<String>, String>;
27    fn try_describe_table(&self, name: &str) -> Result<Option<Vec<ColumnDef>>, String>;
28    fn try_table_columns(&self, name: &str) -> Result<Vec<String>, String>;
29    fn rules_for(&self, name: &str, event: RuleEvent) -> Result<Vec<StoredRule>, SQLError>;
30    fn rule_definitions_for(
31        &self,
32        name: &str,
33        event: RuleEvent,
34    ) -> Result<Vec<StoredRule>, SQLError>;
35    fn has_trigger_definition(
36        &self,
37        name: &str,
38        timing: TriggerTiming,
39        event: TriggerEvent,
40        row: bool,
41    ) -> Result<bool, SQLError>;
42    fn rule_new_row_columns(&self, rule: &StoredRule)
43        -> Result<Option<BTreeSet<String>>, SQLError>;
44    fn target_view_kind(&self, name: &str) -> Result<Option<StoredViewKind>, SQLError>;
45    fn binding_scope(&self) -> Result<BindingSnapshot, SQLError>;
46    fn restored_view_catalog(&self) -> (CatalogReadView, RelationNameResolution);
47}
48
49#[derive(Clone, Copy)]
50pub struct ViewRewriteContext<'a> {
51    pub catalog: &'a dyn ViewRewriteCatalog,
52    pub routines: &'a dyn SetFunctionCatalog,
53    pub authorization: &'a dyn super::super::view_privileges::ViewPrivilegeCatalog,
54}
55
56pub fn stored_view_schema(
57    services: ViewRewriteContext<'_>,
58    definition: &ViewRewriteDefinition,
59) -> Result<RowSchema, SQLError> {
60    let (catalog, resolution) = services.catalog.restored_view_catalog();
61    definition.row_schema(services.routines, catalog, resolution)
62}
63
64pub(super) fn analyze_source_plan_schema(
65    services: ViewRewriteContext<'_>,
66    source: &SourcePlan,
67    params: &[SQLParam],
68    scope: &BindingSnapshot,
69    outer: Option<&RowSchema>,
70) -> Result<RowSchema, SQLError> {
71    crate::binding::analyze_source_plan_schema(
72        services.routines,
73        source,
74        params,
75        &scope.context(),
76        outer,
77    )
78}
79pub(super) fn analyze_query_plan_schema(
80    services: ViewRewriteContext<'_>,
81    query: &QueryPlan,
82    params: &[SQLParam],
83    scope: &BindingSnapshot,
84    outer: Option<&RowSchema>,
85) -> Result<RowSchema, SQLError> {
86    crate::binding::analyze_query_plan_schema(
87        services.routines,
88        query,
89        params,
90        &scope.context(),
91        outer,
92    )
93}
94pub(super) fn target_is_view(
95    services: ViewRewriteContext<'_>,
96    name: &str,
97) -> Result<bool, SQLError> {
98    Ok(services.catalog.target_view_kind(name)?.is_some())
99}
100
101pub(super) fn relation_suppresses_original_query(
102    services: ViewRewriteContext<'_>,
103    table: &str,
104    event: RuleEvent,
105) -> Result<bool, SQLError> {
106    Ok(services
107        .catalog
108        .rules_for(table, event)?
109        .iter()
110        .any(|rule| rule.definition.instead && rule.definition.condition.is_none()))
111}
112pub(super) fn relation_has_returning_provider(
113    services: ViewRewriteContext<'_>,
114    table: &str,
115    event: RuleEvent,
116) -> Result<bool, SQLError> {
117    Ok(services
118        .catalog
119        .rules_for(table, event)?
120        .iter()
121        .any(|rule| {
122            rule.definition
123                .actions
124                .iter()
125                .any(crate::semantics::rules::statement_has_returning)
126        }))
127}