limbo_sqlite3_parser/parser/ast/
check.rs1use crate::ast::fmt::ToTokens;
3use crate::ast::macros::TableOptions;
4use crate::ast::*;
5use crate::custom_err;
6use crate::parser::ParserError;
7use std::fmt::{Display, Formatter};
8
9impl Cmd {
10 pub fn stmt(&self) -> &Stmt {
12 match self {
13 Self::Explain(stmt) => stmt,
14 Self::ExplainQueryPlan(stmt) => stmt,
15 Self::Stmt(stmt) => stmt,
16 }
17 }
18 pub fn column_count(&self) -> ColumnCount {
20 match self {
21 Self::Explain(_) => ColumnCount::Fixed(8),
22 Self::ExplainQueryPlan(_) => ColumnCount::Fixed(4),
23 Self::Stmt(stmt) => stmt.column_count(),
24 }
25 }
26 pub fn is_explain(&self) -> bool {
28 matches!(self, Self::Explain(_) | Self::ExplainQueryPlan(_))
29 }
30 pub fn readonly(&self) -> bool {
32 self.stmt().readonly()
33 }
34 pub fn check(&self) -> Result<(), ParserError> {
36 self.stmt().check()
37 }
38}
39
40pub enum ColumnCount {
42 Dynamic,
44 Fixed(usize),
46 None,
48}
49
50impl ColumnCount {
51 fn incr(&mut self) {
52 if let Self::Fixed(n) = self {
53 *n += 1;
54 }
55 }
56}
57
58impl Stmt {
59 pub fn column_count(&self) -> ColumnCount {
61 match self {
62 Self::Delete(delete) => {
63 let Delete { returning, .. } = &**delete;
64 match returning {
65 Some(returning) => column_count(returning),
66 None => ColumnCount::None,
67 }
68 }
69 Self::Insert(insert) => {
70 let Insert { returning, .. } = &**insert;
71 match returning {
72 Some(returning) => column_count(returning),
73 None => ColumnCount::None,
74 }
75 }
76 Self::Pragma(..) => ColumnCount::Dynamic,
77 Self::Select(s) => s.column_count(),
78 Self::Update(update) => {
79 let Update { returning, .. } = &**update;
80 match returning {
81 Some(returning) => column_count(returning),
82 None => ColumnCount::None,
83 }
84 }
85 _ => ColumnCount::None,
86 }
87 }
88
89 pub fn readonly(&self) -> bool {
91 match self {
92 Self::Attach { .. } => true,
93 Self::Begin(..) => true,
94 Self::Commit(..) => true,
95 Self::Detach(..) => true,
96 Self::Pragma(..) => true, Self::Reindex { .. } => true,
98 Self::Release(..) => true,
99 Self::Rollback { .. } => true,
100 Self::Savepoint(..) => true,
101 Self::Select(..) => true,
102 _ => false,
103 }
104 }
105
106 pub fn check(&self) -> Result<(), ParserError> {
108 match self {
109 Self::AlterTable(alter_table) => {
110 let (_, body) = &**alter_table;
111 match body {
112 AlterTableBody::AddColumn(cd) => {
113 for c in cd {
114 if let ColumnConstraint::PrimaryKey { .. } = c {
115 return Err(custom_err!("Cannot add a PRIMARY KEY column"));
116 }
117 if let ColumnConstraint::Unique(..) = c {
118 return Err(custom_err!("Cannot add a UNIQUE column"));
119 }
120 }
121 }
122 _ => {}
123 }
124 Ok(())
125 }
126 Self::CreateTable {
127 temporary,
128 tbl_name,
129 body,
130 ..
131 } => {
132 if *temporary {
133 if let Some(ref db_name) = tbl_name.db_name {
134 if db_name != "TEMP" {
135 return Err(custom_err!("temporary table name must be unqualified"));
136 }
137 }
138 }
139 body.check(tbl_name)
140 }
141 Self::CreateView {
142 view_name,
143 columns: Some(columns),
144 select,
145 ..
146 } => {
147 for (i, c) in columns.iter().enumerate() {
149 for o in &columns[i + 1..] {
150 if c.col_name == o.col_name {
151 return Err(custom_err!("duplicate column name: {}", c.col_name,));
152 }
153 }
154 }
155 match select.column_count() {
157 ColumnCount::Fixed(n) if n != columns.len() => Err(custom_err!(
158 "expected {} columns for {} but got {}",
159 columns.len(),
160 view_name,
161 n
162 )),
163 _ => Ok(()),
164 }
165 }
166 Self::Delete(delete) => {
167 let Delete {
168 order_by, limit, ..
169 } = &**delete;
170 if let Some(_) = order_by {
171 if limit.is_none() {
172 return Err(custom_err!("ORDER BY without LIMIT on DELETE"));
173 }
174 }
175 Ok(())
176 }
177 Self::Insert(insert) => {
178 let Insert { columns, body, .. } = &**insert;
179 if columns.is_none() {
180 return Ok(());
181 }
182 let columns = columns
183 .as_ref()
184 .expect("columns is Some after is_none() guard above");
185 match &*body {
186 InsertBody::Select(select, ..) => match select.body.select.column_count() {
187 ColumnCount::Fixed(n) if n != columns.len() => {
188 Err(custom_err!("{} values for {} columns", n, columns.len()))
189 }
190 _ => Ok(()),
191 },
192 InsertBody::DefaultValues => {
193 Err(custom_err!("0 values for {} columns", columns.len()))
194 }
195 }
196 }
197 Self::Update(update) => {
198 let Update {
199 order_by, limit, ..
200 } = &**update;
201 if let Some(_) = order_by {
202 if limit.is_none() {
203 return Err(custom_err!("ORDER BY without LIMIT on UPDATE"));
204 }
205 }
206
207 Ok(())
208 }
209 _ => Ok(()),
210 }
211 }
212}
213
214impl CreateTableBody {
215 pub fn check(&self, tbl_name: &QualifiedName) -> Result<(), ParserError> {
217 if let Self::ColumnsAndConstraints {
218 columns,
219 constraints: _,
220 options,
221 } = self
222 {
223 let mut generated_count = 0;
224 for c in columns.values() {
225 if c.col_name == "rowid" {
226 return Err(custom_err!("cannot use reserved word: ROWID"));
227 }
228 for cs in &c.constraints {
229 if let ColumnConstraint::Generated { .. } = cs.constraint {
230 generated_count += 1;
231 }
232 }
233 }
234 if generated_count == columns.len() {
235 return Err(custom_err!("must have at least one non-generated column"));
236 }
237
238 if options.contains(TableOptions::STRICT) {
239 for c in columns.values() {
240 match &c.col_type {
241 Some(Type { name, .. }) => {
242 if !(name.eq_ignore_ascii_case("INT")
244 || name.eq_ignore_ascii_case("INTEGER")
245 || name.eq_ignore_ascii_case("REAL")
246 || name.eq_ignore_ascii_case("TEXT")
247 || name.eq_ignore_ascii_case("BLOB")
248 || name.eq_ignore_ascii_case("ANY"))
249 {
250 return Err(custom_err!(
251 "unknown datatype for {}.{}: \"{}\"",
252 tbl_name,
253 c.col_name,
254 name
255 ));
256 }
257 }
258 _ => {
259 return Err(custom_err!(
261 "missing datatype for {}.{}",
262 tbl_name,
263 c.col_name
264 ));
265 }
266 }
267 }
268 }
269 if options.contains(TableOptions::WITHOUT_ROWID) && !self.has_primary_key() {
270 return Err(custom_err!("PRIMARY KEY missing on table {}", tbl_name,));
271 }
272 }
273 Ok(())
274 }
275
276 pub fn has_primary_key(&self) -> bool {
278 if let Self::ColumnsAndConstraints {
279 columns,
280 constraints,
281 ..
282 } = self
283 {
284 for col in columns.values() {
285 for c in col {
286 if let ColumnConstraint::PrimaryKey { .. } = c {
287 return true;
288 }
289 }
290 }
291 if let Some(constraints) = constraints {
292 for c in constraints {
293 if let TableConstraint::PrimaryKey { .. } = c.constraint {
294 return true;
295 }
296 }
297 }
298 }
299 false
300 }
301}
302
303impl<'a> IntoIterator for &'a ColumnDefinition {
304 type Item = &'a ColumnConstraint;
305 type IntoIter = std::iter::Map<
306 std::slice::Iter<'a, NamedColumnConstraint>,
307 fn(&'a NamedColumnConstraint) -> &'a ColumnConstraint,
308 >;
309
310 fn into_iter(self) -> Self::IntoIter {
311 self.constraints.iter().map(|nc| &nc.constraint)
312 }
313}
314
315impl Select {
316 pub fn column_count(&self) -> ColumnCount {
318 self.body.select.column_count()
319 }
320}
321
322impl OneSelect {
323 pub fn column_count(&self) -> ColumnCount {
325 match self {
326 Self::Select(select) => {
327 let SelectInner { columns, .. } = &**select;
328 column_count(columns)
329 }
330 Self::Values(values) => {
331 assert!(!values.is_empty()); ColumnCount::Fixed(values[0].len())
333 }
334 }
335 }
336 pub fn push(values: &mut Vec<Vec<Expr>>, v: Vec<Expr>) -> Result<(), ParserError> {
338 if values[0].len() != v.len() {
339 return Err(custom_err!("all VALUES must have the same number of terms"));
340 }
341 values.push(v);
342 Ok(())
343 }
344}
345
346impl Display for QualifiedName {
347 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
348 self.to_fmt(f)
349 }
350}
351
352impl ResultColumn {
353 fn column_count(&self) -> ColumnCount {
354 match self {
355 Self::Expr(..) => ColumnCount::Fixed(1),
356 _ => ColumnCount::Dynamic,
357 }
358 }
359}
360fn column_count(cols: &[ResultColumn]) -> ColumnCount {
361 assert!(!cols.is_empty());
362 let mut count = ColumnCount::Fixed(0);
363 for col in cols {
364 match col.column_count() {
365 ColumnCount::Fixed(_) => count.incr(),
366 _ => return ColumnCount::Dynamic,
367 }
368 }
369 count
370}