Handle `DROP FUNCTION [IF EXISTS] ` Requires superuser or tenant_admin — same privilege level as CREATE FUNCTION.
(
state: &SharedState,
identity: &AuthenticatedIdentity,
parts: &[&str],
)
| 15 | /// |
| 16 | /// Requires superuser or tenant_admin — same privilege level as CREATE FUNCTION. |
| 17 | pub fn drop_function( |
| 18 | state: &SharedState, |
| 19 | identity: &AuthenticatedIdentity, |
| 20 | parts: &[&str], |
| 21 | ) -> PgWireResult<Vec<Response>> { |
| 22 | require_tenant_admin(identity, "drop functions")?; |
| 23 | |
| 24 | let (name, if_exists) = parse_drop_function(parts)?; |
| 25 | let tenant_id = identity.tenant_id.as_u64(); |
| 26 | |
| 27 | let catalog = state |
| 28 | .credentials |
| 29 | .catalog() |
| 30 | .as_ref() |
| 31 | .ok_or_else(|| sqlstate_error("XX000", "system catalog not available"))?; |
| 32 | |
| 33 | // Check if function exists. |
| 34 | let func_exists = catalog |
| 35 | .get_function(tenant_id, &name) |
| 36 | .map_err(|e| sqlstate_error("XX000", &format!("catalog read: {e}")))? |
| 37 | .is_some(); |
| 38 | |
| 39 | if !func_exists && !if_exists { |
| 40 | return Err(sqlstate_error( |
| 41 | "42883", |
| 42 | &format!("function '{name}' does not exist"), |
| 43 | )); |
| 44 | } |
| 45 | |
| 46 | if !func_exists { |
| 47 | // IF EXISTS and function doesn't exist — no-op. |
| 48 | return Ok(vec![Response::Execution(Tag::new("DROP FUNCTION"))]); |
| 49 | } |
| 50 | |
| 51 | // Check dependencies: block DROP if other objects depend on this function. |
| 52 | let dependents = catalog |
| 53 | .find_dependents(tenant_id, "function", &name) |
| 54 | .map_err(|e| sqlstate_error("XX000", &format!("dependency check: {e}")))?; |
| 55 | if !dependents.is_empty() { |
| 56 | let dep_list: Vec<String> = dependents |
| 57 | .iter() |
| 58 | .map(|(t, n)| format!("{t} '{n}'")) |
| 59 | .collect(); |
| 60 | return Err(sqlstate_error( |
| 61 | "2BP01", |
| 62 | &format!( |
| 63 | "cannot drop function '{name}': depended on by {}", |
| 64 | dep_list.join(", ") |
| 65 | ), |
| 66 | )); |
| 67 | } |
| 68 | |
| 69 | // If the function is a WASM function, clean up the stored binary. |
| 70 | if let Ok(Some(func)) = catalog.get_function(tenant_id, &name) |
| 71 | && let Some(ref hash) = func.wasm_hash |
| 72 | { |
| 73 | let _ = crate::control::planner::wasm::store::delete_wasm_binary(catalog, hash); |
| 74 | } |
no test coverage detected