diff options
author | Alexander Nozdrin <alik@sun.com> | 2010-01-30 22:13:36 +0300 |
---|---|---|
committer | Alexander Nozdrin <alik@sun.com> | 2010-01-30 22:13:36 +0300 |
commit | 85c54dddc7f6303b0e48f6d9fb9c0c7561292e4b (patch) | |
tree | fa297f7fa59f84c3c05e83388795c51d18dd89a7 /sql | |
parent | a59e381efabf9733a300ed3be322aefaede88d44 (diff) | |
parent | 788c28aceb023702282bfbf372016da79f9ab49f (diff) | |
download | mariadb-git-85c54dddc7f6303b0e48f6d9fb9c0c7561292e4b.tar.gz |
Manual merge from mysql-5.1-bugteam.
Conflicts:
- mysql-test/collections/default.experimental
- mysql-test/suite/rpl/r/rpl_binlog_grant.result
- mysql-test/suite/rpl/r/rpl_sp.result
- mysql-test/suite/rpl/t/rpl_binlog_grant.test
- mysql-test/suite/rpl/t/rpl_get_master_version_and_clock.test
Diffstat (limited to 'sql')
-rw-r--r-- | sql/events.cc | 79 | ||||
-rw-r--r-- | sql/field.h | 7 | ||||
-rw-r--r-- | sql/filesort.cc | 2 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 37 | ||||
-rw-r--r-- | sql/item_strfunc.h | 4 | ||||
-rw-r--r-- | sql/log_event.cc | 39 | ||||
-rw-r--r-- | sql/log_event.h | 17 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/mysqld.cc | 42 | ||||
-rw-r--r-- | sql/rpl_injector.cc | 12 | ||||
-rw-r--r-- | sql/rpl_record.cc | 17 | ||||
-rw-r--r-- | sql/sql_acl.cc | 124 | ||||
-rw-r--r-- | sql/sql_db.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.h | 25 | ||||
-rw-r--r-- | sql/sql_parse.cc | 6 | ||||
-rw-r--r-- | sql/sql_select.cc | 13 | ||||
-rw-r--r-- | sql/sql_table.cc | 2 | ||||
-rw-r--r-- | sql/sql_test.cc | 24 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 36 |
19 files changed, 379 insertions, 111 deletions
diff --git a/sql/events.cc b/sql/events.cc index f6c4ea6d54f..a8f9a108161 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -341,31 +341,48 @@ common_1_lev_code: } -/** - Create a new query string for removing executable comments - for avoiding leak and keeping consistency of the execution - on master and slave. - +/* + Binlog '{CREATE|ALTER} EVENT' statements. + Definer part is always rewritten, for definer can be CURRENT_USER() function. + @param[in] thd Thread handler - @param[in] buf Query string + @param[in] create CREATE or ALTER statement @return - 0 ok - 1 error + FASE ok + TRUE error */ -static int -create_query_string(THD *thd, String *buf) +static bool event_write_bin_log(THD *thd, bool create) { - /* Append the "CREATE" part of the query */ - if (buf->append(STRING_WITH_LEN("CREATE "))) - return 1; - /* Append definer */ - append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); + String log_query; + if (create) + { + /* Append the "CREATE" part of the query */ + if (log_query.append(STRING_WITH_LEN("CREATE "))) + return TRUE; + } + else + { + /* Append the "ALETR " part of the query */ + if (log_query.append(STRING_WITH_LEN("ALTER "))) + return TRUE; + } + + /* Append definer + If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER + will be written into the binary log as the definer for the SQL thread. + */ + append_definer(thd, &log_query, &(thd->lex->definer->user), + &(thd->lex->definer->host)); + /* Append the left part of thd->query after "DEFINER" part */ - if (buf->append(thd->lex->stmt_definition_begin)) - return 1; - - return 0; + if (log_query.append(thd->lex->stmt_definition_begin, + thd->lex->stmt_definition_end - + thd->lex->stmt_definition_begin)) + return TRUE; + + return write_bin_log(thd, TRUE, log_query.c_ptr_safe(), log_query.length()) + != 0; } /** @@ -380,8 +397,7 @@ create_query_string(THD *thd, String *buf) @sa Events::drop_event for the notes about locking, pre-locking and Events DDL. - @retval FALSE OK - @retval TRUE Error (reported) + @retval FALSE OK @retval TRUE Error (reported) */ bool @@ -465,22 +481,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, binlog the create event unless it's been successfully dropped */ if (!dropped) - { - /* Binlog the create event. */ - DBUG_ASSERT(thd->query() && thd->query_length()); - String log_query; - if (create_query_string(thd, &log_query)) - { - sql_print_error("Event Error: An error occurred while creating query string, " - "before writing it into binary log."); - /* Restore the state of binlog format */ - thd->current_stmt_binlog_row_based= save_binlog_row_based; - DBUG_RETURN(TRUE); - } - /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER - will be written into the binary log as the definer for the SQL thread. */ - ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length()); - } + ret= event_write_bin_log(thd, TRUE); } pthread_mutex_unlock(&LOCK_event_metadata); /* Restore the state of binlog format */ @@ -602,9 +603,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, if (event_queue) event_queue->update_event(thd, parse_data->dbname, parse_data->name, new_element); - /* Binlog the alter event. */ - DBUG_ASSERT(thd->query() && thd->query_length()); - ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + ret= event_write_bin_log(thd, FALSE); } } pthread_mutex_unlock(&LOCK_event_metadata); diff --git a/sql/field.h b/sql/field.h index 159e4bf707c..8cfed9647f7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1929,7 +1929,12 @@ public: uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } - int reset(void) { bzero(ptr, bytes_in_rec); return 0; } + int reset(void) { + bzero(ptr, bytes_in_rec); + if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits + clr_rec_bits(bit_ptr, bit_ofs, bit_len); + return 0; + } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr); int store(longlong nr, bool unsigned_val); diff --git a/sql/filesort.cc b/sql/filesort.cc index 8f18471b378..9528d10dba7 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -145,6 +145,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, error= 1; bzero((char*) ¶m,sizeof(param)); param.sort_length= sortlength(thd, sortorder, s_length, &multi_byte_charset); + /* filesort cannot handle zero-length records. */ + DBUG_ASSERT(param.sort_length); param.ref_length= table->file->ref_length; param.addon_field= 0; param.addon_length= 0; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 3cb978381ef..990f2ef951e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -42,6 +42,20 @@ C_MODE_END String my_empty_string("",default_charset_info); +/* + Convert an array of bytes to a hexadecimal representation. + + Used to generate a hexadecimal representation of a message digest. +*/ +static void array_to_hex(char *to, const char *str, uint len) +{ + const char *str_end= str + len; + for (; str != str_end; ++str) + { + *to++= _dig_vec_lower[((uchar) *str) >> 4]; + *to++= _dig_vec_lower[((uchar) *str) & 0x0F]; + } +} bool Item_str_func::fix_fields(THD *thd, Item **ref) @@ -114,12 +128,7 @@ String *Item_func_md5::val_str(String *str) null_value=1; return 0; } - sprintf((char *) str->ptr(), - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - digest[0], digest[1], digest[2], digest[3], - digest[4], digest[5], digest[6], digest[7], - digest[8], digest[9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15]); + array_to_hex((char *) str->ptr(), (const char*) digest, 16); str->length((uint) 32); return str; } @@ -160,15 +169,7 @@ String *Item_func_sha::val_str(String *str) if (!( str->alloc(SHA1_HASH_SIZE*2) || (mysql_sha1_result(&context,digest)))) { - sprintf((char *) str->ptr(), - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\ -%02x%02x%02x%02x%02x%02x%02x%02x", - digest[0], digest[1], digest[2], digest[3], - digest[4], digest[5], digest[6], digest[7], - digest[8], digest[9], digest[10], digest[11], - digest[12], digest[13], digest[14], digest[15], - digest[16], digest[17], digest[18], digest[19]); - + array_to_hex((char *) str->ptr(), (const char*) digest, SHA1_HASH_SIZE); str->length((uint) SHA1_HASH_SIZE*2); null_value=0; return str; @@ -1764,19 +1765,19 @@ String *Item_func_encode::val_str(String *str) null_value= 0; res= copy_if_not_alloced(str, res, res->length()); - transform(res); + crypto_transform(res); sql_crypt.reinit(); return res; } -void Item_func_encode::transform(String *res) +void Item_func_encode::crypto_transform(String *res) { sql_crypt.encode((char*) res->ptr(),res->length()); res->set_charset(&my_charset_bin); } -void Item_func_decode::transform(String *res) +void Item_func_decode::crypto_transform(String *res) { sql_crypt.decode((char*) res->ptr(),res->length()); } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index ced164554e4..09a7da021c0 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -366,7 +366,7 @@ public: void fix_length_and_dec(); const char *func_name() const { return "encode"; } protected: - virtual void transform(String *); + virtual void crypto_transform(String *); private: /** Provide a seed for the PRNG sequence. */ bool seed(); @@ -379,7 +379,7 @@ public: Item_func_decode(Item *a, Item *seed): Item_func_encode(a, seed) {} const char *func_name() const { return "decode"; } protected: - void transform(String *); + void crypto_transform(String *); }; diff --git a/sql/log_event.cc b/sql/log_event.cc index 3fc331e0683..b6c84dd95f4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2296,10 +2296,22 @@ bool Query_log_event::write(IO_CACHE* file) int8store(start, table_map_for_update); start+= 8; } + if (master_data_written != 0) + { + /* + Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master + has binlog_version<4 and the slave has binlog_version=4. See comment + for master_data_written in log_event.h for details. + */ + *start++= Q_MASTER_DATA_WRITTEN_CODE; + int4store(start, master_data_written); + start+= 4; + } + /* NOTE: When adding new status vars, please don't forget to update - the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function - code_name in this file. + the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function + code_name() in this file. Here there could be code like if (command-line-option-which-says-"log_this_variable" && inited) @@ -2375,7 +2387,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, auto_increment_offset(thd_arg->variables.auto_increment_offset), lc_time_names_number(thd_arg->variables.lc_time_names->number), charset_database_number(0), - table_map_for_update((ulonglong)thd_arg->table_map_for_update) + table_map_for_update((ulonglong)thd_arg->table_map_for_update), + master_data_written(0) { time_t end_time; @@ -2515,6 +2528,7 @@ code_name(int code) case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE"; case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE"; case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE"; + case Q_MASTER_DATA_WRITTEN_CODE: return "Q_MASTER_DATA_WRITTEN_CODE"; } sprintf(buf, "CODE#%d", code); return buf; @@ -2552,7 +2566,7 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, flags2_inited(0), sql_mode_inited(0), charset_inited(0), auto_increment_increment(1), auto_increment_offset(1), time_zone_len(0), lc_time_names_number(0), charset_database_number(0), - table_map_for_update(0) + table_map_for_update(0), master_data_written(0) { ulong data_len; uint32 tmp; @@ -2608,6 +2622,18 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u", (uint) status_vars_len)); tmp-= 2; + } + else + { + /* + server version < 5.0 / binlog_version < 4 master's event is + relay-logged with storing the original size of the event in + Q_MASTER_DATA_WRITTEN_CODE status variable. + The size is to be restored at reading Q_MASTER_DATA_WRITTEN_CODE-marked + event from the relay log. + */ + DBUG_ASSERT(description_event->binlog_version < 4); + master_data_written= data_written; } /* We have parsed everything we know in the post header for QUERY_EVENT, @@ -2699,6 +2725,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, table_map_for_update= uint8korr(pos); pos+= 8; break; + case Q_MASTER_DATA_WRITTEN_CODE: + CHECK_SPACE(pos, end, 4); + data_written= master_data_written= uint4korr(pos); + pos+= 4; + break; default: /* That's why you must write status vars in growing order of code */ DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\ diff --git a/sql/log_event.h b/sql/log_event.h index 1fdd7a05968..0dcc5ebc71f 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -264,7 +264,8 @@ struct sql_ex_info 1 + 1 + 255 /* type, length, time_zone */ + \ 1 + 2 /* type, lc_time_names_number */ + \ 1 + 2 /* type, charset_database_number */ + \ - 1 + 8 /* type, table_map_for_update */) + 1 + 8 /* type, table_map_for_update */ + \ + 1 + 4 /* type, master_data_written */) #define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \ LOG_EVENT_HEADER_LEN + /* write_header */ \ QUERY_HEADER_LEN + /* write_data */ \ @@ -331,6 +332,10 @@ struct sql_ex_info #define Q_TABLE_MAP_FOR_UPDATE_CODE 9 +#define Q_MASTER_DATA_WRITTEN_CODE 10 + +/* Intvar event post-header */ + /* Intvar event data */ #define I_TYPE_OFFSET 0 #define I_VAL_OFFSET 1 @@ -1641,6 +1646,16 @@ public: statement, for other query statements, this will be zero. */ ulonglong table_map_for_update; + /* + Holds the original length of a Query_log_event that comes from a + master of version < 5.0 (i.e., binlog_version < 4). When the IO + thread writes the relay log, it augments the Query_log_event with a + Q_MASTER_DATA_WRITTEN_CODE status_var that holds the original event + length. This field is initialized to non-zero in the SQL thread when + it reads this augmented event. SQL thread does not write + Q_MASTER_DATA_WRITTEN_CODE to the slave's server binlog. + */ + uint32 master_data_written; #ifndef MYSQL_CLIENT diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 30eaf17d7a4..5714db92af0 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -134,7 +134,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); (Old), (Ver), (New)); \ else \ sql_print_warning("The syntax '%s' is deprecated and will be removed " \ - "in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \ + "in a future release. Please use %s instead.", (Old), (New)); \ } while(0) extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index aad06cd5445..57a00a3f4d0 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1978,10 +1978,10 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); + DBUG_LEAVE; // Must match DBUG_ENTER() my_thread_end(); (void) pthread_cond_broadcast(&COND_thread_count); - DBUG_LEAVE; // Must match DBUG_ENTER() pthread_exit(0); return 0; // Avoid compiler warnings } @@ -5744,6 +5744,9 @@ enum options_mysqld OPT_TABLE_LOCK_WAIT_TIMEOUT, OPT_PLUGIN_LOAD, OPT_PLUGIN_DIR, + OPT_SYMBOLIC_LINKS, + OPT_WARNINGS, + OPT_RECORD_BUFFER_OLD, OPT_LOG_OUTPUT, OPT_PORT_OPEN_TIMEOUT, OPT_PROFILING, @@ -6577,7 +6580,7 @@ log and this option does nothing anymore.", {"transaction-isolation", OPT_TX_ISOLATION, "Default transaction isolation level.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"use-symbolic-links", 's', "Enable symbolic link support. Deprecated option; use --symbolic-links instead.", + {"use-symbolic-links", OPT_SYMBOLIC_LINKS, "Enable symbolic link support. Deprecated option; use --symbolic-links instead.", (uchar**) &my_use_symdir, (uchar**) &my_use_symdir, 0, GET_BOOL, NO_ARG, IF_PURIFY(0,1), 0, 0, 0, 0, 0}, {"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG, @@ -6587,7 +6590,7 @@ log and this option does nothing anymore.", 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"warnings", 'W', "Deprecated; use --log-warnings instead.", + {"warnings", OPT_WARNINGS, "Deprecated; use --log-warnings instead.", (uchar**) &global_system_variables.log_warnings, (uchar**) &max_system_variables.log_warnings, 0, GET_ULONG, OPT_ARG, 1, 0, ULONG_MAX, 0, 0, 0}, @@ -6840,7 +6843,8 @@ The minimum value for this variable is 4096.", (uchar**) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, 6, 2, 7, 0, 1, 0}, {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, - "Deprecated option", + "This is a deprecated option that does nothing anymore. It will be removed in MySQL " + VER_CELOSIA, (uchar**) &global_system_variables.myisam_max_extra_sort_file_size, (uchar**) &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH, @@ -6997,8 +7001,8 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.read_rnd_buff_size, 0, GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, - {"record_buffer", OPT_RECORD_BUFFER, - "Alias for read_buffer_size", + {"record_buffer", OPT_RECORD_BUFFER_OLD, + "Alias for read_buffer_size. This variable is deprecated and will be removed in a future release.", (uchar**) &global_system_variables.read_buff_size, (uchar**) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, INT_MAX32, MALLOC_OVERHEAD, IO_SIZE, 0}, @@ -8067,6 +8071,9 @@ mysqld_get_one_option(int optid, print_version(); exit(0); #endif /*EMBEDDED_LIBRARY*/ + case OPT_WARNINGS: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--warnings", "--log-warnings"); + /* Note: fall-through to 'W' */ case 'W': if (!argument) global_system_variables.log_warnings++; @@ -8088,6 +8095,9 @@ mysqld_get_one_option(int optid, case (int) OPT_LOG_BIN_TRUST_FUNCTION_CREATORS_OLD: WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-bin-trust-routine-creators", "--log-bin-trust-function-creators"); break; + case (int) OPT_ENABLE_LOCK: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--enable-locking", "--external-locking"); + break; case (int) OPT_BIG_TABLES: thd_startup_options|=OPTION_BIG_TABLES; break; @@ -8098,6 +8108,7 @@ mysqld_get_one_option(int optid, opt_myisam_log=1; break; case (int) OPT_UPDATE_LOG: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--log-update", "--log-bin"); opt_update_log=1; break; case (int) OPT_BIN_LOG: @@ -8266,8 +8277,18 @@ mysqld_get_one_option(int optid, "give threads different priorities."); break; case (int) OPT_SKIP_LOCK: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-locking", "--skip-external-locking"); opt_external_locking=0; break; + case (int) OPT_SQL_BIN_UPDATE_SAME: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--sql-bin-update-same", "the binary log"); + break; + case (int) OPT_RECORD_BUFFER_OLD: + WARN_DEPRECATED(NULL, VER_CELOSIA, "record_buffer", "read_buffer_size"); + break; + case (int) OPT_SYMBOLIC_LINKS: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--use-symbolic-links", "--symbolic-links"); + break; case (int) OPT_SKIP_HOST_CACHE: opt_specialflag|= SPECIAL_NO_HOST_CACHE; break; @@ -8293,6 +8314,7 @@ mysqld_get_one_option(int optid, test_flags|=TEST_NO_STACKTRACE; break; case (int) OPT_SKIP_SYMLINKS: + WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-symlink", "--skip-symbolic-links"); my_use_symdir=0; break; case (int) OPT_BIND_ADDRESS: @@ -8368,6 +8390,9 @@ mysqld_get_one_option(int optid, server_id_supplied = 1; break; case OPT_DELAY_KEY_WRITE_ALL: + WARN_DEPRECATED(NULL, VER_CELOSIA, + "--delay-key-write-for-all-tables", + "--delay-key-write=ALL"); if (argument != disabled_my_option) argument= (char*) "ALL"; /* Fall through */ @@ -8383,6 +8408,11 @@ mysqld_get_one_option(int optid, delay_key_write_options= (uint) type-1; } break; + case OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE: + sql_print_warning("--myisam_max_extra_sort_file_size is deprecated and " + "does nothing in this version. It will be removed in " + "a future release."); + break; case OPT_CHARSETS_DIR: strmake(mysql_charsets_dir, argument, sizeof(mysql_charsets_dir)-1); charsets_dir = mysql_charsets_dir; diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index 666622dbac4..43f4e7d849d 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -114,8 +114,8 @@ int injector::transaction::write_row (server_id_type sid, table tbl, { DBUG_ENTER("injector::transaction::write_row(...)"); - int error= 0; - if (error= check_state(ROW_STATE)) + int error= check_state(ROW_STATE); + if (error) DBUG_RETURN(error); server_id_type save_id= m_thd->server_id; @@ -133,8 +133,8 @@ int injector::transaction::delete_row(server_id_type sid, table tbl, { DBUG_ENTER("injector::transaction::delete_row(...)"); - int error= 0; - if (error= check_state(ROW_STATE)) + int error= check_state(ROW_STATE); + if (error) DBUG_RETURN(error); server_id_type save_id= m_thd->server_id; @@ -152,8 +152,8 @@ int injector::transaction::update_row(server_id_type sid, table tbl, { DBUG_ENTER("injector::transaction::update_row(...)"); - int error= 0; - if (error= check_state(ROW_STATE)) + int error= check_state(ROW_STATE); + if (error) DBUG_RETURN(error); server_id_type save_id= m_thd->server_id; diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 8e80620dd2c..3a46bbcd6ee 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -231,6 +231,22 @@ unpack_row(Relay_log_info const *rli, { DBUG_PRINT("debug", ("Was NULL; null mask: 0x%x; null bits: 0x%x", null_mask, null_bits)); + /** + Calling reset just in case one is unpacking on top a + record with data. + + This could probably go into set_null() but doing so, + (i) triggers assertion in other parts of the code at + the moment; (ii) it would make us reset the field, + always when setting null, which right now doesn't seem + needed anywhere else except here. + + TODO: maybe in the future we should consider moving + the reset to make it part of set_null. But then + the assertions triggered need to be + addressed/revisited. + */ + f->reset(); f->set_null(); } else @@ -366,7 +382,6 @@ int prepare_record(TABLE *const table, */ for (Field **field_ptr= table->field+skip; *field_ptr; ++field_ptr) { - uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG; Field *const f= *field_ptr; if ((f->flags & NO_DEFAULT_VALUE_FLAG) && (f->real_type() != MYSQL_TYPE_ENUM)) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ea781080a38..2787f3d297d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -194,6 +194,7 @@ static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); static my_bool acl_load(THD *thd, TABLE_LIST *tables); static my_bool grant_load(THD *thd, TABLE_LIST *tables); +static bool acl_write_bin_log(THD *thd, List <LEX_USER> &list, bool clear_error); /* Convert scrambled password to binary form, according to scramble type, @@ -3228,7 +3229,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!result) /* success */ { - result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + if (acl_write_bin_log(thd, user_list, TRUE)) + result= -1; } rw_unlock(&LOCK_grant); @@ -3404,8 +3406,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (write_to_binlog) { - if (write_bin_log(thd, FALSE, thd->query(), thd->query_length())) - result= TRUE; + result|= acl_write_bin_log(thd, user_list, FALSE); } rw_unlock(&LOCK_grant); @@ -3534,7 +3535,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (!result) { - result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + result= acl_write_bin_log(thd, list, TRUE); } rw_unlock(&LOCK_grant); @@ -5776,9 +5777,9 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop, } -static void append_user(String *str, LEX_USER *user) +static void append_user(String *str, LEX_USER *user, bool comma= TRUE) { - if (str->length()) + if (comma && str->length()) str->append(','); str->append('\''); str->append(user->user.str); @@ -5787,6 +5788,65 @@ static void append_user(String *str, LEX_USER *user) str->append('\''); } +/* + The operations(DROP, RENAME, REVOKE, GRANT) will cause inconsistency between + master and slave, when CURRENT_USER() is used. To solve this problem, we + construct a new binlog statement in which CURRENT_USER() is replaced by + the real user name and host name. + */ +static bool acl_write_bin_log(THD *thd, List <LEX_USER> &list, bool clear_error) +{ + String log_query; + LEX *lex= thd->lex; + List_iterator <LEX_USER> user_list(list); + LEX_USER *user, *tmp_user; + + if (!mysql_bin_log.is_open()) + return FALSE; + + if (log_query.append(lex->stmt_begin, lex->stmt_user_begin - lex->stmt_begin)) + return TRUE; + while ((tmp_user= user_list++)) + { + if (!(user= get_current_user(thd, tmp_user))) + continue; + + /* + No User, but a password? + They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... ! + Get the current user, and shallow-copy the new password to them! + */ + if (!tmp_user->user.str && tmp_user->password.str) + user->password= tmp_user->password; + + if (log_query.append(" ", 1)) + return TRUE; + append_user(&log_query, user, FALSE); + /* Only 'GRANT' have password */ + if (user->password.str) + { + if (log_query.append(STRING_WITH_LEN(" IDENTIFIED BY ")) || + log_query.append(STRING_WITH_LEN("PASSWORD ")) || + log_query.append("'", 1) || + log_query.append(user->password.str, + user->password.length) || + log_query.append("'", 1)) + return TRUE; + } + if (log_query.append(",", 1)) + return TRUE; + } + /* It is binlogged only when at least one user is in the query */ + if (log_query.c_ptr()[log_query.length()-1] == ',') + { + log_query.length(log_query.length()-1); + if (log_query.append(lex->stmt_user_end, lex->stmt_end - lex->stmt_user_end)) + return TRUE; + return write_bin_log(thd, clear_error, log_query.c_ptr_safe(), + log_query.length()) != 0; + } + return FALSE; +} /* Create a list of users. @@ -5893,6 +5953,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) { int result; String wrong_users; + String log_query; LEX_USER *user_name, *tmp_user_name; List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; @@ -5922,6 +5983,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); + log_query.append(STRING_WITH_LEN("DROP USER")); while ((tmp_user_name= user_list++)) { if (!(user_name= get_current_user(thd, tmp_user_name))) @@ -5929,6 +5991,17 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) result= TRUE; continue; } + + /* + The operation will cause inconsistency between master and slave, when + CURRENT_USER() is used. To solve this problem, we construct a new + binlog statement in which CURRENT_USER() is replaced by the real user + name and host name. + */ + log_query.append(STRING_WITH_LEN(" ")); + append_user(&log_query, user_name, FALSE); + log_query.append(STRING_WITH_LEN(",")); + if (handle_grant_data(tables, 1, user_name, NULL) <= 0) { append_user(&wrong_users, user_name); @@ -5947,7 +6020,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); if (some_users_deleted) - result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); + { + if (log_query.c_ptr()[log_query.length()-1] == ',') + { + log_query.length(log_query.length()-1); + result|= write_bin_log(thd, FALSE, log_query.c_ptr_safe(), log_query.length()); + } + } rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5975,6 +6054,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) { int result; String wrong_users; + String log_query; LEX_USER *user_from, *tmp_user_from; LEX_USER *user_to, *tmp_user_to; List_iterator <LEX_USER> user_list(list); @@ -6002,6 +6082,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); + log_query.append(STRING_WITH_LEN("RENAME USER")); while ((tmp_user_from= user_list++)) { if (!(user_from= get_current_user(thd, tmp_user_from))) @@ -6018,6 +6099,18 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) DBUG_ASSERT(user_to != 0); /* Syntax enforces pairs of users. */ /* + The operation will cause inconsistency between master and slave, when + CURRENT_USER() is used. To solve this problem, we construct a new + binlog statement in which CURRENT_USER() is replaced by the real user + name and host name. + */ + log_query.append(STRING_WITH_LEN(" ")); + append_user(&log_query, user_from, FALSE); + log_query.append(STRING_WITH_LEN(" TO ")); + append_user(&log_query, user_to, FALSE); + log_query.append(STRING_WITH_LEN(",")); + + /* Search all in-memory structures and grant tables for a mention of the new user name. */ @@ -6038,9 +6131,15 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) if (result) my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); - - if (some_users_renamed && mysql_bin_log.is_open()) - result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); + + if (some_users_renamed) + { + if (log_query.c_ptr()[log_query.length()-1] == ',') + { + log_query.length(log_query.length()-1); + result|= write_bin_log(thd, FALSE, log_query.c_ptr_safe(), log_query.length()); + } + } rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -6230,8 +6329,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - int binlog_error= - write_bin_log(thd, FALSE, thd->query(), thd->query_length()); + int binlog_error= 0; + if (acl_write_bin_log(thd, list, FALSE)) + binlog_error= 1; rw_unlock(&LOCK_grant); close_thread_tables(thd); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index cac22c0a053..71054c923ca 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -829,7 +829,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) qinfo.db_len = strlen(db); /* These DDL methods and logging protected with LOCK_mysql_create_db */ - if (error= mysql_bin_log.write(&qinfo)) + if ((error= mysql_bin_log.write(&qinfo))) goto exit; } my_ok(thd, result); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4bf8cd41aee..13a289eac1d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1799,6 +1799,8 @@ struct LEX: public Query_tables_list - CREATE TRIGGER (points to "TRIGGER"); - CREATE PROCEDURE (points to "PROCEDURE"); - CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE"); + - CREATE VIEW(points to "VIEW"); + - CREATE EVENT(points to "EVENT"); This pointer is required to add possibly omitted DEFINER-clause to the DDL-statement before dumping it to the binlog. @@ -1807,6 +1809,29 @@ struct LEX: public Query_tables_list const char *stmt_definition_end; + /* + stmt_begin is intended to point to the begin of every statement. + It is now used in the following statements: + - GRANT ALL PRIVELEGES ON *.* (points to "GRANT"); + - REVOKE ALL PRIVELEGES ON *.* (points to "REVOKE"); + */ + const char *stmt_begin; + const char *stmt_end; + + /* + stmt_user_begin is intended to point to the begin of the user list in + the following statements: + - GRANT ALL PRIVELEGES ON *.* TO 'username'@'hostname' + (points to "'username'"); + - REVOKE ALL PRIVELEGES ON *.* FROM 'username'@'hostname' + (points to "'username'"); + + these pointers are required to replace the CURRENT_USER() + function by the real user before dumping it to the binlog. + */ + const char *stmt_user_begin; + const char *stmt_user_end; + /** During name resolution search only in the table list given by Name_resolution_context::first_name_resolution_table and diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6bb01f0b50c..96e4fb05988 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3490,9 +3490,9 @@ end_with_restore_list: select_lex->where, 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, (ORDER *)NULL, - select_lex->options | thd->options | + (select_lex->options | thd->options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | - OPTION_SETUP_TABLES_DONE, + OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, del_result, unit, select_lex); res|= thd->is_error(); MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted()); @@ -4127,7 +4127,7 @@ end_with_restore_list: */ if (!lex->no_write_to_binlog && write_to_binlog) { - if (res= write_bin_log(thd, FALSE, thd->query(), thd->query_length())) + if ((res= write_bin_log(thd, FALSE, thd->query(), thd->query_length()))) break; } my_ok(thd); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index cb4a9b5943a..f8ebc0492a6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -543,13 +543,26 @@ JOIN::prepare(Item ***rref_pointer_array, if (order) { + bool real_order= FALSE; ORDER *ord; for (ord= order; ord; ord= ord->next) { Item *item= *ord->item; + /* + Disregard sort order if there's only "{VAR}CHAR(0) NOT NULL" fields + there. Such fields don't contain any data to sort. + */ + if (!real_order && + (item->type() != Item::Item::FIELD_ITEM || + ((Item_field *) item)->field->maybe_null() || + ((Item_field *) item)->field->sort_length())) + real_order= TRUE; + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) item->split_sum_func(thd, ref_pointer_array, all_fields); } + if (!real_order) + order= NULL; } if (having && having->with_sum_func) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 42b63108e1f..b17edbdd234 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6608,7 +6608,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, thd->clear_error(); Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, FALSE, 0); - if (error= mysql_bin_log.write(&qinfo)) + if ((error= mysql_bin_log.write(&qinfo))) goto view_err_unlock; } my_ok(thd); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 6c0cb08cc79..845a6792801 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -168,6 +168,21 @@ TEST_join(JOIN *join) uint i,ref; DBUG_ENTER("TEST_join"); + /* + Assemble results of all the calls to full_name() first, + in order not to garble the tabular output below. + */ + String ref_key_parts[MAX_TABLES]; + for (i= 0; i < join->tables; i++) + { + JOIN_TAB *tab= join->join_tab + i; + for (ref= 0; ref < tab->ref.key_parts; ref++) + { + ref_key_parts[i].append(tab->ref.items[ref]->full_name()); + ref_key_parts[i].append(" "); + } + } + DBUG_LOCK_FILE; VOID(fputs("\nInfo about JOIN\n",DBUG_FILE)); for (i=0 ; i < join->tables ; i++) @@ -199,13 +214,8 @@ TEST_join(JOIN *join) } if (tab->ref.key_parts) { - VOID(fputs(" refs: ",DBUG_FILE)); - for (ref=0 ; ref < tab->ref.key_parts ; ref++) - { - Item *item=tab->ref.items[ref]; - fprintf(DBUG_FILE,"%s ", item->full_name()); - } - VOID(fputc('\n',DBUG_FILE)); + fprintf(DBUG_FILE, + " refs: %s\n", ref_key_parts[i].ptr()); } } DBUG_UNLOCK_FILE; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 36a910b7a99..9b34c05f3ae 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1590,7 +1590,11 @@ opt_end_of_input: ; verb_clause: - statement + remember_name statement remember_end + { + Lex->stmt_begin= $1; + Lex->stmt_end= $3; + } | begin ; @@ -6061,7 +6065,7 @@ alter: } view_tail {} - | ALTER definer_opt EVENT_SYM sp_name + | ALTER definer_opt remember_name EVENT_SYM sp_name { /* It is safe to use Lex->spname because @@ -6073,7 +6077,8 @@ alter: if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD))) MYSQL_YYABORT; - Lex->event_parse_data->identifier= $4; + Lex->event_parse_data->identifier= $5; + Lex->stmt_definition_begin= $3; Lex->sql_command= SQLCOM_ALTER_EVENT; } @@ -6083,7 +6088,7 @@ alter: opt_ev_comment opt_ev_sql_stmt { - if (!($6 || $7 || $8 || $9 || $10)) + if (!($7 || $8 || $9 || $10 || $11)) { my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; @@ -6144,7 +6149,16 @@ opt_ev_rename_to: ; opt_ev_sql_stmt: - /* empty*/ { $$= 0;} + /* empty*/ + { + $$= 0; + /* + Lex->sp_head is not initialized when event body is empty. + So we can not use Lex->sp_head->set_stmt_end() to set + stmt_definition_end. + */ + Lex->stmt_definition_end= (char*) YYLIP->get_cpp_tok_end(); + } | DO_SYM ev_sql_stmt { $$= 1; } ; @@ -11894,6 +11908,7 @@ user: $$->user = $1; $$->host.str= (char *) "%"; $$->host.length= 1; + Lex->stmt_user_end= YYLIP->get_cpp_ptr(); if (check_string_char_length(&$$->user, ER(ER_USERNAME), USERNAME_CHAR_LENGTH, @@ -11906,6 +11921,7 @@ user: if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) MYSQL_YYABORT; $$->user = $1; $$->host=$3; + Lex->stmt_user_end= YYLIP->get_cpp_ptr(); if (check_string_char_length(&$$->user, ER(ER_USERNAME), USERNAME_CHAR_LENGTH, @@ -11915,6 +11931,7 @@ user: } | CURRENT_USER optional_braces { + Lex->stmt_user_end= YYLIP->get_cpp_ptr(); if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user)))) MYSQL_YYABORT; /* @@ -13119,9 +13136,10 @@ user_list: ; grant_list: + { Lex->stmt_user_begin= YYLIP->get_cpp_ptr(); } grant_user { - if (Lex->users_list.push_back($1)) + if (Lex->users_list.push_back($2)) MYSQL_YYABORT; } | grant_list ',' grant_user @@ -13134,6 +13152,7 @@ grant_list: grant_user: user IDENTIFIED_SYM BY TEXT_STRING { + Lex->stmt_user_end= YYLIP->get_cpp_ptr(); $$=$1; $1->password=$4; if ($4.length) { @@ -13160,7 +13179,10 @@ grant_user: } } | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING - { $$= $1; $1->password= $5; } + { + Lex->stmt_user_end= YYLIP->get_cpp_ptr(); + $$= $1; $1->password= $5; + } | user { $$= $1; $1->password= null_lex_str; } ; |