1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Approximative fixes for BUG#2610,2611,9100 i.e. WL#2146 binlogging/replication of routines (stored procs and functions).

Approximative, because it's using our binlogging way (what we call "query"-level) and this is not as good as record-level binlog (5.1) would be. It imposes several
  limitations to routines, and has caveats (which I'll document, and for which the server will try to issue errors but that is not always possible).
  Reason I don't propagate caller info to the binlog as planned is that on master and slave
  users may be different; even with that some caveats would remain.
This commit is contained in:
gbichot@quadita2.mysql.com
2005-05-05 14:20:53 +02:00
parent c78b2d25ac
commit b72ae4fe57
18 changed files with 733 additions and 44 deletions

View File

@ -4097,7 +4097,43 @@ unsent_create_error:
thd->variables.select_limit= HA_POS_ERROR;
thd->row_count_func= 0;
tmp_disable_binlog(thd); /* don't binlog the substatements */
res= sp->execute_procedure(thd, &lex->value_list);
reenable_binlog(thd);
/*
We write CALL to binlog; on the opposite we didn't write the
substatements. That choice is necessary because the substatements
may use local vars.
Binlogging should happen when all tables are locked. They are locked
just above, and unlocked by close_thread_tables(). All tables which
are to be updated are locked like with a table-level write lock, and
this also applies to InnoDB (I tested - note that it reduces
InnoDB's concurrency as we don't use row-level locks). So binlogging
below is safe.
Note the limitation: if the SP returned an error, but still did some
updates, we do NOT binlog it. This is because otherwise "permission
denied", "table does not exist" etc would stop the slave quite
often. There is no easy way to know if the SP updated something
(even no_trans_update is not suitable, as it may be a transactional
autocommit update which happened, and no_trans_update covers only
INSERT/UPDATE/LOAD).
*/
if (mysql_bin_log.is_open() &&
(sp->m_chistics->daccess == SP_CONTAINS_SQL ||
sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
{
if (res)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_FAILED_ROUTINE_BREAK_BINLOG,
ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
else
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
/*
If warnings have been cleared, we have to clear total_warn_count
@ -4153,14 +4189,32 @@ unsent_create_error:
sp->m_name.str, 0))
goto error;
memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
else
result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
if (!trust_routine_creators && mysql_bin_log.is_open() &&
!sp->m_chistics->detistic &&
(chistics.daccess == SP_CONTAINS_SQL ||
chistics.daccess == SP_MODIFIES_SQL_DATA))
{
my_message(ER_BINLOG_UNSAFE_ROUTINE,
ER(ER_BINLOG_UNSAFE_ROUTINE), MYF(0));
result= SP_INTERNAL_ERROR;
}
else
{
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
else
result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
}
}
switch (result)
{
case SP_OK:
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
break;
case SP_KEY_NOT_FOUND:
@ -4237,6 +4291,12 @@ unsent_create_error:
switch (result)
{
case SP_OK:
if (mysql_bin_log.is_open())
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
break;
case SP_KEY_NOT_FOUND:
@ -4495,6 +4555,7 @@ unsent_create_error:
break;
}
thd->proc_info="query end";
/* Two binlog-related cleanups: */
if (thd->one_shot_set)
{
/*