summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2010-01-31 01:06:50 +0300
committerAlexander Nozdrin <alik@sun.com>2010-01-31 01:06:50 +0300
commit2b0f6b5ace4b455344dc25e400873d3d68c90090 (patch)
tree64c1a58bb6f6f5516fbf930759b54e0081b98b90 /sql
parent22e0e72370ddbd95d0438b769ac5dda82b2c9b0a (diff)
parentd9e9a73e8f1355a24b27d64d56d555d045ee0b4c (diff)
downloadmariadb-git-2b0f6b5ace4b455344dc25e400873d3d68c90090.tar.gz
Manual merge from mysql-trunk-merge.
Conflicts: - 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 - sql/sql_parse.cc - sql/sql_table.cc - sql/sql_test.cc
Diffstat (limited to 'sql')
-rw-r--r--sql/events.cc79
-rw-r--r--sql/filesort.cc2
-rw-r--r--sql/item_strfunc.cc6
-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/rpl_injector.cc12
-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_test.cc24
-rw-r--r--sql/sql_yacc.yy36
14 files changed, 303 insertions, 86 deletions
diff --git a/sql/events.cc b/sql/events.cc
index 73f3427607d..35fbca871bb 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -246,31 +246,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;
}
/**
@@ -285,8 +302,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
@@ -368,22 +384,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);
}
mysql_mutex_unlock(&LOCK_event_metadata);
/* Restore the state of binlog format */
@@ -502,9 +503,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);
}
}
mysql_mutex_unlock(&LOCK_event_metadata);
diff --git a/sql/filesort.cc b/sql/filesort.cc
index c6156b8243f..79887577f8f 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 0286a51683a..c33e0f4c6fb 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1765,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 c92a528dfab..be167451cb3 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2297,10 +2297,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)
@@ -2376,7 +2388,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;
@@ -2605,6 +2618,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;
@@ -2642,7 +2656,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;
@@ -2698,6 +2712,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,
@@ -2789,6 +2815,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 9f14b30d2e2..5530444b0d4 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
@@ -1681,6 +1686,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/rpl_injector.cc b/sql/rpl_injector.cc
index ac879b5033f..64f79092057 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -112,8 +112,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;
@@ -131,8 +131,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;
@@ -150,8 +150,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/sql_acl.cc b/sql/sql_acl.cc
index 012542a9467..8283123f51c 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -196,6 +196,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,
@@ -3270,7 +3271,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;
}
mysql_rwlock_unlock(&LOCK_grant);
@@ -3446,8 +3448,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);
}
mysql_rwlock_unlock(&LOCK_grant);
@@ -3576,7 +3577,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);
}
mysql_rwlock_unlock(&LOCK_grant);
@@ -5755,9 +5756,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);
@@ -5766,6 +5767,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.
@@ -5872,6 +5932,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];
@@ -5901,6 +5962,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
mysql_rwlock_wrlock(&LOCK_grant);
mysql_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)))
@@ -5908,6 +5970,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);
@@ -5926,7 +5999,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());
+ }
+ }
mysql_rwlock_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5954,6 +6033,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);
@@ -5981,6 +6061,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
mysql_rwlock_wrlock(&LOCK_grant);
mysql_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)))
@@ -5997,6 +6078,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.
*/
@@ -6017,9 +6110,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());
+ }
+ }
mysql_rwlock_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -6209,8 +6308,9 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
mysql_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;
mysql_rwlock_unlock(&LOCK_grant);
close_thread_tables(thd);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 6713a8f58f8..1be84751581 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -854,7 +854,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 800a16cf2b6..67e1861a993 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1986,6 +1986,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.
@@ -1994,6 +1996,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 dd7101a46bb..73ed2e3f017 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3260,9 +3260,9 @@ end_with_restore_list:
select_lex->where,
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
- select_lex->options | thd->variables.option_bits |
+ (select_lex->options | thd->variables.option_bits |
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());
@@ -3883,7 +3883,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 5cef405fe53..edeeb143333 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -542,13 +542,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_test.cc b/sql/sql_test.cc
index 8dc4b4ffeb6..fe56d6acf3e 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 ab128a9b701..9f4bad45ce5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1681,7 +1681,11 @@ opt_end_of_input:
;
verb_clause:
- statement
+ remember_name statement remember_end
+ {
+ Lex->stmt_begin= $1;
+ Lex->stmt_end= $3;
+ }
| begin
;
@@ -6192,7 +6196,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
@@ -6204,7 +6208,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;
}
@@ -6214,7 +6219,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;
@@ -6275,7 +6280,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; }
;
@@ -12054,6 +12068,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,
@@ -12066,6 +12081,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,
@@ -12075,6 +12091,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;
/*
@@ -13280,9 +13297,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
@@ -13295,6 +13313,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)
{
@@ -13321,7 +13340,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; }
;