uqa_sql/schema/
view_creation.rs1use crate::{ast::RelationPersistence, RowSchema, SQLError};
9use uqa_core::RelationIdentity;
10
11pub trait ViewCreationNamespace {
12 fn relation_target(
14 &self,
15 name: &str,
16 persistence: RelationPersistence,
17 ) -> Result<(String, RelationPersistence), SQLError>;
18}
19
20pub fn view_becomes_temporary(
22 persistence: RelationPersistence,
23 uses_temporary_relation: bool,
24) -> bool {
25 uses_temporary_relation && persistence == RelationPersistence::Permanent
26}
27
28pub fn temporary_view_notice(name: &str) -> Result<crate::SQLNotice, SQLError> {
30 let (_, relation) = RelationIdentity::parse_reference(name).map_err(SQLError::Unsupported)?;
31 Ok(crate::SQLNotice::notice(format!(
32 "view \"{relation}\" will be a temporary view"
33 )))
34}
35
36pub fn view_creation_target(
38 namespace: &dyn ViewCreationNamespace,
39 name: &str,
40 persistence: RelationPersistence,
41 uses_temporary_relation: bool,
42) -> Result<(String, RelationPersistence), SQLError> {
43 let persistence = if view_becomes_temporary(persistence, uses_temporary_relation) {
44 RelationPersistence::Temporary
45 } else {
46 persistence
47 };
48 namespace.relation_target(name, persistence)
49}
50
51pub fn replacement_is_view(
53 name: &str,
54 kind: Option<&str>,
55 or_replace: bool,
56) -> Result<bool, SQLError> {
57 let local = || {
58 uqa_core::RelationIdentity::from_legacy_name(name)
59 .map_or_else(|_| name.to_string(), |relation| relation.name)
60 };
61 match kind {
62 Some(_) if !or_replace => Err(SQLError::Routine {
63 sqlstate: "42P07".into(),
64 message: format!("relation \"{}\" already exists", local()),
65 }),
66 Some("view") => Ok(true),
67 Some(_) => Err(SQLError::Routine {
68 sqlstate: "42809".into(),
69 message: format!("\"{}\" is not a view", local()),
70 }),
71 None => Ok(false),
72 }
73}
74
75pub fn validate_replacement_schema(old: &RowSchema, new: &RowSchema) -> Result<(), SQLError> {
76 if new.len() < old.len() {
77 return Err(SQLError::Routine {
78 sqlstate: "42P16".into(),
79 message: "cannot drop columns from view".into(),
80 });
81 }
82 for position in 0..old.len() {
83 let old_name = old
84 .public_name(position)
85 .unwrap_or(&old.columns()[position]);
86 let new_name = new
87 .public_name(position)
88 .unwrap_or(&new.columns()[position]);
89 if old_name != new_name {
90 return Err(SQLError::Routine {
91 sqlstate: "42P16".into(),
92 message: format!(
93 "cannot change name of view column \"{old_name}\" to \"{new_name}\""
94 ),
95 });
96 }
97 if old.column_type(position) != new.column_type(position) {
98 return Err(SQLError::Routine {
99 sqlstate: "42P16".into(),
100 message: format!("cannot change data type of view column \"{old_name}\""),
101 });
102 }
103 }
104 Ok(())
105}
106
107#[cfg(test)]
108mod tests;