zql_cli/db/plugin/
mysql.rs1use 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 itertools::Itertools;
8use std::borrow::Cow;
9
10pub struct MySQLPlugin;
11
12impl MySQLPlugin {
13 pub fn new() -> Self {
14 Self { }
15 }
16}
17
18impl Plugin for MySQLPlugin {
19 fn populate_catalog(&self, database: &Database, catalog: &mut Catalog) -> MyResult<()> {
20 fetch_databases(database, catalog)?;
21 fetch_columns(database, catalog)?;
22 fetch_procedures(database, catalog)?;
23 fetch_keywords(database, catalog)?;
24 fetch_functions(catalog);
25 Ok(())
26 }
27
28 fn query_context(&self, database: &Database) -> Context {
29 Context::new(Some(fetch_context(database)), None)
30 }
31
32 fn get_batch(&self) -> &str {
33 ";"
34 }
35}
36
37const MYSQL_FUNCTIONS: &[&str] = &[
39 "AVG", "BIT_AND", "BIT_OR", "BIT_XOR", "COUNT", "GROUP_CONCAT",
40 "JSON_ARRAYAGG", "JSON_OBJECTAGG", "MAX", "MIN", "STD", "STDDEV",
41 "STDDEV_POP", "STDDEV_SAMP", "SUM", "VARIANCE", "VAR_POP", "VAR_SAMP",
42];
43const MYSQL_COLUMNS: &str = "\
44SELECT table_schema, table_name, column_name, ordinal_position, is_nullable,
45data_type, character_maximum_length, numeric_precision, numeric_scale
46FROM information_schema.columns";
47const MYSQL_ROUTINES: &str = "\
48SELECT routine_schema, routine_name
49FROM information_schema.routines";
50const MYSQL_KEYWORDS: &str = "\
51SELECT word
52FROM information_schema.keywords";
53
54fn fetch_databases(database: &Database, catalog: &mut Catalog) -> MyResult<()> {
55 database.fetch_one("SHOW DATABASES", |database| {
56 catalog.insert_database(database, cow_str!(""));
57 Ok(())
58 })?;
59 Ok(())
60}
61
62fn fetch_columns(database: &Database, catalog: &mut Catalog) -> MyResult<()> {
63 database.fetch_records(MYSQL_COLUMNS, |record| {
64 if let Some((database, table, column, index, null, dtype, dsize, nsize, nprec)) = record.into_iter().next_tuple() {
65 let dsize = nsize.parse().unwrap_or_else(|_| dsize.parse().unwrap_or_default());
66 let dprec = nprec.parse().unwrap_or_default();
67 let dtype = parse_type(dtype, dsize, dprec);
68 let null = parse_null(null);
69 let index = index.parse().unwrap_or_default();
70 catalog.insert_column(
71 database,
72 cow_str!(""),
73 table,
74 column,
75 dtype,
76 null,
77 index,
78 );
79 }
80 Ok(())
81 })?;
82 Ok(())
83}
84
85fn fetch_procedures(database: &Database, catalog: &mut Catalog) -> MyResult<()> {
86 database.fetch_two(MYSQL_ROUTINES, |database, routine| {
87 catalog.insert_procedure(database, cow_str!(""), routine);
88 Ok(())
89 })?;
90 Ok(())
91}
92
93fn fetch_keywords(database: &Database, catalog: &mut Catalog) -> MyResult<()> {
94 database.fetch_one(MYSQL_KEYWORDS, |keyword| {
95 catalog.insert_keyword(keyword);
96 Ok(())
97 })?;
98 Ok(())
99}
100
101fn fetch_functions(catalog: &mut Catalog) {
102 for function in MYSQL_FUNCTIONS {
103 catalog.insert_function(Cow::Borrowed(function));
104 }
105}
106
107fn fetch_context(database: &Database) -> String {
108 let mut name = String::new();
109 let _ = database.fetch_one("SELECT DATABASE()", |value| {
110 name = value.to_string();
111 Ok(())
112 });
113 name
114}