Skip to main content

nodedb_sql/planner/index_ddl/
drop.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Plan a `DROP INDEX` statement parsed by sqlparser.
4
5use sqlparser::ast;
6
7use crate::SqlPlan;
8use crate::error::{Result, SqlError};
9use crate::parser::normalize::normalize_object_name_checked;
10
11/// Plan a `DROP INDEX [IF EXISTS] name [ON collection]` statement.
12///
13/// A missing or schema-qualified index name is a hard error — silently
14/// defaulting to an empty string would produce cryptic "index not found"
15/// failures downstream.
16pub fn plan_drop_index(stmt: &ast::Statement) -> Result<SqlPlan> {
17    let ast::Statement::Drop {
18        object_type: ast::ObjectType::Index,
19        names,
20        if_exists,
21        table,
22        ..
23    } = stmt
24    else {
25        return Err(SqlError::Parse {
26            detail: "DROP INDEX: unexpected statement shape".into(),
27        });
28    };
29
30    let name = names.first().ok_or_else(|| SqlError::Parse {
31        detail: "DROP INDEX: an index name is required".into(),
32    })?;
33    let index_name = normalize_object_name_checked(name)?;
34    if index_name.is_empty() {
35        return Err(SqlError::Parse {
36            detail: "DROP INDEX: empty index name".into(),
37        });
38    }
39
40    let collection = match table.as_ref() {
41        Some(t) => Some(normalize_object_name_checked(t)?),
42        None => None,
43    };
44
45    Ok(SqlPlan::DropIndex {
46        index_name,
47        collection,
48        if_exists: *if_exists,
49    })
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use crate::parser::statement::parse_sql;
56
57    fn plan(sql: &str) -> Result<SqlPlan> {
58        let stmts = parse_sql(sql).expect("parse");
59        plan_drop_index(&stmts[0])
60    }
61
62    #[test]
63    fn basic_drop() {
64        let SqlPlan::DropIndex {
65            index_name,
66            collection,
67            if_exists,
68        } = plan("DROP INDEX idx_users_email").unwrap()
69        else {
70            panic!("expected DropIndex");
71        };
72        assert_eq!(index_name, "idx_users_email");
73        assert!(collection.is_none());
74        assert!(!if_exists);
75    }
76
77    #[test]
78    fn if_exists_honored() {
79        let SqlPlan::DropIndex { if_exists, .. } = plan("DROP INDEX IF EXISTS idx").unwrap() else {
80            panic!("expected DropIndex");
81        };
82        assert!(if_exists);
83    }
84
85    #[test]
86    fn schema_qualified_name_rejected() {
87        let err = plan("DROP INDEX public.idx").unwrap_err();
88        assert!(matches!(err, SqlError::Unsupported { .. }), "{err:?}");
89    }
90}