Commit 1bfe0bdf authored by guilhem@gbichot3.local's avatar guilhem@gbichot3.local

Merge gbichot3.local:/home/mysql_src/mysql-5.1-new-19630

into  gbichot3.local:/home/mysql_src/mysql-5.1
parents b3977379 fdb0f85a
Branches unavailable
Tags unavailable
No related merge requests found
This diff is collapsed.
...@@ -426,7 +426,9 @@ Item *create_func_unhex(Item* a) ...@@ -426,7 +426,9 @@ Item *create_func_unhex(Item* a)
Item *create_func_uuid(void) Item *create_func_uuid(void)
{ {
THD *thd= current_thd; THD *thd= current_thd;
thd->lex->binlog_row_based_if_mixed= 1; #ifdef HAVE_ROW_BASED_REPLICATION
thd->lex->binlog_row_based_if_mixed= TRUE;
#endif
return new(thd->mem_root) Item_func_uuid(); return new(thd->mem_root) Item_func_uuid();
} }
......
...@@ -1343,9 +1343,9 @@ bool sys_var_thd_binlog_format::is_readonly() const ...@@ -1343,9 +1343,9 @@ bool sys_var_thd_binlog_format::is_readonly() const
return 1; return 1;
} }
/* /*
if in a stored function, it's too late to change mode if in a stored function/trigger, it's too late to change mode
*/ */
if (thd->spcont && thd->prelocked_mode) if (thd->in_sub_stmt)
{ {
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
return 1; return 1;
......
...@@ -1632,6 +1632,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, ...@@ -1632,6 +1632,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
sp->add_used_tables_to_table_list(thd, &lex->query_tables_last, sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
rt->belong_to_view); rt->belong_to_view);
} }
sp->propagate_attributes(lex);
} }
first= FALSE; first= FALSE;
} }
...@@ -1729,14 +1730,16 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, ...@@ -1729,14 +1730,16 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{ {
for (int j= 0; j < (int)TRG_ACTION_MAX; j++) for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
{ {
if (triggers->bodies[i][j]) sp_head *trigger_body= triggers->bodies[i][j];
if (trigger_body)
{ {
(void)triggers->bodies[i][j]-> (void)trigger_body->
add_used_tables_to_table_list(thd, &lex->query_tables_last, add_used_tables_to_table_list(thd, &lex->query_tables_last,
table->belong_to_view); table->belong_to_view);
sp_update_stmt_used_routines(thd, lex, sp_update_stmt_used_routines(thd, lex,
&triggers->bodies[i][j]->m_sroutines, &trigger_body->m_sroutines,
table->belong_to_view); table->belong_to_view);
trigger_body->propagate_attributes(lex);
} }
} }
} }
......
...@@ -1675,6 +1675,16 @@ sp_head::restore_lex(THD *thd) ...@@ -1675,6 +1675,16 @@ sp_head::restore_lex(THD *thd)
oldlex->next_state= sublex->next_state; oldlex->next_state= sublex->next_state;
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If this substatement needs row-based, the entire routine does too (we
cannot switch from statement-based to row-based only for this
substatement).
*/
if (sublex->binlog_row_based_if_mixed)
m_flags|= BINLOG_ROW_BASED_IF_MIXED;
#endif
/* /*
Add routines which are used by statement to respective set for Add routines which are used by statement to respective set for
this routine. this routine.
......
...@@ -126,7 +126,8 @@ class sp_head :private Query_arena ...@@ -126,7 +126,8 @@ class sp_head :private Query_arena
/* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */ /* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */
HAS_COMMIT_OR_ROLLBACK= 128, HAS_COMMIT_OR_ROLLBACK= 128,
LOG_SLOW_STATEMENTS= 256, // Used by events LOG_SLOW_STATEMENTS= 256, // Used by events
LOG_GENERAL_LOG= 512 // Used by events LOG_GENERAL_LOG= 512, // Used by events
BINLOG_ROW_BASED_IF_MIXED= 1024
}; };
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */ /* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
...@@ -351,6 +352,25 @@ class sp_head :private Query_arena ...@@ -351,6 +352,25 @@ class sp_head :private Query_arena
int show_routine_code(THD *thd); int show_routine_code(THD *thd);
#endif #endif
/*
This method is intended for attributes of a routine which need
to propagate upwards to the LEX of the caller (when a property of a
sp_head needs to "taint" the caller).
*/
void propagate_attributes(LEX *lex)
{
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If this routine needs row-based binary logging, the entire top statement
too (we cannot switch from statement-based to row-based only for this
routine, as in statement-based the top-statement may be binlogged and
the substatements not).
*/
if (m_flags & BINLOG_ROW_BASED_IF_MIXED)
lex->binlog_row_based_if_mixed= TRUE;
#endif
}
private: private:
......
...@@ -49,6 +49,8 @@ static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias, ...@@ -49,6 +49,8 @@ static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
static void close_old_data_files(THD *thd, TABLE *table, bool abort_locks, static void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
bool send_refresh); bool send_refresh);
static bool reopen_table(TABLE *table); static bool reopen_table(TABLE *table);
static bool
has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables);
extern "C" byte *table_cache_key(const byte *record,uint *length, extern "C" byte *table_cache_key(const byte *record,uint *length,
...@@ -3315,6 +3317,18 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) ...@@ -3315,6 +3317,18 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
*need_reopen= FALSE; *need_reopen= FALSE;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
CREATE ... SELECT UUID() locks no tables, we have to test here.
Note that we will not do the resetting if inside a stored
function/trigger, because the binlogging of those is decided earlier (by
the caller) and can't be changed afterwards.
*/
thd->reset_current_stmt_binlog_row_based();
if (thd->lex->binlog_row_based_if_mixed)
thd->set_current_stmt_binlog_row_based_if_mixed();
#endif /*HAVE_ROW_BASED_REPLICATION*/
if (!tables) if (!tables)
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -3345,6 +3359,19 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) ...@@ -3345,6 +3359,19 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
{ {
thd->in_lock_tables=1; thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK; thd->options|= OPTION_TABLE_LOCK;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If we have >= 2 different tables to update with auto_inc columns,
statement-based binlogging won't work. We can solve this problem in
mixed mode by switching to row-based binlogging:
*/
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
has_two_write_locked_tables_with_auto_increment(tables))
{
thd->lex->binlog_row_based_if_mixed= TRUE;
thd->set_current_stmt_binlog_row_based_if_mixed();
}
#endif
} }
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
...@@ -6477,3 +6504,46 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table ...@@ -6477,3 +6504,46 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/*
Tells if two (or more) tables have auto_increment columns and we want to
lock those tables with a write lock.
SYNOPSIS
has_two_write_locked_tables_with_auto_increment
tables Table list
NOTES:
Call this function only when you have established the list of all tables
which you'll want to update (including stored functions, triggers, views
inside your statement).
RETURN
0 No
1 Yes
*/
static bool
has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables)
{
char *first_table_name= NULL, *first_db;
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
/* we must do preliminary checks as table->table may be NULL */
if (!table->placeholder() && !table->schema_table &&
table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE))
{
if (first_table_name == NULL)
{
first_table_name= table->table_name;
first_db= table->db;
DBUG_ASSERT(first_db);
}
else if (strcmp(first_db, table->db) ||
strcmp(first_table_name, table->table_name))
return 1;
}
}
return 0;
}
...@@ -1418,7 +1418,17 @@ class THD :public Statement, ...@@ -1418,7 +1418,17 @@ class THD :public Statement,
inline void set_current_stmt_binlog_row_based_if_mixed() inline void set_current_stmt_binlog_row_based_if_mixed()
{ {
#ifdef HAVE_ROW_BASED_REPLICATION #ifdef HAVE_ROW_BASED_REPLICATION
if (variables.binlog_format == BINLOG_FORMAT_MIXED) /*
If in a stored/function trigger, the caller should already have done the
change. We test in_sub_stmt to prevent introducing bugs where people
wouldn't ensure that, and would switch to row-based mode in the middle
of executing a stored function/trigger (which is too late, see also
reset_current_stmt_binlog_row_based()); this condition will make their
tests fail and so force them to propagate the
lex->binlog_row_based_if_mixed upwards to the caller.
*/
if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
(in_sub_stmt == 0))
current_stmt_binlog_row_based= TRUE; current_stmt_binlog_row_based= TRUE;
#endif #endif
} }
...@@ -1437,8 +1447,26 @@ class THD :public Statement, ...@@ -1437,8 +1447,26 @@ class THD :public Statement,
inline void reset_current_stmt_binlog_row_based() inline void reset_current_stmt_binlog_row_based()
{ {
#ifdef HAVE_ROW_BASED_REPLICATION #ifdef HAVE_ROW_BASED_REPLICATION
current_stmt_binlog_row_based= /*
test(variables.binlog_format == BINLOG_FORMAT_ROW); If there are temporary tables, don't reset back to
statement-based. Indeed it could be that:
CREATE TEMPORARY TABLE t SELECT UUID(); # row-based
# and row-based does not store updates to temp tables
# in the binlog.
INSERT INTO u SELECT * FROM t; # stmt-based
and then the INSERT will fail as data inserted into t was not logged.
So we continue with row-based until the temp table is dropped.
If we are in a stored function or trigger, we mustn't reset in the
middle of its execution (as the binary logging way of a stored function
or trigger is decided when it starts executing, depending for example on
the caller (for a stored function: if caller is SELECT or
INSERT/UPDATE/DELETE...).
*/
if ((temporary_tables == NULL) && (in_sub_stmt == 0))
{
current_stmt_binlog_row_based=
test(variables.binlog_format == BINLOG_FORMAT_ROW);
}
#else #else
current_stmt_binlog_row_based= FALSE; current_stmt_binlog_row_based= FALSE;
#endif #endif
......
...@@ -183,7 +183,6 @@ void lex_start(THD *thd, const uchar *buf, uint length) ...@@ -183,7 +183,6 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->nest_level=0 ; lex->nest_level=0 ;
lex->allow_sum_func= 0; lex->allow_sum_func= 0;
lex->in_sum_func= NULL; lex->in_sum_func= NULL;
lex->binlog_row_based_if_mixed= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1625,6 +1624,9 @@ void Query_tables_list::reset_query_tables_list(bool init) ...@@ -1625,6 +1624,9 @@ void Query_tables_list::reset_query_tables_list(bool init)
sroutines_list.empty(); sroutines_list.empty();
sroutines_list_own_last= sroutines_list.next; sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0; sroutines_list_own_elements= 0;
#ifdef HAVE_ROW_BASED_REPLICATION
binlog_row_based_if_mixed= FALSE;
#endif
} }
......
...@@ -793,6 +793,16 @@ class Query_tables_list ...@@ -793,6 +793,16 @@ class Query_tables_list
byte **sroutines_list_own_last; byte **sroutines_list_own_last;
uint sroutines_list_own_elements; uint sroutines_list_own_elements;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
Tells if the parsing stage detected that some items require row-based
binlogging to give a reliable binlog/replication, or if we will use
stored functions or triggers which themselves need require row-based
binlogging.
*/
bool binlog_row_based_if_mixed;
#endif
/* /*
These constructor and destructor serve for creation/destruction These constructor and destructor serve for creation/destruction
of Query_tables_list instances which are used as backup storage. of Query_tables_list instances which are used as backup storage.
...@@ -970,11 +980,7 @@ typedef struct st_lex : public Query_tables_list ...@@ -970,11 +980,7 @@ typedef struct st_lex : public Query_tables_list
uint8 create_view_check; uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set; bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog; bool in_comment, ignore_space, verbose, no_write_to_binlog;
/* bool tx_chain, tx_release;
binlog_row_based_if_mixed tells if the parsing stage detected that some
items require row-based binlogging to give a reliable binlog/replication.
*/
bool tx_chain, tx_release, binlog_row_based_if_mixed;
/* /*
Special JOIN::prepare mode: changing of query is prohibited. Special JOIN::prepare mode: changing of query is prohibited.
When creating a view, we need to just check its syntax omitting When creating a view, we need to just check its syntax omitting
......
...@@ -2503,11 +2503,6 @@ mysql_execute_command(THD *thd) ...@@ -2503,11 +2503,6 @@ mysql_execute_command(THD *thd)
statistic_increment(thd->status_var.com_stat[lex->sql_command], statistic_increment(thd->status_var.com_stat[lex->sql_command],
&LOCK_status); &LOCK_status);
#ifdef HAVE_ROW_BASED_REPLICATION
if (lex->binlog_row_based_if_mixed)
thd->set_current_stmt_binlog_row_based_if_mixed();
#endif /*HAVE_ROW_BASED_REPLICATION*/
switch (lex->sql_command) { switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS: case SQLCOM_SHOW_EVENTS:
if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
...@@ -5166,9 +5161,6 @@ mysql_execute_command(THD *thd) ...@@ -5166,9 +5161,6 @@ mysql_execute_command(THD *thd)
*/ */
if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
reset_one_shot_variables(thd); reset_one_shot_variables(thd);
#ifdef HAVE_ROW_BASED_REPLICATION
thd->reset_current_stmt_binlog_row_based();
#endif /*HAVE_ROW_BASED_REPLICATION*/
/* /*
The return value for ROW_COUNT() is "implementation dependent" if the The return value for ROW_COUNT() is "implementation dependent" if the
...@@ -5846,6 +5838,11 @@ void mysql_reset_thd_for_next_command(THD *thd) ...@@ -5846,6 +5838,11 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->rand_used= 0; thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0; thd->sent_row_count= thd->examined_row_count= 0;
} }
#ifdef HAVE_ROW_BASED_REPLICATION
/* If in a routine, we reset only at end of top statement. */
thd->reset_current_stmt_binlog_row_based();
#endif /*HAVE_ROW_BASED_REPLICATION*/
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -997,6 +997,15 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table) ...@@ -997,6 +997,15 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
table->next_global= view_tables; table->next_global= view_tables;
} }
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If the view's body needs row-based binlogging (e.g. the VIEW is created
from SELECT UUID()), the top statement also needs it.
*/
if (lex->binlog_row_based_if_mixed)
old_lex->binlog_row_based_if_mixed= TRUE;
#endif
/* /*
If we are opening this view as part of implicit LOCK TABLES, then If we are opening this view as part of implicit LOCK TABLES, then
this view serves as simple placeholder and we should not continue this view serves as simple placeholder and we should not continue
......
...@@ -6374,7 +6374,7 @@ simple_expr: ...@@ -6374,7 +6374,7 @@ simple_expr:
if (udf->type == UDFTYPE_AGGREGATE) if (udf->type == UDFTYPE_AGGREGATE)
Select->in_sum_expr--; Select->in_sum_expr--;
Lex->binlog_row_based_if_mixed= 1; Lex->binlog_row_based_if_mixed= TRUE;
switch (udf->returns) { switch (udf->returns) {
case STRING_RESULT: case STRING_RESULT:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment