Details
-
Bug
-
Status: Approved (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.11, 11.4
-
None
Description
Sp_handler::sp_drop_routine_internal() (sql/sp.cc) deletes the existing mysql.proc row when CREATE OR REPLACE FUNCTION/PROCEDURE replaces a routine that already exists:
int
|
Sp_handler::sp_drop_routine_internal(THD *thd,
|
const Database_qualified_name *name,
|
TABLE *table) const
|
{
|
DBUG_ENTER("sp_drop_routine_internal");
|
|
|
if (table->file->ha_delete_row(table->record[0]))
|
DBUG_RETURN(SP_DELETE_ROW_FAILED);
|
...
|
If ha_delete_row() fails, the function returns SP_DELETE_ROW_FAILED without ever calling my_error(). The only caller, Sp_handler::sp_create_routine(), doesn't push an error either:
case SP_TYPE_FUNCTION:
|
case SP_TYPE_PROCEDURE:
|
if (sp_drop_routine_internal(thd, sp, table))
|
goto done; // sql/sp.cc:1286 — no my_error() on this path
|
done: returns ret (still TRUE, i.e. failure) up through mysql_create_routine() → mysql_execute_command(). Nothing along that chain pushes an error into the Diagnostics_area, and mysql_parse() discards mysql_execute_command()'s return value (int error _attribute_((unused))
. The statement therefore finishes with an empty Diagnostics_area (DA_EMPTY).
Protocol::end_statement() (sql/protocol.cc) hits DBUG_ASSERT(0) on the DA_EMPTY case, then falls through to send_ok() regardless:
case Diagnostics_area::DA_EMPTY:
|
default:
|
DBUG_ASSERT(0);
|
error= send_ok(thd->server_status, 0, 0, 0, NULL);
|
break;
|
Impact:
- Debug builds: the DBUG_ASSERT(0) aborts the server (SIGABRT) on a routine ha_delete_row() failure during CREATE OR REPLACE.
- Release builds: DBUG_ASSERT is a no-op, so the server silently sends the client an OK for a statement that actually failed. The routine'sd never reinserted, and itsmysql.procs_priv grants are left dangling — with no error reported anywhere.
ha_delete_row() can fail for ordinary operational reasons (disk full, I/O error, storage-engine
lock-wait timeout, corrupted table) —l.
Reproduction (debug build):
Add a temporary fault-injection pointe_internal():
DBUG_EXECUTE_IF("sp_drop_routine_inte
|
DBUG_RETURN(SP_DELETE_ROW_FAILED););
|
Then:
CREATE FUNCTION f1() RETURNS INT RETURN 1;
|
SET @@session.debug_dbug="+d,sp_drop_
|
CREATE OR REPLACE FUNCTION f1() RETURNS INT RETURN 2;
|
Server crashes:
mariadbd: sql/protocol.cc:618: void Pertion `0' failed.
Suggested fix direction: sp_drop_rout_error(ER_SP_DROP_FAILED, MYF(0),type_str(), name->m_name.str) (or similar) before returning SP_DELETE_ROW_FAILED, mirroring the sibling
ha_write_row() failure a few lines la/sp.cc:1475, which does callmy_error(ER_SP_ALREADY_EXISTS, ...)).
Found while working on: MDEV-39993 (unrelated fix; this is a pre-existing, separate defect surfaced during code review of that patch, andut of scope for a scripts-onlychange).
Attachments
Issue Links
- relates to
-
MDEV-39993 mariadb-upgrade Drops Existing EXECUTE Grants on sys Stored Routines During Upgrade from 10.11 to 11.4
-
- Closed
-