Skip to content

Commit b385eb6

Browse files
fix(frontend): support drop function without arguments (#9561)
Signed-off-by: Runji Wang <[email protected]>
1 parent 5752b12 commit b385eb6

File tree

5 files changed

+74
-16
lines changed

5 files changed

+74
-16
lines changed

e2e_test/udf/python.slt

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,22 @@ drop materialized view mv;
165165
statement ok
166166
drop table t;
167167

168-
# TODO: drop function without arguments
169-
170-
# # Drop a function but ambiguous.
171-
# statement error is not unique
172-
# drop function gcd;
173-
174168
# Drop a function
175169
statement ok
176170
drop function int_42();
177171

178-
# Drop a function
172+
# Drop a function without arguments, but the function name is not unique.
173+
statement error is not unique
174+
drop function gcd;
175+
176+
# Drop a function with arguments.
179177
statement ok
180178
drop function gcd(int, int);
181179

182-
# Drop a function
180+
# foo() is different from foo.
181+
statement error function not found
182+
drop function gcd();
183+
184+
# Drop a function without arguments. Now the function name is unique.
183185
statement ok
184-
drop function gcd(int, int, int);
186+
drop function gcd;

src/frontend/src/catalog/root_catalog.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,31 @@ impl Catalog {
568568
.get_schema_by_name(db_name, schema_name)?
569569
.get_function_by_name_args(function_name, args))
570570
})?
571+
.ok_or_else(|| {
572+
CatalogError::NotFound(
573+
"function",
574+
format!(
575+
"{}({})",
576+
function_name,
577+
args.iter().map(|a| a.to_string()).join(", ")
578+
),
579+
)
580+
})
581+
}
582+
583+
/// Gets all functions with the given name.
584+
pub fn get_functions_by_name<'a>(
585+
&self,
586+
db_name: &str,
587+
schema_path: SchemaPath<'a>,
588+
function_name: &str,
589+
) -> CatalogResult<(Vec<&Arc<FunctionCatalog>>, &'a str)> {
590+
schema_path
591+
.try_find(|schema_name| {
592+
Ok(self
593+
.get_schema_by_name(db_name, schema_name)?
594+
.get_functions_by_name(function_name))
595+
})?
571596
.ok_or_else(|| CatalogError::NotFound("function", function_name.to_string()))
572597
}
573598

src/frontend/src/catalog/schema_catalog.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,14 @@ impl SchemaCatalog {
483483
self.function_by_name.get(name)?.get(args)
484484
}
485485

486+
pub fn get_functions_by_name(&self, name: &str) -> Option<Vec<&Arc<FunctionCatalog>>> {
487+
let functions = self.function_by_name.get(name)?;
488+
if functions.is_empty() {
489+
return None;
490+
}
491+
Some(functions.values().collect())
492+
}
493+
486494
pub fn get_connection_by_name(&self, connection_name: &str) -> Option<&Arc<ConnectionCatalog>> {
487495
self.connection_by_name.get(connection_name)
488496
}

src/frontend/src/handler/drop_function.rs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,38 @@ pub async fn handle_drop_function(
4343
let user_name = &session.auth_context().user_name;
4444
let schema_path = SchemaPath::new(schema_name.as_deref(), &search_path, user_name);
4545

46-
// TODO: argument is not specified, drop the only function with the name
47-
let mut arg_types = vec![];
48-
for arg in func_desc.args.unwrap_or_default() {
49-
arg_types.push(bind_data_type(&arg.data_type)?);
50-
}
46+
let arg_types = match func_desc.args {
47+
Some(args) => {
48+
let mut arg_types = vec![];
49+
for arg in args {
50+
arg_types.push(bind_data_type(&arg.data_type)?);
51+
}
52+
Some(arg_types)
53+
}
54+
None => None,
55+
};
5156

5257
let function_id = {
5358
let reader = session.env().catalog_reader().read_guard();
54-
match reader.get_function_by_name_args(db_name, schema_path, &function_name, &arg_types) {
59+
let res = match arg_types {
60+
Some(arg_types) => {
61+
reader.get_function_by_name_args(db_name, schema_path, &function_name, &arg_types)
62+
}
63+
// check if there is only one function if arguments are not specified
64+
None => match reader.get_functions_by_name(db_name, schema_path, &function_name) {
65+
Ok((functions, schema_name)) => {
66+
if functions.len() > 1 {
67+
return Err(ErrorCode::CatalogError(format!("function name {function_name:?} is not unique\nHINT: Specify the argument list to select the function unambiguously.").into()).into());
68+
}
69+
Ok((
70+
functions.into_iter().next().expect("no functions"),
71+
schema_name,
72+
))
73+
}
74+
Err(e) => Err(e),
75+
},
76+
};
77+
match res {
5578
Ok((function, schema_name)) => {
5679
session.check_privilege_for_drop_alter(schema_name, &**function)?;
5780
function.id

src/sqlparser/src/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2108,7 +2108,7 @@ impl Parser {
21082108

21092109
let args = if self.consume_token(&Token::LParen) {
21102110
if self.consume_token(&Token::RParen) {
2111-
None
2111+
Some(vec![])
21122112
} else {
21132113
let args = self.parse_comma_separated(Parser::parse_function_arg)?;
21142114
self.expect_token(&Token::RParen)?;

0 commit comments

Comments
 (0)