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.as_ref().unwrap();
180                match &*body {
181                    InsertBody::Select(select, ..) => match select.body.select.column_count() {
182                        ColumnCount::Fixed(n) if n != columns.len() => {
183                            Err(custom_err!("{} values for {} columns", n, columns.len()))
184                        }
185                        _ => Ok(()),
186                    },
187                    InsertBody::DefaultValues => {
188                        Err(custom_err!("0 values for {} columns", columns.len()))
189                    }
190                }
191            }
192            Self::Update(update) => {
193                let Update {
194                    order_by, limit, ..
195                } = &**update;
196                if let Some(_) = order_by {
197                    if limit.is_none() {
198                        return Err(custom_err!("ORDER BY without LIMIT on UPDATE"));
199                    }
200                }
201
202                Ok(())
203            }
204            _ => Ok(()),
205        }
206    }
207}
208
209impl CreateTableBody {
210    /// check for extra rules
211    pub fn check(&self, tbl_name: &QualifiedName) -> Result<(), ParserError> {
212        if let Self::ColumnsAndConstraints {
213            columns,
214            constraints: _,
215            options,
216        } = self
217        {
218            let mut generated_count = 0;
219            for c in columns.values() {
220                if c.col_name == "rowid" {
221                    return Err(custom_err!("cannot use reserved word: ROWID"));
222                }
223                for cs in &c.constraints {
224                    if let ColumnConstraint::Generated { .. } = cs.constraint {
225                        generated_count += 1;
226                    }
227                }
228            }
229            if generated_count == columns.len() {
230                return Err(custom_err!("must have at least one non-generated column"));
231            }
232
233            if options.contains(TableOptions::STRICT) {
234                for c in columns.values() {
235                    match &c.col_type {
236                        Some(Type { name, .. }) => {
237                            // The datatype must be one of following: INT INTEGER REAL TEXT BLOB ANY
238                            if !(name.eq_ignore_ascii_case("INT")
239                                || name.eq_ignore_ascii_case("INTEGER")
240                                || name.eq_ignore_ascii_case("REAL")
241                                || name.eq_ignore_ascii_case("TEXT")
242                                || name.eq_ignore_ascii_case("BLOB")
243                                || name.eq_ignore_ascii_case("ANY"))
244                            {
245                                return Err(custom_err!(
246                                    "unknown datatype for {}.{}: \"{}\"",
247                                    tbl_name,
248                                    c.col_name,
249                                    name
250                                ));
251                            }
252                        }
253                        _ => {
254                            // Every column definition must specify a datatype for that column. The freedom to specify a column without a datatype is removed.
255                            return Err(custom_err!(
256                                "missing datatype for {}.{}",
257                                tbl_name,
258                                c.col_name
259                            ));
260                        }
261                    }
262                }
263            }
264            if options.contains(TableOptions::WITHOUT_ROWID) && !self.has_primary_key() {
265                return Err(custom_err!("PRIMARY KEY missing on table {}", tbl_name,));
266            }
267        }
268        Ok(())
269    }
270
271    /// explicit primary key constraint ?
272    pub fn has_primary_key(&self) -> bool {
273        if let Self::ColumnsAndConstraints {
274            columns,
275            constraints,
276            ..
277        } = self
278        {
279            for col in columns.values() {
280                for c in col {
281                    if let ColumnConstraint::PrimaryKey { .. } = c {
282                        return true;
283                    }
284                }
285            }
286            if let Some(constraints) = constraints {
287                for c in constraints {
288                    if let TableConstraint::PrimaryKey { .. } = c.constraint {
289                        return true;
290                    }
291                }
292            }
293        }
294        false
295    }
296}
297
298impl<'a> IntoIterator for &'a ColumnDefinition {
299    type Item = &'a ColumnConstraint;
300    type IntoIter = std::iter::Map<
301        std::slice::Iter<'a, NamedColumnConstraint>,
302        fn(&'a NamedColumnConstraint) -> &'a ColumnConstraint,
303    >;
304
305    fn into_iter(self) -> Self::IntoIter {
306        self.constraints.iter().map(|nc| &nc.constraint)
307    }
308}
309
310impl Select {
311    /// Like `sqlite3_column_count` but more limited
312    pub fn column_count(&self) -> ColumnCount {
313        self.body.select.column_count()
314    }
315}
316
317impl OneSelect {
318    /// Like `sqlite3_column_count` but more limited
319    pub fn column_count(&self) -> ColumnCount {
320        match self {
321            Self::Select(select) => {
322                let SelectInner { columns, .. } = &**select;
323                column_count(columns)
324            }
325            Self::Values(values) => {
326                assert!(!values.is_empty()); // TODO Validate
327                ColumnCount::Fixed(values[0].len())
328            }
329        }
330    }
331    /// Check all VALUES have the same number of terms
332    pub fn push(values: &mut Vec<Vec<Expr>>, v: Vec<Expr>) -> Result<(), ParserError> {
333        if values[0].len() != v.len() {
334            return Err(custom_err!("all VALUES must have the same number of terms"));
335        }
336        values.push(v);
337        Ok(())
338    }
339}
340
341impl Display for QualifiedName {
342    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
343        self.to_fmt(f)
344    }
345}
346
347impl ResultColumn {
348    fn column_count(&self) -> ColumnCount {
349        match self {
350            Self::Expr(..) => ColumnCount::Fixed(1),
351            _ => ColumnCount::Dynamic,
352        }
353    }
354}
355fn column_count(cols: &[ResultColumn]) -> ColumnCount {
356    assert!(!cols.is_empty());
357    let mut count = ColumnCount::Fixed(0);
358    for col in cols {
359        match col.column_count() {
360            ColumnCount::Fixed(_) => count.incr(),
361            _ => return ColumnCount::Dynamic,
362        }
363    }
364    count
365}