risingwave_frontend/handler/
drop_function.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 super::*;
16use crate::catalog::root_catalog::SchemaPath;
17use crate::{Binder, bind_data_type};
18
19/// Drop a function or an aggregate.
20pub async fn handle_drop_function(
21    handler_args: HandlerArgs,
22    if_exists: bool,
23    mut func_desc: Vec<FunctionDesc>,
24    option: Option<ReferentialAction>,
25    aggregate: bool,
26) -> Result<RwPgResponse> {
27    if func_desc.len() != 1 {
28        bail_not_implemented!("only support dropping 1 function");
29    }
30    let stmt_type = if aggregate {
31        StatementType::DROP_AGGREGATE
32    } else {
33        StatementType::DROP_FUNCTION
34    };
35    let func_desc = func_desc.remove(0);
36
37    let session = handler_args.session;
38    let db_name = &session.database();
39    let (schema_name, function_name) =
40        Binder::resolve_schema_qualified_name(db_name, &func_desc.name)?;
41    let search_path = session.config().search_path();
42    let user_name = &session.user_name();
43    let schema_path = SchemaPath::new(schema_name.as_deref(), &search_path, user_name);
44
45    let arg_types = match func_desc.args {
46        Some(args) => {
47            let mut arg_types = vec![];
48            for arg in args {
49                arg_types.push(bind_data_type(&arg.data_type)?);
50            }
51            Some(arg_types)
52        }
53        None => None,
54    };
55
56    let function_id = {
57        let reader = session.env().catalog_reader().read_guard();
58        let res = match arg_types {
59            Some(arg_types) => {
60                reader.get_function_by_name_args(db_name, schema_path, &function_name, &arg_types)
61            }
62            // check if there is only one function if arguments are not specified
63            None => match reader.get_functions_by_name(db_name, schema_path, &function_name) {
64                Ok((functions, schema_name)) => {
65                    if functions.len() > 1 {
66                        return Err(ErrorCode::CatalogError(format!("function name {function_name:?} is not unique\nHINT: Specify the argument list to select the function unambiguously.").into()).into());
67                    }
68                    Ok((
69                        functions.into_iter().next().expect("no functions"),
70                        schema_name,
71                    ))
72                }
73                Err(e) => Err(e),
74            },
75        };
76        match res {
77            Ok((function, schema_name)) => {
78                session.check_privilege_for_drop_alter(schema_name, &**function)?;
79                if !aggregate && function.kind.is_aggregate() {
80                    return Err(ErrorCode::CatalogError(
81                        format!("\"{function_name}\" is an aggregate function\nHINT:  Use DROP AGGREGATE to drop aggregate functions.").into(),
82                    )
83                    .into());
84                } else if aggregate && !function.kind.is_aggregate() {
85                    return Err(ErrorCode::CatalogError(
86                        format!("\"{function_name}\" is not an aggregate").into(),
87                    )
88                    .into());
89                }
90                function.id
91            }
92            Err(e) => {
93                if if_exists && e.is_not_found("function") {
94                    return Ok(RwPgResponse::builder(stmt_type)
95                        .notice(format!(
96                            "function \"{}\" does not exist, skipping",
97                            function_name
98                        ))
99                        .into());
100                }
101                return Err(e.into());
102            }
103        }
104    };
105
106    let catalog_writer = session.catalog_writer()?;
107    let cascade = matches!(option, Some(ReferentialAction::Cascade));
108    catalog_writer.drop_function(function_id, cascade).await?;
109
110    Ok(PgResponse::empty_result(stmt_type))
111}