uqa_sql/semantics/view_rewrite/
context.rs1use 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}