risingwave_frontend/handler/
drop_database.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use pgwire::pg_response::{PgResponse, StatementType};
16use risingwave_sqlparser::ast::{DropMode, ObjectName};
17
18use super::RwPgResponse;
19use crate::binder::Binder;
20use crate::error::{ErrorCode, Result};
21use crate::handler::HandlerArgs;
22
23pub async fn handle_drop_database(
24    handler_args: HandlerArgs,
25    database_name: ObjectName,
26    if_exists: bool,
27    mode: Option<DropMode>,
28) -> Result<RwPgResponse> {
29    let session = handler_args.session;
30    let catalog_reader = session.env().catalog_reader();
31    let database_name = Binder::resolve_database_name(database_name)?;
32    if session.database() == database_name {
33        return Err(ErrorCode::PermissionDenied(
34            "cannot drop the currently open database".to_owned(),
35        )
36        .into());
37    }
38    if mode.is_some() {
39        return Err(ErrorCode::BindError("Drop database not support drop mode".to_owned()).into());
40    }
41    let database = {
42        let reader = catalog_reader.read_guard();
43        match reader.get_database_by_name(&database_name) {
44            Ok(db) => db.clone(),
45            Err(err) => {
46                // Unable to find this database. If `if_exists` is true,
47                // we can just return success.
48                return if if_exists {
49                    Ok(PgResponse::builder(StatementType::DROP_DATABASE)
50                        .notice(format!(
51                            "database \"{}\" does not exist, skipping",
52                            database_name
53                        ))
54                        .into())
55                } else {
56                    Err(err.into())
57                };
58            }
59        }
60    };
61
62    session.check_privilege_for_drop_alter_db_schema(&database)?;
63
64    let catalog_writer = session.catalog_writer()?;
65    catalog_writer.drop_database(database.id()).await?;
66    Ok(PgResponse::empty_result(StatementType::DROP_DATABASE))
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::test_utils::LocalFrontend;
72
73    #[tokio::test]
74    async fn test_drop_database() {
75        let frontend = LocalFrontend::new(Default::default()).await;
76        let session = frontend.session_ref();
77        let catalog_reader = session.env().catalog_reader();
78
79        frontend.run_sql("CREATE DATABASE database").await.unwrap();
80
81        frontend.run_sql("CREATE SCHEMA schema").await.unwrap();
82
83        frontend.run_sql("DROP SCHEMA public").await.unwrap();
84
85        frontend.run_sql("CREATE USER user WITH NOSUPERUSER NOCREATEDB PASSWORD 'md5827ccb0eea8a706c4c34a16891f84e7b'").await.unwrap();
86        let user_id = {
87            let user_reader = session.env().user_info_reader();
88            user_reader
89                .read_guard()
90                .get_user_by_name("user")
91                .unwrap()
92                .id
93        };
94        let res = frontend
95            .run_user_sql(
96                "DROP DATABASE database",
97                "dev".to_owned(),
98                "user".to_owned(),
99                user_id,
100            )
101            .await;
102        assert!(res.is_err());
103
104        frontend.run_sql("DROP DATABASE database").await.unwrap();
105
106        let database = catalog_reader
107            .read_guard()
108            .get_database_by_name("database")
109            .ok()
110            .cloned();
111        assert!(database.is_none());
112    }
113}