diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_archive.cc | 5 | ||||
-rw-r--r-- | sql/ha_berkeley.cc | 4 | ||||
-rw-r--r-- | sql/ha_blackhole.cc | 4 | ||||
-rw-r--r-- | sql/ha_federated.cc | 4 | ||||
-rw-r--r-- | sql/ha_heap.cc | 4 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 5 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 4 | ||||
-rw-r--r-- | sql/ha_myisammrg.cc | 4 | ||||
-rw-r--r-- | sql/ha_ndbcluster_binlog.cc | 2 | ||||
-rw-r--r-- | sql/ha_partition.cc | 6 | ||||
-rw-r--r-- | sql/handler.cc | 8 | ||||
-rw-r--r-- | sql/handler.h | 7 | ||||
-rw-r--r-- | sql/item_func.cc | 1 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 1 | ||||
-rw-r--r-- | sql/log.cc | 10 | ||||
-rw-r--r-- | sql/log.h | 20 | ||||
-rw-r--r-- | sql/log_event.cc | 6 | ||||
-rw-r--r-- | sql/log_event.h | 8 | ||||
-rw-r--r-- | sql/mysql_priv.h | 4 | ||||
-rw-r--r-- | sql/mysqld.cc | 89 | ||||
-rw-r--r-- | sql/partition_info.cc | 8 | ||||
-rw-r--r-- | sql/set_var.cc | 57 | ||||
-rw-r--r-- | sql/set_var.h | 12 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 10 | ||||
-rw-r--r-- | sql/sp_head.cc | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 2 | ||||
-rw-r--r-- | sql/sql_class.cc | 21 | ||||
-rw-r--r-- | sql/sql_class.h | 15 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 8 | ||||
-rw-r--r-- | sql/sql_load.cc | 7 | ||||
-rw-r--r-- | sql/sql_parse.cc | 1 | ||||
-rw-r--r-- | sql/sql_partition.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 2 | ||||
-rw-r--r-- | sql/sql_table.cc | 18 |
35 files changed, 225 insertions, 138 deletions
diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index 8ed16949edd..a8bc0822a85 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -177,9 +177,10 @@ handlerton archive_hton = { NULL, /* Partition flags */ NULL, /* Alter table flags */ NULL, /* Alter interface */ + NULL, /* fill_files_table */ HTON_NO_FLAGS, - NULL, /* binlog_func */ - NULL /* binlog_log_query */ + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; static handler *archive_create_handler(TABLE_SHARE *table) diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 6866b50fd19..910a703fdeb 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -153,7 +153,9 @@ handlerton berkeley_hton = { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill Files Table */ - HTON_CLOSE_CURSORS_AT_COMMIT | HTON_FLUSH_AFTER_RENAME + HTON_CLOSE_CURSORS_AT_COMMIT | HTON_FLUSH_AFTER_RENAME, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; handler *berkeley_create_handler(TABLE_SHARE *table) diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index 42c785e2003..7d28344a0a4 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -61,7 +61,9 @@ handlerton blackhole_hton= { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill FILES table */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index f7e0c1242fe..976f3739386 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -398,7 +398,9 @@ handlerton federated_hton= { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill FILES table */ - HTON_ALTER_NOT_SUPPORTED + HTON_ALTER_NOT_SUPPORTED, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index d4790cf7d01..96f760a7a44 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -58,7 +58,9 @@ handlerton heap_hton= { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill Files Table */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; static handler *heap_create_handler(TABLE_SHARE *table) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 0002ab0123f..153c456c06c 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -237,8 +237,11 @@ handlerton innobase_hton = { innobase_show_status, /* Show status */ NULL, /* Partition flags */ NULL, /* Alter table flags */ + NULL, /* alter_tablespace */ NULL, /* Fill FILES table */ - HTON_NO_FLAGS + HTON_NO_FLAGS, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 4b84d3efa7f..fba36450d81 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -90,7 +90,9 @@ handlerton myisam_hton= { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill Files Table */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 32b67cd23e5..a24b32435a8 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -68,7 +68,9 @@ handlerton myisammrg_hton= { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill Files Table */ - HTON_CAN_RECREATE + HTON_CAN_RECREATE, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; static handler *myisammrg_create_handler(TABLE_SHARE *table) diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 892a5e02453..72c03819b8a 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -2774,7 +2774,7 @@ pthread_handler_t ndb_binlog_thread_func(void *arg) ndb_binlog_thread_running= 1; if (opt_bin_log) { - if (binlog_row_based) + if (global_system_variables.binlog_format == BINLOG_FORMAT_ROW) { ndb_binlog_running= TRUE; } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 7e92f8a7739..e7a324481db 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -102,7 +102,9 @@ handlerton partition_hton = { alter_table_flags, /* Partition flags */ NULL, /* Alter Tablespace */ NULL, /* Fill FILES table */ - HTON_NOT_USER_SELECTABLE | HTON_HIDDEN + HTON_NOT_USER_SELECTABLE | HTON_HIDDEN, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; /* @@ -2609,7 +2611,7 @@ void ha_partition::unlock_row() ADDITIONAL INFO: Most handlers set timestamp when calling write row if any such fields - exists. Since we are calling an underlying handler we assume the“ + exists. Since we are calling an underlying handler we assume theĀ“ underlying handler will assume this responsibility. Underlying handlers will also call update_auto_increment to calculate diff --git a/sql/handler.cc b/sql/handler.cc index 68ca3855158..3c79a1af8bd 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -64,7 +64,11 @@ const handlerton default_hton = NULL, NULL, NULL, create_default, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - HTON_NO_FLAGS + NULL, /* alter_tablespace */ + NULL, /* fill_files_table */ + HTON_NO_FLAGS, /* flags */ + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; @@ -3147,7 +3151,7 @@ namespace { bool check_table_binlog_row_based(THD *thd, TABLE *table) { return - binlog_row_based && + thd->current_stmt_binlog_row_based && thd && (thd->options & OPTION_BIN_LOG) && (table->s->tmp_table == NO_TMP_TABLE) && binlog_filter->db_ok(table->s->db.str); diff --git a/sql/handler.h b/sql/handler.h index 2d415854d2b..b0cc3116288 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -543,10 +543,9 @@ typedef struct struct st_table_list *tables, class Item *cond); uint32 flags; /* global handler flags */ - /* - Handlerton functions are not set in the different storage - engines static initialization. They are initialized at handler init. - Thus, leave them last in the struct. + /* + Those handlerton functions below are properly initialized at handler + init. */ int (*binlog_func)(THD *thd, enum_binlog_func fn, void *arg); void (*binlog_log_query)(THD *thd, enum_binlog_command binlog_command, diff --git a/sql/item_func.cc b/sql/item_func.cc index 22200732861..d2e0911557f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2657,6 +2657,7 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, u_d->name.str, ER(ER_UNKNOWN_ERROR)); DBUG_RETURN(TRUE); } + thd->set_current_stmt_binlog_row_based_if_mixed(); DBUG_RETURN(FALSE); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index a3e47154bc3..eb89eb7708c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -3002,6 +3002,7 @@ String *Item_func_uuid::val_str(String *str) char *s; THD *thd= current_thd; + thd->set_current_stmt_binlog_row_based_if_mixed(); pthread_mutex_lock(&LOCK_uuid_generator); if (! uuid_time) /* first UUID() call. initializing data */ { diff --git a/sql/log.cc b/sql/log.cc index 323b6df86d9..ff14b986aa4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -102,7 +102,9 @@ handlerton binlog_hton = { NULL, /* Alter table flags */ NULL, /* Alter Tablespace */ NULL, /* Fill FILES table */ - HTON_NOT_USER_SELECTABLE | HTON_HIDDEN + HTON_NOT_USER_SELECTABLE | HTON_HIDDEN, + NULL, /* binlog_func */ + NULL /* binlog_log_query */ }; @@ -2630,7 +2632,7 @@ THD::binlog_set_pending_rows_event(Rows_log_event* ev) int MYSQL_LOG::flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event) { DBUG_ENTER("MYSQL_LOG::flush_and_set_pending_rows_event(event)"); - DBUG_ASSERT(binlog_row_based && mysql_bin_log.is_open()); + DBUG_ASSERT(thd->current_stmt_binlog_row_based && mysql_bin_log.is_open()); DBUG_PRINT("enter", ("event=%p", event)); int error= 0; @@ -2847,7 +2849,7 @@ bool MYSQL_LOG::write(Log_event *event_info) */ if (thd) { - if (!binlog_row_based) + if (!thd->current_stmt_binlog_row_based) { if (thd->last_insert_id_used) { @@ -3517,7 +3519,7 @@ bool MYSQL_LOG::write_table_map(THD *thd, IO_CACHE *file, TABLE* table, table, table->s->table_name, table->s->table_map_id)); /* Pre-conditions */ - DBUG_ASSERT(binlog_row_based && is_open()); + DBUG_ASSERT(thd->current_stmt_binlog_row_based && is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); #ifndef DBUG_OFF diff --git a/sql/log.h b/sql/log.h index 98a86072fca..8a83e7b66d0 100644 --- a/sql/log.h +++ b/sql/log.h @@ -507,4 +507,24 @@ public: void init_general_log(uint general_log_printer); }; + +enum enum_binlog_format { + BINLOG_FORMAT_STMT= 0, // statement-based +#ifdef HAVE_ROW_BASED_REPLICATION + BINLOG_FORMAT_ROW= 1, // row_based + /* + statement-based except for cases where only row-based can work (UUID() + etc): + */ + BINLOG_FORMAT_MIXED= 2, +#endif +/* + This value is last, after the end of binlog_format_typelib: it has no + corresponding cell in this typelib. We use this value to be able to know if + the user has explicitely specified a binlog format at startup or not. +*/ + BINLOG_FORMAT_UNSPEC= 3 +}; +extern TYPELIB binlog_format_typelib; + #endif /* LOG_H */ diff --git a/sql/log_event.cc b/sql/log_event.cc index 5b95b87bcd2..15905731577 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5854,13 +5854,17 @@ int Table_map_log_event::exec_event(st_relay_log_info *rli) (!rpl_filter->is_on() || rpl_filter->tables_ok("", &table_list))) { /* + TODO: Mats will soon change this test below so that a SBR slave always + accepts RBR events from the master (and binlogs them RBR). + */ + /* Check if the slave is set to use SBR. If so, the slave should stop immediately since it is not possible to daisy-chain from RBR to SBR. Once RBR is used, the rest of the chain has to use RBR. */ if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG) && - !binlog_row_based) + !thd->current_stmt_binlog_row_based) { slave_print_msg(ERROR_LEVEL, rli, ER_BINLOG_ROW_RBR_TO_SBR, "It is not possible to use statement-based binlogging " diff --git a/sql/log_event.h b/sql/log_event.h index a7c532d4c24..d7212c5a195 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -28,14 +28,6 @@ #include <my_bitmap.h> -#if !defined(MYSQL_CLIENT) -#ifdef HAVE_ROW_BASED_REPLICATION -extern my_bool binlog_row_based; -#else -extern const my_bool binlog_row_based; -#endif -#endif - #define LOG_READ_EOF -1 #define LOG_READ_BOGUS -2 #define LOG_READ_IO -3 diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8e85e70fccd..4db6dafcd59 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1288,12 +1288,8 @@ extern ulong what_to_log,flush_time; extern ulong query_buff_size, thread_stack; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; -extern const char *opt_binlog_format; #ifdef HAVE_ROW_BASED_REPLICATION -extern my_bool binlog_row_based; extern ulong opt_binlog_rows_event_max_size; -#else -extern const my_bool binlog_row_based; #endif extern ulong rpl_recovery_rank, thread_cache_size; extern ulong back_log; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e1c8ed966ee..1147b8a82cf 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -465,31 +465,14 @@ my_bool opt_noacl; my_bool sp_automatic_privileges= 1; #ifdef HAVE_ROW_BASED_REPLICATION -/* - This variable below serves as an optimization for (opt_binlog_format == - BF_ROW) as we need to do this test for every row. Stmt-based is default. -*/ -my_bool binlog_row_based= FALSE; ulong opt_binlog_rows_event_max_size; -const char *binlog_format_names[]= {"STATEMENT", "ROW", NullS}; -/* - Note that BF_UNSPECIFIED is last, after the end of binlog_format_names: it - has no corresponding cell in this array. We use this value to be able to - know if the user has explicitely specified a binlog format (then we require - also --log-bin) or not (then we fall back to statement-based). -*/ -enum binlog_format { BF_STMT= 0, BF_ROW= 1, BF_UNSPECIFIED= 2 }; +const char *binlog_format_names[]= {"STATEMENT", "ROW", "MIXED", NullS}; #else -const my_bool binlog_row_based= FALSE; const char *binlog_format_names[]= {"STATEMENT", NullS}; -enum binlog_format { BF_STMT= 0, BF_UNSPECIFIED= 2 }; #endif - TYPELIB binlog_format_typelib= { array_elements(binlog_format_names)-1,"", binlog_format_names, NULL }; -const char *opt_binlog_format= 0; -enum binlog_format opt_binlog_format_id= BF_UNSPECIFIED; #ifdef HAVE_INITGROUPS static bool calling_initgroups= FALSE; /* Used in SIGSEGV handler. */ @@ -3187,42 +3170,25 @@ with --log-bin instead."); unireg_abort(1); } - if (!opt_bin_log && (opt_binlog_format_id != BF_UNSPECIFIED)) + if (!opt_bin_log && (global_system_variables.binlog_format != BINLOG_FORMAT_UNSPEC)) { sql_print_warning("You need to use --log-bin to make " "--binlog-format work."); unireg_abort(1); } - if (opt_binlog_format_id == BF_UNSPECIFIED) + if (global_system_variables.binlog_format == BINLOG_FORMAT_UNSPEC) { #ifdef HAVE_NDB_BINLOG if (opt_bin_log && have_ndbcluster == SHOW_OPTION_YES) - opt_binlog_format_id= BF_ROW; + global_system_variables.binlog_format= BINLOG_FORMAT_ROW; else #endif - opt_binlog_format_id= BF_STMT; - } -#ifdef HAVE_ROW_BASED_REPLICATION - if (opt_binlog_format_id == BF_ROW) - { - binlog_row_based= TRUE; - /* - Row-based binlogging turns on InnoDB unsafe locking, because the locks - are not needed when using row-based binlogging. In fact - innodb-locks-unsafe-for-binlog is unsafe only for stmt-based, it's - safe for row-based. - */ -#ifdef HAVE_INNOBASE_DB - innobase_locks_unsafe_for_binlog= TRUE; -#endif - /* Trust stored function creators because they can do no harm */ - trust_function_creators= 1; + global_system_variables.binlog_format= BINLOG_FORMAT_STMT; } -#endif + /* Check that we have not let the format to unspecified at this point */ - DBUG_ASSERT((uint)opt_binlog_format_id <= + DBUG_ASSERT((uint)global_system_variables.binlog_format <= array_elements(binlog_format_names)-1); - opt_binlog_format= binlog_format_names[opt_binlog_format_id]; #ifdef HAVE_REPLICATION if (opt_log_slave_updates && replicate_same_server_id) @@ -4929,23 +4895,23 @@ Disable with --skip-bdb (will save memory).", {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to.", (gptr*) &my_bind_addr_str, (gptr*) &my_bind_addr_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"binlog-format", OPT_BINLOG_FORMAT, + {"binlog_format", OPT_BINLOG_FORMAT, #ifdef HAVE_ROW_BASED_REPLICATION "Tell the master the form of binary logging to use: either 'row' for " - "row-based binary logging (which automatically turns on " - "innodb_locks_unsafe_for_binlog as it is safe in this case), or " - "'statement' for statement-based logging. " + "row-based binary logging, or 'statement' for statement-based binary " + "logging, or 'mixed'. 'mixed' is statement-based binary logging except " + "for those statements where only row-based is correct: those which " + "involve user-defined functions (i.e. UDFs) or the UUID() function; for " + "those, row-based binary logging is automatically used. " #ifdef HAVE_NDB_BINLOG - "If ndbcluster is enabled, the default will be set to 'row'." + "If ndbcluster is enabled, the default is 'row'." #endif - , #else - "Tell the master the form of binary logging to use: this release build " + "Tell the master the form of binary logging to use: this build " "supports only statement-based binary logging, so only 'statement' is " - "a legal value; MySQL-Max release builds support row-based binary logging " - "in addition.", + "a legal value." #endif - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + , 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"binlog-do-db", OPT_BINLOG_DO_DB, "Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -5148,9 +5114,7 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, (gptr*) &innobase_unix_file_flush_method, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_locks_unsafe_for_binlog", OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG, - "Force InnoDB not to use next-key locking, to use only row-level locking." - " This is unsafe if you are using statement-based binary logging, and safe" - " if you are using row-based binary logging.", + "Force InnoDB to not use next-key locking, to use only row-level locking.", (gptr*) &innobase_locks_unsafe_for_binlog, (gptr*) &innobase_locks_unsafe_for_binlog, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"innodb_log_arch_dir", OPT_INNODB_LOG_ARCH_DIR, @@ -5231,8 +5195,9 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, "a stored function (or trigger) is allowed only to users having the SUPER privilege " "and only if this stored function (trigger) may not break binary logging." #ifdef HAVE_ROW_BASED_REPLICATION - " If using --binlog-format=row, the security issues do not exist and the " - "binary logging cannot break so this option is automatically set to 1." + "Note that if ALL connections to this server ALWAYS use row-based binary " + "logging, the security issues do not exist and the binary logging cannot " + "break, so you can safely set this to 1." #endif ,(gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -7070,6 +7035,7 @@ static void mysql_init_variables(void) max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; global_system_variables.old_alter_table= 0; + global_system_variables.binlog_format= BINLOG_FORMAT_UNSPEC; /* Default behavior for 4.1 and 5.0 is to treat NULL values as unequal when collecting index statistics for MyISAM tables. @@ -7314,18 +7280,19 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), #ifdef HAVE_ROW_BASED_REPLICATION fprintf(stderr, "Unknown binary log format: '%s' " - "(should be '%s' or '%s')\n", + "(should be one of '%s', '%s', '%s')\n", argument, - binlog_format_names[BF_STMT], - binlog_format_names[BF_ROW]); + binlog_format_names[BINLOG_FORMAT_STMT], + binlog_format_names[BINLOG_FORMAT_ROW], + binlog_format_names[BINLOG_FORMAT_MIXED]); #else fprintf(stderr, "Unknown binary log format: '%s' (only legal value is '%s')\n", - argument, binlog_format_names[BF_STMT]); + argument, binlog_format_names[BINLOG_FORMAT_STMT]); #endif exit(1); } - opt_binlog_format_id= (enum binlog_format)(id-1); + global_system_variables.binlog_format= id-1; break; } case (int)OPT_BINLOG_DO_DB: diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 5d30dba5fbd..89f54a6497a 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -278,7 +278,7 @@ bool partition_info::has_unique_name(partition_element *element) List_iterator<partition_element> parts_it(partitions); partition_element *el; - while (el= (parts_it++)) + while ((el= (parts_it++))) { if (!(my_strcasecmp(system_charset_info, el->partition_name, name_to_check)) && el != element) @@ -288,7 +288,7 @@ bool partition_info::has_unique_name(partition_element *element) { partition_element *sub_el; List_iterator<partition_element> subparts_it(el->subpartitions); - while (sub_el= (subparts_it++)) + while ((sub_el= (subparts_it++))) { if (!(my_strcasecmp(system_charset_info, sub_el->partition_name, name_to_check)) && sub_el != element) @@ -323,7 +323,7 @@ char *partition_info::has_unique_names() List_iterator<partition_element> parts_it(partitions); partition_element *el; - while (el= (parts_it++)) + while ((el= (parts_it++))) { if (! has_unique_name(el)) DBUG_RETURN(el->partition_name); @@ -332,7 +332,7 @@ char *partition_info::has_unique_names() { List_iterator<partition_element> subparts_it(el->subpartitions); partition_element *subel; - while (subel= (subparts_it++)) + while ((subel= (subparts_it++))) { if (! has_unique_name(subel)) DBUG_RETURN(subel->partition_name); diff --git a/sql/set_var.cc b/sql/set_var.cc index 12f3a61aa4e..7ff3401b102 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -141,6 +141,7 @@ static int check_log_update(THD *thd, set_var *var); static bool set_log_update(THD *thd, set_var *var); static int check_pseudo_thread_id(THD *thd, set_var *var); static bool set_log_bin(THD *thd, set_var *var); +void fix_binlog_format_after_update(THD *thd, enum_var_type type); static void fix_low_priority_updates(THD *thd, enum_var_type type); static int check_tx_isolation(THD *thd, set_var *var); static void fix_tx_isolation(THD *thd, enum_var_type type); @@ -185,6 +186,8 @@ sys_var_bool_ptr sys_automatic_sp_privileges("automatic_sp_privileges", sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size", &binlog_cache_size); +sys_var_thd_binlog_format sys_binlog_format("binlog_format", + &SV::binlog_format); sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size", &SV::bulk_insert_buff_size); sys_var_character_set_server sys_character_set_server("character_set_server"); @@ -653,11 +656,11 @@ static int show_slave_skip_errors(THD *thd, SHOW_VAR *var, char *buff) var->value= buff; if (!use_slave_mask || bitmap_is_clear_all(&slave_error_mask)) { - var->value= "OFF"; + var->value= const_cast<char *>("OFF"); } else if (bitmap_is_set_all(&slave_error_mask)) { - var->value= "ALL"; + var->value= const_cast<char *>("ALL"); } else { @@ -706,7 +709,7 @@ SHOW_VAR init_vars[]= { {"bdb_shared_data", (char*) &berkeley_shared_data, SHOW_BOOL}, {"bdb_tmpdir", (char*) &berkeley_tmpdir, SHOW_CHAR_PTR}, {sys_binlog_cache_size.name,(char*) &sys_binlog_cache_size, SHOW_SYS}, - {"binlog_format", (char*) &opt_binlog_format, SHOW_CHAR_PTR}, + {sys_binlog_format.name, (char*) &sys_binlog_format, SHOW_SYS}, {sys_bulk_insert_buff_size.name,(char*) &sys_bulk_insert_buff_size,SHOW_SYS}, {sys_character_set_client.name,(char*) &sys_character_set_client, SHOW_SYS}, {sys_character_set_connection.name,(char*) &sys_character_set_connection,SHOW_SYS}, @@ -1243,6 +1246,54 @@ extern void fix_delay_key_write(THD *thd, enum_var_type type) } } + +bool sys_var_thd_binlog_format::is_readonly() const +{ + /* + Under certain circumstances, the variable is read-only (unchangeable): + */ + THD *thd= current_thd; + /* + If RBR and open temporary tables, their CREATE TABLE may not be in the + binlog, so we can't toggle to SBR in this connection. + The test below will also prevent SET GLOBAL, well it was not easy to test + if global or not here. + And this test will also prevent switching from RBR to RBR (a no-op which + should not happen too often). + */ + if ((thd->variables.binlog_format == BINLOG_FORMAT_ROW) && + thd->temporary_tables) + { + my_error(ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR, MYF(0)); + return 1; + } + /* + if in a stored function, it's too late to change mode + */ + if (thd->spcont && thd->prelocked_mode) + { + DBUG_ASSERT(thd->variables.binlog_format != BINLOG_FORMAT_ROW); + my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); + return 1; + } +#ifdef HAVE_NDB_BINLOG + /* + Cluster does not support changing the binlog format on the fly yet. + */ + if (opt_bin_log && (have_ndbcluster == SHOW_OPTION_YES)) + { + my_error(ER_NDB_CANT_SWITCH_BINLOG_FORMAT, MYF(0)); + return 1; + } +#endif + return sys_var_thd_enum::is_readonly(); +} + +void fix_binlog_format_after_update(THD *thd, enum_var_type type) +{ + thd->reset_current_stmt_binlog_row_based(); +} + static void fix_max_binlog_size(THD *thd, enum_var_type type) { DBUG_ENTER("fix_max_binlog_size"); diff --git a/sql/set_var.h b/sql/set_var.h index 0961f6d4325..f62d6ce8d2a 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -826,6 +826,18 @@ public: bool update(THD *thd, set_var *var); }; +extern void fix_binlog_format_after_update(THD *thd, enum_var_type type); + +class sys_var_thd_binlog_format :public sys_var_thd_enum +{ +public: + sys_var_thd_binlog_format(const char *name_arg, ulong SV::*offset_arg) + :sys_var_thd_enum(name_arg, offset_arg, + &binlog_format_typelib, + fix_binlog_format_after_update) + {}; + bool is_readonly() const; +}; /**************************************************************************** Classes for parsing of the SET command diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index e1bea5009ff..376f4b7da7a 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5812,8 +5812,12 @@ ER_CANT_CHANGE_TX_ISOLATION 25001 eng "Transaction isolation level can't be changed while a transaction is in progress" ER_WARN_DEPRECATED_STATEMENT eng "The '%s' statement is deprecated and will be removed in MySQL %s. Please use client programs (e.g. %s) instead." - -ER_TABLE_NEEDS_UPGRADE - eng "Table upgrade required. Please do \"REPAIR TABLE `%-.32s`\" to fix it!" ER_SP_NO_AGGREGATE 42000 eng "AGGREGATE is not supported for stored functions" +ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR + eng "Cannot switch out of the row-based binary log format when the session has open temporary tables" +ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT + eng "Cannot change the binary logging format inside a stored function or trigger" +ER_NDB_CANT_SWITCH_BINLOG_FORMAT + eng "The NDB cluster engine does not support changing the binlog format on the fly yet" + diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1f29468a61f..22311322322 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1301,7 +1301,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, each substatement be binlogged its way. */ need_binlog_call= mysql_bin_log.is_open() && - (thd->options & OPTION_BIN_LOG) && !binlog_row_based; + (thd->options & OPTION_BIN_LOG) && !thd->current_stmt_binlog_row_based; if (need_binlog_call) { reset_dynamic(&thd->user_var_events); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c4cb7ddbc4a..e519c976aa4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1189,7 +1189,7 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1, 1); } if (query && found_user_tables && mysql_bin_log.is_open() && - !binlog_row_based) // CREATE TEMP TABLE not binlogged if row-based + !thd->current_stmt_binlog_row_based) // CREATE TEMP TABLE not binlogged if row-based { /* The -1 is to remove last ',' */ thd->clear_error(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e68bcb9e281..4da71593b83 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -329,6 +329,7 @@ void THD::init(void) bzero((char*) warn_count, sizeof(warn_count)); total_warn_count= 0; update_charset(); + reset_current_stmt_binlog_row_based(); bzero((char *) &status_var, sizeof(status_var)); } @@ -2026,12 +2027,12 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, INSERT INTO t1 VALUES (1), (foo()), (2); */ - if (binlog_row_based) + if (current_stmt_binlog_row_based) binlog_flush_pending_rows_event(false); #endif /* HAVE_ROW_BASED_REPLICATION */ if ((!lex->requires_prelocking() || is_update_query(lex->sql_command)) && - !binlog_row_based) + !current_stmt_binlog_row_based) options&= ~OPTION_BIN_LOG; /* Disable result sets */ client_capabilities &= ~CLIENT_MULTI_RESULTS; @@ -2394,7 +2395,7 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, my_size_t colcnt, byte const *record) { - DBUG_ASSERT(binlog_row_based && mysql_bin_log.is_open()); + DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); /* Pack records into format for transfer. We are allocating more @@ -2441,7 +2442,7 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, const byte *before_record, const byte *after_record) { - DBUG_ASSERT(binlog_row_based && mysql_bin_log.is_open()); + DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); bool error= 0; my_size_t const before_maxlen = max_row_length(table, before_record); @@ -2489,7 +2490,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, my_size_t colcnt, byte const *record) { - DBUG_ASSERT(binlog_row_based && mysql_bin_log.is_open()); + DBUG_ASSERT(current_stmt_binlog_row_based && mysql_bin_log.is_open()); /* Pack records into format for transfer. We are allocating more @@ -2520,7 +2521,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, int THD::binlog_flush_pending_rows_event(bool stmt_end) { DBUG_ENTER("THD::binlog_flush_pending_rows_event"); - if (!binlog_row_based || !mysql_bin_log.is_open()) + if (!current_stmt_binlog_row_based || !mysql_bin_log.is_open()) DBUG_RETURN(0); /* @@ -2561,8 +2562,8 @@ void THD::binlog_delete_pending_rows_event() /* Member function that will log query, either row-based or - statement-based depending on the value of the 'binlog_row_based' - variable and the value of the 'qtype' flag. + statement-based depending on the value of the 'current_stmt_binlog_row_based' + the value of the 'qtype' flag. This function should be called after the all calls to ha_*_row() functions have been issued, but before tables are unlocked and @@ -2586,11 +2587,11 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, moving back and forth between using RBR for replication of system tables and not using it. - Make sure to change in check_table_binlog_row_based() according + Make sure to change in check_table_current_stmt_binlog_row_based according to how you treat this. */ case THD::ROW_QUERY_TYPE: - if (binlog_row_based) + if (current_stmt_binlog_row_based) DBUG_RETURN(binlog_flush_pending_rows_event(true)); /* Otherwise, we fall through */ case THD::STMT_QUERY_TYPE: diff --git a/sql/sql_class.h b/sql/sql_class.h index 00440449be8..e7fe8f448d7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -248,13 +248,15 @@ struct system_variables #endif /* HAVE_REPLICATION */ my_bool innodb_table_locks; my_bool innodb_support_xa; - ulong ndb_autoincrement_prefetch_sz; my_bool ndb_force_send; my_bool ndb_use_exact_count; my_bool ndb_use_transactions; my_bool ndb_index_stat_enable; + ulong ndb_autoincrement_prefetch_sz; ulong ndb_index_stat_cache_entries; ulong ndb_index_stat_update_freq; + ulong binlog_format; // binlog format for this thd (see enum_binlog_format) + my_bool old_alter_table; my_bool old_passwords; @@ -1123,6 +1125,8 @@ public: char scramble[SCRAMBLE_LENGTH+1]; bool slave_thread, one_shot_set; + /* tells if current statement should binlog row-based(1) or stmt-based(0) */ + bool current_stmt_binlog_row_based; bool locked, some_tables_deleted; bool last_cuted_field; bool no_errors, password, is_fatal_error; @@ -1377,6 +1381,15 @@ public: void restore_sub_statement_state(Sub_statement_state *backup); void set_n_backup_active_arena(Query_arena *set, Query_arena *backup); void restore_active_arena(Query_arena *set, Query_arena *backup); + inline void set_current_stmt_binlog_row_based_if_mixed() + { + if (variables.binlog_format == BINLOG_FORMAT_MIXED) + current_stmt_binlog_row_based= 1; + } + inline void reset_current_stmt_binlog_row_based() + { + current_stmt_binlog_row_based= test(variables.binlog_format == BINLOG_FORMAT_ROW); + } }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index c9cb1ccd5c2..34947e35b17 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -962,7 +962,7 @@ end: { /* TRUNCATE must always be statement-based binlogged (not row-based) so - we don't test binlog_row_based. + we don't test current_stmt_binlog_row_based. */ thd->clear_error(); thd->binlog_query(THD::STMT_QUERY_TYPE, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 6655491ca57..bd7be110b88 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2411,7 +2411,7 @@ void select_insert::send_error(uint errcode,const char *err) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, table->file->has_transactions(), FALSE); } - if (!binlog_row_based && !table->s->tmp_table) + if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } if (info.copied || info.deleted || info.updated) @@ -2556,7 +2556,7 @@ select_create::binlog_show_create_table() on rollback, we clear the OPTION_STATUS_NO_TRANS_UPDATE bit of thd->options. */ - DBUG_ASSERT(binlog_row_based && !create_table_written); + DBUG_ASSERT(thd->current_stmt_binlog_row_based && !create_table_written); thd->options&= ~OPTION_STATUS_NO_TRANS_UPDATE; char buf[2048]; @@ -2582,7 +2582,7 @@ void select_create::store_values(List<Item> &values) Before writing the first row, we write the CREATE TABLE statement to the binlog. */ - if (binlog_row_based && !create_table_written) + if (thd->current_stmt_binlog_row_based && !create_table_written) { binlog_show_create_table(); create_table_written= TRUE; @@ -2611,7 +2611,7 @@ bool select_create::send_eof() If no rows where written to the binary log, we write the CREATE TABLE statement to the binlog. */ - if (binlog_row_based && !create_table_written) + if (thd->current_stmt_binlog_row_based && !create_table_written) { binlog_show_create_table(); create_table_written= TRUE; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 1d6442ba7d6..e816b792005 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -426,7 +426,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, version for the binary log to mark that table maps are invalid after this point. */ - if (binlog_row_based) + if (thd->current_stmt_binlog_row_based) thd->binlog_flush_pending_rows_event(true); else #endif @@ -491,7 +491,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, version for the binary log to mark that table maps are invalid after this point. */ - if (binlog_row_based) + if (thd->current_stmt_binlog_row_based) thd->binlog_flush_pending_rows_event(true); else #endif @@ -948,7 +948,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs, if (get_it_from_net) cache.read_function = _my_b_net_read; - if (!binlog_row_based && mysql_bin_log.is_open()) + if (((LOAD_FILE_INFO*)cache.arg)->thd->current_stmt_binlog_row_based && + mysql_bin_log.is_open()) cache.pre_read = cache.pre_close = (IO_CACHE_CALLBACK) log_loaded_block; #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b84eb1cfcb8..f779f6e8c21 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4990,6 +4990,7 @@ end_with_restore_list: */ if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) reset_one_shot_variables(thd); + thd->reset_current_stmt_binlog_row_based(); /* The return value for ROW_COUNT() is "implementation dependent" if the diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 7f4518c2b85..e6b26223752 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -697,7 +697,7 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type, my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); goto end; } - if (same_name= part_info->has_unique_names()) + if ((same_name= part_info->has_unique_names())) { my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name); goto end; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b8ab46f21cb..66cc0db6ac7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1654,7 +1654,7 @@ static int show_var_cmp(const void *var1, const void *var2) */ static void shrink_var_array(DYNAMIC_ARRAY *array) { - int a,b; + uint a,b; SHOW_VAR *all= dynamic_element(array, 0, SHOW_VAR *); for (a= b= 0; b < array->elements; b++) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 2737e9448f9..861d7ffeb8f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -565,7 +565,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, String built_query; DBUG_ENTER("mysql_rm_table_part2"); - if (binlog_row_based && !dont_log_query) + if (thd->current_stmt_binlog_row_based && !dont_log_query) { built_query.set_charset(system_charset_info); if (if_exists) @@ -612,7 +612,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, being built. The string always end in a comma and the comma will be chopped off before being written to the binary log. */ - if (binlog_row_based && !dont_log_query) + if (thd->current_stmt_binlog_row_based && !dont_log_query) { ++non_temp_tables_count; /* @@ -722,7 +722,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, query_cache_invalidate3(thd, tables, 0); if (!dont_log_query) { - if (!binlog_row_based || + if (!thd->current_stmt_binlog_row_based || non_temp_tables_count > 0 && !tmp_table_deleted) { /* @@ -734,7 +734,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, */ write_bin_log(thd, !error, thd->query, thd->query_length); } - else if (binlog_row_based && + else if (thd->current_stmt_binlog_row_based && non_temp_tables_count > 0 && tmp_table_deleted) { @@ -2248,8 +2248,8 @@ bool mysql_create_table_internal(THD *thd, Otherwise, the statement shall be binlogged. */ if (!internal_tmp_table && - (!binlog_row_based || - (binlog_row_based && + (!thd->current_stmt_binlog_row_based || + (thd->current_stmt_binlog_row_based && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) write_bin_log(thd, TRUE, thd->query, thd->query_length); error= FALSE; @@ -3475,7 +3475,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* We have to write the query before we unlock the tables. */ - if (binlog_row_based) + if (thd->current_stmt_binlog_row_based) { /* Since temporary tables are not replicated under row-based @@ -4861,7 +4861,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err; } /* We don't replicate alter table statement on temporary tables */ - if (!binlog_row_based) + if (!thd->current_stmt_binlog_row_based) write_bin_log(thd, TRUE, thd->query, thd->query_length); goto end_temporary; } @@ -5031,7 +5031,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, thd->query, thd->query_length, db, table_name); - DBUG_ASSERT(!(mysql_bin_log.is_open() && binlog_row_based && + DBUG_ASSERT(!(mysql_bin_log.is_open() && thd->current_stmt_binlog_row_based && (create_info->options & HA_LEX_CREATE_TMP_TABLE))); write_bin_log(thd, TRUE, thd->query, thd->query_length); /* |