Skip to main content

nodedb_sql/ddl_ast/parse/database/
dispatch.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Database-DDL dispatch: matches the leading verb tokens and delegates to
4//! the per-operation parser. Keep this file thin — the actual parsing logic
5//! belongs in the sibling modules.
6
7use crate::ddl_ast::statement::NodedbStatement;
8use crate::error::SqlError;
9
10use super::alter::parse_alter_database;
11use super::backup_restore::{parse_backup_database, parse_restore_database};
12use super::clone::parse_clone_database;
13use super::create::parse_create_database;
14use super::drop_db::parse_drop_database;
15use super::mirror::{parse_mirror_database, parse_show_database_mirror_status};
16use super::move_tenant::parse_move_tenant;
17use super::show_extras::{parse_show_database_lineage, parse_show_database_quota_or_usage};
18use super::use_db::parse_use_database;
19
20/// Try to parse a database-level DDL statement.
21///
22/// Returns `None` for SQL that does not match any database-DDL prefix.
23/// Returns `Some(Err(...))` for structurally valid database DDL that contains a
24/// parse error (e.g. missing required name token).
25pub fn try_parse(
26    _upper: &str,
27    parts: &[&str],
28    original: &str,
29) -> Option<Result<NodedbStatement, SqlError>> {
30    let first = parts.first().copied().unwrap_or("");
31    let second = parts.get(1).copied().unwrap_or("").to_uppercase();
32
33    match first.to_uppercase().as_str() {
34        "CREATE" if second == "DATABASE" => Some(parse_create_database(parts, original)),
35        "DROP" if second == "DATABASE" => Some(parse_drop_database(parts)),
36        "ALTER" if second == "DATABASE" => Some(parse_alter_database(parts, original)),
37        "USE" if second == "DATABASE" => Some(parse_use_database(parts)),
38        "CLONE" if second == "DATABASE" => Some(parse_clone_database(parts, original)),
39        "MIRROR" if second == "DATABASE" => Some(parse_mirror_database(parts)),
40        "MOVE" if second == "TENANT" => Some(parse_move_tenant(parts)),
41        "BACKUP" if second == "DATABASE" => Some(parse_backup_database(parts)),
42        "RESTORE" if second == "DATABASE" => Some(parse_restore_database(parts)),
43        "SHOW" if second == "DATABASES" && parts.len() == 2 => {
44            Some(Ok(NodedbStatement::ShowDatabases))
45        }
46        // SHOW DATABASE QUOTA FOR <name>
47        "SHOW"
48            if second == "DATABASE"
49                && parts.get(2).map(|w| w.to_uppercase()).as_deref() == Some("QUOTA") =>
50        {
51            Some(parse_show_database_quota_or_usage(parts, false))
52        }
53        // SHOW DATABASE USAGE FOR <name>
54        "SHOW"
55            if second == "DATABASE"
56                && parts.get(2).map(|w| w.to_uppercase()).as_deref() == Some("USAGE") =>
57        {
58            Some(parse_show_database_quota_or_usage(parts, true))
59        }
60        // SHOW DATABASE LINEAGE FOR <name>
61        "SHOW"
62            if second == "DATABASE"
63                && parts.get(2).map(|w| w.to_uppercase()).as_deref() == Some("LINEAGE") =>
64        {
65            Some(parse_show_database_lineage(parts))
66        }
67        // SHOW DATABASE MIRROR STATUS [FOR <name>]
68        "SHOW"
69            if second == "DATABASE"
70                && parts.get(2).map(|w| w.to_uppercase()).as_deref() == Some("MIRROR")
71                && parts.get(3).map(|w| w.to_uppercase()).as_deref() == Some("STATUS") =>
72        {
73            Some(parse_show_database_mirror_status(parts))
74        }
75        _ => None,
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn parse_show_databases() {
85        let sql = "SHOW DATABASES";
86        let upper = sql.to_uppercase();
87        let parts: Vec<&str> = sql.split_whitespace().collect();
88        let stmt = try_parse(&upper, &parts, sql).unwrap().unwrap();
89        assert_eq!(stmt, NodedbStatement::ShowDatabases);
90    }
91}