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: SetFunctionCatalog {
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 authorization: &'a dyn super::super::view_privileges::ViewPrivilegeCatalog,
53}
54
55pub fn stored_view_schema(
56 services: ViewRewriteContext<'_>,
57 definition: &ViewRewriteDefinition,
58) -> Result<RowSchema, SQLError> {
59 let (catalog, resolution) = services.catalog.restored_view_catalog();
60 definition.row_schema(services.catalog, catalog, resolution)
61}
62
63pub(super) fn analyze_source_plan_schema(
64 services: ViewRewriteContext<'_>,
65 source: &SourcePlan,
66 params: &[SQLParam],
67 scope: &BindingSnapshot,
68 outer: Option<&RowSchema>,
69) -> Result<RowSchema, SQLError> {
70 crate::binding::analyze_source_plan_schema(
71 services.catalog,
72 source,
73 params,
74 &scope.context(),
75 outer,
76 )
77}
78pub(super) fn analyze_query_plan_schema(
79 services: ViewRewriteContext<'_>,
80 query: &QueryPlan,
81 params: &[SQLParam],
82 scope: &BindingSnapshot,
83 outer: Option<&RowSchema>,
84) -> Result<RowSchema, SQLError> {
85 crate::binding::analyze_query_plan_schema(
86 services.catalog,
87 query,
88 params,
89 &scope.context(),
90 outer,
91 )
92}
93pub(super) fn target_is_view(
94 services: ViewRewriteContext<'_>,
95 name: &str,
96) -> Result<bool, SQLError> {
97 Ok(services.catalog.target_view_kind(name)?.is_some())
98}
99
100pub(super) fn relation_suppresses_original_query(
101 services: ViewRewriteContext<'_>,
102 table: &str,
103 event: RuleEvent,
104) -> Result<bool, SQLError> {
105 Ok(services
106 .catalog
107 .rules_for(table, event)?
108 .iter()
109 .any(|rule| rule.definition.instead && rule.definition.condition.is_none()))
110}
111pub(super) fn relation_has_returning_provider(
112 services: ViewRewriteContext<'_>,
113 table: &str,
114 event: RuleEvent,
115) -> Result<bool, SQLError> {
116 Ok(services
117 .catalog
118 .rules_for(table, event)?
119 .iter()
120 .any(|rule| {
121 rule.definition
122 .actions
123 .iter()
124 .any(crate::semantics::rules::statement_has_returning)
125 }))
126}