MDEV-35510 ASAN build crashes during bootstrap

Avoid ASAN failure by collecting statistics from Result objects
before cleaning them up.  In related single-table cases, statistics
are maintained directly by the single-table update and delete
functions.
This commit is contained in:
Dave Gosselin 2025-02-03 10:42:16 -05:00 committed by Dave Gosselin
parent 6cff704e57
commit d3c9a2ee21
6 changed files with 64 additions and 30 deletions

View File

@ -20,6 +20,8 @@
#ifndef SQL_CMD_INCLUDED #ifndef SQL_CMD_INCLUDED
#define SQL_CMD_INCLUDED #define SQL_CMD_INCLUDED
#include <my_base.h>
/* /*
When a command is added here, be sure it's also added in mysqld.cc When a command is added here, be sure it's also added in mysqld.cc
in "struct show_var_st status_vars[]= {" ... in "struct show_var_st status_vars[]= {" ...
@ -225,6 +227,11 @@ public:
*/ */
virtual bool is_dml() const { return false; } virtual bool is_dml() const { return false; }
virtual void get_dml_stat (ha_rows &found, ha_rows &changed)
{
found= changed= 0;
}
/** /**
@brief Unprepare prepared statement for the command @brief Unprepare prepared statement for the command
@param thd global context of the processed statement @param thd global context of the processed statement

View File

@ -328,7 +328,6 @@ bool Sql_cmd_delete::delete_from_single_table(THD *thd)
SQL_SELECT *select= 0; SQL_SELECT *select= 0;
SORT_INFO *file_sort= 0; SORT_INFO *file_sort= 0;
READ_RECORD info; READ_RECORD info;
ha_rows deleted= 0;
bool reverse= FALSE; bool reverse= FALSE;
bool binlog_is_row; bool binlog_is_row;
killed_state killed_status= NOT_KILLED; killed_state killed_status= NOT_KILLED;
@ -427,6 +426,7 @@ bool Sql_cmd_delete::delete_from_single_table(THD *thd)
has_triggers= table->triggers && table->triggers->has_delete_triggers(); has_triggers= table->triggers && table->triggers->has_delete_triggers();
transactional_table= table->file->has_transactions_and_rollback(); transactional_table= table->file->has_transactions_and_rollback();
deleted= 0;
if (!returning && !using_limit && const_cond_result && if (!returning && !using_limit && const_cond_result &&
(!thd->is_current_stmt_binlog_format_row() && !has_triggers) (!thd->is_current_stmt_binlog_format_row() && !has_triggers)
@ -1861,6 +1861,9 @@ bool Sql_cmd_delete::execute_inner(THD *thd)
if (result) if (result)
{ {
/* In single table case, this->deleted set by delete_from_single_table */
if (res && multitable)
deleted= ((multi_delete*)get_result())->num_deleted();
res= false; res= false;
delete result; delete result;
} }

View File

@ -43,6 +43,7 @@ template <typename T> class SQL_I_List;
class Sql_cmd_delete final : public Sql_cmd_dml class Sql_cmd_delete final : public Sql_cmd_dml
{ {
public: public:
ha_rows deleted{0};
Sql_cmd_delete(bool multitable_arg) Sql_cmd_delete(bool multitable_arg)
: orig_multitable(multitable_arg), multitable(multitable_arg), : orig_multitable(multitable_arg), multitable(multitable_arg),
save_protocol(NULL) save_protocol(NULL)
@ -66,6 +67,12 @@ public:
void remove_order_by_without_limit(THD *thd); void remove_order_by_without_limit(THD *thd);
void get_dml_stat (ha_rows &found, ha_rows &changed) override
{
found= 0;
changed= deleted;
}
protected: protected:
/** /**
@brief Perform precheck of table privileges for delete statements @brief Perform precheck of table privileges for delete statements

View File

@ -34268,39 +34268,38 @@ static void MYSQL_DML_START(THD *thd)
} }
static void MYSQL_DML_DONE(THD *thd, int rc) static void MYSQL_DML_GET_STAT(THD * thd, ha_rows &found, ha_rows &changed)
{ {
switch (thd->lex->sql_command) { switch (thd->lex->sql_command) {
case SQLCOM_UPDATE: case SQLCOM_UPDATE:
MYSQL_UPDATE_DONE(
rc,
(rc ? 0 :
((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result()))
->num_found()),
(rc ? 0 :
((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result()))
->num_updated()));
break;
case SQLCOM_UPDATE_MULTI: case SQLCOM_UPDATE_MULTI:
MYSQL_MULTI_UPDATE_DONE( case SQLCOM_DELETE_MULTI:
rc, thd->lex->m_sql_cmd->get_dml_stat(found, changed);
(rc ? 0 :
((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result()))
->num_found()),
(rc ? 0 :
((multi_update*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result()))
->num_updated()));
break; break;
case SQLCOM_DELETE: case SQLCOM_DELETE:
MYSQL_DELETE_DONE(rc, (rc ? 0 : (ulong) (thd->get_row_count_func()))); found= 0;
changed= (thd->get_row_count_func());
break;
default:
DBUG_ASSERT(0);
}
}
static void MYSQL_DML_DONE(THD *thd, int rc, ha_rows found, ha_rows changed)
{
switch (thd->lex->sql_command) {
case SQLCOM_UPDATE:
MYSQL_UPDATE_DONE(rc, found, changed);
break;
case SQLCOM_UPDATE_MULTI:
MYSQL_MULTI_UPDATE_DONE(rc, found, changed);
break;
case SQLCOM_DELETE:
MYSQL_DELETE_DONE(rc, changed);
break; break;
case SQLCOM_DELETE_MULTI: case SQLCOM_DELETE_MULTI:
MYSQL_MULTI_DELETE_DONE( MYSQL_MULTI_DELETE_DONE(rc, changed);
rc,
(rc ? 0 :
((multi_delete*)(((Sql_cmd_dml*)(thd->lex->m_sql_cmd))->get_result()))
->num_deleted()));
break; break;
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
@ -34389,6 +34388,7 @@ err:
bool Sql_cmd_dml::execute(THD *thd) bool Sql_cmd_dml::execute(THD *thd)
{ {
lex = thd->lex; lex = thd->lex;
ha_rows found= 0, changed= 0;
bool res; bool res;
SELECT_LEX_UNIT *unit = &lex->unit; SELECT_LEX_UNIT *unit = &lex->unit;
@ -34439,6 +34439,8 @@ bool Sql_cmd_dml::execute(THD *thd)
if (res) if (res)
goto err; goto err;
else
MYSQL_DML_GET_STAT(thd, found, changed);
res= unit->cleanup(); res= unit->cleanup();
@ -34447,13 +34449,13 @@ bool Sql_cmd_dml::execute(THD *thd)
THD_STAGE_INFO(thd, stage_end); THD_STAGE_INFO(thd, stage_end);
MYSQL_DML_DONE(thd, res); MYSQL_DML_DONE(thd, 0, found, changed);
return res; return res;
err: err:
DBUG_ASSERT(thd->is_error() || thd->killed); DBUG_ASSERT(thd->is_error() || thd->killed);
MYSQL_DML_DONE(thd, 1); MYSQL_DML_DONE(thd, 1, 0, 0);
THD_STAGE_INFO(thd, stage_end); THD_STAGE_INFO(thd, stage_end);
(void)unit->cleanup(); (void)unit->cleanup();
if (is_prepared()) if (is_prepared())

View File

@ -366,7 +366,7 @@ bool Sql_cmd_update::update_single_table(THD *thd)
ha_rows dup_key_found; ha_rows dup_key_found;
bool need_sort= TRUE; bool need_sort= TRUE;
bool reverse= FALSE; bool reverse= FALSE;
ha_rows updated, updated_or_same, found; ha_rows updated_or_same;
key_map old_covering_keys; key_map old_covering_keys;
TABLE *table; TABLE *table;
SQL_SELECT *select= NULL; SQL_SELECT *select= NULL;
@ -3140,6 +3140,13 @@ bool Sql_cmd_update::execute_inner(THD *thd)
if (result) if (result)
{ {
/* In single table case, this->updated set by update_single_table */
if (res && multitable)
{
found= ((multi_update*)get_result())->num_found();
updated= ((multi_update*)get_result())->num_updated();
}
res= false; res= false;
delete result; delete result;
} }

View File

@ -45,6 +45,7 @@ bool compare_record(const TABLE *table);
class Sql_cmd_update final : public Sql_cmd_dml class Sql_cmd_update final : public Sql_cmd_dml
{ {
public: public:
ha_rows found{0}, updated{0};
Sql_cmd_update(bool multitable_arg) Sql_cmd_update(bool multitable_arg)
: orig_multitable(multitable_arg), multitable(multitable_arg) : orig_multitable(multitable_arg), multitable(multitable_arg)
{} {}
@ -65,6 +66,13 @@ public:
void set_as_multitable() { multitable= true; } void set_as_multitable() { multitable= true; }
void get_dml_stat (ha_rows &found, ha_rows &changed) override
{
found= this->found;
changed= this->updated;
}
protected: protected:
/** /**
@brief Perform precheck of table privileges for update statements @brief Perform precheck of table privileges for update statements