Commit 0b4e65e1 authored by lars@black.(none)'s avatar lars@black.(none)

Merge mysql.com:/home/bkroot/mysql-5.1-new-rpl

into  mysql.com:/home/bk/MERGE/mysql-5.1-merge
parents 84e4df33 1023aecb
...@@ -476,6 +476,30 @@ static bool check_database(const char *log_dbname) ...@@ -476,6 +476,30 @@ static bool check_database(const char *log_dbname)
} }
static int
write_event_header_and_base64(Log_event *ev, FILE *result_file,
PRINT_EVENT_INFO *print_event_info)
{
DBUG_ENTER("write_event_header_and_base64");
/* Write header and base64 output to cache */
IO_CACHE result_cache;
if (init_io_cache(&result_cache, -1, 0, WRITE_CACHE, 0L, FALSE,
MYF(MY_WME | MY_NABP)))
{
return 1;
}
ev->print_header(&result_cache, print_event_info, FALSE);
ev->print_base64(&result_cache, print_event_info, FALSE);
/* Read data from cache and write to result file */
my_b_copy_to_file(&result_cache, result_file);
end_io_cache(&result_cache);
DBUG_RETURN(0);
}
/* /*
Process an event Process an event
...@@ -538,18 +562,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -538,18 +562,18 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
print_event_info->base64_output= opt_base64_output; print_event_info->base64_output= opt_base64_output;
DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
switch (ev_type) { switch (ev_type) {
case QUERY_EVENT: case QUERY_EVENT:
if (check_database(((Query_log_event*)ev)->db)) if (check_database(((Query_log_event*)ev)->db))
goto end; goto end;
if (opt_base64_output) if (opt_base64_output)
{ write_event_header_and_base64(ev, result_file, print_event_info);
ev->print_header(result_file, print_event_info);
ev->print_base64(result_file, print_event_info);
}
else else
ev->print(result_file, print_event_info); ev->print(result_file, print_event_info);
break; break;
case CREATE_FILE_EVENT: case CREATE_FILE_EVENT:
{ {
Create_file_log_event* ce= (Create_file_log_event*)ev; Create_file_log_event* ce= (Create_file_log_event*)ev;
...@@ -570,8 +594,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, ...@@ -570,8 +594,7 @@ int process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
*/ */
if (opt_base64_output) if (opt_base64_output)
{ {
ce->print_header(result_file, print_event_info); write_event_header_and_base64(ce, result_file, print_event_info);
ce->print_base64(result_file, print_event_info);
} }
else else
ce->print(result_file, print_event_info, TRUE); ce->print(result_file, print_event_info, TRUE);
......
...@@ -39,7 +39,8 @@ int base64_encode(const void *src, size_t src_len, char *dst); ...@@ -39,7 +39,8 @@ int base64_encode(const void *src, size_t src_len, char *dst);
/* /*
Decode a base64 string into data Decode a base64 string into data
*/ */
int base64_decode(const char *src, size_t src_len, void *dst); int base64_decode(const char *src, size_t src_len,
void *dst, const char **end_ptr);
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -517,6 +517,7 @@ typedef int (*qsort2_cmp)(const void *, const void *, const void *); ...@@ -517,6 +517,7 @@ typedef int (*qsort2_cmp)(const void *, const void *, const void *);
(uint) (*(info)->current_pos - (info)->request_pos)) (uint) (*(info)->current_pos - (info)->request_pos))
/* tell write offset in the SEQ_APPEND cache */ /* tell write offset in the SEQ_APPEND cache */
int my_b_copy_to_file(IO_CACHE *cache, FILE *file);
my_off_t my_b_append_tell(IO_CACHE* info); my_off_t my_b_append_tell(IO_CACHE* info);
my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */ my_off_t my_b_safe_tell(IO_CACHE* info); /* picks the correct tell() */
......
...@@ -359,15 +359,6 @@ show binlog events from 102; ...@@ -359,15 +359,6 @@ show binlog events from 102;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; BEGIN
master-bin.000001 # Query 1 # use `test`; CREATE TABLE `t2` (
`a` int(11) NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB
master-bin.000001 # Table_map 1 # table_id: # (test.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # COMMIT /* xid= */
master-bin.000001 # Query 1 # use `test`; DROP TABLE if exists t2 master-bin.000001 # Query 1 # use `test`; DROP TABLE if exists t2
master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
...@@ -375,15 +366,6 @@ master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS t2 ...@@ -375,15 +366,6 @@ master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS t2
master-bin.000001 # Query 1 # use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb master-bin.000001 # Query 1 # use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb
master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `test`; BEGIN
master-bin.000001 # Query 1 # use `test`; CREATE TABLE `t2` (
`a` int(11) NOT NULL DEFAULT '0',
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB
master-bin.000001 # Table_map 1 # table_id: # (test.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # COMMIT /* xid= */
master-bin.000001 # Query 1 # use `test`; TRUNCATE table t2 master-bin.000001 # Query 1 # use `test`; TRUNCATE table t2
master-bin.000001 # Xid 1 # COMMIT /* xid= */ master-bin.000001 # Xid 1 # COMMIT /* xid= */
master-bin.000001 # Table_map 1 # table_id: # (test.t1) master-bin.000001 # Table_map 1 # table_id: # (test.t1)
......
...@@ -347,13 +347,13 @@ create view v3 (x,y,z) as select b, a, b from t1; ...@@ -347,13 +347,13 @@ create view v3 (x,y,z) as select b, a, b from t1;
create view v4 (x,y,z) as select c+1, b, a from t1; create view v4 (x,y,z) as select c+1, b, a from t1;
create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
# try insert to VIEW with fields duplicate # try insert to VIEW with fields duplicate
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v3 values (-60,4,30); insert into v3 values (-60,4,30);
# try insert to VIEW with expression in SELECT list # try insert to VIEW with expression in SELECT list
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v4 values (-60,4,30); insert into v4 values (-60,4,30);
# try insert to VIEW using temporary table algorithm # try insert to VIEW using temporary table algorithm
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v5 values (-60,4,30); insert into v5 values (-60,4,30);
insert into v1 values (-60,4,30); insert into v1 values (-60,4,30);
insert into v1 (z,y,x) values (50,6,-100); insert into v1 (z,y,x) values (50,6,-100);
...@@ -375,13 +375,13 @@ create view v3 (x,y,z) as select b, a, b from t1; ...@@ -375,13 +375,13 @@ create view v3 (x,y,z) as select b, a, b from t1;
create view v4 (x,y,z) as select c+1, b, a from t1; create view v4 (x,y,z) as select c+1, b, a from t1;
create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1; create algorithm=temptable view v5 (x,y,z) as select c, b, a from t1;
# try insert to VIEW with fields duplicate # try insert to VIEW with fields duplicate
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v3 select c, b, a from t2; insert into v3 select c, b, a from t2;
# try insert to VIEW with expression in SELECT list # try insert to VIEW with expression in SELECT list
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v4 select c, b, a from t2; insert into v4 select c, b, a from t2;
# try insert to VIEW using temporary table algorithm # try insert to VIEW using temporary table algorithm
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v5 select c, b, a from t2; insert into v5 select c, b, a from t2;
insert into v1 select c, b, a from t2; insert into v1 select c, b, a from t2;
insert into v1 (z,y,x) select a+20,b+2,-100 from t2; insert into v1 (z,y,x) select a+20,b+2,-100 from t2;
...@@ -1249,14 +1249,14 @@ drop table t1; ...@@ -1249,14 +1249,14 @@ drop table t1;
# #
create table t1 (s1 smallint); create table t1 (s1 smallint);
create view v1 as select * from t1 where 20 < (select (s1) from t1); create view v1 as select * from t1 where 20 < (select (s1) from t1);
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v1 values (30); insert into v1 values (30);
create view v2 as select * from t1; create view v2 as select * from t1;
create view v3 as select * from t1 where 20 < (select (s1) from v2); create view v3 as select * from t1 where 20 < (select (s1) from v2);
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v3 values (30); insert into v3 values (30);
create view v4 as select * from v2 where 20 < (select (s1) from t1); create view v4 as select * from v2 where 20 < (select (s1) from t1);
-- error 1573 -- error ER_NON_INSERTABLE_TABLE
insert into v4 values (30); insert into v4 values (30);
drop view v4, v3, v2, v1; drop view v4, v3, v2, v1;
drop table t1; drop table t1;
...@@ -2861,7 +2861,7 @@ DROP TABLE t1; ...@@ -2861,7 +2861,7 @@ DROP TABLE t1;
# #
create table t1 (s1 int); create table t1 (s1 int);
create view v1 as select s1 as a, s1 as b from t1; create view v1 as select s1 as a, s1 as b from t1;
--error 1573 --error ER_NON_INSERTABLE_TABLE
insert into v1 values (1,1); insert into v1 values (1,1);
update v1 set a = 5; update v1 set a = 5;
drop view v1; drop view v1;
......
...@@ -125,44 +125,69 @@ pos(unsigned char c) ...@@ -125,44 +125,69 @@ pos(unsigned char c)
/* /*
Decode a base64 string Decode a base64 string
Note: We require that dst is pre-allocated to correct size. SYNOPSIS
See base64_needed_decoded_length(). base64_decode()
src Pointer to base64-encoded string
RETURN Number of bytes produced in dst or -1 in case of failure len Length of string at 'src'
dst Pointer to location where decoded data will be stored
end_ptr Pointer to variable that will refer to the character
after the end of the encoded data that were decoded. Can
be NULL.
DESCRIPTION
The base64-encoded data in the range ['src','*end_ptr') will be
decoded and stored starting at 'dst'. The decoding will stop
after 'len' characters have been read from 'src', or when padding
occurs in the base64-encoded data. In either case: if 'end_ptr' is
non-null, '*end_ptr' will be set to point to the character after
the last read character, even in the presence of error.
NOTE
We require that 'dst' is pre-allocated to correct size.
SEE ALSO
base64_needed_decoded_length().
RETURN VALUE
Number of bytes written at 'dst' or -1 in case of failure
*/ */
int int
base64_decode(const char *src, size_t size, void *dst) base64_decode(const char *const src_base, size_t const len,
void *dst, const char **end_ptr)
{ {
char b[3]; char b[3];
size_t i= 0; size_t i= 0;
char *dst_base= (char *)dst; char *dst_base= (char *)dst;
char const *src= src_base;
char *d= dst_base; char *d= dst_base;
size_t j; size_t j;
while (i < size) while (i < len)
{ {
unsigned c= 0; unsigned c= 0;
size_t mark= 0; size_t mark= 0;
SKIP_SPACE(src, i, size); SKIP_SPACE(src, i, len);
c += pos(*src++); c += pos(*src++);
c <<= 6; c <<= 6;
i++; i++;
SKIP_SPACE(src, i, size); SKIP_SPACE(src, i, len);
c += pos(*src++); c += pos(*src++);
c <<= 6; c <<= 6;
i++; i++;
SKIP_SPACE(src, i, size); SKIP_SPACE(src, i, len);
if (* src != '=') if (*src != '=')
c += pos(*src++); c += pos(*src++);
else else
{ {
i= size; src += 2; /* There should be two bytes padding */
i= len;
mark= 2; mark= 2;
c <<= 6; c <<= 6;
goto end; goto end;
...@@ -170,13 +195,14 @@ base64_decode(const char *src, size_t size, void *dst) ...@@ -170,13 +195,14 @@ base64_decode(const char *src, size_t size, void *dst)
c <<= 6; c <<= 6;
i++; i++;
SKIP_SPACE(src, i, size); SKIP_SPACE(src, i, len);
if (*src != '=') if (*src != '=')
c += pos(*src++); c += pos(*src++);
else else
{ {
i= size; src += 1; /* There should be one byte padding */
i= len;
mark= 1; mark= 1;
goto end; goto end;
} }
...@@ -191,11 +217,14 @@ base64_decode(const char *src, size_t size, void *dst) ...@@ -191,11 +217,14 @@ base64_decode(const char *src, size_t size, void *dst)
*d++= b[j]; *d++= b[j];
} }
if (i != size) if (end_ptr != NULL)
{ *end_ptr= src;
return -1;
} /*
return d - dst_base; The variable 'i' is set to 'len' when padding has been read, so it
does not actually reflect the number of bytes read from 'src'.
*/
return i != len ? -1 : d - dst_base;
} }
......
...@@ -24,6 +24,54 @@ ...@@ -24,6 +24,54 @@
#include <stdarg.h> #include <stdarg.h>
#include <m_ctype.h> #include <m_ctype.h>
/*
Copy contents of an IO_CACHE to a file.
SYNOPSIS
my_b_copy_to_file()
cache IO_CACHE to copy from
file File to copy to
DESCRIPTION
Copy the contents of the cache to the file. The cache will be
re-inited to a read cache and will read from the beginning of the
cache.
If a failure to write fully occurs, the cache is only copied
partially.
TODO
Make this function solid by handling partial reads from the cache
in a correct manner: it should be atomic.
RETURN VALUE
0 All OK
1 An error occured
*/
int
my_b_copy_to_file(IO_CACHE *cache, FILE *file)
{
byte buf[IO_SIZE];
uint bytes_in_cache;
DBUG_ENTER("my_b_copy_to_file");
/* Reinit the cache to read from the beginning of the cache */
if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
DBUG_RETURN(1);
bytes_in_cache= my_b_bytes_in_cache(cache);
while (bytes_in_cache > 0) {
uint const read_bytes= min(bytes_in_cache, sizeof(buf));
DBUG_PRINT("debug", ("Remaining %u bytes - Reading %u bytes",
bytes_in_cache, read_bytes));
if (my_b_read(cache, buf, read_bytes))
DBUG_RETURN(1);
if (my_fwrite(file, buf, read_bytes, MYF(MY_WME | MY_NABP)) == (uint) -1)
DBUG_RETURN(1);
bytes_in_cache -= read_bytes;
}
DBUG_RETURN(0);
}
my_off_t my_b_append_tell(IO_CACHE* info) my_off_t my_b_append_tell(IO_CACHE* info)
{ {
/* /*
......
This diff is collapsed.
This diff is collapsed.
...@@ -519,14 +519,30 @@ typedef struct st_print_event_info ...@@ -519,14 +519,30 @@ typedef struct st_print_event_info
bzero(db, sizeof(db)); bzero(db, sizeof(db));
bzero(charset, sizeof(charset)); bzero(charset, sizeof(charset));
bzero(time_zone_str, sizeof(time_zone_str)); bzero(time_zone_str, sizeof(time_zone_str));
uint const flags = MYF(MY_WME | MY_NABP);
init_io_cache(&head_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
init_io_cache(&body_cache, -1, 0, WRITE_CACHE, 0L, FALSE, flags);
} }
~st_print_event_info() {
end_io_cache(&head_cache);
end_io_cache(&body_cache);
}
/* Settings on how to print the events */ /* Settings on how to print the events */
bool short_form; bool short_form;
bool base64_output; bool base64_output;
my_off_t hexdump_from; my_off_t hexdump_from;
uint8 common_header_len; uint8 common_header_len;
/*
These two caches are used by the row-based replication events to
collect the header information and the main body of the events
making up a statement.
*/
IO_CACHE head_cache;
IO_CACHE body_cache;
} PRINT_EVENT_INFO; } PRINT_EVENT_INFO;
#endif #endif
...@@ -637,9 +653,11 @@ public: ...@@ -637,9 +653,11 @@ public:
const Format_description_log_event *description_event); const Format_description_log_event *description_event);
/* print*() functions are used by mysqlbinlog */ /* print*() functions are used by mysqlbinlog */
virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0; virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
void print_timestamp(FILE* file, time_t *ts = 0); void print_timestamp(IO_CACHE* file, time_t *ts = 0);
void print_header(FILE* file, PRINT_EVENT_INFO* print_event_info); void print_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
void print_base64(FILE* file, PRINT_EVENT_INFO* print_event_info); bool is_more);
void print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
bool is_more);
#endif #endif
static void *operator new(size_t size) static void *operator new(size_t size)
...@@ -804,7 +822,7 @@ public: ...@@ -804,7 +822,7 @@ public:
uint32 q_len_arg); uint32 q_len_arg);
#endif /* HAVE_REPLICATION */ #endif /* HAVE_REPLICATION */
#else #else
void print_query_header(FILE* file, PRINT_EVENT_INFO* print_event_info); void print_query_header(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info);
void print(FILE* file, PRINT_EVENT_INFO* print_event_info); void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif #endif
...@@ -1864,6 +1882,10 @@ protected: ...@@ -1864,6 +1882,10 @@ protected:
Log_event_type event_type, Log_event_type event_type,
const Format_description_log_event *description_event); const Format_description_log_event *description_event);
#ifdef MYSQL_CLIENT
void print_helper(FILE *, PRINT_EVENT_INFO *, char const *const name);
#endif
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
virtual int do_add_row_data(byte *data, my_size_t length); virtual int do_add_row_data(byte *data, my_size_t length);
#endif #endif
......
...@@ -5968,6 +5968,9 @@ ER_CANT_ACTIVATE_LOG ...@@ -5968,6 +5968,9 @@ ER_CANT_ACTIVATE_LOG
ger "Kann Logdatei '%-.64s' nicht aktivieren" ger "Kann Logdatei '%-.64s' nicht aktivieren"
ER_RBR_NOT_AVAILABLE ER_RBR_NOT_AVAILABLE
eng "The server was not built with row-based replication" eng "The server was not built with row-based replication"
ER_BASE64_DECODE_ERROR
eng "Decoding of base64 string failed"
swe "Avkodning av base64 strng misslyckades"
ger "Der Server hat keine zeilenbasierte Replikation" ger "Der Server hat keine zeilenbasierte Replikation"
ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
eng "Triggers can not be created on system tables" eng "Triggers can not be created on system tables"
......
...@@ -3101,17 +3101,22 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) ...@@ -3101,17 +3101,22 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT)) type_code != START_EVENT_V3 && type_code!= FORMAT_DESCRIPTION_EVENT))
{ {
DBUG_PRINT("info", ("event skipped")); DBUG_PRINT("info", ("event skipped"));
if (thd->options & OPTION_BEGIN) /*
rli->inc_event_relay_log_pos(); We only skip the event here and do not increase the group log
else position. In the event that we have to restart, this means
{ that we might have to skip the event again, but that is a
rli->inc_group_relay_log_pos((type_code == ROTATE_EVENT || minor issue.
type_code == STOP_EVENT ||
type_code == FORMAT_DESCRIPTION_EVENT) ? If we were to increase the group log position when skipping an
LL(0) : ev->log_pos, event, it might be that we are restarting at the wrong
1/* skip lock*/); position and have events before that we should have executed,
flush_relay_log_info(rli); so not increasing the group log position is a sure bet in this
} case.
In this way, we just step the group log position when we
*know* that we are at the end of a group.
*/
rli->inc_event_relay_log_pos();
/* /*
Protect against common user error of setting the counter to 1 Protect against common user error of setting the counter to 1
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
void mysql_client_binlog_statement(THD* thd) void mysql_client_binlog_statement(THD* thd)
{ {
DBUG_ENTER("mysql_client_binlog_statement");
DBUG_PRINT("info",("binlog base64: '%*s'", DBUG_PRINT("info",("binlog base64: '%*s'",
(thd->lex->comment.length < 2048 ? (thd->lex->comment.length < 2048 ?
thd->lex->comment.length : 2048), thd->lex->comment.length : 2048),
...@@ -43,8 +44,8 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -43,8 +44,8 @@ void mysql_client_binlog_statement(THD* thd)
my_bool nsok= thd->net.no_send_ok; my_bool nsok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE; thd->net.no_send_ok= TRUE;
const my_size_t coded_len= thd->lex->comment.length + 1; my_size_t coded_len= thd->lex->comment.length + 1;
const my_size_t event_len= base64_needed_decoded_length(coded_len); my_size_t decoded_len= base64_needed_decoded_length(coded_len);
DBUG_ASSERT(coded_len > 0); DBUG_ASSERT(coded_len > 0);
/* /*
...@@ -57,9 +58,8 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -57,9 +58,8 @@ void mysql_client_binlog_statement(THD* thd)
new Format_description_log_event(4); new Format_description_log_event(4);
const char *error= 0; const char *error= 0;
char *buf= (char *) my_malloc(event_len, MYF(MY_WME)); char *buf= (char *) my_malloc(decoded_len, MYF(MY_WME));
Log_event *ev = 0; Log_event *ev = 0;
int res;
/* /*
Out of memory check Out of memory check
...@@ -73,43 +73,97 @@ void mysql_client_binlog_statement(THD* thd) ...@@ -73,43 +73,97 @@ void mysql_client_binlog_statement(THD* thd)
thd->rli_fake->sql_thd= thd; thd->rli_fake->sql_thd= thd;
thd->rli_fake->no_storage= TRUE; thd->rli_fake->no_storage= TRUE;
res= base64_decode(thd->lex->comment.str, coded_len, buf); for (char const *strptr= thd->lex->comment.str ;
strptr < thd->lex->comment.str + thd->lex->comment.length ; )
DBUG_PRINT("info",("binlog base64 decoded_len=%d, event_len=%d\n",
res, uint4korr(buf + EVENT_LEN_OFFSET)));
/*
Note that 'res' is the correct event length, 'event_len' was
calculated based on the base64-string that possibly contained
extra spaces, so it can be longer than the real event.
*/
if (res < EVENT_LEN_OFFSET
|| (uint) res != uint4korr(buf+EVENT_LEN_OFFSET))
{ {
my_error(ER_SYNTAX_ERROR, MYF(0)); char const *endptr= 0;
goto end; int bytes_decoded= base64_decode(strptr, coded_len, buf, &endptr);
}
DBUG_PRINT("info",
ev= Log_event::read_log_event(buf, res, &error, desc); ("bytes_decoded=%d; strptr=0x%lu; endptr=0x%lu ('%c':%d)",
bytes_decoded, strptr, endptr, *endptr, *endptr));
if (bytes_decoded < 0)
{
my_error(ER_BASE64_DECODE_ERROR, MYF(0));
goto end;
}
else if (bytes_decoded == 0)
break; // If no bytes where read, the string contained only whitespace
DBUG_ASSERT(bytes_decoded > 0);
DBUG_ASSERT(endptr > strptr);
coded_len-= endptr - strptr;
strptr= endptr;
DBUG_PRINT("info",("binlog base64 err=%s", error));
if (!ev)
{
/* /*
This could actually be an out-of-memory, but it is more Now we have one or more events stored in the buffer. The size of
likely causes by a bad statement the buffer is computed based on how much base64-encoded data
there were, so there should be ample space for the data (maybe
even too much, since a statement can consist of a considerable
number of events).
TODO: Switch to use a stream-based base64 encoder/decoder in
order to be able to read exactly what is necessary.
*/ */
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;
}
DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code())); DBUG_PRINT("info",("binlog base64 decoded_len=%d, bytes_decoded=%d",
DBUG_PRINT("info",("buf+EVENT_TYPE_OFFSET=%d", buf+EVENT_TYPE_OFFSET)); decoded_len, bytes_decoded));
ev->thd= thd; /*
if (ev->exec_event(thd->rli_fake)) Now we start to read events of the buffer, until there are no
{ more.
my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement"); */
goto end; for (char *bufptr= buf ; bytes_decoded > 0 ; )
{
/*
Checking that the first event in the buffer is not truncated.
*/
ulong event_len= uint4korr(bufptr + EVENT_LEN_OFFSET);
DBUG_PRINT("info", ("event_len=%lu, bytes_decoded=%d",
event_len, bytes_decoded));
if (bytes_decoded < EVENT_LEN_OFFSET || (uint) bytes_decoded < event_len)
{
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;
}
ev= Log_event::read_log_event(bufptr, event_len, &error, desc);
DBUG_PRINT("info",("binlog base64 err=%s", error));
if (!ev)
{
/*
This could actually be an out-of-memory, but it is more likely
causes by a bad statement
*/
my_error(ER_SYNTAX_ERROR, MYF(0));
goto end;
}
bytes_decoded -= event_len;
bufptr += event_len;
DBUG_PRINT("info",("ev->get_type_code()=%d", ev->get_type_code()));
DBUG_PRINT("info",("bufptr+EVENT_TYPE_OFFSET=0x%lx",
bufptr+EVENT_TYPE_OFFSET));
DBUG_PRINT("info", ("bytes_decoded=%d; bufptr=0x%lx; buf[EVENT_LEN_OFFSET]=%u",
bytes_decoded, bufptr, uint4korr(bufptr+EVENT_LEN_OFFSET)));
ev->thd= thd;
if (int err= ev->exec_event(thd->rli_fake))
{
DBUG_PRINT("info", ("exec_event() - error=%d", error));
/*
TODO: Maybe a better error message since the BINLOG statement
now contains several events.
*/
my_error(ER_UNKNOWN_ERROR, MYF(0), "Error executing BINLOG statement");
goto end;
}
delete ev;
ev= 0;
}
} }
/* /*
...@@ -126,10 +180,7 @@ end: ...@@ -126,10 +180,7 @@ end:
*/ */
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
if (ev) delete desc;
delete ev; my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
if (desc) DBUG_VOID_RETURN;
delete desc;
if (buf)
my_free(buf, MYF(0));
} }
...@@ -930,6 +930,7 @@ public: ...@@ -930,6 +930,7 @@ public:
/* /*
Public interface to write RBR events to the binlog Public interface to write RBR events to the binlog
*/ */
void binlog_start_trans_and_stmt();
int binlog_write_table_map(TABLE *table, bool is_transactional); int binlog_write_table_map(TABLE *table, bool is_transactional);
int binlog_write_row(TABLE* table, bool is_transactional, int binlog_write_row(TABLE* table, bool is_transactional,
MY_BITMAP const* cols, my_size_t colcnt, MY_BITMAP const* cols, my_size_t colcnt,
......
...@@ -1266,7 +1266,7 @@ err: ...@@ -1266,7 +1266,7 @@ err:
if (thd->lex->current_select) if (thd->lex->current_select)
thd->lex->current_select->no_error= 0; // Give error thd->lex->current_select->no_error= 0; // Give error
table->file->print_error(error,MYF(0)); table->file->print_error(error,MYF(0));
before_trg_err: before_trg_err:
table->file->restore_auto_increment(prev_insert_id); table->file->restore_auto_increment(prev_insert_id);
if (key) if (key)
...@@ -2033,6 +2033,10 @@ err: ...@@ -2033,6 +2033,10 @@ err:
rolled back. We only need to roll back a potential statement rolled back. We only need to roll back a potential statement
transaction, since real transactions are rolled back in transaction, since real transactions are rolled back in
close_thread_tables(). close_thread_tables().
TODO: This is not true any more, table maps are generated on the
first call to ha_*_row() instead. Remove code that are used to
cover for the case outlined above.
*/ */
ha_rollback_stmt(thd); ha_rollback_stmt(thd);
...@@ -2402,6 +2406,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2402,6 +2406,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_ENTER("select_insert::prepare"); DBUG_ENTER("select_insert::prepare");
unit= u; unit= u;
/* /*
Since table in which we are going to insert is added to the first Since table in which we are going to insert is added to the first
select, LEX::current_select should point to the first select while select, LEX::current_select should point to the first select while
...@@ -2631,58 +2636,56 @@ void select_insert::send_error(uint errcode,const char *err) ...@@ -2631,58 +2636,56 @@ void select_insert::send_error(uint errcode,const char *err)
if (errcode != ER_UNKNOWN_ERROR && !thd->net.report_error) if (errcode != ER_UNKNOWN_ERROR && !thd->net.report_error)
my_message(errcode, err, MYF(0)); my_message(errcode, err, MYF(0));
if (!table) /*
If the creation of the table failed (due to a syntax error, for
example), no table will have been opened and therefore 'table'
will be NULL. In that case, we still need to execute the rollback
and the end of the function to truncate the binary log, but we can
skip all the intermediate steps.
*/
if (table)
{ {
/* /*
This can only happen when using CREATE ... SELECT and the table was not If we are not in prelocked mode, we end the bulk insert started
created becasue of an syntax error before.
*/ */
DBUG_VOID_RETURN; if (!thd->prelocked_mode)
} table->file->ha_end_bulk_insert();
if (!thd->prelocked_mode)
table->file->ha_end_bulk_insert(); /*
/* If at least one row has been inserted/modified and will stay in
If at least one row has been inserted/modified and will stay in the table the table (the table doesn't have transactions) we must write to
(the table doesn't have transactions) we must write to the binlog (and the binlog (and the error code will make the slave stop).
the error code will make the slave stop).
For many errors (example: we got a duplicate key error while
For many errors (example: we got a duplicate key error while inserting into a MyISAM table), no row will be added to the table,
inserting into a MyISAM table), no row will be added to the table, so passing the error to the slave will not help since there will
so passing the error to the slave will not help since there will be an error code mismatch (the inserts will succeed on the slave
be an error code mismatch (the inserts will succeed on the slave with no error).
with no error).
If table creation failed, the number of rows modified will also be
If we are using row-based replication we have two cases where this zero, so no check for that is made.
code is executed: replication of CREATE-SELECT and replication of */
INSERT-SELECT. if (info.copied || info.deleted || info.updated)
When replicating a CREATE-SELECT statement, we shall not write the
events to the binary log and should thus not set
OPTION_STATUS_NO_TRANS_UPDATE.
When replicating INSERT-SELECT, we shall not write the events to
the binary log for transactional table, but shall write all events
if there is one or more writes to non-transactional tables. In
this case, the OPTION_STATUS_NO_TRANS_UPDATE is set if there is a
write to a non-transactional table, otherwise it is cleared.
*/
if (info.copied || info.deleted || info.updated)
{
if (!table->file->has_transactions())
{ {
if (mysql_bin_log.is_open()) DBUG_ASSERT(table != NULL);
if (!table->file->has_transactions())
{ {
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, if (mysql_bin_log.is_open())
table->file->has_transactions(), FALSE); {
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
table->file->has_transactions(), FALSE);
}
if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table &&
!can_rollback_data())
thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
query_cache_invalidate3(thd, table, 1);
} }
if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table &&
!can_rollback_data())
thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
query_cache_invalidate3(thd, table, 1);
} }
table->file->ha_release_auto_increment();
} }
ha_rollback_stmt(thd); ha_rollback_stmt(thd);
table->file->ha_release_auto_increment();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2690,8 +2693,11 @@ void select_insert::send_error(uint errcode,const char *err) ...@@ -2690,8 +2693,11 @@ void select_insert::send_error(uint errcode,const char *err)
bool select_insert::send_eof() bool select_insert::send_eof()
{ {
int error,error2; int error,error2;
bool const trans_table= table->file->has_transactions();
ulonglong id; ulonglong id;
DBUG_ENTER("select_insert::send_eof"); DBUG_ENTER("select_insert::send_eof");
DBUG_PRINT("enter", ("trans_table=%d, table_type='%s'",
trans_table, table->file->table_type()));
error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0; error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
...@@ -2711,9 +2717,8 @@ bool select_insert::send_eof() ...@@ -2711,9 +2717,8 @@ bool select_insert::send_eof()
are not logged in RBR) are not logged in RBR)
- We are using statement based replication - We are using statement based replication
*/ */
if (!table->file->has_transactions() && if (!trans_table &&
(!table->s->tmp_table || (!table->s->tmp_table || !thd->current_stmt_binlog_row_based))
!thd->current_stmt_binlog_row_based))
thd->options|= OPTION_STATUS_NO_TRANS_UPDATE; thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
} }
...@@ -2729,11 +2734,22 @@ bool select_insert::send_eof() ...@@ -2729,11 +2734,22 @@ bool select_insert::send_eof()
thd->clear_error(); thd->clear_error();
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length, thd->query, thd->query_length,
table->file->has_transactions(), FALSE); trans_table, FALSE);
}
/*
We will call ha_autocommit_or_rollback() also for
non-transactional tables under row-based replication: there might
be events in the binary logs transaction, and we need to write
them to the binary log.
*/
if (trans_table || thd->current_stmt_binlog_row_based)
{
int const error2= ha_autocommit_or_rollback(thd, error);
if (error2 && !error)
error=error2;
} }
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
error=error2;
table->file->ha_release_auto_increment(); table->file->ha_release_auto_increment();
if (error) if (error)
{ {
table->file->print_error(error,MYF(0)); table->file->print_error(error,MYF(0));
...@@ -2930,14 +2946,19 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2930,14 +2946,19 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
class MY_HOOKS : public TABLEOP_HOOKS { class MY_HOOKS : public TABLEOP_HOOKS {
public: public:
MY_HOOKS(select_create *x) : ptr(x) { } MY_HOOKS(select_create *x) : ptr(x) { }
private:
virtual void do_prelock(TABLE **tables, uint count) virtual void do_prelock(TABLE **tables, uint count)
{ {
if (ptr->get_thd()->current_stmt_binlog_row_based && TABLE const *const table = *tables;
!(ptr->get_create_info()->options & HA_LEX_CREATE_TMP_TABLE)) if (ptr->get_thd()->current_stmt_binlog_row_based &&
ptr->binlog_show_create_table(tables, count); table->s->tmp_table == NO_TMP_TABLE &&
!ptr->get_create_info()->table_existed)
{
ptr->binlog_show_create_table(tables, count);
}
} }
private:
select_create *ptr; select_create *ptr;
}; };
...@@ -2946,6 +2967,20 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) ...@@ -2946,6 +2967,20 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
#endif #endif
unit= u; unit= u;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
Start a statement transaction before the create if we are creating
a non-temporary table and are using row-based replication for the
statement.
*/
if ((thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) == 0 &&
thd->current_stmt_binlog_row_based)
{
thd->binlog_start_trans_and_stmt();
}
#endif
if (!(table= create_table_from_items(thd, create_info, create_table, if (!(table= create_table_from_items(thd, create_info, create_table,
extra_fields, keys, &values, extra_fields, keys, &values,
&thd->extra_lock, hook_ptr))) &thd->extra_lock, hook_ptr)))
...@@ -3093,8 +3128,17 @@ void select_create::abort() ...@@ -3093,8 +3128,17 @@ void select_create::abort()
table->s->version= 0; table->s->version= 0;
hash_delete(&open_cache,(byte*) table); hash_delete(&open_cache,(byte*) table);
if (!create_info->table_existed) if (!create_info->table_existed)
{
quick_rm_table(table_type, create_table->db, quick_rm_table(table_type, create_table->db,
create_table->table_name, 0); create_table->table_name, 0);
/*
We roll back the statement, including truncating the
transaction cache of the binary log, if the statement
failed.
*/
if (thd->current_stmt_binlog_row_based)
ha_rollback_stmt(thd);
}
/* Tell threads waiting for refresh that something has happened */ /* Tell threads waiting for refresh that something has happened */
if (version != refresh_version) if (version != refresh_version)
broadcast_refresh(); broadcast_refresh();
......
...@@ -2013,7 +2013,7 @@ ndb_mgm_get_configuration(NdbMgmHandle handle, unsigned int version) { ...@@ -2013,7 +2013,7 @@ ndb_mgm_get_configuration(NdbMgmHandle handle, unsigned int version) {
break; break;
void *tmp_data = malloc(base64_needed_decoded_length((size_t) (len - 1))); void *tmp_data = malloc(base64_needed_decoded_length((size_t) (len - 1)));
const int res = base64_decode(buf64, len-1, tmp_data); const int res = base64_decode(buf64, len-1, tmp_data, NULL);
delete[] buf64; delete[] buf64;
UtilBuffer tmp; UtilBuffer tmp;
tmp.append((void *) tmp_data, res); tmp.append((void *) tmp_data, res);
......
...@@ -54,7 +54,7 @@ main(void) ...@@ -54,7 +54,7 @@ main(void)
/* Decode */ /* Decode */
dst= (char *) malloc(base64_needed_decoded_length(strlen(str))); dst= (char *) malloc(base64_needed_decoded_length(strlen(str)));
dst_len= base64_decode(str, strlen(str), dst); dst_len= base64_decode(str, strlen(str), dst, NULL);
ok(dst_len == src_len, "Comparing lengths"); ok(dst_len == src_len, "Comparing lengths");
cmp= memcmp(src, dst, src_len); cmp= memcmp(src, dst, src_len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment