1use crate::core::catalog::Catalog;
2use crate::cow_str;
3use crate::db::context::Context;
4use crate::db::database::{Database, Plugin};
5use crate::error::MyResult;
6use crate::util::convert::{parse_null, parse_type};
7use std::borrow::Cow;
8
9pub struct SQLitePlugin;
10
11impl SQLitePlugin {
12 pub fn new() -> Self {
13 Self { }
14 }
15}
16
17impl Plugin for SQLitePlugin {
18 fn populate_catalog(&self, database: &Database, catalog: &mut Catalog) -> MyResult<()> {
19 fetch_tables(database, catalog)?;
20 fetch_keywords(catalog);
21 fetch_functions(database, catalog)?;
22 Ok(())
23 }
24
25 fn query_context(&self, _database: &Database) -> Context {
26 Context::default()
27 }
28
29 fn get_batch(&self) -> &str {
30 ";"
31 }
32}
33
34const SQLITE_KEYWORDS: &[&str] = &[
36 "ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ALWAYS", "ANALYZE",
37 "AND", "AS", "ASC", "ATTACH", "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN",
38 "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", "COMMIT",
39 "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT", "CURRENT_DATE",
40 "CURRENT_TIME", "CURRENT_TIMESTAMP", "DATABASE", "DEFAULT", "DEFERRABLE",
41 "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DO", "DROP", "EACH",
42 "ELSE", "END", "ESCAPE", "EXCEPT", "EXCLUDE", "EXCLUSIVE", "EXISTS",
43 "EXPLAIN", "FAIL", "FILTER", "FIRST", "FOLLOWING", "FOR", "FOREIGN", "FROM",
44 "FULL", "GENERATED", "GLOB", "GROUP", "GROUPS", "HAVING", "IF", "IGNORE",
45 "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT",
46 "INSTEAD", "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LAST",
47 "LEFT", "LIKE", "LIMIT", "MATCH", "MATERIALIZED", "NATURAL", "NO", "NOT",
48 "NOTHING", "NOTNULL", "NULL", "NULLS", "OF", "OFFSET", "ON", "OR", "ORDER",
49 "OTHERS", "OUTER", "OVER", "PARTITION", "PLAN", "PRAGMA", "PRECEDING",
50 "PRIMARY", "QUERY", "RAISE", "RANGE", "RECURSIVE", "REFERENCES", "REGEXP",
51 "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RETURNING", "RIGHT",
52 "ROLLBACK", "ROW", "ROWS", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP",
53 "TEMPORARY", "THEN", "TIES", "TO", "TRANSACTION", "TRIGGER", "UNBOUNDED",
54 "UNION", "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL",
55 "WHEN", "WHERE", "WINDOW", "WITH", "WITHOUT",
56];
57
58fn fetch_tables(database: &Database, catalog: &mut Catalog) -> MyResult<()> {
59 database.fetch_two("PRAGMA main.table_list", |_, table| {
60 if !table.starts_with("sqlite_") {
61 fetch_columns(database, catalog, table)?;
62 }
63 Ok(())
64 })?;
65 Ok(())
66}
67
68fn fetch_columns(database: &Database, catalog: &mut Catalog, table: Cow<str>) -> MyResult<()> {
69 let query = format!("PRAGMA main.table_info ({})", table);
70 database.fetch_four(&query, |index, column, dtype, null| {
71 let dtype = parse_type(dtype, 0, 0);
72 let null = parse_null(null);
73 let index = index.parse::<usize>().unwrap_or_default() + 1;
74 catalog.insert_column(
75 cow_str!(""),
76 cow_str!(""),
77 table.clone(),
78 column,
79 dtype,
80 null,
81 index,
82 );
83 Ok(())
84 })?;
85 Ok(())
86}
87
88fn fetch_keywords(catalog: &mut Catalog) {
89 for keyword in SQLITE_KEYWORDS {
90 catalog.insert_keyword(Cow::Borrowed(keyword));
91 }
92}
93
94fn fetch_functions(database: &Database, catalog: &mut Catalog) -> MyResult<()> {
95 database.fetch_one("PRAGMA main.function_list", |function| {
96 if function.chars().all(is_word_character) {
97 catalog.insert_function(function);
98 }
99 Ok(())
100 })?;
101 Ok(())
102}
103
104fn is_word_character(c: char) -> bool {
105 c.is_alphanumeric() || c == '_'
106}