use crate::control::security::identity::AuthenticatedIdentity;
use crate::control::state::SharedState;
use super::super::super::result::{DdlError, DdlResult};
use super::super::auth_support::{require_tenant_admin, status};
pub fn drop_procedure(
state: &SharedState,
identity: &AuthenticatedIdentity,
parts: &[&str],
) -> Result<Vec<DdlResult>, DdlError> {
require_tenant_admin(identity, "drop procedures")?;
if parts.len() < 3 {
return Err(DdlError {
sqlstate: "42601".to_string(),
message: "syntax: DROP PROCEDURE [IF EXISTS] <name>".to_string(),
});
}
let mut idx = 2;
let if_exists = if parts.len() > 4
&& parts[2].eq_ignore_ascii_case("IF")
&& parts[3].eq_ignore_ascii_case("EXISTS")
{
idx = 4;
true
} else {
false
};
if idx >= parts.len() {
return Err(DdlError {
sqlstate: "42601".to_string(),
message: "procedure name required".to_string(),
});
}
let name = parts[idx].to_lowercase().trim_end_matches(';').to_string();
let tenant_id = identity.tenant_id.as_u64();
let catalog = state.credentials.catalog();
let exists_before = catalog
.get_procedure(tenant_id, &name)
.map_err(|e| DdlError {
sqlstate: "XX000".to_string(),
message: format!("catalog read: {e}"),
})?
.is_some();
if !exists_before && !if_exists {
return Err(DdlError {
sqlstate: "42883".to_string(),
message: format!("procedure '{name}' does not exist"),
});
}
if !exists_before {
return Ok(status("DROP PROCEDURE"));
}
let entry = crate::control::catalog_entry::CatalogEntry::DeleteProcedure {
tenant_id,
name: name.clone(),
};
let log_index = crate::control::metadata_proposer::propose_catalog_entry(state, &entry)
.map_err(|e| DdlError {
sqlstate: "XX000".to_string(),
message: format!("metadata propose: {e}"),
})?;
if log_index == 0 {
let _ = catalog
.delete_procedure(tenant_id, &name)
.map_err(|e| DdlError {
sqlstate: "XX000".to_string(),
message: format!("catalog write: {e}"),
})?;
}
{
use nodedb_types::sync::wire::DefinitionSyncMsg;
let msg = DefinitionSyncMsg {
definition_type: "procedure".into(),
name: name.clone(),
action: "delete".into(),
payload: vec![],
};
state.definition_sync_fanout.broadcast(&msg);
}
state.audit_record(
crate::control::security::audit::AuditEvent::AdminAction,
Some(identity.tenant_id),
&identity.username,
&format!("DROP PROCEDURE {name}"),
);
Ok(status("DROP PROCEDURE"))
}