summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <Li-Bing.Song@sun.com>2010-06-27 12:42:06 +0800
committerunknown <Li-Bing.Song@sun.com>2010-06-27 12:42:06 +0800
commit451cea3f62a1b53c441995c8e1f052875c4fb3bd (patch)
tree81bce2c4d3e4822ad29ea031ab6cf72a5ecc3413 /sql
parentb4593605e0604f22bec09981709a202c809516fc (diff)
downloadmariadb-git-451cea3f62a1b53c441995c8e1f052875c4fb3bd.tar.gz
The following statements support the CURRENT_USER() where a user is needed.
DROP USER RENAME USER CURRENT_USER() ... GRANT ... TO CURRENT_USER() REVOKE ... FROM CURRENT_USER() ALTER DEFINER = CURRENT_USER() EVENTbut, When these statements are binlogged, CURRENT_USER() just is binlogged as 'CURRENT_USER()', it is not expanded to the real user name. When slave executes the log event, 'CURRENT_USER()' is expand to the user of slave SQL thread, but SQL thread's user name always NULL. This breaks the replication. After this patch, session's user will be written into query log events if these statements call CURREN_USER() or 'ALTER EVENT' does not assign a definer. mysql-test/include/diff_tables.inc: Expend its abilities. Now it can diff not only in sessions of 'master' and 'slave', but other sessions as well. mysql-test/include/rpl_diff_tables.inc: Diff the same table between master and slaves. sql/log_event.cc: session's user will be written into Query_log_event, if is_current_user_used() is TRUE. On slave SQL thread, Only thd->variables.current_user is written into Query_log_event, if it exists. sql/sql_acl.cc: On slave SQL thread, grantor should copy from thd->variables.current_user, if it exists sql/sql_class.h: On slave SQL thread, thd->variables.current_user is used to store the applying event's invoker.
Diffstat (limited to 'sql')
-rw-r--r--sql/log_event.cc67
-rw-r--r--sql/log_event.h7
-rw-r--r--sql/sql_acl.cc23
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h16
-rw-r--r--sql/sql_parse.cc2
6 files changed, 107 insertions, 9 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 9c6de5bb42e..cdf059b5e1f 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -2307,6 +2307,53 @@ bool Query_log_event::write(IO_CACHE* file)
start+= 4;
}
+ if (thd && thd->is_current_user_used())
+ {
+ LEX_STRING user;
+ LEX_STRING host;
+ bzero(&user, sizeof(user));
+ bzero(&host, sizeof(host));
+
+ if (thd->slave_thread)
+ {
+ /* user will be null, if master is older than this patch */
+ user= thd->variables.current_user.user;
+ host= thd->variables.current_user.host;
+ }
+ else if (thd->security_ctx->priv_user)
+ {
+ Security_context *ctx= thd->security_ctx;
+
+ user.length= strlen(ctx->priv_user);
+ user.str= ctx->priv_user;
+ if (ctx->priv_host[0] != '\0')
+ {
+ host.str= ctx->priv_host;
+ host.length= strlen(ctx->priv_host);
+ }
+ }
+
+ if (user.length > 0)
+ {
+ *start++= Q_INVOKER;
+
+ /*
+ Store user length and user. The max length of use is 16, so 1 byte is
+ enough to store the user's length.
+ */
+ *start++= (uchar)user.length;
+ memcpy(start, user.str, user.length);
+ start+= user.length;
+
+ /*
+ Store host length and host. The max length of host is 60, so 1 byte is
+ enough to store the host's length.
+ */
+ *start++= (uchar)host.length;
+ memcpy(start, host.str, host.length);
+ start+= host.length;
+ }
+ }
/*
NOTE: When adding new status vars, please don't forget to update
the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
@@ -2575,6 +2622,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
bool catalog_nz= 1;
DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
+ bzero(&user, sizeof(user));
+ bzero(&host, sizeof(host));
common_header_len= description_event->common_header_len;
post_header_len= description_event->post_header_len[event_type-1];
DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d",
@@ -2729,6 +2778,20 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
data_written= master_data_written= uint4korr(pos);
pos+= 4;
break;
+ case Q_INVOKER:
+ {
+ CHECK_SPACE(pos, end, 1);
+ user.length= *pos++;
+ CHECK_SPACE(pos, end, user.length);
+ user.str= my_strndup((const char *)pos, user.length, MYF(0));
+ pos+= user.length;
+
+ CHECK_SPACE(pos, end, 1);
+ host.length= *pos++;
+ CHECK_SPACE(pos, end, host.length);
+ host.str= my_strndup((const char *)pos, host.length, MYF(0));
+ pos+= host.length;
+ }
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\
@@ -3178,7 +3241,9 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
thd->variables.collation_database= thd->db_charset;
thd->table_map_for_update= (table_map)table_map_for_update;
-
+ thd->variables.current_user.user= user;
+ thd->variables.current_user.host= host;
+ thd->variables.current_user.password= {0, 0};
/* Execute the query (note that we bypass dispatch_command()) */
const char* found_semicolon= NULL;
mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon);
diff --git a/sql/log_event.h b/sql/log_event.h
index e3ca4ca3321..816a241e55d 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -264,7 +264,8 @@ struct sql_ex_info
1 + 2 /* type, lc_time_names_number */ + \
1 + 2 /* type, charset_database_number */ + \
1 + 8 /* type, table_map_for_update */ + \
- 1 + 4 /* type, master_data_written */)
+ 1 + 4 /* type, master_data_written */ + \
+ 1 + 16 + 1 + 60/* type, user_len, user, host_len, host */)
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
LOG_EVENT_HEADER_LEN + /* write_header */ \
QUERY_HEADER_LEN + /* write_data */ \
@@ -333,6 +334,8 @@ struct sql_ex_info
#define Q_MASTER_DATA_WRITTEN_CODE 10
+#define Q_INVOKER 11
+
/* Intvar event post-header */
/* Intvar event data */
@@ -1546,6 +1549,8 @@ protected:
*/
class Query_log_event: public Log_event
{
+ LEX_STRING user;
+ LEX_STRING host;
protected:
Log_event::Byte* data_buf;
public:
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index dd256c70ecb..acf14fc91c4 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 inline void get_grantor(THD *thd, char* grantor);
/*
Convert scrambled password to binary form, according to scramble type,
@@ -2704,6 +2705,20 @@ end:
DBUG_RETURN(result);
}
+static inline void get_grantor(THD *thd, char *grantor)
+{
+ const char *user= thd->security_ctx->user;
+ const char *host= thd->security_ctx->host_or_ip;
+
+#if defined(HAVE_REPLICATION)
+ if (thd->slave_thread && thd->variables.current_user.user.length > 0)
+ {
+ user= thd->variables.current_user.user.str;
+ host= thd->variables.current_user.host.str;
+ }
+#endif
+ strxmov(grantor, user, "@", host, NullS);
+}
static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
TABLE *table, const LEX_USER &combo,
@@ -2718,9 +2733,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
uchar user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table");
- strxmov(grantor, thd->security_ctx->user, "@",
- thd->security_ctx->host_or_ip, NullS);
-
+ get_grantor(thd, grantor);
/*
The following should always succeed as new users are created before
this function is called!
@@ -2850,9 +2863,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
DBUG_RETURN(-1);
}
- strxmov(grantor, thd->security_ctx->user, "@",
- thd->security_ctx->host_or_ip, NullS);
-
+ get_grantor(thd, grantor);
/*
New users are created before this function is called.
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 93aa6a8268c..cd2bb2a51df 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1236,6 +1236,7 @@ void THD::cleanup_after_query()
where= THD::DEFAULT_WHERE;
/* reset table map for multi-table update */
table_map_for_update= 0;
+ clean_current_user_used();
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4c1d4a98db0..72ffa2e6ba4 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -401,6 +401,7 @@ struct system_variables
DATE_TIME_FORMAT *datetime_format;
DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
+ LEX_USER current_user;
};
@@ -2340,6 +2341,19 @@ public:
Protected with LOCK_thd_data mutex.
*/
void set_query(char *query_arg, uint32 query_length_arg);
+ void set_current_user_used() { current_user_used= TRUE; }
+ bool is_current_user_used() { return current_user_used; }
+ void clean_current_user_used() { current_user_used= FALSE; }
+ void get_definer(LEX_USER *definer)
+ {
+ set_current_user_used();
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ if (slave_thread && variables.current_user.user.length)
+ *definer= variables.current_user;
+ else
+#endif
+ get_default_definer(this, definer);
+ }
private:
/** The current internal error handler for this thread, or NULL. */
Internal_error_handler *m_internal_handler;
@@ -2359,6 +2373,8 @@ private:
tree itself is reused between executions and thus is stored elsewhere.
*/
MEM_ROOT main_mem_root;
+
+ bool current_user_used;
};
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c4d4f2c9d9d..ec9199b33a5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -7650,7 +7650,7 @@ LEX_USER *create_default_definer(THD *thd)
if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
return 0;
- get_default_definer(thd, definer);
+ thd->get_definer(definer);
return definer;
}