Skip to main content

limbo_sqlite3_parser/parser/ast/
check.rs

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