'Replicate user variables' task
This commit is contained in:
parent
edb019aeaf
commit
57a805de6c
@ -17,6 +17,7 @@ bell@sanja.is.com.ua
|
|||||||
bk@admin.bk
|
bk@admin.bk
|
||||||
davida@isil.mysql.com
|
davida@isil.mysql.com
|
||||||
gluh@gluh.(none)
|
gluh@gluh.(none)
|
||||||
|
gluh@gluh.mysql.r18.ru
|
||||||
heikki@donna.mysql.fi
|
heikki@donna.mysql.fi
|
||||||
heikki@hundin.mysql.fi
|
heikki@hundin.mysql.fi
|
||||||
heikki@rescue.
|
heikki@rescue.
|
||||||
|
@ -701,6 +701,7 @@ extern void freeze_size(DYNAMIC_ARRAY *array);
|
|||||||
#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element)
|
#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element)
|
||||||
#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
|
#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
|
||||||
#define push_dynamic(A,B) insert_dynamic(A,B)
|
#define push_dynamic(A,B) insert_dynamic(A,B)
|
||||||
|
#define reset_dynamic(array) ((array)->elements= 0)
|
||||||
|
|
||||||
extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
|
extern my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
|
||||||
uint init_alloc,uint alloc_increment);
|
uint init_alloc,uint alloc_increment);
|
||||||
|
78
mysql-test/r/rpl_user_variables.result
Normal file
78
mysql-test/r/rpl_user_variables.result
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
stop slave;
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
reset master;
|
||||||
|
reset slave;
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
start slave;
|
||||||
|
stop slave;
|
||||||
|
reset master;
|
||||||
|
drop table if exists t1;
|
||||||
|
create table t1(n char(30));
|
||||||
|
set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1;
|
||||||
|
set @s1:='This is a test', @r1:=12.5, @r2:=-12.5;
|
||||||
|
set @n1:=null;
|
||||||
|
set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def';
|
||||||
|
insert into t1 values (@i1), (@i2), (@i3), (@i4);
|
||||||
|
insert into t1 values (@r1), (@r2);
|
||||||
|
insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5);
|
||||||
|
insert into t1 values (@n1);
|
||||||
|
insert into t1 values (@n2);
|
||||||
|
insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1);
|
||||||
|
insert into t1 values (@a+(@b:=@a+1));
|
||||||
|
set @q:='abc';
|
||||||
|
insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'));
|
||||||
|
set @a:=5;
|
||||||
|
insert into t1 values (@a),(@a);
|
||||||
|
start slave;
|
||||||
|
select * from t1;
|
||||||
|
n
|
||||||
|
12345678901234
|
||||||
|
-12345678901234
|
||||||
|
0
|
||||||
|
-1
|
||||||
|
12.5
|
||||||
|
-12.5
|
||||||
|
This is a test
|
||||||
|
|
||||||
|
abc'def
|
||||||
|
abc\def
|
||||||
|
abc'def
|
||||||
|
NULL
|
||||||
|
NULL
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
5
|
||||||
|
abc
|
||||||
|
abcn1
|
||||||
|
abcn1n2
|
||||||
|
5
|
||||||
|
5
|
||||||
|
show binlog events from 141;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
slave-bin.000001 141 User var 2 141 @i1=12345678901234
|
||||||
|
slave-bin.000001 184 User var 2 184 @i2=-12345678901234
|
||||||
|
slave-bin.000001 227 User var 2 227 @i3=0
|
||||||
|
slave-bin.000001 270 User var 2 270 @i4=-1
|
||||||
|
slave-bin.000001 313 Query 1 313 use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4)
|
||||||
|
slave-bin.000001 396 User var 2 396 @r1=12.5
|
||||||
|
slave-bin.000001 439 User var 2 439 @r2=-12.5
|
||||||
|
slave-bin.000001 482 Query 1 482 use `test`; insert into t1 values (@r1), (@r2)
|
||||||
|
slave-bin.000001 551 User var 2 551 @s1='This is a test'
|
||||||
|
slave-bin.000001 601 User var 2 601 @s2=''
|
||||||
|
slave-bin.000001 637 User var 2 637 @s3='abc'def'
|
||||||
|
slave-bin.000001 680 User var 2 680 @s4='abc\def'
|
||||||
|
slave-bin.000001 723 User var 2 723 @s5='abc'def'
|
||||||
|
slave-bin.000001 766 Query 1 766 use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5)
|
||||||
|
slave-bin.000001 856 User var 2 856 @n1=NULL
|
||||||
|
slave-bin.000001 882 Query 1 882 use `test`; insert into t1 values (@n1)
|
||||||
|
slave-bin.000001 944 Query 1 944 use `test`; insert into t1 values (@n2)
|
||||||
|
slave-bin.000001 1006 Query 1 1006 use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1)
|
||||||
|
slave-bin.000001 1094 User var 2 1094 @a='2'
|
||||||
|
slave-bin.000001 1130 Query 1 1130 use `test`; insert into t1 values (@a+(@b:=@a+1))
|
||||||
|
slave-bin.000001 1202 User var 2 1202 @q='abc'
|
||||||
|
slave-bin.000001 1240 Query 1 1240 use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'))
|
||||||
|
slave-bin.000001 1344 User var 2 1344 @a=5
|
||||||
|
slave-bin.000001 1386 Query 1 1386 use `test`; insert into t1 values (@a),(@a)
|
||||||
|
drop table t1;
|
||||||
|
stop slave;
|
39
mysql-test/t/rpl_user_variables.test
Normal file
39
mysql-test/t/rpl_user_variables.test
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
source include/master-slave.inc;
|
||||||
|
connection master;
|
||||||
|
save_master_pos;
|
||||||
|
connection slave;
|
||||||
|
sync_with_master;
|
||||||
|
stop slave;
|
||||||
|
reset master;
|
||||||
|
connection master;
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1;
|
||||||
|
--enable_warnings
|
||||||
|
create table t1(n char(30));
|
||||||
|
set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1;
|
||||||
|
set @s1:='This is a test', @r1:=12.5, @r2:=-12.5;
|
||||||
|
set @n1:=null;
|
||||||
|
set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def';
|
||||||
|
insert into t1 values (@i1), (@i2), (@i3), (@i4);
|
||||||
|
insert into t1 values (@r1), (@r2);
|
||||||
|
insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5);
|
||||||
|
insert into t1 values (@n1);
|
||||||
|
insert into t1 values (@n2);
|
||||||
|
insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1);
|
||||||
|
insert into t1 values (@a+(@b:=@a+1));
|
||||||
|
set @q:='abc';
|
||||||
|
insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2'));
|
||||||
|
set @a:=5;
|
||||||
|
insert into t1 values (@a),(@a);
|
||||||
|
save_master_pos;
|
||||||
|
connection slave;
|
||||||
|
start slave;
|
||||||
|
sync_with_master;
|
||||||
|
select * from t1;
|
||||||
|
show binlog events from 141;
|
||||||
|
connection master;
|
||||||
|
drop table t1;
|
||||||
|
save_master_pos;
|
||||||
|
connection slave;
|
||||||
|
sync_with_master;
|
||||||
|
stop slave;
|
@ -1940,6 +1940,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
|
|||||||
entry->value=0;
|
entry->value=0;
|
||||||
entry->length=0;
|
entry->length=0;
|
||||||
entry->update_query_id=0;
|
entry->update_query_id=0;
|
||||||
|
entry->used_query_id=current_thd->query_id;
|
||||||
entry->type=STRING_RESULT;
|
entry->type=STRING_RESULT;
|
||||||
memcpy(entry->name.str, name.str, name.length+1);
|
memcpy(entry->name.str, name.str, name.length+1);
|
||||||
if (hash_insert(hash,(byte*) entry))
|
if (hash_insert(hash,(byte*) entry))
|
||||||
@ -2172,14 +2173,58 @@ longlong Item_func_get_user_var::val_int()
|
|||||||
return LL(0); // Impossible
|
return LL(0); // Impossible
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* From sql_parse.cc */
|
||||||
|
extern bool is_update_query(enum enum_sql_command command);
|
||||||
|
|
||||||
void Item_func_get_user_var::fix_length_and_dec()
|
void Item_func_get_user_var::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
|
BINLOG_USER_VAR_EVENT *user_var_event;
|
||||||
THD *thd=current_thd;
|
THD *thd=current_thd;
|
||||||
maybe_null=1;
|
maybe_null=1;
|
||||||
decimals=NOT_FIXED_DEC;
|
decimals=NOT_FIXED_DEC;
|
||||||
max_length=MAX_BLOB_WIDTH;
|
max_length=MAX_BLOB_WIDTH;
|
||||||
var_entry= get_variable(&thd->user_vars, name, 0);
|
|
||||||
|
if ((var_entry= get_variable(&thd->user_vars, name, 0)))
|
||||||
|
{
|
||||||
|
if (opt_bin_log && is_update_query(thd->lex.sql_command) &&
|
||||||
|
var_entry->used_query_id != thd->query_id)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
First we need to store value of var_entry, when the next situation appers:
|
||||||
|
> set @a:=1;
|
||||||
|
> insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
|
||||||
|
We have to write to binlog value @a= 1;
|
||||||
|
*/
|
||||||
|
uint size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
|
||||||
|
if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
user_var_event->value= (char*) user_var_event +
|
||||||
|
ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
|
||||||
|
user_var_event->user_var_event= var_entry;
|
||||||
|
user_var_event->type= var_entry->type;
|
||||||
|
user_var_event->charset_number= var_entry->var_charset->number;
|
||||||
|
if (!var_entry->value)
|
||||||
|
{
|
||||||
|
/* NULL value*/
|
||||||
|
user_var_event->length= 0;
|
||||||
|
user_var_event->value= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user_var_event->length= var_entry->length;
|
||||||
|
memcpy(user_var_event->value, var_entry->value,
|
||||||
|
var_entry->length);
|
||||||
|
}
|
||||||
|
var_entry->used_query_id= thd->query_id;
|
||||||
|
if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
err:
|
||||||
|
thd->fatal_error= 1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
17
sql/log.cc
17
sql/log.cc
@ -1097,6 +1097,23 @@ bool MYSQL_LOG::write(Log_event* event_info)
|
|||||||
if (e.write(file))
|
if (e.write(file))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
if (thd->user_var_events.elements)
|
||||||
|
{
|
||||||
|
for (uint i= 0; i < thd->user_var_events.elements; i++)
|
||||||
|
{
|
||||||
|
BINLOG_USER_VAR_EVENT *user_var_event;
|
||||||
|
get_dynamic(&thd->user_var_events,(gptr) &user_var_event, i);
|
||||||
|
User_var_log_event e(thd, user_var_event->user_var_event->name.str,
|
||||||
|
user_var_event->user_var_event->name.length,
|
||||||
|
user_var_event->value,
|
||||||
|
user_var_event->length,
|
||||||
|
user_var_event->type,
|
||||||
|
user_var_event->charset_number);
|
||||||
|
e.set_log_pos(this);
|
||||||
|
if (e.write(file))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (thd->variables.convert_set)
|
if (thd->variables.convert_set)
|
||||||
{
|
{
|
||||||
char buf[256], *p;
|
char buf[256], *p;
|
||||||
|
240
sql/log_event.cc
240
sql/log_event.cc
@ -227,6 +227,7 @@ const char* Log_event::get_type_str()
|
|||||||
case DELETE_FILE_EVENT: return "Delete_file";
|
case DELETE_FILE_EVENT: return "Delete_file";
|
||||||
case EXEC_LOAD_EVENT: return "Exec_load";
|
case EXEC_LOAD_EVENT: return "Exec_load";
|
||||||
case RAND_EVENT: return "RAND";
|
case RAND_EVENT: return "RAND";
|
||||||
|
case USER_VAR_EVENT: return "User var";
|
||||||
default: /* impossible */ return "Unknown";
|
default: /* impossible */ return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,6 +594,9 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
|
|||||||
case RAND_EVENT:
|
case RAND_EVENT:
|
||||||
ev = new Rand_log_event(buf, old_format);
|
ev = new Rand_log_event(buf, old_format);
|
||||||
break;
|
break;
|
||||||
|
case USER_VAR_EVENT:
|
||||||
|
ev = new User_var_log_event(buf, old_format);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1894,6 +1898,242 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
|
|||||||
}
|
}
|
||||||
#endif // !MYSQL_CLIENT
|
#endif // !MYSQL_CLIENT
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*****************************************************************************
|
||||||
|
|
||||||
|
User_var_log_event methods
|
||||||
|
|
||||||
|
*****************************************************************************
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
User_var_log_event::pack_info()
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef MYSQL_CLIENT
|
||||||
|
void User_var_log_event::pack_info(Protocol* protocol)
|
||||||
|
{
|
||||||
|
char *buf= 0;
|
||||||
|
uint val_offset= 2 + name_len;
|
||||||
|
uint event_len= val_offset;
|
||||||
|
|
||||||
|
if (is_null)
|
||||||
|
{
|
||||||
|
buf= my_malloc(val_offset + 5, MYF(MY_WME));
|
||||||
|
strmov(buf + val_offset, "NULL");
|
||||||
|
event_len= val_offset + 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case REAL_RESULT:
|
||||||
|
double real_val;
|
||||||
|
float8get(real_val, val);
|
||||||
|
buf= my_malloc(val_offset + FLOATING_POINT_BUFFER, MYF(MY_WME));
|
||||||
|
event_len += my_sprintf(buf + val_offset,
|
||||||
|
(buf + val_offset, "%.14g", real_val));
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
buf= my_malloc(val_offset + 22, MYF(MY_WME));
|
||||||
|
event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
|
||||||
|
break;
|
||||||
|
case STRING_RESULT:
|
||||||
|
/*
|
||||||
|
This is correct as pack_info is used for SHOW BINLOG command
|
||||||
|
only. But be carefull this is may be incorrect in other cases as
|
||||||
|
string may contain \ and '.
|
||||||
|
*/
|
||||||
|
buf= my_malloc(val_offset + 2 + val_len, MYF(MY_WME));
|
||||||
|
buf[val_offset]= '\'';
|
||||||
|
memcpy(buf + val_offset + 1, val, val_len);
|
||||||
|
buf[val_offset + val_len]= '\'';
|
||||||
|
event_len= val_offset + 1 + val_len;
|
||||||
|
break;
|
||||||
|
case ROW_RESULT:
|
||||||
|
DBUG_ASSERT(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf[0]= '@';
|
||||||
|
buf[1+name_len]= '=';
|
||||||
|
memcpy(buf+1, name, name_len);
|
||||||
|
protocol->store(buf, event_len);
|
||||||
|
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
|
||||||
|
}
|
||||||
|
#endif // !MYSQL_CLIENT
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
User_var_log_event::User_var_log_event()
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
User_var_log_event::User_var_log_event(const char* buf, bool old_format)
|
||||||
|
:Log_event(buf, old_format)
|
||||||
|
{
|
||||||
|
buf+= (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
|
||||||
|
name_len= uint4korr(buf);
|
||||||
|
name= (char *) buf + UV_NAME_LEN_SIZE;
|
||||||
|
is_null= buf[UV_NAME_LEN_SIZE + name_len];
|
||||||
|
if (is_null)
|
||||||
|
{
|
||||||
|
type= STRING_RESULT;
|
||||||
|
val_len= 0;
|
||||||
|
val= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type= (Item_result) buf[UV_VAL_IS_NULL + UV_NAME_LEN_SIZE + name_len];
|
||||||
|
charset_number= uint4korr(buf + UV_NAME_LEN_SIZE + name_len +
|
||||||
|
UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
|
||||||
|
val_len= uint4korr(buf + UV_NAME_LEN_SIZE + name_len +
|
||||||
|
UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
|
||||||
|
UV_CHARSET_NUMBER_SIZE);
|
||||||
|
val= (char *) buf + UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL +
|
||||||
|
UV_VAL_TYPE_SIZE + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
User_var_log_event::write_data()
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
int User_var_log_event::write_data(IO_CACHE* file)
|
||||||
|
{
|
||||||
|
char buf[UV_NAME_LEN_SIZE];
|
||||||
|
char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
|
||||||
|
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
|
||||||
|
char buf2[8];
|
||||||
|
char *pos= buf2;
|
||||||
|
int4store(buf, name_len);
|
||||||
|
buf1[0]= is_null;
|
||||||
|
if (!is_null)
|
||||||
|
{
|
||||||
|
buf1[1]= type;
|
||||||
|
int4store(buf1 + 2, charset_number);
|
||||||
|
int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case REAL_RESULT:
|
||||||
|
float8store(buf2, *(double*) val);
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
int8store(buf2, *(longlong*) val);
|
||||||
|
break;
|
||||||
|
case STRING_RESULT:
|
||||||
|
pos= val;
|
||||||
|
break;
|
||||||
|
case ROW_RESULT:
|
||||||
|
DBUG_ASSERT(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (my_b_safe_write(file, (byte*) buf, sizeof(buf)) ||
|
||||||
|
my_b_safe_write(file, (byte*) name, name_len) ||
|
||||||
|
my_b_safe_write(file, (byte*) buf1, sizeof(buf1)) ||
|
||||||
|
my_b_safe_write(file, (byte*) pos, val_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (my_b_safe_write(file, (byte*) buf, sizeof(buf)) ||
|
||||||
|
my_b_safe_write(file, (byte*) name, name_len) ||
|
||||||
|
my_b_safe_write(file, (byte*) buf1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
User_var_log_event::print()
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
#ifdef MYSQL_CLIENT
|
||||||
|
void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
|
||||||
|
{
|
||||||
|
if (!short_form)
|
||||||
|
{
|
||||||
|
print_header(file);
|
||||||
|
fprintf(file, "\tUser_var\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(file, "SET @");
|
||||||
|
my_fwrite(file, (byte*) name, (uint) (name_len), MYF(MY_NABP | MY_WME));
|
||||||
|
|
||||||
|
if (is_null)
|
||||||
|
{
|
||||||
|
fprintf(file, ":=NULL;\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case REAL_RESULT:
|
||||||
|
double real_val;
|
||||||
|
float8get(real_val, val);
|
||||||
|
fprintf(file, ":=%.14g;\n", real_val);
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
char int_buf[22];
|
||||||
|
longlong10_to_str(uint8korr(val), int_buf, -10);
|
||||||
|
fprintf(file, ":=%s;\n", int_buf);
|
||||||
|
break;
|
||||||
|
case STRING_RESULT:
|
||||||
|
fprintf(file, ":='%s';\n", val);
|
||||||
|
break;
|
||||||
|
case ROW_RESULT:
|
||||||
|
DBUG_ASSERT(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fflush(file);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
User_var_log_event::exec_event()
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef MYSQL_CLIENT
|
||||||
|
int User_var_log_event::exec_event(struct st_relay_log_info* rli)
|
||||||
|
{
|
||||||
|
Item *it= 0;
|
||||||
|
CHARSET_INFO *charset= log_cs;
|
||||||
|
LEX_STRING user_var_name;
|
||||||
|
user_var_name.str= name;
|
||||||
|
user_var_name.length= name_len;
|
||||||
|
|
||||||
|
if (type != ROW_RESULT)
|
||||||
|
init_sql_alloc(&thd->mem_root, 8192,0);
|
||||||
|
|
||||||
|
if (is_null)
|
||||||
|
{
|
||||||
|
it= new Item_null();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case REAL_RESULT:
|
||||||
|
double real_val;
|
||||||
|
float8get(real_val, val);
|
||||||
|
it= new Item_real(real_val);
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
it= new Item_int((longlong) uint8korr(val));
|
||||||
|
break;
|
||||||
|
case STRING_RESULT:
|
||||||
|
it= new Item_string(val, val_len, charset);
|
||||||
|
break;
|
||||||
|
case ROW_RESULT:
|
||||||
|
DBUG_ASSERT(1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
charset= get_charset(charset_number, MYF(0));
|
||||||
|
}
|
||||||
|
Item_func_set_user_var e(user_var_name, it);
|
||||||
|
e.fix_fields(thd, 0, 0);
|
||||||
|
e.update_hash(val, val_len, type, charset);
|
||||||
|
free_root(&thd->mem_root,0);
|
||||||
|
|
||||||
|
rli->inc_pending(get_event_len());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // !MYSQL_CLIENT
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
|
@ -173,6 +173,14 @@ struct sql_ex_info
|
|||||||
#define RAND_SEED1_OFFSET 0
|
#define RAND_SEED1_OFFSET 0
|
||||||
#define RAND_SEED2_OFFSET 8
|
#define RAND_SEED2_OFFSET 8
|
||||||
|
|
||||||
|
/* User_var event post-header */
|
||||||
|
|
||||||
|
#define UV_VAL_LEN_SIZE 4
|
||||||
|
#define UV_VAL_IS_NULL 1
|
||||||
|
#define UV_VAL_TYPE_SIZE 1
|
||||||
|
#define UV_NAME_LEN_SIZE 4
|
||||||
|
#define UV_CHARSET_NUMBER_SIZE 4
|
||||||
|
|
||||||
/* Load event post-header */
|
/* Load event post-header */
|
||||||
|
|
||||||
#define L_THREAD_ID_OFFSET 0
|
#define L_THREAD_ID_OFFSET 0
|
||||||
@ -222,7 +230,7 @@ enum Log_event_type
|
|||||||
START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4,
|
START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4,
|
||||||
INTVAR_EVENT=5, LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8,
|
INTVAR_EVENT=5, LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8,
|
||||||
APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11,
|
APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11,
|
||||||
NEW_LOAD_EVENT=12, RAND_EVENT=13
|
NEW_LOAD_EVENT=12, RAND_EVENT=13, USER_VAR_EVENT=14
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Int_event_type
|
enum Int_event_type
|
||||||
@ -590,6 +598,46 @@ class Rand_log_event: public Log_event
|
|||||||
bool is_valid() { return 1; }
|
bool is_valid() { return 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
User var Log Event class
|
||||||
|
|
||||||
|
****************************************************************************/
|
||||||
|
class User_var_log_event: public Log_event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
char *name;
|
||||||
|
uint name_len;
|
||||||
|
char *val;
|
||||||
|
ulong val_len;
|
||||||
|
Item_result type;
|
||||||
|
uint charset_number;
|
||||||
|
byte is_null;
|
||||||
|
#ifndef MYSQL_CLIENT
|
||||||
|
User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
|
||||||
|
char *val_arg, ulong val_len_arg, Item_result type_arg,
|
||||||
|
uint charset_number_arg)
|
||||||
|
:Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
|
||||||
|
val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
|
||||||
|
{ is_null= !val; }
|
||||||
|
void pack_info(Protocol* protocol);
|
||||||
|
int exec_event(struct st_relay_log_info* rli);
|
||||||
|
#else
|
||||||
|
void print(FILE* file, bool short_form = 0, char* last_db = 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
User_var_log_event(const char* buf, bool old_format);
|
||||||
|
~User_var_log_event() {}
|
||||||
|
Log_event_type get_type_code() { return USER_VAR_EVENT;}
|
||||||
|
int get_data_size()
|
||||||
|
{
|
||||||
|
return (is_null ? UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL :
|
||||||
|
UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
|
||||||
|
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE + val_len);
|
||||||
|
}
|
||||||
|
int write_data(IO_CACHE* file);
|
||||||
|
bool is_valid() { return 1; }
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
|
@ -145,6 +145,17 @@ THD::THD():user_time(0), fatal_error(0),
|
|||||||
(hash_get_key) get_var_key,
|
(hash_get_key) get_var_key,
|
||||||
(hash_free_key) free_user_var,0);
|
(hash_free_key) free_user_var,0);
|
||||||
|
|
||||||
|
/* For user vars replication*/
|
||||||
|
if (opt_bin_log)
|
||||||
|
my_init_dynamic_array(&user_var_events,
|
||||||
|
sizeof(BINLOG_USER_VAR_EVENT *),
|
||||||
|
16,
|
||||||
|
16);
|
||||||
|
else
|
||||||
|
bzero((char*) &user_var_events, sizeof(user_var_events));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Prepared statements */
|
/* Prepared statements */
|
||||||
last_prepared_stmt= 0;
|
last_prepared_stmt= 0;
|
||||||
init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT),
|
init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT),
|
||||||
@ -244,6 +255,7 @@ void THD::cleanup(void)
|
|||||||
close_thread_tables(this);
|
close_thread_tables(this);
|
||||||
}
|
}
|
||||||
close_temporary_tables(this);
|
close_temporary_tables(this);
|
||||||
|
delete_dynamic(&user_var_events);
|
||||||
hash_free(&user_vars);
|
hash_free(&user_vars);
|
||||||
if (global_read_lock)
|
if (global_read_lock)
|
||||||
unlock_global_read_lock(this);
|
unlock_global_read_lock(this);
|
||||||
|
@ -57,6 +57,15 @@ typedef struct st_log_info
|
|||||||
~st_log_info() { pthread_mutex_destroy(&lock);}
|
~st_log_info() { pthread_mutex_destroy(&lock);}
|
||||||
} LOG_INFO;
|
} LOG_INFO;
|
||||||
|
|
||||||
|
typedef struct st_user_var_events
|
||||||
|
{
|
||||||
|
user_var_entry *user_var_event;
|
||||||
|
char *value;
|
||||||
|
ulong length;
|
||||||
|
Item_result type;
|
||||||
|
uint charset_number;
|
||||||
|
} BINLOG_USER_VAR_EVENT;
|
||||||
|
|
||||||
class Log_event;
|
class Log_event;
|
||||||
|
|
||||||
class MYSQL_LOG {
|
class MYSQL_LOG {
|
||||||
@ -511,6 +520,8 @@ public:
|
|||||||
uint check_loops_counter; //last id used to check loops
|
uint check_loops_counter; //last id used to check loops
|
||||||
/* variables.transaction_isolation is reset to this after each commit */
|
/* variables.transaction_isolation is reset to this after each commit */
|
||||||
enum_tx_isolation session_tx_isolation;
|
enum_tx_isolation session_tx_isolation;
|
||||||
|
/* for user variables replication*/
|
||||||
|
DYNAMIC_ARRAY user_var_events;
|
||||||
// extend scramble to handle new auth
|
// extend scramble to handle new auth
|
||||||
char scramble[SCRAMBLE41_LENGTH+1];
|
char scramble[SCRAMBLE41_LENGTH+1];
|
||||||
// old scramble is needed to handle old clients
|
// old scramble is needed to handle old clients
|
||||||
@ -896,7 +907,7 @@ class user_var_entry
|
|||||||
public:
|
public:
|
||||||
LEX_STRING name;
|
LEX_STRING name;
|
||||||
char *value;
|
char *value;
|
||||||
ulong length, update_query_id;
|
ulong length, update_query_id, used_query_id;
|
||||||
Item_result type;
|
Item_result type;
|
||||||
CHARSET_INFO *var_charset;
|
CHARSET_INFO *var_charset;
|
||||||
};
|
};
|
||||||
|
@ -390,6 +390,10 @@ void init_update_queries(void)
|
|||||||
uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
|
uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_update_query(enum enum_sql_command command)
|
||||||
|
{
|
||||||
|
return uc_update_queries[command];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if maximum queries per hour limit has been reached
|
Check if maximum queries per hour limit has been reached
|
||||||
@ -3077,6 +3081,8 @@ mysql_init_query(THD *thd)
|
|||||||
thd->sent_row_count= thd->examined_row_count= 0;
|
thd->sent_row_count= thd->examined_row_count= 0;
|
||||||
thd->fatal_error= thd->rand_used= 0;
|
thd->fatal_error= thd->rand_used= 0;
|
||||||
thd->possible_loops= 0;
|
thd->possible_loops= 0;
|
||||||
|
if (opt_bin_log)
|
||||||
|
reset_dynamic(&thd->user_var_events);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +136,8 @@ bfill((A)->null_flags,(A)->null_bytes,255);\
|
|||||||
|
|
||||||
#define BIN_LOG_HEADER_SIZE 4
|
#define BIN_LOG_HEADER_SIZE 4
|
||||||
|
|
||||||
|
#define FLOATING_POINT_BUFFER 331
|
||||||
|
|
||||||
/* Include prototypes for unireg */
|
/* Include prototypes for unireg */
|
||||||
|
|
||||||
#include "mysqld_error.h"
|
#include "mysqld_error.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user