summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2010-01-30 22:13:36 +0300
committerAlexander Nozdrin <alik@sun.com>2010-01-30 22:13:36 +0300
commit85c54dddc7f6303b0e48f6d9fb9c0c7561292e4b (patch)
treefa297f7fa59f84c3c05e83388795c51d18dd89a7 /sql
parenta59e381efabf9733a300ed3be322aefaede88d44 (diff)
parent788c28aceb023702282bfbf372016da79f9ab49f (diff)
downloadmariadb-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.cc79
-rw-r--r--sql/field.h7
-rw-r--r--sql/filesort.cc2
-rw-r--r--sql/item_strfunc.cc37
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/log_event.cc39
-rw-r--r--sql/log_event.h17
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/mysqld.cc42
-rw-r--r--sql/rpl_injector.cc12
-rw-r--r--sql/rpl_record.cc17
-rw-r--r--sql/sql_acl.cc124
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_lex.h25
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_select.cc13
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_test.cc24
-rw-r--r--sql/sql_yacc.yy36
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*) &param,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; }
;