rupg_analyze/ddl/
schema_elements.rs1use rupg_common::{Error, Result, SqlState};
4use rupg_sql::nodes::{
5 AlterTableCmd, AlterTableStmt, AlterTableType, ConstrType, Constraint, CreateStmt, Node,
6 ObjectType, RangeVar,
7};
8use rupg_sql::{Lexer, character, token};
9
10use super::table::constraint_attrs;
11use crate::coerce::AtOpt;
12use crate::typename::place;
13
14#[derive(Debug)]
16pub struct SchemaElements {
17 pub owner: u32,
19 pub schema: String,
21 pub elements: Vec<(Node, String)>,
23}
24
25pub(super) fn schema_elements(
27 elements: &[Node],
28 schema: &str,
29 text: &str,
30) -> Result<Vec<(Node, String)>> {
31 let texts = element_texts(text, elements.len());
32 let mut groups: [Vec<(Node, String)>; 7] = Default::default();
33 for (element, text) in elements.iter().zip(texts) {
34 let (group, relation) = match element {
35 Node::CreateSeqStmt(stmt) => (0, stmt.sequence.as_deref()),
36 Node::CreateStmt(stmt) => (1, stmt.relation.as_deref()),
37 Node::ViewStmt(stmt) => (2, stmt.view.as_deref()),
38 Node::IndexStmt(stmt) => (3, stmt.relation.as_deref()),
39 Node::CreateTrigStmt(stmt) => (4, stmt.relation.as_deref()),
40 Node::GrantStmt(_) => (5, None),
41 _ => return Err(Error::internal("unrecognized node type in CREATE SCHEMA")),
42 };
43 if let Some(relation) = relation {
44 check_schema_name(relation, schema)?;
45 }
46 let element = match element {
47 Node::CreateStmt(stmt) => {
48 let mut keys = Vec::new();
49 let table = without_foreign_keys(stmt, &mut keys)?;
50 groups[6].extend(keys.into_iter().map(|key| (key, String::new())));
51 Node::CreateStmt(Box::new(table))
52 }
53 element => element.clone(),
54 };
55 groups[group].push((element, text));
56 }
57 Ok(groups.into_iter().flatten().collect())
58}
59
60fn check_schema_name(relation: &RangeVar, schema: &str) -> Result<()> {
62 let at = place(relation.location);
63 if let Some(name) = relation.schemaname.as_deref()
64 && name != schema
65 {
66 return Err(Error::new(
67 SqlState::INVALID_SCHEMA_DEFINITION,
68 format!(
69 "CREATE specifies a schema ({name}) different from the one being created ({schema})"
70 ),
71 )
72 .at_opt(at));
73 }
74 if relation.relpersistence == b't' {
75 return Err(Error::new(
76 SqlState::INVALID_TABLE_DEFINITION,
77 "cannot create temporary relation in non-temporary schema",
78 )
79 .at_opt(at));
80 }
81 Ok(())
82}
83
84fn without_foreign_keys(stmt: &CreateStmt, keys: &mut Vec<Node>) -> Result<CreateStmt> {
86 let add = |con: Constraint| {
87 Node::AlterTableStmt(Box::new(AlterTableStmt {
88 relation: stmt.relation.clone(),
89 cmds: vec![Some(Node::AlterTableCmd(Box::new(AlterTableCmd {
90 subtype: AlterTableType::AT_AddConstraint,
91 def: Some(Node::Constraint(Box::new(con))),
92 ..AlterTableCmd::default()
93 })))],
94 objtype: ObjectType::OBJECT_TABLE,
95 missing_ok: false,
96 }))
97 };
98 let mut table = stmt.clone();
99 table.tableElts.clear();
100 for element in &stmt.tableElts {
101 match element {
102 Some(Node::Constraint(con)) if con.contype == ConstrType::CONSTR_FOREIGN => {
103 keys.push(add((**con).clone()));
104 }
105 Some(Node::ColumnDef(def)) => {
106 let mut cons: Vec<Constraint> = def
107 .constraints
108 .iter()
109 .flatten()
110 .filter_map(|n| match n {
111 Node::Constraint(c) => Some((**c).clone()),
112 _ => None,
113 })
114 .collect();
115 constraint_attrs(&mut cons)?;
116 let mut after_key = false;
118 let mut kept = Vec::new();
119 for mut con in cons {
120 match con.contype {
121 ConstrType::CONSTR_FOREIGN => {
122 let name = def.colname.as_deref().unwrap_or_default();
123 con.fk_attrs = vec![Some(Node::String(name.into()))];
124 keys.push(add(con));
125 after_key = true;
126 }
127 ConstrType::CONSTR_ATTR_DEFERRABLE
128 | ConstrType::CONSTR_ATTR_NOT_DEFERRABLE
129 | ConstrType::CONSTR_ATTR_DEFERRED
130 | ConstrType::CONSTR_ATTR_IMMEDIATE
131 | ConstrType::CONSTR_ATTR_ENFORCED
132 | ConstrType::CONSTR_ATTR_NOT_ENFORCED => {
133 if !after_key {
134 kept.push(con);
135 }
136 }
137 _ => {
138 after_key = false;
139 kept.push(con);
140 }
141 }
142 }
143 let mut def = (**def).clone();
144 def.constraints =
145 kept.into_iter().map(|con| Some(Node::Constraint(Box::new(con)))).collect();
146 table.tableElts.push(Some(Node::ColumnDef(Box::new(def))));
147 }
148 element => table.tableElts.push(element.clone()),
149 }
150 }
151 Ok(table)
152}
153
154fn element_texts(text: &str, count: usize) -> Vec<String> {
156 let (open, close, comma) = (character(b'('), character(b')'), character(b','));
157 let mut lexer = Lexer::new(text);
158 let mut starts = Vec::new();
159 let mut depth = 0usize;
160 let mut previous = None;
161 while let Ok(word) = lexer.next_token() {
162 let kind = Some(word.kind);
163 if word.kind == 0 {
164 break;
165 } else if kind == open {
166 depth += 1;
167 } else if kind == close {
168 depth = depth.saturating_sub(1);
169 } else if depth == 0 && previous.is_some() {
170 let create =
171 word.kind == token::CREATE && previous != Some(token::GRANT) && previous != comma;
172 let grant = word.kind == token::GRANT && previous != Some(token::WITH);
173 if create || grant {
174 starts.push(word.start);
175 }
176 }
177 previous = kind;
178 }
179 if starts.len() != count {
180 return vec![text.to_string(); count];
181 }
182 let ends = starts.iter().skip(1).copied().chain([text.len()]);
183 starts.iter().zip(ends).map(|(&start, end)| text[start..end].trim_end().to_string()).collect()
184}