Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
26a1d888
Commit
26a1d888
authored
Oct 31, 2002
by
peter@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Merge mysql.com:/home/pz/mysql/mysql-4.1-root
into mysql.com:/home/pz/mysql/mysql-4.1
parents
cc18dc72
9e3f16df
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
1994 additions
and
1096 deletions
+1994
-1096
.bzrignore
.bzrignore
+13
-10
BitKeeper/etc/config
BitKeeper/etc/config
+1
-0
include/thr_lock.h
include/thr_lock.h
+4
-0
mysql-test/r/derived.result
mysql-test/r/derived.result
+6
-0
mysql-test/std_data/master-bin.001
mysql-test/std_data/master-bin.001
+0
-0
mysql-test/t/derived.test
mysql-test/t/derived.test
+2
-0
mysys/thr_lock.c
mysys/thr_lock.c
+4
-4
sql/lock.cc
sql/lock.cc
+11
-0
sql/log_event.cc
sql/log_event.cc
+1647
-1030
sql/log_event.h
sql/log_event.h
+97
-10
sql/sql_derived.cc
sql/sql_derived.cc
+2
-1
sql/sql_parse.cc
sql/sql_parse.cc
+7
-3
sql/sql_test.cc
sql/sql_test.cc
+111
-18
sql/sql_yacc.yy
sql/sql_yacc.yy
+0
-14
strings/longlong2str-x86.s
strings/longlong2str-x86.s
+89
-6
No files found.
.bzrignore
View file @
26a1d888
...
@@ -75,6 +75,7 @@ Makefile.in'
...
@@ -75,6 +75,7 @@ Makefile.in'
PENDING/*
PENDING/*
TAGS
TAGS
aclocal.m4
aclocal.m4
autom4te.cache/*
bdb/README
bdb/README
bdb/btree/btree_auto.c
bdb/btree/btree_auto.c
bdb/build_unix/*
bdb/build_unix/*
...
@@ -192,6 +193,7 @@ config.h.in
...
@@ -192,6 +193,7 @@ config.h.in
config.log
config.log
config.status
config.status
configure
configure
configure.lineno
core
core
db-*.*.*
db-*.*.*
dbug/user.t
dbug/user.t
...
@@ -209,10 +211,13 @@ include/my_config.h
...
@@ -209,10 +211,13 @@ include/my_config.h
include/my_global.h
include/my_global.h
include/mysql_version.h
include/mysql_version.h
include/widec.h
include/widec.h
innobase/autom4te.cache/*
innobase/configure.lineno
innobase/conftest.s1
innobase/conftest.s1
innobase/conftest.subs
innobase/conftest.subs
innobase/ib_config.h
innobase/ib_config.h
innobase/ib_config.h.in
innobase/ib_config.h.in
innobase/stamp-h1
isam/isamchk
isam/isamchk
isam/isamlog
isam/isamlog
isam/pack_isam
isam/pack_isam
...
@@ -302,6 +307,7 @@ libmysqld/sql_db.cc
...
@@ -302,6 +307,7 @@ libmysqld/sql_db.cc
libmysqld/sql_delete.cc
libmysqld/sql_delete.cc
libmysqld/sql_do.cc
libmysqld/sql_do.cc
libmysqld/sql_handler.cc
libmysqld/sql_handler.cc
libmysqld/sql_help.cc
libmysqld/sql_insert.cc
libmysqld/sql_insert.cc
libmysqld/sql_lex.cc
libmysqld/sql_lex.cc
libmysqld/sql_list.cc
libmysqld/sql_list.cc
...
@@ -361,6 +367,8 @@ myisam/myisamchk
...
@@ -361,6 +367,8 @@ myisam/myisamchk
myisam/myisamlog
myisam/myisamlog
myisam/myisampack
myisam/myisampack
myisam/rt_test
myisam/rt_test
myisam/rt_test.MYD
myisam/rt_test.MYI
myisam/sp_test
myisam/sp_test
myisam/test1.MYD
myisam/test1.MYD
myisam/test1.MYI
myisam/test1.MYI
...
@@ -405,6 +413,8 @@ repl-tests/test-repl/foo-dump-slave.master.
...
@@ -405,6 +413,8 @@ repl-tests/test-repl/foo-dump-slave.master.
repl-tests/test-repl/sum-wlen-slave.master.
repl-tests/test-repl/sum-wlen-slave.master.
repl-tests/test-repl/sum-wlen-slave.master.re
repl-tests/test-repl/sum-wlen-slave.master.re
repl-tests/test-repl/sum-wlen-slave.master.reje
repl-tests/test-repl/sum-wlen-slave.master.reje
scripts/fill_func_tables
scripts/fill_func_tables.sql
scripts/make_binary_distribution
scripts/make_binary_distribution
scripts/msql2mysql
scripts/msql2mysql
scripts/mysql_config
scripts/mysql_config
...
@@ -474,8 +484,11 @@ sql/sql_select.cc.orig
...
@@ -474,8 +484,11 @@ sql/sql_select.cc.orig
sql/sql_yacc.cc
sql/sql_yacc.cc
sql/sql_yacc.h
sql/sql_yacc.h
sql/sql_yacc.yy.orig
sql/sql_yacc.yy.orig
sql_error.cc
sql_prepare.cc
stamp-h
stamp-h
stamp-h.in
stamp-h.in
stamp-h1
strings/conf_to_src
strings/conf_to_src
strings/ctype_autoconf.c
strings/ctype_autoconf.c
strings/ctype_extra_sources.c
strings/ctype_extra_sources.c
...
@@ -503,13 +516,3 @@ vio/test-ssl
...
@@ -503,13 +516,3 @@ vio/test-ssl
vio/test-sslclient
vio/test-sslclient
vio/test-sslserver
vio/test-sslserver
vio/viotest-ssl
vio/viotest-ssl
sql_error.cc
sql_prepare.cc
autom4te.cache/*
innobase/autom4te.cache/*
configure.lineno
innobase/configure.lineno
innobase/stamp-h1
myisam/rt_test.MYD
myisam/rt_test.MYI
stamp-h1
BitKeeper/etc/config
View file @
26a1d888
...
@@ -69,4 +69,5 @@ pager:
...
@@ -69,4 +69,5 @@ pager:
hours:
hours:
[serg:]checkout:get
[serg:]checkout:get
[arjen:]checkout:get
[arjen:]checkout:get
[nick:]checkout:get
checkout:edit
checkout:edit
include/thr_lock.h
View file @
26a1d888
...
@@ -74,6 +74,7 @@ typedef struct st_thr_lock_data {
...
@@ -74,6 +74,7 @@ typedef struct st_thr_lock_data {
enum
thr_lock_type
type
;
enum
thr_lock_type
type
;
ulong
thread_id
;
ulong
thread_id
;
void
*
status_param
;
/* Param to status functions */
void
*
status_param
;
/* Param to status functions */
void
*
debug_print_param
;
}
THR_LOCK_DATA
;
}
THR_LOCK_DATA
;
struct
st_lock_list
{
struct
st_lock_list
{
...
@@ -97,6 +98,9 @@ typedef struct st_thr_lock {
...
@@ -97,6 +98,9 @@ typedef struct st_thr_lock {
}
THR_LOCK
;
}
THR_LOCK
;
extern
LIST
*
thr_lock_thread_list
;
extern
pthread_mutex_t
THR_LOCK_lock
;
my_bool
init_thr_lock
(
void
);
/* Must be called once/thread */
my_bool
init_thr_lock
(
void
);
/* Must be called once/thread */
void
thr_lock_init
(
THR_LOCK
*
lock
);
void
thr_lock_init
(
THR_LOCK
*
lock
);
void
thr_lock_delete
(
THR_LOCK
*
lock
);
void
thr_lock_delete
(
THR_LOCK
*
lock
);
...
...
mysql-test/r/derived.result
View file @
26a1d888
...
@@ -18,3 +18,9 @@ a y
...
@@ -18,3 +18,9 @@ a y
3 3
3 3
3 3
3 3
drop table if exists t1.t2,t3;
drop table if exists t1.t2,t3;
select * from (select 1);
1
1
select a from (select 1 as a);
a
1
mysql-test/std_data/master-bin.001
deleted
100644 → 0
View file @
cc18dc72
File deleted
mysql-test/t/derived.test
View file @
26a1d888
...
@@ -9,3 +9,5 @@ CREATE TABLE t3 (a int not null, b char (10) not null);
...
@@ -9,3 +9,5 @@ CREATE TABLE t3 (a int not null, b char (10) not null);
insert
into
t3
values
(
3
,
'f'
),(
4
,
'y'
),(
5
,
'z'
),(
6
,
'c'
);
insert
into
t3
values
(
3
,
'f'
),(
4
,
'y'
),(
5
,
'z'
),(
6
,
'c'
);
select
t1
.
a
,
t4
.
y
from
t1
,(
select
t2
.
a
as
y
from
t2
,(
select
t3
.
b
from
t3
where
t3
.
a
>
3
)
as
t5
where
t2
.
b
=
t5
.
b
)
as
t4
where
t1
.
a
=
t4
.
y
;
select
t1
.
a
,
t4
.
y
from
t1
,(
select
t2
.
a
as
y
from
t2
,(
select
t3
.
b
from
t3
where
t3
.
a
>
3
)
as
t5
where
t2
.
b
=
t5
.
b
)
as
t4
where
t1
.
a
=
t4
.
y
;
drop
table
if
exists
t1
.
t2
,
t3
;
drop
table
if
exists
t1
.
t2
,
t3
;
select
*
from
(
select
1
);
select
a
from
(
select
1
as
a
);
mysys/thr_lock.c
View file @
26a1d888
...
@@ -91,7 +91,7 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
...
@@ -91,7 +91,7 @@ enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
#define MAX_LOCKS 100
#define MAX_LOCKS 100
static
LIST
*
thread_list
;
/* List of threads in use */
LIST
*
thr_lock_
thread_list
;
/* List of threads in use */
ulong
max_write_lock_count
=
~
(
ulong
)
0L
;
ulong
max_write_lock_count
=
~
(
ulong
)
0L
;
static
inline
pthread_cond_t
*
get_cond
(
void
)
static
inline
pthread_cond_t
*
get_cond
(
void
)
...
@@ -307,7 +307,7 @@ void thr_lock_init(THR_LOCK *lock)
...
@@ -307,7 +307,7 @@ void thr_lock_init(THR_LOCK *lock)
pthread_mutex_lock
(
&
THR_LOCK_lock
);
/* Add to locks in use */
pthread_mutex_lock
(
&
THR_LOCK_lock
);
/* Add to locks in use */
lock
->
list
.
data
=
(
void
*
)
lock
;
lock
->
list
.
data
=
(
void
*
)
lock
;
thr
ead_list
=
list_add
(
thread_list
,
&
lock
->
list
);
thr
_lock_thread_list
=
list_add
(
thr_lock_
thread_list
,
&
lock
->
list
);
pthread_mutex_unlock
(
&
THR_LOCK_lock
);
pthread_mutex_unlock
(
&
THR_LOCK_lock
);
DBUG_VOID_RETURN
;
DBUG_VOID_RETURN
;
}
}
...
@@ -318,7 +318,7 @@ void thr_lock_delete(THR_LOCK *lock)
...
@@ -318,7 +318,7 @@ void thr_lock_delete(THR_LOCK *lock)
DBUG_ENTER
(
"thr_lock_delete"
);
DBUG_ENTER
(
"thr_lock_delete"
);
VOID
(
pthread_mutex_destroy
(
&
lock
->
mutex
));
VOID
(
pthread_mutex_destroy
(
&
lock
->
mutex
));
pthread_mutex_lock
(
&
THR_LOCK_lock
);
pthread_mutex_lock
(
&
THR_LOCK_lock
);
thr
ead_list
=
list_delete
(
thread_list
,
&
lock
->
list
);
thr
_lock_thread_list
=
list_delete
(
thr_lock_
thread_list
,
&
lock
->
list
);
pthread_mutex_unlock
(
&
THR_LOCK_lock
);
pthread_mutex_unlock
(
&
THR_LOCK_lock
);
DBUG_VOID_RETURN
;
DBUG_VOID_RETURN
;
}
}
...
@@ -1061,7 +1061,7 @@ void thr_print_locks(void)
...
@@ -1061,7 +1061,7 @@ void thr_print_locks(void)
pthread_mutex_lock
(
&
THR_LOCK_lock
);
pthread_mutex_lock
(
&
THR_LOCK_lock
);
puts
(
"Current locks:"
);
puts
(
"Current locks:"
);
for
(
list
=
thread_list
;
list
&&
count
++
<
MAX_THREADS
;
list
=
rest
(
list
))
for
(
list
=
thr
_lock_thr
ead_list
;
list
&&
count
++
<
MAX_THREADS
;
list
=
rest
(
list
))
{
{
THR_LOCK
*
lock
=
(
THR_LOCK
*
)
list
->
data
;
THR_LOCK
*
lock
=
(
THR_LOCK
*
)
list
->
data
;
VOID
(
pthread_mutex_lock
(
&
lock
->
mutex
));
VOID
(
pthread_mutex_lock
(
&
lock
->
mutex
));
...
...
sql/lock.cc
View file @
26a1d888
...
@@ -69,6 +69,12 @@
...
@@ -69,6 +69,12 @@
#include "mysql_priv.h"
#include "mysql_priv.h"
#include <hash.h>
#include <hash.h>
#include <assert.h>
#include <assert.h>
#include <ha_myisammrg.h>
#ifndef MASTER
#include "../srclib/myisammrg/myrg_def.h"
#else
#include "../myisammrg/myrg_def.h"
#endif
extern
HASH
open_cache
;
extern
HASH
open_cache
;
...
@@ -154,6 +160,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
...
@@ -154,6 +160,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
sql_lock
=
0
;
sql_lock
=
0
;
}
}
}
}
thd
->
lock_time
();
thd
->
lock_time
();
DBUG_RETURN
(
sql_lock
);
DBUG_RETURN
(
sql_lock
);
}
}
...
@@ -410,8 +417,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
...
@@ -410,8 +417,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
return
0
;
return
0
;
}
}
}
}
THR_LOCK_DATA
**
org_locks
=
locks
;
locks
=
table
->
file
->
store_lock
(
thd
,
locks
,
get_old_locks
?
TL_IGNORE
:
locks
=
table
->
file
->
store_lock
(
thd
,
locks
,
get_old_locks
?
TL_IGNORE
:
lock_type
);
lock_type
);
if
(
locks
)
for
(
;
org_locks
!=
locks
;
org_locks
++
)
(
*
org_locks
)
->
debug_print_param
=
(
void
*
)
table
;
}
}
return
sql_lock
;
return
sql_lock
;
}
}
...
...
sql/log_event.cc
View file @
26a1d888
...
@@ -26,6 +26,11 @@
...
@@ -26,6 +26,11 @@
#include <assert.h>
#include <assert.h>
/*****************************************************************************
my_b_safe_write()
****************************************************************************/
inline
int
my_b_safe_write
(
IO_CACHE
*
file
,
const
byte
*
buf
,
inline
int
my_b_safe_write
(
IO_CACHE
*
file
,
const
byte
*
buf
,
int
len
)
int
len
)
{
{
...
@@ -40,6 +45,11 @@ inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
...
@@ -40,6 +45,11 @@ inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
return
my_b_write
(
file
,
buf
,
len
);
return
my_b_write
(
file
,
buf
,
len
);
}
}
/*****************************************************************************
pretty_print_str()
****************************************************************************/
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
static
void
pretty_print_str
(
FILE
*
file
,
char
*
str
,
int
len
)
static
void
pretty_print_str
(
FILE
*
file
,
char
*
str
,
int
len
)
{
{
...
@@ -63,16 +73,26 @@ static void pretty_print_str(FILE* file, char* str, int len)
...
@@ -63,16 +73,26 @@ static void pretty_print_str(FILE* file, char* str, int len)
}
}
fputc
(
'\''
,
file
);
fputc
(
'\''
,
file
);
}
}
#endif
#endif
// MYSQL_CLIENT
#ifndef MYSQL_CLIENT
/*****************************************************************************
ignored_error_code()
****************************************************************************/
#ifndef MYSQL_CLIENT
inline
int
ignored_error_code
(
int
err_code
)
inline
int
ignored_error_code
(
int
err_code
)
{
{
return
use_slave_mask
&&
bitmap_is_set
(
&
slave_error_mask
,
err_code
);
return
use_slave_mask
&&
bitmap_is_set
(
&
slave_error_mask
,
err_code
);
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
pretty_print_str()
****************************************************************************/
#ifndef MYSQL_CLIENT
static
void
pretty_print_str
(
String
*
packet
,
char
*
str
,
int
len
)
static
void
pretty_print_str
(
String
*
packet
,
char
*
str
,
int
len
)
{
{
char
*
end
=
str
+
len
;
char
*
end
=
str
+
len
;
...
@@ -95,8 +115,14 @@ static void pretty_print_str(String* packet, char* str, int len)
...
@@ -95,8 +115,14 @@ static void pretty_print_str(String* packet, char* str, int len)
}
}
packet
->
append
(
'\''
);
packet
->
append
(
'\''
);
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
slave_load_file_stem()
****************************************************************************/
#ifndef MYSQL_CLIENT
static
inline
char
*
slave_load_file_stem
(
char
*
buf
,
uint
file_id
,
static
inline
char
*
slave_load_file_stem
(
char
*
buf
,
uint
file_id
,
int
event_server_id
)
int
event_server_id
)
{
{
...
@@ -108,9 +134,81 @@ static inline char* slave_load_file_stem(char*buf, uint file_id,
...
@@ -108,9 +134,81 @@ static inline char* slave_load_file_stem(char*buf, uint file_id,
*
buf
++
=
'-'
;
*
buf
++
=
'-'
;
return
int10_to_str
(
file_id
,
buf
,
10
);
return
int10_to_str
(
file_id
,
buf
,
10
);
}
}
#endif // !MYSQL_CLIENT
#endif
/*****************************************************************************
cleanup_load_tmpdir()
Delete all temporary files used for SQL_LOAD.
TODO
- When we get a 'server start' event, we should only remove
the files associated with the server id that just started.
Easily fixable by adding server_id as a prefix to the log files.
****************************************************************************/
#ifndef MYSQL_CLIENT
static
void
cleanup_load_tmpdir
()
{
MY_DIR
*
dirp
;
FILEINFO
*
file
;
uint
i
;
if
(
!
(
dirp
=
my_dir
(
slave_load_tmpdir
,
MYF
(
MY_WME
))))
return
;
for
(
i
=
0
;
i
<
(
uint
)
dirp
->
number_off_files
;
i
++
)
{
file
=
dirp
->
dir_entry
+
i
;
if
(
is_prefix
(
file
->
name
,
"SQL_LOAD-"
))
my_delete
(
file
->
name
,
MYF
(
0
));
}
my_dirend
(
dirp
);
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
write_str()
****************************************************************************/
static
bool
write_str
(
IO_CACHE
*
file
,
char
*
str
,
byte
length
)
{
return
(
my_b_safe_write
(
file
,
&
length
,
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
str
,
(
int
)
length
));
}
/*****************************************************************************
read_str()
****************************************************************************/
static
inline
int
read_str
(
char
*
&
buf
,
char
*
buf_end
,
char
*
&
str
,
uint8
&
len
)
{
if
(
buf
+
(
uint
)
(
uchar
)
*
buf
>=
buf_end
)
return
1
;
len
=
(
uint8
)
*
buf
;
str
=
buf
+
1
;
buf
+=
(
uint
)
len
+
1
;
return
0
;
}
/*****************************************************************************
*****************************************************************************
Log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Log_event::get_type_str()
****************************************************************************/
const
char
*
Log_event
::
get_type_str
()
const
char
*
Log_event
::
get_type_str
()
{
{
switch
(
get_type_code
())
{
switch
(
get_type_code
())
{
...
@@ -131,6 +229,11 @@ const char* Log_event::get_type_str()
...
@@ -131,6 +229,11 @@ const char* Log_event::get_type_str()
}
}
}
}
/*****************************************************************************
Log_event::Log_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
Log_event
::
Log_event
(
THD
*
thd_arg
,
uint16
flags_arg
)
Log_event
::
Log_event
(
THD
*
thd_arg
,
uint16
flags_arg
)
:
exec_time
(
0
),
flags
(
flags_arg
),
cached_event_len
(
0
),
:
exec_time
(
0
),
flags
(
flags_arg
),
cached_event_len
(
0
),
...
@@ -139,46 +242,23 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg)
...
@@ -139,46 +242,23 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg)
if
(
thd
)
if
(
thd
)
{
{
server_id
=
thd
->
server_id
;
server_id
=
thd
->
server_id
;
when
=
thd
->
start_time
;
when
=
thd
->
start_time
;
log_pos
=
thd
->
log_pos
;
log_pos
=
thd
->
log_pos
;
}
}
else
else
{
{
server_id
=
::
server_id
;
server_id
=
::
server_id
;
when
=
time
(
NULL
);
when
=
time
(
NULL
);
log_pos
=
0
;
log_pos
=
0
;
}
}
}
}
#endif // !MYSQL_CLIENT
/*
/*****************************************************************************
Delete all temporary files used for SQL_LOAD.
TODO
- When we get a 'server start' event, we should only remove
the files associated with the server id that just started.
Easily fixable by adding server_id as a prefix to the log files.
*/
static
void
cleanup_load_tmpdir
()
{
MY_DIR
*
dirp
;
FILEINFO
*
file
;
uint
i
;
if
(
!
(
dirp
=
my_dir
(
slave_load_tmpdir
,
MYF
(
MY_WME
))))
return
;
for
(
i
=
0
;
i
<
(
uint
)
dirp
->
number_off_files
;
i
++
)
{
file
=
dirp
->
dir_entry
+
i
;
if
(
is_prefix
(
file
->
name
,
"SQL_LOAD-"
))
my_delete
(
file
->
name
,
MYF
(
0
));
}
my_dirend
(
dirp
);
}
#endif
Log_event::Log_event()
****************************************************************************/
Log_event
::
Log_event
(
const
char
*
buf
,
bool
old_format
)
Log_event
::
Log_event
(
const
char
*
buf
,
bool
old_format
)
:
cached_event_len
(
0
),
temp_buf
(
0
)
:
cached_event_len
(
0
),
temp_buf
(
0
)
{
{
...
@@ -202,6 +282,11 @@ Log_event::Log_event(const char* buf, bool old_format)
...
@@ -202,6 +282,11 @@ Log_event::Log_event(const char* buf, bool old_format)
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
/*****************************************************************************
Log_event::exec_event()
****************************************************************************/
int
Log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
int
Log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
if
(
rli
)
// QQ When is this not true ?
if
(
rli
)
// QQ When is this not true ?
...
@@ -213,219 +298,73 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
...
@@ -213,219 +298,73 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
return
0
;
return
0
;
}
}
/*****************************************************************************
Log_event::pack_info()
****************************************************************************/
void
Log_event
::
pack_info
(
String
*
packet
)
void
Log_event
::
pack_info
(
String
*
packet
)
{
{
net_store_data
(
packet
,
""
,
0
);
net_store_data
(
packet
,
""
,
0
);
}
}
void
Query_log_event
::
pack_info
(
String
*
packet
)
/*****************************************************************************
{
char
buf
[
256
];
String
tmp
(
buf
,
sizeof
(
buf
),
system_charset_info
);
tmp
.
length
(
0
);
if
(
db
&&
db_len
)
{
tmp
.
append
(
"use `"
,
5
);
tmp
.
append
(
db
,
db_len
);
tmp
.
append
(
"`; "
,
3
);
}
if
(
query
&&
q_len
)
Log_event::init_show_field_list()
tmp
.
append
(
query
,
q_len
);
net_store_data
(
packet
,
(
char
*
)
tmp
.
ptr
(),
tmp
.
length
());
}
void
Start_log_event
::
pack_info
(
String
*
packet
)
****************************************************************************/
void
Log_event
::
init_show_field_list
(
List
<
Item
>*
field_list
)
{
{
char
buf1
[
256
];
field_list
->
push_back
(
new
Item_empty_string
(
"Log_name"
,
20
));
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
field_list
->
push_back
(
new
Item_empty_string
(
"Pos"
,
20
));
tmp
.
length
(
0
);
field_list
->
push_back
(
new
Item_empty_string
(
"Event_type"
,
20
));
char
buf
[
22
];
field_list
->
push_back
(
new
Item_empty_string
(
"Server_id"
,
20
));
field_list
->
push_back
(
new
Item_empty_string
(
"Orig_log_pos"
,
20
));
tmp
.
append
(
"Server ver: "
);
field_list
->
push_back
(
new
Item_empty_string
(
"Info"
,
20
));
tmp
.
append
(
server_version
);
tmp
.
append
(
", Binlog ver: "
);
tmp
.
append
(
llstr
(
binlog_version
,
buf
));
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
}
void
Load_log_event
::
pack_info
(
String
*
packet
)
/*****************************************************************************
{
char
buf
[
256
];
String
tmp
(
buf
,
sizeof
(
buf
),
system_charset_info
);
tmp
.
length
(
0
);
if
(
db
&&
db_len
)
{
tmp
.
append
(
"use "
);
tmp
.
append
(
db
,
db_len
);
tmp
.
append
(
"; "
,
2
);
}
tmp
.
append
(
"LOAD DATA INFILE '"
);
Log_event::net_send()
tmp
.
append
(
fname
,
fname_len
);
tmp
.
append
(
"' "
,
2
);
if
(
sql_ex
.
opt_flags
&&
REPLACE_FLAG
)
tmp
.
append
(
" REPLACE "
);
else
if
(
sql_ex
.
opt_flags
&&
IGNORE_FLAG
)
tmp
.
append
(
" IGNORE "
);
tmp
.
append
(
"INTO TABLE "
);
tmp
.
append
(
table_name
);
if
(
sql_ex
.
field_term_len
)
{
tmp
.
append
(
" FIELDS TERMINATED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
field_term
,
sql_ex
.
field_term_len
);
}
if
(
sql_ex
.
enclosed_len
)
Only called by SHOW BINLOG EVENTS
{
if
(
sql_ex
.
opt_flags
&&
OPT_ENCLOSED_FLAG
)
tmp
.
append
(
" OPTIONALLY "
);
tmp
.
append
(
" ENCLOSED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
enclosed
,
sql_ex
.
enclosed_len
);
}
if
(
sql_ex
.
escaped_len
)
{
tmp
.
append
(
" ESCAPED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
escaped
,
sql_ex
.
escaped_len
);
}
if
(
sql_ex
.
line_term_len
)
{
tmp
.
append
(
" LINES TERMINATED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
line_term
,
sql_ex
.
line_term_len
);
}
if
(
sql_ex
.
line_start_len
)
****************************************************************************/
{
int
Log_event
::
net_send
(
THD
*
thd
,
const
char
*
log_name
,
my_off_t
pos
)
tmp
.
append
(
" LINES STARTING BY "
);
{
pretty_print_str
(
&
tmp
,
sql_ex
.
line_start
,
sql_ex
.
line_start_len
);
String
*
packet
=
&
thd
->
packet
;
}
const
char
*
p
=
strrchr
(
log_name
,
FN_LIBCHAR
);
const
char
*
event_type
;
if
((
int
)
skip_lines
>
0
)
if
(
p
)
tmp
.
append
(
" IGNORE %ld LINES "
,
(
long
)
skip_lines
);
log_name
=
p
+
1
;
packet
->
length
(
0
);
net_store_data
(
packet
,
log_name
,
strlen
(
log_name
));
net_store_data
(
packet
,
(
longlong
)
pos
);
event_type
=
get_type_str
();
net_store_data
(
packet
,
event_type
,
strlen
(
event_type
));
net_store_data
(
packet
,
server_id
);
net_store_data
(
packet
,
(
longlong
)
log_pos
);
pack_info
(
packet
);
return
my_net_write
(
&
thd
->
net
,
(
char
*
)
packet
->
ptr
(),
packet
->
length
());
}
#endif // !MYSQL_CLIENT
if
(
num_fields
)
/*****************************************************************************
{
uint
i
;
const
char
*
field
=
fields
;
tmp
.
append
(
" ("
);
for
(
i
=
0
;
i
<
num_fields
;
i
++
)
{
if
(
i
)
tmp
.
append
(
" ,"
);
tmp
.
append
(
field
);
field
+=
field_lens
[
i
]
+
1
;
}
tmp
.
append
(
')'
);
}
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
void
Rotate_log_event
::
pack_info
(
String
*
packet
)
{
char
buf1
[
256
],
buf
[
22
];
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
tmp
.
length
(
0
);
tmp
.
append
(
new_log_ident
,
ident_len
);
tmp
.
append
(
";pos="
);
tmp
.
append
(
llstr
(
pos
,
buf
));
if
(
flags
&
LOG_EVENT_FORCED_ROTATE_F
)
tmp
.
append
(
"; forced by master"
);
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
void
Intvar_log_event
::
pack_info
(
String
*
packet
)
{
char
buf1
[
256
],
buf
[
22
];
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
tmp
.
length
(
0
);
tmp
.
append
(
get_var_type_name
());
tmp
.
append
(
'='
);
tmp
.
append
(
llstr
(
val
,
buf
));
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
void
Rand_log_event
::
pack_info
(
String
*
packet
)
{
char
buf1
[
256
],
buf
[
22
];
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
tmp
.
length
(
0
);
tmp
.
append
(
"randseed1="
);
tmp
.
append
(
llstr
(
seed1
,
buf
));
tmp
.
append
(
",randseed2="
);
tmp
.
append
(
llstr
(
seed2
,
buf
));
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
void
Slave_log_event
::
pack_info
(
String
*
packet
)
{
char
buf1
[
256
],
buf
[
22
],
*
end
;
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
tmp
.
length
(
0
);
tmp
.
append
(
"host="
);
tmp
.
append
(
master_host
);
tmp
.
append
(
",port="
);
end
=
int10_to_str
((
long
)
master_port
,
buf
,
10
);
tmp
.
append
(
buf
,
(
uint32
)
(
end
-
buf
));
tmp
.
append
(
",log="
);
tmp
.
append
(
master_log
);
tmp
.
append
(
",pos="
);
tmp
.
append
(
llstr
(
master_pos
,
buf
));
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
void
Log_event
::
init_show_field_list
(
List
<
Item
>*
field_list
)
{
field_list
->
push_back
(
new
Item_empty_string
(
"Log_name"
,
20
));
field_list
->
push_back
(
new
Item_empty_string
(
"Pos"
,
20
));
field_list
->
push_back
(
new
Item_empty_string
(
"Event_type"
,
20
));
field_list
->
push_back
(
new
Item_empty_string
(
"Server_id"
,
20
));
field_list
->
push_back
(
new
Item_empty_string
(
"Orig_log_pos"
,
20
));
field_list
->
push_back
(
new
Item_empty_string
(
"Info"
,
20
));
}
/*
* only called by SHOW BINLOG EVENTS
*/
int
Log_event
::
net_send
(
THD
*
thd
,
const
char
*
log_name
,
my_off_t
pos
)
{
String
*
packet
=
&
thd
->
packet
;
const
char
*
p
=
strrchr
(
log_name
,
FN_LIBCHAR
);
const
char
*
event_type
;
if
(
p
)
log_name
=
p
+
1
;
packet
->
length
(
0
);
net_store_data
(
packet
,
log_name
,
strlen
(
log_name
));
net_store_data
(
packet
,
(
longlong
)
pos
);
event_type
=
get_type_str
();
net_store_data
(
packet
,
event_type
,
strlen
(
event_type
));
net_store_data
(
packet
,
server_id
);
net_store_data
(
packet
,
(
longlong
)
log_pos
);
pack_info
(
packet
);
return
my_net_write
(
&
thd
->
net
,
(
char
*
)
packet
->
ptr
(),
packet
->
length
());
}
#endif
/* MYSQL_CLIENT */
int
Query_log_event
::
write
(
IO_CACHE
*
file
)
{
return
query
?
Log_event
::
write
(
file
)
:
-
1
;
}
Log_event::write()
****************************************************************************/
int
Log_event
::
write
(
IO_CACHE
*
file
)
int
Log_event
::
write
(
IO_CACHE
*
file
)
{
{
return
(
write_header
(
file
)
||
write_data
(
file
))
?
-
1
:
0
;
return
(
write_header
(
file
)
||
write_data
(
file
))
?
-
1
:
0
;
}
}
/*****************************************************************************
Log_event::write_header()
****************************************************************************/
int
Log_event
::
write_header
(
IO_CACHE
*
file
)
int
Log_event
::
write_header
(
IO_CACHE
*
file
)
{
{
char
buf
[
LOG_EVENT_HEADER_LEN
];
char
buf
[
LOG_EVENT_HEADER_LEN
];
...
@@ -445,8 +384,13 @@ int Log_event::write_header(IO_CACHE* file)
...
@@ -445,8 +384,13 @@ int Log_event::write_header(IO_CACHE* file)
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
(
uint
)
(
pos
-
buf
)));
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
(
uint
)
(
pos
-
buf
)));
}
}
#ifndef MYSQL_CLIENT
/*****************************************************************************
Log_event::read_log_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Log_event
::
read_log_event
(
IO_CACHE
*
file
,
String
*
packet
,
int
Log_event
::
read_log_event
(
IO_CACHE
*
file
,
String
*
packet
,
pthread_mutex_t
*
log_lock
)
pthread_mutex_t
*
log_lock
)
{
{
...
@@ -501,8 +445,7 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
...
@@ -501,8 +445,7 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_unlock
(
log_lock
);
pthread_mutex_unlock
(
log_lock
);
DBUG_RETURN
(
result
);
DBUG_RETURN
(
result
);
}
}
#endif // !MYSQL_CLIENT
#endif // MYSQL_CLIENT
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
...
@@ -513,7 +456,13 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
...
@@ -513,7 +456,13 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
#define LOCK_MUTEX
#define LOCK_MUTEX
#endif
#endif
// allocates memory - the caller is responsible for clean-up
/*****************************************************************************
Log_event::read_log_event()
Allocates memory--the caller is responsible for clean-up
****************************************************************************/
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
Log_event
*
Log_event
::
read_log_event
(
IO_CACHE
*
file
,
Log_event
*
Log_event
::
read_log_event
(
IO_CACHE
*
file
,
pthread_mutex_t
*
log_lock
,
pthread_mutex_t
*
log_lock
,
...
@@ -576,7 +525,11 @@ data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]);
...
@@ -576,7 +525,11 @@ data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]);
return
res
;
return
res
;
}
}
/*****************************************************************************
Log_event::read_log_event()
****************************************************************************/
Log_event
*
Log_event
::
read_log_event
(
const
char
*
buf
,
int
event_len
,
Log_event
*
Log_event
::
read_log_event
(
const
char
*
buf
,
int
event_len
,
const
char
**
error
,
bool
old_format
)
const
char
**
error
,
bool
old_format
)
{
{
...
@@ -642,8 +595,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
...
@@ -642,8 +595,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
return
ev
;
return
ev
;
}
}
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
/*****************************************************************************
Log_event::print_header()
****************************************************************************/
void
Log_event
::
print_header
(
FILE
*
file
)
void
Log_event
::
print_header
(
FILE
*
file
)
{
{
char
llbuff
[
22
];
char
llbuff
[
22
];
...
@@ -653,6 +611,11 @@ void Log_event::print_header(FILE* file)
...
@@ -653,6 +611,11 @@ void Log_event::print_header(FILE* file)
llstr
(
log_pos
,
llbuff
));
llstr
(
log_pos
,
llbuff
));
}
}
/*****************************************************************************
Log_event::print_timestamp()
****************************************************************************/
void
Log_event
::
print_timestamp
(
FILE
*
file
,
time_t
*
ts
)
void
Log_event
::
print_timestamp
(
FILE
*
file
,
time_t
*
ts
)
{
{
struct
tm
*
res
;
struct
tm
*
res
;
...
@@ -674,113 +637,91 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
...
@@ -674,113 +637,91 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
res
->
tm_sec
);
res
->
tm_sec
);
}
}
#endif // MYSQL_CLIENT
void
Start_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
/*****************************************************************************
{
if
(
short_form
)
return
;
print_header
(
file
);
Log_event::set_log_pos()
fprintf
(
file
,
"
\t
Start: binlog v %d, server v %s created "
,
binlog_version
,
server_version
);
print_timestamp
(
file
,
(
time_t
*
)
&
created
);
fputc
(
'\n'
,
file
);
fflush
(
file
);
}
void
Stop_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Log_event
::
set_log_pos
(
MYSQL_LOG
*
log
)
{
{
if
(
short_form
)
if
(
!
log_pos
)
return
;
log_pos
=
my_b_tell
(
&
log
->
log_file
);
print_header
(
file
);
fprintf
(
file
,
"
\t
Stop
\n
"
);
fflush
(
file
);
}
}
#endif // !MYSQL_CLIENT
void
Rotate_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
char
buf
[
22
];
if
(
short_form
)
return
;
print_header
(
file
);
fprintf
(
file
,
"
\t
Rotate to "
);
if
(
new_log_ident
)
my_fwrite
(
file
,
(
byte
*
)
new_log_ident
,
(
uint
)
ident_len
,
MYF
(
MY_NABP
|
MY_WME
));
fprintf
(
file
,
" pos: %s"
,
llstr
(
pos
,
buf
));
if
(
flags
&
LOG_EVENT_FORCED_ROTATE_F
)
fprintf
(
file
,
" forced by master"
);
fputc
(
'\n'
,
file
);
fflush
(
file
);
}
#endif
/* #ifdef MYSQL_CLIENT */
/*****************************************************************************
*****************************************************************************
Query_log_event methods
Start_log_event
::
Start_log_event
(
const
char
*
buf
,
*****************************************************************************
bool
old_format
)
****************************************************************************/
:
Log_event
(
buf
,
old_format
)
{
buf
+=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
binlog_version
=
uint2korr
(
buf
+
ST_BINLOG_VER_OFFSET
);
memcpy
(
server_version
,
buf
+
ST_SERVER_VER_OFFSET
,
ST_SERVER_VER_LEN
);
created
=
uint4korr
(
buf
+
ST_CREATED_OFFSET
);
}
int
Start_log_event
::
write_data
(
IO_CACHE
*
file
)
#ifndef MYSQL_CLIENT
{
/*****************************************************************************
char
buff
[
START_HEADER_LEN
];
int2store
(
buff
+
ST_BINLOG_VER_OFFSET
,
binlog_version
);
memcpy
(
buff
+
ST_SERVER_VER_OFFSET
,
server_version
,
ST_SERVER_VER_LEN
);
int4store
(
buff
+
ST_CREATED_OFFSET
,
created
);
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buff
,
sizeof
(
buff
))
?
-
1
:
0
);
}
Query_log_event::pack_info()
Rotate_log_event
::
Rotate_log_event
(
const
char
*
buf
,
int
event_len
,
****************************************************************************/
bool
old_format
)
void
Query_log_event
::
pack_info
(
String
*
packet
)
:
Log_event
(
buf
,
old_format
),
new_log_ident
(
NULL
),
alloced
(
0
)
{
{
// The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
char
buf
[
256
];
int
header_size
=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
String
tmp
(
buf
,
sizeof
(
buf
),
system_charset_info
);
uint
ident_offset
;
tmp
.
length
(
0
);
if
(
event_len
<
header_size
)
if
(
db
&&
db_len
)
return
;
buf
+=
header_size
;
if
(
old_format
)
{
ident_len
=
(
uint
)(
event_len
-
OLD_HEADER_LEN
);
pos
=
4
;
ident_offset
=
0
;
}
else
{
{
ident_len
=
(
uint
)(
event_len
-
ROTATE_EVENT_OVERHEAD
);
tmp
.
append
(
"use `"
,
5
);
pos
=
uint8korr
(
buf
+
R_POS_OFFSET
);
tmp
.
append
(
db
,
db_len
);
ident_offset
=
ROTATE_HEADER_LEN
;
tmp
.
append
(
"`; "
,
3
)
;
}
}
set_if_smaller
(
ident_len
,
FN_REFLEN
-
1
);
if
(
!
(
new_log_ident
=
my_strdup_with_length
((
byte
*
)
buf
+
if
(
query
&&
q_len
)
ident_offset
,
tmp
.
append
(
query
,
q_len
);
(
uint
)
ident_len
,
net_store_data
(
packet
,
(
char
*
)
tmp
.
ptr
(),
tmp
.
length
());
MYF
(
MY_WME
))))
}
return
;
#endif // !MYSQL_CLIENT
alloced
=
1
;
/*****************************************************************************
Query_log_event::write()
****************************************************************************/
int
Query_log_event
::
write
(
IO_CACHE
*
file
)
{
return
query
?
Log_event
::
write
(
file
)
:
-
1
;
}
}
/*****************************************************************************
int
Rotate_log_event
::
write_data
(
IO_CACHE
*
file
)
Query_log_event::write_data()
****************************************************************************/
int
Query_log_event
::
write_data
(
IO_CACHE
*
file
)
{
{
char
buf
[
ROTATE_HEADER_LEN
];
if
(
!
query
)
int8store
(
buf
,
pos
+
R_POS_OFFSET
);
return
-
1
;
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
ROTATE_HEADER_LEN
)
||
my_b_safe_write
(
file
,
(
byte
*
)
new_log_ident
,
(
uint
)
ident_len
));
char
buf
[
QUERY_HEADER_LEN
];
int4store
(
buf
+
Q_THREAD_ID_OFFSET
,
thread_id
);
int4store
(
buf
+
Q_EXEC_TIME_OFFSET
,
exec_time
);
buf
[
Q_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
int2store
(
buf
+
Q_ERR_CODE_OFFSET
,
error_code
);
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
QUERY_HEADER_LEN
)
||
my_b_safe_write
(
file
,
(
db
)
?
(
byte
*
)
db
:
(
byte
*
)
""
,
db_len
+
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
query
,
q_len
))
?
-
1
:
0
;
}
}
/*****************************************************************************
Query_log_event::Query_log_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
Query_log_event
::
Query_log_event
(
THD
*
thd_arg
,
const
char
*
query_arg
,
Query_log_event
::
Query_log_event
(
THD
*
thd_arg
,
const
char
*
query_arg
,
ulong
query_length
,
bool
using_trans
)
ulong
query_length
,
bool
using_trans
)
...
@@ -796,8 +737,13 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
...
@@ -796,8 +737,13 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
exec_time
=
(
ulong
)
(
end_time
-
thd
->
start_time
);
exec_time
=
(
ulong
)
(
end_time
-
thd
->
start_time
);
db_len
=
(
db
)
?
(
uint32
)
strlen
(
db
)
:
0
;
db_len
=
(
db
)
?
(
uint32
)
strlen
(
db
)
:
0
;
}
}
#endif
#endif // MYSQL_CLIENT
/*****************************************************************************
Query_log_event::Query_log_event()
****************************************************************************/
Query_log_event
::
Query_log_event
(
const
char
*
buf
,
int
event_len
,
Query_log_event
::
Query_log_event
(
const
char
*
buf
,
int
event_len
,
bool
old_format
)
bool
old_format
)
:
Log_event
(
buf
,
old_format
),
data_buf
(
0
),
query
(
NULL
),
db
(
NULL
)
:
Log_event
(
buf
,
old_format
),
data_buf
(
0
),
query
(
NULL
),
db
(
NULL
)
...
@@ -833,9 +779,12 @@ Query_log_event::Query_log_event(const char* buf, int event_len,
...
@@ -833,9 +779,12 @@ Query_log_event::Query_log_event(const char* buf, int event_len,
*
((
char
*
)
query
+
q_len
)
=
0
;
*
((
char
*
)
query
+
q_len
)
=
0
;
}
}
/*****************************************************************************
#ifdef MYSQL_CLIENT
Query_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Query_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
void
Query_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
{
char
buff
[
40
],
*
end
;
// Enough for SET TIMESTAMP
char
buff
[
40
],
*
end
;
// Enough for SET TIMESTAMP
...
@@ -863,233 +812,348 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
...
@@ -863,233 +812,348 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
my_fwrite
(
file
,
(
byte
*
)
query
,
q_len
,
MYF
(
MY_NABP
|
MY_WME
));
my_fwrite
(
file
,
(
byte
*
)
query
,
q_len
,
MYF
(
MY_NABP
|
MY_WME
));
fprintf
(
file
,
";
\n
"
);
fprintf
(
file
,
";
\n
"
);
}
}
#endif
#endif // MYSQL_CLIENT
int
Query_log_event
::
write_data
(
IO_CACHE
*
file
)
/*****************************************************************************
{
if
(
!
query
)
return
-
1
;
char
buf
[
QUERY_HEADER_LEN
];
int4store
(
buf
+
Q_THREAD_ID_OFFSET
,
thread_id
);
int4store
(
buf
+
Q_EXEC_TIME_OFFSET
,
exec_time
);
buf
[
Q_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
int2store
(
buf
+
Q_ERR_CODE_OFFSET
,
error_code
);
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
QUERY_HEADER_LEN
)
||
Query_log_event::exec_event()
my_b_safe_write
(
file
,
(
db
)
?
(
byte
*
)
db
:
(
byte
*
)
""
,
db_len
+
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
query
,
q_len
))
?
-
1
:
0
;
}
Intvar_log_event
::
Intvar_log_event
(
const
char
*
buf
,
bool
old_format
)
****************************************************************************/
:
Log_event
(
buf
,
old_format
)
#ifndef MYSQL_CLIENT
int
Query_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
buf
+=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
int
expected_error
,
actual_error
=
0
;
type
=
buf
[
I_TYPE_OFFSET
];
init_sql_alloc
(
&
thd
->
mem_root
,
8192
,
0
);
val
=
uint8korr
(
buf
+
I_VAL_OFFSET
);
thd
->
db
=
rewrite_db
((
char
*
)
db
);
}
const
char
*
Intvar_log_event
::
get_var_type_name
()
/*
{
InnoDB internally stores the master log position it has processed so far;
switch
(
type
)
{
position to store is really pos + pending + event_len
case
LAST_INSERT_ID_EVENT
:
return
"LAST_INSERT_ID"
;
since we must store the pos of the END of the current log event
case
INSERT_ID_EVENT
:
return
"INSERT_ID"
;
*/
default:
/* impossible */
return
"UNKNOWN"
;
rli
->
event_len
=
get_event_len
();
if
(
db_ok
(
thd
->
db
,
replicate_do_db
,
replicate_ignore_db
))
{
thd
->
query
=
(
char
*
)
query
;
thd
->
set_time
((
time_t
)
when
);
thd
->
current_tablenr
=
0
;
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
thd
->
query_id
=
query_id
++
;
VOID
(
pthread_mutex_unlock
(
&
LOCK_thread_count
));
thd
->
query_error
=
0
;
// clear error
thd
->
net
.
last_errno
=
0
;
thd
->
net
.
last_error
[
0
]
=
0
;
thd
->
slave_proxy_id
=
thread_id
;
// for temp tables
/*
Sanity check to make sure the master did not get a really bad
error on the query.
*/
if
(
ignored_error_code
((
expected_error
=
error_code
))
||
!
check_expected_error
(
thd
,
rli
,
expected_error
))
{
mysql_log
.
write
(
thd
,
COM_QUERY
,
"%s"
,
thd
->
query
);
DBUG_PRINT
(
"query"
,(
"%s"
,
thd
->
query
));
mysql_parse
(
thd
,
thd
->
query
,
q_len
);
DBUG_PRINT
(
"info"
,(
"expected_error: %d last_errno: %d"
,
expected_error
,
thd
->
net
.
last_errno
));
if
((
expected_error
!=
(
actual_error
=
thd
->
net
.
last_errno
))
&&
expected_error
&&
!
ignored_error_code
(
actual_error
)
&&
!
ignored_error_code
(
expected_error
))
{
const
char
*
errmsg
=
"Slave: did not get the expected error\
running query from master - expected: '%s' (%d), got '%s' (%d)"
;
sql_print_error
(
errmsg
,
ER_SAFE
(
expected_error
),
expected_error
,
actual_error
?
thd
->
net
.
last_error
:
"no error"
,
actual_error
);
thd
->
query_error
=
1
;
}
else
if
(
expected_error
==
actual_error
||
ignored_error_code
(
actual_error
))
{
DBUG_PRINT
(
"info"
,(
"error ignored"
));
thd
->
query_error
=
0
;
*
rli
->
last_slave_error
=
0
;
rli
->
last_slave_errno
=
0
;
}
}
else
{
// master could be inconsistent, abort and tell DBA to check/fix it
thd
->
db
=
thd
->
query
=
0
;
thd
->
variables
.
convert_set
=
0
;
close_thread_tables
(
thd
);
free_root
(
&
thd
->
mem_root
,
0
);
return
1
;
}
}
thd
->
db
=
0
;
// prevent db from being freed
thd
->
query
=
0
;
// just to be sure
// assume no convert for next query unless set explictly
thd
->
variables
.
convert_set
=
0
;
close_thread_tables
(
thd
);
if
(
thd
->
query_error
||
thd
->
fatal_error
)
{
slave_print_error
(
rli
,
actual_error
,
"error '%s' on query '%s'"
,
actual_error
?
thd
->
net
.
last_error
:
"unexpected success or fatal error"
,
query
);
free_root
(
&
thd
->
mem_root
,
0
);
return
1
;
}
}
free_root
(
&
thd
->
mem_root
,
0
);
return
Log_event
::
exec_event
(
rli
);
}
}
#endif // !MYSQL_CLIENT
int
Intvar_log_event
::
write_data
(
IO_CACHE
*
file
)
{
char
buf
[
9
];
buf
[
I_TYPE_OFFSET
]
=
type
;
int8store
(
buf
+
I_VAL_OFFSET
,
val
);
return
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
));
}
#ifdef MYSQL_CLIENT
/*****************************************************************************
void
Intvar_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
*****************************************************************************
{
char
llbuff
[
22
];
const
char
*
msg
;
LINT_INIT
(
msg
);
if
(
!
short_form
)
Start_log_event methods
{
print_header
(
file
);
fprintf
(
file
,
"
\t
Intvar
\n
"
);
}
fprintf
(
file
,
"SET "
);
*****************************************************************************
switch
(
type
)
{
****************************************************************************/
case
LAST_INSERT_ID_EVENT
:
msg
=
"LAST_INSERT_ID"
;
break
;
case
INSERT_ID_EVENT
:
msg
=
"INSERT_ID"
;
break
;
}
fprintf
(
file
,
"%s=%s;
\n
"
,
msg
,
llstr
(
val
,
llbuff
));
fflush
(
file
);
}
#endif
/*****************************************************************************
/*****************************************************************************
*
* Rand log event
Start_log_event::pack_info()
*
****************************************************************************/
****************************************************************************/
Rand_log_event
::
Rand_log_event
(
const
char
*
buf
,
bool
old_format
)
#ifndef MYSQL_CLIENT
:
Log_event
(
buf
,
old_forma
t
)
void
Start_log_event
::
pack_info
(
String
*
packe
t
)
{
{
buf
+=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
char
buf1
[
256
]
;
seed1
=
uint8korr
(
buf
+
RAND_SEED1_OFFSET
);
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
seed2
=
uint8korr
(
buf
+
RAND_SEED2_OFFSET
);
tmp
.
length
(
0
);
}
char
buf
[
22
];
int
Rand_log_event
::
write_data
(
IO_CACHE
*
file
)
tmp
.
append
(
"Server ver: "
);
{
tmp
.
append
(
server_version
);
char
buf
[
16
];
tmp
.
append
(
", Binlog ver: "
);
int8store
(
buf
+
RAND_SEED1_OFFSET
,
seed1
);
tmp
.
append
(
llstr
(
binlog_version
,
buf
));
int8store
(
buf
+
RAND_SEED2_OFFSET
,
seed2
);
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
return
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
));
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Start_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
void
Rand
_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
void
Start
_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
{
char
llbuff
[
22
];
if
(
short_form
)
if
(
!
short_form
)
return
;
{
print_header
(
file
);
print_header
(
file
);
fprintf
(
file
,
"
\t
Rand
\n
"
);
fprintf
(
file
,
"
\t
Start: binlog v %d, server v %s created "
,
binlog_version
,
}
server_version
);
fprintf
(
file
,
"SET RAND SEED1=%s;
\n
"
,
llstr
(
seed1
,
llbuff
)
);
print_timestamp
(
file
,
(
time_t
*
)
&
created
);
fp
rintf
(
file
,
"SET RAND SEED2=%s;
\n
"
,
llstr
(
seed2
,
llbuff
)
);
fp
utc
(
'\n'
,
file
);
fflush
(
file
);
fflush
(
file
);
}
}
#endif
#endif
// MYSQL_CLIENT
int
Load_log_event
::
write_data_header
(
IO_CACHE
*
file
)
/*****************************************************************************
{
char
buf
[
LOAD_HEADER_LEN
];
int4store
(
buf
+
L_THREAD_ID_OFFSET
,
thread_id
);
int4store
(
buf
+
L_EXEC_TIME_OFFSET
,
exec_time
);
int4store
(
buf
+
L_SKIP_LINES_OFFSET
,
skip_lines
);
buf
[
L_TBL_LEN_OFFSET
]
=
(
char
)
table_name_len
;
buf
[
L_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
int4store
(
buf
+
L_NUM_FIELDS_OFFSET
,
num_fields
);
return
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
LOAD_HEADER_LEN
);
}
int
Load_log_event
::
write_data_body
(
IO_CACHE
*
file
)
Start_log_event::Start_log_event()
****************************************************************************/
Start_log_event
::
Start_log_event
(
const
char
*
buf
,
bool
old_format
)
:
Log_event
(
buf
,
old_format
)
{
{
if
(
sql_ex
.
write_data
(
file
))
buf
+=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
return
1
;
binlog_version
=
uint2korr
(
buf
+
ST_BINLOG_VER_OFFSET
);
if
(
num_fields
&&
fields
&&
field_lens
)
memcpy
(
server_version
,
buf
+
ST_SERVER_VER_OFFSET
,
{
ST_SERVER_VER_LEN
);
if
(
my_b_safe_write
(
file
,
(
byte
*
)
field_lens
,
num_fields
)
||
created
=
uint4korr
(
buf
+
ST_CREATED_OFFSET
);
my_b_safe_write
(
file
,
(
byte
*
)
fields
,
field_block_len
))
return
1
;
}
return
(
my_b_safe_write
(
file
,
(
byte
*
)
table_name
,
table_name_len
+
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
db
,
db_len
+
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
fname
,
fname_len
));
}
}
/*****************************************************************************
Start_log_event::write_data()
static
bool
write_str
(
IO_CACHE
*
file
,
char
*
str
,
byte
length
)
****************************************************************************/
int
Start_log_event
::
write_data
(
IO_CACHE
*
file
)
{
{
return
(
my_b_safe_write
(
file
,
&
length
,
1
)
||
char
buff
[
START_HEADER_LEN
];
my_b_safe_write
(
file
,
(
byte
*
)
str
,
(
int
)
length
));
int2store
(
buff
+
ST_BINLOG_VER_OFFSET
,
binlog_version
);
memcpy
(
buff
+
ST_SERVER_VER_OFFSET
,
server_version
,
ST_SERVER_VER_LEN
);
int4store
(
buff
+
ST_CREATED_OFFSET
,
created
);
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buff
,
sizeof
(
buff
))
?
-
1
:
0
);
}
}
/*****************************************************************************
int
sql_ex_info
::
write_data
(
IO_CACHE
*
file
)
Start_log_event::exec_event()
{
if
(
new_format
())
The master started
IMPLEMENTATION
- To handle the case where the master died without a stop event,
we clean up all temporary tables + locks that we got.
TODO
- Remove all active user locks
- If we have an active transaction at this point, the master died
in the middle while writing the transaction to the binary log.
In this case we should stop the slave.
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Start_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
/* All temporary tables was deleted on the master */
close_temporary_tables
(
thd
);
/*
If we have old format, load_tmpdir is cleaned up by the I/O thread
*/
if
(
!
rli
->
mi
->
old_format
)
cleanup_load_tmpdir
();
return
Log_event
::
exec_event
(
rli
);
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
Load_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Load_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Load_log_event
::
pack_info
(
String
*
packet
)
{
char
buf
[
256
];
String
tmp
(
buf
,
sizeof
(
buf
),
system_charset_info
);
tmp
.
length
(
0
);
if
(
db
&&
db_len
)
{
{
return
(
write_str
(
file
,
field_term
,
field_term_len
)
||
tmp
.
append
(
"use "
);
write_str
(
file
,
enclosed
,
enclosed_len
)
||
tmp
.
append
(
db
,
db_len
);
write_str
(
file
,
line_term
,
line_term_len
)
||
tmp
.
append
(
"; "
,
2
);
write_str
(
file
,
line_start
,
line_start_len
)
||
write_str
(
file
,
escaped
,
escaped_len
)
||
my_b_safe_write
(
file
,(
byte
*
)
&
opt_flags
,
1
));
}
}
else
tmp
.
append
(
"LOAD DATA INFILE '"
);
tmp
.
append
(
fname
,
fname_len
);
tmp
.
append
(
"' "
,
2
);
if
(
sql_ex
.
opt_flags
&&
REPLACE_FLAG
)
tmp
.
append
(
" REPLACE "
);
else
if
(
sql_ex
.
opt_flags
&&
IGNORE_FLAG
)
tmp
.
append
(
" IGNORE "
);
tmp
.
append
(
"INTO TABLE "
);
tmp
.
append
(
table_name
);
if
(
sql_ex
.
field_term_len
)
{
{
old_sql_ex
old_ex
;
tmp
.
append
(
" FIELDS TERMINATED BY "
);
old_ex
.
field_term
=
*
field_term
;
pretty_print_str
(
&
tmp
,
sql_ex
.
field_term
,
sql_ex
.
field_term_len
);
old_ex
.
enclosed
=
*
enclosed
;
}
old_ex
.
line_term
=
*
line_term
;
old_ex
.
line_start
=
*
line_start
;
if
(
sql_ex
.
enclosed_len
)
old_ex
.
escaped
=
*
escaped
;
{
old_ex
.
opt_flags
=
opt_flags
;
if
(
sql_ex
.
opt_flags
&&
OPT_ENCLOSED_FLAG
)
old_ex
.
empty_flags
=
empty_flags
;
tmp
.
append
(
" OPTIONALLY "
);
return
my_b_safe_write
(
file
,
(
byte
*
)
&
old_ex
,
sizeof
(
old_ex
));
tmp
.
append
(
" ENCLOSED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
enclosed
,
sql_ex
.
enclosed_len
);
}
if
(
sql_ex
.
escaped_len
)
{
tmp
.
append
(
" ESCAPED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
escaped
,
sql_ex
.
escaped_len
);
}
if
(
sql_ex
.
line_term_len
)
{
tmp
.
append
(
" LINES TERMINATED BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
line_term
,
sql_ex
.
line_term_len
);
}
if
(
sql_ex
.
line_start_len
)
{
tmp
.
append
(
" LINES STARTING BY "
);
pretty_print_str
(
&
tmp
,
sql_ex
.
line_start
,
sql_ex
.
line_start_len
);
}
if
((
int
)
skip_lines
>
0
)
tmp
.
append
(
" IGNORE %ld LINES "
,
(
long
)
skip_lines
);
if
(
num_fields
)
{
uint
i
;
const
char
*
field
=
fields
;
tmp
.
append
(
" ("
);
for
(
i
=
0
;
i
<
num_fields
;
i
++
)
{
if
(
i
)
tmp
.
append
(
" ,"
);
tmp
.
append
(
field
);
field
+=
field_lens
[
i
]
+
1
;
}
tmp
.
append
(
')'
);
}
}
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
static
inline
int
read_str
(
char
*
&
buf
,
char
*
buf_end
,
char
*
&
str
,
Load_log_event::write_data_header()
uint8
&
len
)
****************************************************************************/
int
Load_log_event
::
write_data_header
(
IO_CACHE
*
file
)
{
{
if
(
buf
+
(
uint
)
(
uchar
)
*
buf
>=
buf_end
)
char
buf
[
LOAD_HEADER_LEN
];
return
1
;
int4store
(
buf
+
L_THREAD_ID_OFFSET
,
thread_id
);
len
=
(
uint8
)
*
buf
;
int4store
(
buf
+
L_EXEC_TIME_OFFSET
,
exec_time
);
str
=
buf
+
1
;
int4store
(
buf
+
L_SKIP_LINES_OFFSET
,
skip_lines
);
buf
+=
(
uint
)
len
+
1
;
buf
[
L_TBL_LEN_OFFSET
]
=
(
char
)
table_name_len
;
return
0
;
buf
[
L_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
int4store
(
buf
+
L_NUM_FIELDS_OFFSET
,
num_fields
);
return
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
LOAD_HEADER_LEN
);
}
}
/*****************************************************************************
char
*
sql_ex_info
::
init
(
char
*
buf
,
char
*
buf_end
,
bool
use_new_format
)
Load_log_event::write_data_body()
****************************************************************************/
int
Load_log_event
::
write_data_body
(
IO_CACHE
*
file
)
{
{
cached_new_format
=
use_new_format
;
if
(
sql_ex
.
write_data
(
file
))
if
(
use_new_format
)
return
1
;
{
if
(
num_fields
&&
fields
&&
field_lens
)
empty_flags
=
0
;
/*
The code below assumes that buf will not disappear from
under our feet during the lifetime of the event. This assumption
holds true in the slave thread if the log is in new format, but is not
the case when we have old format because we will be reusing net buffer
to read the actual file before we write out the Create_file event.
*/
if
(
read_str
(
buf
,
buf_end
,
field_term
,
field_term_len
)
||
read_str
(
buf
,
buf_end
,
enclosed
,
enclosed_len
)
||
read_str
(
buf
,
buf_end
,
line_term
,
line_term_len
)
||
read_str
(
buf
,
buf_end
,
line_start
,
line_start_len
)
||
read_str
(
buf
,
buf_end
,
escaped
,
escaped_len
))
return
0
;
opt_flags
=
*
buf
++
;
}
else
{
{
field_term_len
=
enclosed_len
=
line_term_len
=
line_start_len
=
escaped_len
=
1
;
if
(
my_b_safe_write
(
file
,
(
byte
*
)
field_lens
,
num_fields
)
||
field_term
=
buf
++
;
// Use first byte in string
my_b_safe_write
(
file
,
(
byte
*
)
fields
,
field_block_len
))
enclosed
=
buf
++
;
return
1
;
line_term
=
buf
++
;
line_start
=
buf
++
;
escaped
=
buf
++
;
opt_flags
=
*
buf
++
;
empty_flags
=
*
buf
++
;
if
(
empty_flags
&
FIELD_TERM_EMPTY
)
field_term_len
=
0
;
if
(
empty_flags
&
ENCLOSED_EMPTY
)
enclosed_len
=
0
;
if
(
empty_flags
&
LINE_TERM_EMPTY
)
line_term_len
=
0
;
if
(
empty_flags
&
LINE_START_EMPTY
)
line_start_len
=
0
;
if
(
empty_flags
&
ESCAPED_EMPTY
)
escaped_len
=
0
;
}
}
return
buf
;
return
(
my_b_safe_write
(
file
,
(
byte
*
)
table_name
,
table_name_len
+
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
db
,
db_len
+
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
fname
,
fname_len
));
}
}
/*****************************************************************************
Load_log_event::Load_log_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
Load_log_event
::
Load_log_event
(
THD
*
thd
,
sql_exchange
*
ex
,
Load_log_event
::
Load_log_event
(
THD
*
thd
,
sql_exchange
*
ex
,
const
char
*
db_arg
,
const
char
*
table_name_arg
,
const
char
*
db_arg
,
const
char
*
table_name_arg
,
...
@@ -1162,14 +1226,16 @@ Load_log_event::Load_log_event(THD* thd, sql_exchange* ex,
...
@@ -1162,14 +1226,16 @@ Load_log_event::Load_log_event(THD* thd, sql_exchange* ex,
field_lens
=
(
const
uchar
*
)
field_lens_buf
.
ptr
();
field_lens
=
(
const
uchar
*
)
field_lens_buf
.
ptr
();
fields
=
fields_buf
.
ptr
();
fields
=
fields_buf
.
ptr
();
}
}
#endif // !MYSQL_CLIENT
#endif
/*****************************************************************************
Load_log_event::Load_log_event()
/*
The caller must do buf[event_len] = 0 before he starts using the
The caller must do buf[event_len] = 0 before he starts using the
constructed event.
constructed event.
*/
****************************************************************************/
Load_log_event
::
Load_log_event
(
const
char
*
buf
,
int
event_len
,
Load_log_event
::
Load_log_event
(
const
char
*
buf
,
int
event_len
,
bool
old_format
)
:
bool
old_format
)
:
Log_event
(
buf
,
old_format
),
num_fields
(
0
),
fields
(
0
),
Log_event
(
buf
,
old_format
),
num_fields
(
0
),
fields
(
0
),
...
@@ -1181,6 +1247,11 @@ Load_log_event::Load_log_event(const char* buf, int event_len,
...
@@ -1181,6 +1247,11 @@ Load_log_event::Load_log_event(const char* buf, int event_len,
copy_log_event
(
buf
,
event_len
,
old_format
);
copy_log_event
(
buf
,
event_len
,
old_format
);
}
}
/*****************************************************************************
Load_log_event::copy_log_event()
****************************************************************************/
int
Load_log_event
::
copy_log_event
(
const
char
*
buf
,
ulong
event_len
,
int
Load_log_event
::
copy_log_event
(
const
char
*
buf
,
ulong
event_len
,
bool
old_format
)
bool
old_format
)
{
{
...
@@ -1225,8 +1296,12 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
...
@@ -1225,8 +1296,12 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
return
0
;
return
0
;
}
}
#ifdef MYSQL_CLIENT
/*****************************************************************************
Load_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Load_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
void
Load_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
{
if
(
!
short_form
)
if
(
!
short_form
)
...
@@ -1307,18 +1382,14 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
...
@@ -1307,18 +1382,14 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf
(
file
,
";
\n
"
);
fprintf
(
file
,
";
\n
"
);
}
}
#endif
/* #ifdef MYSQL_CLIENT */
#endif
/* #ifdef MYSQL_CLIENT */
#ifndef MYSQL_CLIENT
/*****************************************************************************
void
Log_event
::
set_log_pos
(
MYSQL_LOG
*
log
)
{
if
(
!
log_pos
)
log_pos
=
my_b_tell
(
&
log
->
log_file
);
}
Load_log_event::set_fields()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Load_log_event
::
set_fields
(
List
<
Item
>
&
fields
)
void
Load_log_event
::
set_fields
(
List
<
Item
>
&
fields
)
{
{
uint
i
;
uint
i
;
...
@@ -1329,589 +1400,690 @@ void Load_log_event::set_fields(List<Item> &fields)
...
@@ -1329,589 +1400,690 @@ void Load_log_event::set_fields(List<Item> &fields)
field
+=
field_lens
[
i
]
+
1
;
field
+=
field_lens
[
i
]
+
1
;
}
}
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Slave_log_event
::
Slave_log_event
(
THD
*
thd_arg
,
Load_log_event::exec_event()
struct
st_relay_log_info
*
rli
)
:
Log_event
(
thd_arg
),
mem_pool
(
0
),
master_host
(
0
)
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Load_log_event
::
exec_event
(
NET
*
net
,
struct
st_relay_log_info
*
rli
)
{
{
DBUG_ENTER
(
"Slave_log_event"
);
init_sql_alloc
(
&
thd
->
mem_root
,
8192
,
0
);
if
(
!
rli
->
inited
)
// QQ When can this happen ?
thd
->
db
=
rewrite_db
((
char
*
)
db
);
DBUG_VOID_RETURN
;
thd
->
query
=
0
;
thd
->
query_error
=
0
;
MASTER_INFO
*
mi
=
rli
->
mi
;
// TODO: re-write this better without holding both locks at the same time
if
(
db_ok
(
thd
->
db
,
replicate_do_db
,
replicate_ignore_db
))
pthread_mutex_lock
(
&
mi
->
data_lock
);
pthread_mutex_lock
(
&
rli
->
data_lock
);
master_host_len
=
strlen
(
mi
->
host
);
master_log_len
=
strlen
(
rli
->
master_log_name
);
// on OOM, just do not initialize the structure and print the error
if
((
mem_pool
=
(
char
*
)
my_malloc
(
get_data_size
()
+
1
,
MYF
(
MY_WME
))))
{
{
master_host
=
mem_pool
+
SL_MASTER_HOST_OFFSET
;
thd
->
set_time
((
time_t
)
when
);
memcpy
(
master_host
,
mi
->
host
,
master_host_len
+
1
);
thd
->
current_tablenr
=
0
;
master_log
=
master_host
+
master_host_len
+
1
;
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
memcpy
(
master_log
,
rli
->
master_log_name
,
master_log_len
+
1
);
thd
->
query_id
=
query_id
++
;
master_port
=
mi
->
port
;
VOID
(
pthread_mutex_unlock
(
&
LOCK_thread_count
));
master_pos
=
rli
->
master_log_pos
;
DBUG_PRINT
(
"info"
,
(
"master_log: %s pos: %d"
,
master_log
,
TABLE_LIST
tables
;
(
ulong
)
master_pos
));
bzero
((
char
*
)
&
tables
,
sizeof
(
tables
));
tables
.
db
=
thd
->
db
;
tables
.
alias
=
tables
.
real_name
=
(
char
*
)
table_name
;
tables
.
lock_type
=
TL_WRITE
;
// the table will be opened in mysql_load
if
(
table_rules_on
&&
!
tables_ok
(
thd
,
&
tables
))
{
// TODO: this is a bug - this needs to be moved to the I/O thread
if
(
net
)
skip_load_data_infile
(
net
);
}
else
{
char
llbuff
[
22
];
enum
enum_duplicates
handle_dup
=
DUP_IGNORE
;
if
(
sql_ex
.
opt_flags
&&
REPLACE_FLAG
)
handle_dup
=
DUP_REPLACE
;
sql_exchange
ex
((
char
*
)
fname
,
sql_ex
.
opt_flags
&&
DUMPFILE_FLAG
);
String
field_term
(
sql_ex
.
field_term
,
sql_ex
.
field_term_len
,
system_charset_info
);
String
enclosed
(
sql_ex
.
enclosed
,
sql_ex
.
enclosed_len
,
system_charset_info
);
String
line_term
(
sql_ex
.
line_term
,
sql_ex
.
line_term_len
,
system_charset_info
);
String
line_start
(
sql_ex
.
line_start
,
sql_ex
.
line_start_len
,
system_charset_info
);
String
escaped
(
sql_ex
.
escaped
,
sql_ex
.
escaped_len
,
system_charset_info
);
ex
.
opt_enclosed
=
(
sql_ex
.
opt_flags
&
OPT_ENCLOSED_FLAG
);
if
(
sql_ex
.
empty_flags
&
FIELD_TERM_EMPTY
)
ex
.
field_term
->
length
(
0
);
ex
.
skip_lines
=
skip_lines
;
List
<
Item
>
fields
;
set_fields
(
fields
);
thd
->
slave_proxy_id
=
thd
->
thread_id
;
if
(
net
)
{
// mysql_load will use thd->net to read the file
thd
->
net
.
vio
=
net
->
vio
;
/*
Make sure the client does not get confused about the packet sequence
*/
thd
->
net
.
pkt_nr
=
net
->
pkt_nr
;
}
if
(
mysql_load
(
thd
,
&
ex
,
&
tables
,
fields
,
handle_dup
,
net
!=
0
,
TL_WRITE
))
thd
->
query_error
=
1
;
if
(
thd
->
cuted_fields
)
sql_print_error
(
"Slave: load data infile at position %s in log \
'%s' produced %d warning(s)"
,
llstr
(
rli
->
master_log_pos
,
llbuff
),
RPL_LOG_NAME
,
thd
->
cuted_fields
);
if
(
net
)
net
->
pkt_nr
=
thd
->
net
.
pkt_nr
;
}
}
}
else
else
sql_print_error
(
"Out of memory while recording slave event"
);
{
pthread_mutex_unlock
(
&
rli
->
data_lock
);
/*
pthread_mutex_unlock
(
&
mi
->
data_lock
);
We will just ask the master to send us /dev/null if we do not
DBUG_VOID_RETURN
;
want to load the data.
TODO: this a bug - needs to be done in I/O thread
*/
if
(
net
)
skip_load_data_infile
(
net
);
}
thd
->
net
.
vio
=
0
;
thd
->
db
=
0
;
// prevent db from being freed
close_thread_tables
(
thd
);
if
(
thd
->
query_error
)
{
int
sql_error
=
thd
->
net
.
last_errno
;
if
(
!
sql_error
)
sql_error
=
ER_UNKNOWN_ERROR
;
slave_print_error
(
rli
,
sql_error
,
"Slave: Error '%s' running load data infile "
,
ER_SAFE
(
sql_error
));
free_root
(
&
thd
->
mem_root
,
0
);
return
1
;
}
free_root
(
&
thd
->
mem_root
,
0
);
if
(
thd
->
fatal_error
)
{
sql_print_error
(
"Slave: Fatal error running LOAD DATA INFILE "
);
return
1
;
}
return
Log_event
::
exec_event
(
rli
);
}
}
#endif // !MYSQL_CLIENT
#endif
/* ! MYSQL_CLIENT */
/*****************************************************************************
*****************************************************************************
Slave_log_event
::~
Slave_log_event
()
Rotate_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Rotate_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Rotate_log_event
::
pack_info
(
String
*
packet
)
{
{
my_free
(
mem_pool
,
MYF
(
MY_ALLOW_ZERO_PTR
));
char
buf1
[
256
],
buf
[
22
];
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
tmp
.
length
(
0
);
tmp
.
append
(
new_log_ident
,
ident_len
);
tmp
.
append
(
";pos="
);
tmp
.
append
(
llstr
(
pos
,
buf
));
if
(
flags
&
LOG_EVENT_FORCED_ROTATE_F
)
tmp
.
append
(
"; forced by master"
);
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
}
#endif // !MYSQL_CLIENT
#ifdef MYSQL_CLIENT
/*****************************************************************************
void
Slave_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
Rotate_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Rotate_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
{
char
llbuf
f
[
22
];
char
bu
f
[
22
];
if
(
short_form
)
if
(
short_form
)
return
;
return
;
print_header
(
file
);
print_header
(
file
);
fprintf
(
file
,
"
\t
Rotate to "
);
if
(
new_log_ident
)
my_fwrite
(
file
,
(
byte
*
)
new_log_ident
,
(
uint
)
ident_len
,
MYF
(
MY_NABP
|
MY_WME
));
fprintf
(
file
,
" pos: %s"
,
llstr
(
pos
,
buf
));
if
(
flags
&
LOG_EVENT_FORCED_ROTATE_F
)
fprintf
(
file
,
" forced by master"
);
fputc
(
'\n'
,
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"Slave: master_host: '%s' master_port: %d \
fflush
(
file
);
master_log: '%s' master_pos: %s
\n
"
,
master_host
,
master_port
,
master_log
,
llstr
(
master_pos
,
llbuff
));
}
#endif
/* MYSQL_CLIENT */
int
Slave_log_event
::
get_data_size
()
{
return
master_host_len
+
master_log_len
+
1
+
SL_MASTER_HOST_OFFSET
;
}
}
#endif // MYSQL_CLIENT
int
Slave_log_event
::
write_data
(
IO_CACHE
*
file
)
/*****************************************************************************
{
int8store
(
mem_pool
+
SL_MASTER_POS_OFFSET
,
master_pos
);
int2store
(
mem_pool
+
SL_MASTER_PORT_OFFSET
,
master_port
);
// log and host are already there
return
my_b_safe_write
(
file
,
(
byte
*
)
mem_pool
,
get_data_size
());
}
Rotate_log_event::Rotate_log_event()
void
Slave_log_event
::
init_from_mem_pool
(
int
data_size
)
****************************************************************************/
Rotate_log_event
::
Rotate_log_event
(
const
char
*
buf
,
int
event_len
,
bool
old_format
)
:
Log_event
(
buf
,
old_format
),
new_log_ident
(
NULL
),
alloced
(
0
)
{
{
master_pos
=
uint8korr
(
mem_pool
+
SL_MASTER_POS_OFFSET
);
// The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
master_port
=
uint2korr
(
mem_pool
+
SL_MASTER_PORT_OFFSET
);
int
header_size
=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
master_host
=
mem_pool
+
SL_MASTER_HOST_OFFSET
;
uint
ident_offset
;
master_host_len
=
strlen
(
master_host
);
if
(
event_len
<
header_size
)
// safety
master_log
=
master_host
+
master_host_len
+
1
;
if
(
master_log
>
mem_pool
+
data_size
)
{
master_host
=
0
;
return
;
return
;
buf
+=
header_size
;
if
(
old_format
)
{
ident_len
=
(
uint
)(
event_len
-
OLD_HEADER_LEN
);
pos
=
4
;
ident_offset
=
0
;
}
}
master_log_len
=
strlen
(
master_log
);
else
}
{
ident_len
=
(
uint
)(
event_len
-
ROTATE_EVENT_OVERHEAD
);
Slave_log_event
::
Slave_log_event
(
const
char
*
buf
,
int
event_len
)
pos
=
uint8korr
(
buf
+
R_POS_OFFSET
);
:
Log_event
(
buf
,
0
),
mem_pool
(
0
),
master_host
(
0
)
ident_offset
=
ROTATE_HEADER_LEN
;
{
}
event_len
-=
LOG_EVENT_HEADER_LEN
;
set_if_smaller
(
ident_len
,
FN_REFLEN
-
1
);
if
(
event_len
<
0
)
if
(
!
(
new_log_ident
=
my_strdup_with_length
((
byte
*
)
buf
+
return
;
ident_offset
,
if
(
!
(
mem_pool
=
(
char
*
)
my_malloc
(
event_len
+
1
,
MYF
(
MY_WME
))))
(
uint
)
ident_len
,
MYF
(
MY_WME
))))
return
;
return
;
memcpy
(
mem_pool
,
buf
+
LOG_EVENT_HEADER_LEN
,
event_len
);
alloced
=
1
;
mem_pool
[
event_len
]
=
0
;
init_from_mem_pool
(
event_len
);
}
}
#ifndef MYSQL_CLIENT
/*****************************************************************************
Create_file_log_event
::
Create_file_log_event
(
THD
*
thd_arg
,
sql_exchange
*
ex
,
const
char
*
db_arg
,
const
char
*
table_name_arg
,
List
<
Item
>&
fields_arg
,
enum
enum_duplicates
handle_dup
,
char
*
block_arg
,
uint
block_len_arg
)
:
Load_log_event
(
thd_arg
,
ex
,
db_arg
,
table_name_arg
,
fields_arg
,
handle_dup
),
fake_base
(
0
),
block
(
block_arg
),
block_len
(
block_len_arg
),
file_id
(
thd_arg
->
file_id
=
mysql_bin_log
.
next_file_id
())
{
sql_ex
.
force_new_format
();
}
#endif
int
Create_file_log_event
::
write_data_body
(
IO_CACHE
*
file
)
Rotate_log_event::write_data()
{
int
res
;
if
((
res
=
Load_log_event
::
write_data_body
(
file
))
||
fake_base
)
return
res
;
return
(
my_b_safe_write
(
file
,
(
byte
*
)
""
,
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
block
,
block_len
));
}
int
Create_file_log_event
::
write_data_header
(
IO_CACHE
*
file
)
****************************************************************************/
int
Rotate_log_event
::
write_data
(
IO_CACHE
*
file
)
{
{
int
res
;
char
buf
[
ROTATE_HEADER_LEN
];
if
((
res
=
Load_log_event
::
write_data_header
(
file
))
||
fake_base
)
int8store
(
buf
,
pos
+
R_POS_OFFSET
);
return
res
;
return
(
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
ROTATE_HEADER_LEN
)
||
byte
buf
[
CREATE_FILE_HEADER_LEN
];
my_b_safe_write
(
file
,
(
byte
*
)
new_log_ident
,
(
uint
)
ident_len
));
int4store
(
buf
+
CF_FILE_ID_OFFSET
,
file_id
);
return
my_b_safe_write
(
file
,
buf
,
CREATE_FILE_HEADER_LEN
);
}
}
int
Create_file_log_event
::
write_base
(
IO_CACHE
*
file
)
/*****************************************************************************
{
int
res
;
fake_base
=
1
;
// pretend we are Load event
res
=
write
(
file
);
fake_base
=
0
;
return
res
;
}
Create_file_log_event
::
Create_file_log_event
(
const
char
*
buf
,
int
len
,
Rotate_log_event::exec_event()
bool
old_format
)
:
Load_log_event
(
buf
,
0
,
old_format
),
fake_base
(
0
),
block
(
0
),
inited_from_old
(
0
)
Got a rotate log even from the master
{
int
block_offset
;
if
(
copy_log_event
(
buf
,
len
,
old_format
))
return
;
if
(
!
old_format
)
{
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
+
LOAD_HEADER_LEN
+
CF_FILE_ID_OFFSET
);
// + 1 for \0 terminating fname
block_offset
=
(
LOG_EVENT_HEADER_LEN
+
Load_log_event
::
get_data_size
()
+
CREATE_FILE_HEADER_LEN
+
1
);
if
(
len
<
block_offset
)
return
;
block
=
(
char
*
)
buf
+
block_offset
;
block_len
=
len
-
block_offset
;
}
else
{
sql_ex
.
force_new_format
();
inited_from_old
=
1
;
}
}
IMPLEMENTATION
This is mainly used so that we can later figure out the logname and
position for the master.
#ifdef MYSQL_CLIENT
We can't rotate the slave as this will cause infinitive rotations
void
Create_file_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
in a A -> B -> A setup.
char
*
last_db
)
RETURN VALUES
0 ok
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Rotate_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
if
(
short_form
)
char
*
log_name
=
rli
->
master_log_name
;
return
;
DBUG_ENTER
(
"Rotate_log_event::exec_event"
);
Load_log_event
::
print
(
file
,
1
,
last_db
);
fprintf
(
file
,
" file_id: %d block_len: %d
\n
"
,
file_id
,
block_len
);
pthread_mutex_lock
(
&
rli
->
data_lock
);
memcpy
(
log_name
,
new_log_ident
,
ident_len
+
1
);
rli
->
master_log_pos
=
pos
;
rli
->
relay_log_pos
+=
get_event_len
();
DBUG_PRINT
(
"info"
,
(
"master_log_pos: %d"
,
(
ulong
)
rli
->
master_log_pos
));
pthread_mutex_unlock
(
&
rli
->
data_lock
);
pthread_cond_broadcast
(
&
rli
->
data_cond
);
flush_relay_log_info
(
rli
);
DBUG_RETURN
(
0
);
}
}
#endif
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
Intvar_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Intvar_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
void
Create_file
_log_event
::
pack_info
(
String
*
packet
)
void
Intvar
_log_event
::
pack_info
(
String
*
packet
)
{
{
char
buf1
[
256
],
buf
[
22
],
*
end
;
char
buf1
[
256
],
buf
[
22
]
;
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
tmp
.
length
(
0
);
tmp
.
length
(
0
);
tmp
.
append
(
"db="
);
tmp
.
append
(
get_var_type_name
());
tmp
.
append
(
db
,
db_len
);
tmp
.
append
(
'='
);
tmp
.
append
(
";table="
);
tmp
.
append
(
llstr
(
val
,
buf
));
tmp
.
append
(
table_name
,
table_name_len
);
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
tmp
.
append
(
";file_id="
);
end
=
int10_to_str
((
long
)
file_id
,
buf
,
10
);
tmp
.
append
(
buf
,
(
uint32
)
(
end
-
buf
));
tmp
.
append
(
";block_len="
);
end
=
int10_to_str
((
long
)
block_len
,
buf
,
10
);
tmp
.
append
(
buf
,
(
uint32
)
(
end
-
buf
));
net_store_data
(
packet
,
(
char
*
)
tmp
.
ptr
(),
tmp
.
length
());
}
}
#endif
#endif
// !MYSQL_CLIENT
#ifndef MYSQL_CLIENT
/*****************************************************************************
Append_block_log_event
::
Append_block_log_event
(
THD
*
thd_arg
,
char
*
block_arg
,
uint
block_len_arg
)
:
Log_event
(
thd_arg
),
block
(
block_arg
),
block_len
(
block_len_arg
),
file_id
(
thd_arg
->
file_id
)
{
}
#endif
Intvar_log_event::Intvar_log_event()
Append_block_log_event
::
Append_block_log_event
(
const
char
*
buf
,
int
len
)
:
Log_event
(
buf
,
0
),
block
(
0
)
{
if
((
uint
)
len
<
APPEND_BLOCK_EVENT_OVERHEAD
)
return
;
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
AB_FILE_ID_OFFSET
);
block
=
(
char
*
)
buf
+
APPEND_BLOCK_EVENT_OVERHEAD
;
block_len
=
len
-
APPEND_BLOCK_EVENT_OVERHEAD
;
}
int
Append_block_log_event
::
write_data
(
IO_CACHE
*
file
)
****************************************************************************/
Intvar_log_event
::
Intvar_log_event
(
const
char
*
buf
,
bool
old_format
)
:
Log_event
(
buf
,
old_format
)
{
{
byte
buf
[
APPEND_BLOCK_HEADER_LEN
];
buf
+=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
int4store
(
buf
+
AB_FILE_ID_OFFSET
,
file_id
);
type
=
buf
[
I_TYPE_OFFSET
];
return
(
my_b_safe_write
(
file
,
buf
,
APPEND_BLOCK_HEADER_LEN
)
||
val
=
uint8korr
(
buf
+
I_VAL_OFFSET
);
my_b_safe_write
(
file
,
(
byte
*
)
block
,
block_len
));
}
}
#ifdef MYSQL_CLIENT
/*****************************************************************************
void
Append_block_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
if
(
short_form
)
return
;
print_header
(
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"#Append_block: file_id: %d block_len: %d
\n
"
,
file_id
,
block_len
);
}
#endif
#ifndef MYSQL_CLIENT
Intvar_log_event::get_var_type_name()
void
Append_block_log_event
::
pack_info
(
String
*
packet
)
****************************************************************************/
const
char
*
Intvar_log_event
::
get_var_type_name
()
{
{
char
buf
[
256
];
switch
(
type
)
{
uint
length
;
case
LAST_INSERT_ID_EVENT
:
return
"LAST_INSERT_ID"
;
length
=
(
uint
)
my_sprintf
(
buf
,
case
INSERT_ID_EVENT
:
return
"INSERT_ID"
;
(
buf
,
";file_id=%u;block_len=%u"
,
file_id
,
default:
/* impossible */
return
"UNKNOWN"
;
block_len
));
}
net_store_data
(
packet
,
buf
,
(
int32
)
length
);
}
}
/*****************************************************************************
Delete_file_log_event
::
Delete_file_log_event
(
THD
*
thd_arg
)
Intvar_log_event::write_data()
:
Log_event
(
thd_arg
),
file_id
(
thd_arg
->
file_id
)
****************************************************************************/
int
Intvar_log_event
::
write_data
(
IO_CACHE
*
file
)
{
{
char
buf
[
9
];
buf
[
I_TYPE_OFFSET
]
=
type
;
int8store
(
buf
+
I_VAL_OFFSET
,
val
);
return
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
));
}
}
#endif
/*****************************************************************************
Delete_file_log_event
::
Delete_file_log_event
(
const
char
*
buf
,
int
len
)
Intvar_log_event::print()
:
Log_event
(
buf
,
0
),
file_id
(
0
)
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Intvar_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
{
if
((
uint
)
len
<
DELETE_FILE_EVENT_OVERHEAD
)
char
llbuff
[
22
];
return
;
const
char
*
msg
;
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
AB_FILE_ID_OFFSET
);
LINT_INIT
(
msg
);
}
if
(
!
short_form
)
{
print_header
(
file
);
fprintf
(
file
,
"
\t
Intvar
\n
"
);
}
int
Delete_file_log_event
::
write_data
(
IO_CACHE
*
file
)
fprintf
(
file
,
"SET "
);
{
switch
(
type
)
{
byte
buf
[
DELETE_FILE_HEADER_LEN
];
case
LAST_INSERT_ID_EVENT
:
int4store
(
buf
+
DF_FILE_ID_OFFSET
,
file_id
);
msg
=
"LAST_INSERT_ID"
;
return
my_b_safe_write
(
file
,
buf
,
DELETE_FILE_HEADER_LEN
);
break
;
case
INSERT_ID_EVENT
:
msg
=
"INSERT_ID"
;
break
;
}
fprintf
(
file
,
"%s=%s;
\n
"
,
msg
,
llstr
(
val
,
llbuff
));
fflush
(
file
);
}
}
#endif // MYSQL_CLIENT
#ifdef MYSQL_CLIENT
/*****************************************************************************
void
Delete_file_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
Intvar_log_event::exec_event()
{
if
(
short_form
)
return
;
print_header
(
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"#Delete_file: file_id=%u
\n
"
,
file_id
);
}
#endif
****************************************************************************/
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
void
Delete_file_log_event
::
pack_info
(
String
*
packet
)
int
Intvar_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
char
buf
[
64
];
switch
(
type
)
{
uint
length
;
case
LAST_INSERT_ID_EVENT
:
length
=
(
uint
)
my_sprintf
(
buf
,
(
buf
,
";file_id=%u"
,
(
uint
)
file_id
));
thd
->
last_insert_id_used
=
1
;
net_store_data
(
packet
,
buf
,
(
int32
)
length
);
thd
->
last_insert_id
=
val
;
break
;
case
INSERT_ID_EVENT
:
thd
->
next_insert_id
=
val
;
break
;
}
rli
->
inc_pending
(
get_event_len
());
return
0
;
}
}
#endif
#endif
// !MYSQL_CLIENT
#ifndef MYSQL_CLIENT
/*****************************************************************************
Execute_load_log_event
::
Execute_load_log_event
(
THD
*
thd_arg
)
*****************************************************************************
:
Log_event
(
thd_arg
),
file_id
(
thd_arg
->
file_id
)
{
}
#endif
Execute_load_log_event
::
Execute_load_log_event
(
const
char
*
buf
,
int
len
)
Rand_log_event methods
:
Log_event
(
buf
,
0
),
file_id
(
0
)
{
if
((
uint
)
len
<
EXEC_LOAD_EVENT_OVERHEAD
)
return
;
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
EL_FILE_ID_OFFSET
);
}
*****************************************************************************
****************************************************************************/
int
Execute_load_log_event
::
write_data
(
IO_CACHE
*
file
)
/*****************************************************************************
{
byte
buf
[
EXEC_LOAD_HEADER_LEN
];
int4store
(
buf
+
EL_FILE_ID_OFFSET
,
file_id
);
return
my_b_safe_write
(
file
,
buf
,
EXEC_LOAD_HEADER_LEN
);
}
#ifdef MYSQL_CLIENT
Rand_log_event::pack_info()
void
Execute_load_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Rand_log_event
::
pack_info
(
String
*
packet
)
{
{
if
(
short_form
)
char
buf1
[
256
],
buf
[
22
];
return
;
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
print_header
(
file
);
tmp
.
length
(
0
);
fputc
(
'\n'
,
file
);
tmp
.
append
(
"randseed1="
);
fprintf
(
file
,
"#Exec_load: file_id=%d
\n
"
,
tmp
.
append
(
llstr
(
seed1
,
buf
));
file_id
);
tmp
.
append
(
",randseed2="
);
tmp
.
append
(
llstr
(
seed2
,
buf
));
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
}
}
#endif
#endif // !MYSQL_CLIENT
#ifndef MYSQL_CLIENT
void
Execute_load_log_event
::
pack_info
(
String
*
packet
)
/*****************************************************************************
Rand_log_event::Rand_log_event()
****************************************************************************/
Rand_log_event
::
Rand_log_event
(
const
char
*
buf
,
bool
old_format
)
:
Log_event
(
buf
,
old_format
)
{
{
char
buf
[
64
];
buf
+=
(
old_format
)
?
OLD_HEADER_LEN
:
LOG_EVENT_HEADER_LEN
;
uint
length
;
seed1
=
uint8korr
(
buf
+
RAND_SEED1_OFFSET
);
length
=
(
uint
)
my_sprintf
(
buf
,
(
buf
,
";file_id=%u"
,
(
uint
)
file_id
));
seed2
=
uint8korr
(
buf
+
RAND_SEED2_OFFSET
);
net_store_data
(
packet
,
buf
,
(
int32
)
length
);
}
}
#endif
#ifndef MYSQL_CLIENT
/*****************************************************************************
int
Query_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
Rand_log_event::write_data()
****************************************************************************/
int
Rand_log_event
::
write_data
(
IO_CACHE
*
file
)
{
{
int
expected_error
,
actual_error
=
0
;
char
buf
[
16
];
init_sql_alloc
(
&
thd
->
mem_root
,
8192
,
0
);
int8store
(
buf
+
RAND_SEED1_OFFSET
,
seed1
);
thd
->
db
=
rewrite_db
((
char
*
)
db
);
int8store
(
buf
+
RAND_SEED2_OFFSET
,
seed2
);
return
my_b_safe_write
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
));
}
/*
/*****************************************************************************
InnoDB internally stores the master log position it has processed so far;
position to store is really pos + pending + event_len
since we must store the pos of the END of the current log event
*/
rli
->
event_len
=
get_event_len
();
if
(
db_ok
(
thd
->
db
,
replicate_do_db
,
replicate_ignore_db
))
Rand_log_event::print()
{
thd
->
query
=
(
char
*
)
query
;
****************************************************************************/
thd
->
set_time
((
time_t
)
when
);
#ifdef MYSQL_CLIENT
thd
->
current_tablenr
=
0
;
void
Rand_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
{
thd
->
query_id
=
query_id
++
;
char
llbuff
[
22
];
VOID
(
pthread_mutex_unlock
(
&
LOCK_thread_count
));
if
(
!
short_form
)
thd
->
query_error
=
0
;
// clear error
thd
->
net
.
last_errno
=
0
;
thd
->
net
.
last_error
[
0
]
=
0
;
thd
->
slave_proxy_id
=
thread_id
;
// for temp tables
/*
Sanity check to make sure the master did not get a really bad
error on the query.
*/
if
(
ignored_error_code
((
expected_error
=
error_code
))
||
!
check_expected_error
(
thd
,
rli
,
expected_error
))
{
mysql_log
.
write
(
thd
,
COM_QUERY
,
"%s"
,
thd
->
query
);
DBUG_PRINT
(
"query"
,(
"%s"
,
thd
->
query
));
mysql_parse
(
thd
,
thd
->
query
,
q_len
);
DBUG_PRINT
(
"info"
,(
"expected_error: %d last_errno: %d"
,
expected_error
,
thd
->
net
.
last_errno
));
if
((
expected_error
!=
(
actual_error
=
thd
->
net
.
last_errno
))
&&
expected_error
&&
!
ignored_error_code
(
actual_error
)
&&
!
ignored_error_code
(
expected_error
))
{
const
char
*
errmsg
=
"Slave: did not get the expected error\
running query from master - expected: '%s' (%d), got '%s' (%d)"
;
sql_print_error
(
errmsg
,
ER_SAFE
(
expected_error
),
expected_error
,
actual_error
?
thd
->
net
.
last_error
:
"no error"
,
actual_error
);
thd
->
query_error
=
1
;
}
else
if
(
expected_error
==
actual_error
||
ignored_error_code
(
actual_error
))
{
DBUG_PRINT
(
"info"
,(
"error ignored"
));
thd
->
query_error
=
0
;
*
rli
->
last_slave_error
=
0
;
rli
->
last_slave_errno
=
0
;
}
}
else
{
// master could be inconsistent, abort and tell DBA to check/fix it
thd
->
db
=
thd
->
query
=
0
;
thd
->
variables
.
convert_set
=
0
;
close_thread_tables
(
thd
);
free_root
(
&
thd
->
mem_root
,
0
);
return
1
;
}
}
thd
->
db
=
0
;
// prevent db from being freed
thd
->
query
=
0
;
// just to be sure
// assume no convert for next query unless set explictly
thd
->
variables
.
convert_set
=
0
;
close_thread_tables
(
thd
);
if
(
thd
->
query_error
||
thd
->
fatal_error
)
{
{
slave_print_error
(
rli
,
actual_error
,
"error '%s' on query '%s'"
,
print_header
(
file
);
actual_error
?
thd
->
net
.
last_error
:
fprintf
(
file
,
"
\t
Rand
\n
"
);
"unexpected success or fatal error"
,
query
);
free_root
(
&
thd
->
mem_root
,
0
);
return
1
;
}
}
free_root
(
&
thd
->
mem_root
,
0
);
fprintf
(
file
,
"SET RAND SEED1=%s;
\n
"
,
llstr
(
seed1
,
llbuff
));
return
Log_event
::
exec_event
(
rli
);
fprintf
(
file
,
"SET RAND SEED2=%s;
\n
"
,
llstr
(
seed2
,
llbuff
));
fflush
(
file
);
}
}
#endif // MYSQL_CLIENT
/*****************************************************************************
int
Load_log_event
::
exec_event
(
NET
*
net
,
struct
st_relay_log_info
*
rli
)
Rand_log_event::exec_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Rand_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
init_sql_alloc
(
&
thd
->
mem_root
,
8192
,
0
);
thd
->
rand
.
seed1
=
seed1
;
thd
->
db
=
rewrite_db
((
char
*
)
db
);
thd
->
rand
.
seed2
=
seed2
;
thd
->
query
=
0
;
rli
->
inc_pending
(
get_event_len
());
thd
->
query_error
=
0
;
return
0
;
}
if
(
db_ok
(
thd
->
db
,
replicate_do_db
,
replicate_ignore_db
))
#endif // !MYSQL_CLIENT
{
thd
->
set_time
((
time_t
)
when
);
thd
->
current_tablenr
=
0
;
VOID
(
pthread_mutex_lock
(
&
LOCK_thread_count
));
thd
->
query_id
=
query_id
++
;
VOID
(
pthread_mutex_unlock
(
&
LOCK_thread_count
));
TABLE_LIST
tables
;
bzero
((
char
*
)
&
tables
,
sizeof
(
tables
));
tables
.
db
=
thd
->
db
;
tables
.
alias
=
tables
.
real_name
=
(
char
*
)
table_name
;
tables
.
lock_type
=
TL_WRITE
;
// the table will be opened in mysql_load
if
(
table_rules_on
&&
!
tables_ok
(
thd
,
&
tables
))
{
// TODO: this is a bug - this needs to be moved to the I/O thread
if
(
net
)
skip_load_data_infile
(
net
);
}
else
{
char
llbuff
[
22
];
enum
enum_duplicates
handle_dup
=
DUP_IGNORE
;
if
(
sql_ex
.
opt_flags
&&
REPLACE_FLAG
)
handle_dup
=
DUP_REPLACE
;
sql_exchange
ex
((
char
*
)
fname
,
sql_ex
.
opt_flags
&&
DUMPFILE_FLAG
);
String
field_term
(
sql_ex
.
field_term
,
sql_ex
.
field_term_len
,
system_charset_info
);
String
enclosed
(
sql_ex
.
enclosed
,
sql_ex
.
enclosed_len
,
system_charset_info
);
String
line_term
(
sql_ex
.
line_term
,
sql_ex
.
line_term_len
,
system_charset_info
);
String
line_start
(
sql_ex
.
line_start
,
sql_ex
.
line_start_len
,
system_charset_info
);
String
escaped
(
sql_ex
.
escaped
,
sql_ex
.
escaped_len
,
system_charset_info
);
ex
.
opt_enclosed
=
(
sql_ex
.
opt_flags
&
OPT_ENCLOSED_FLAG
);
/*****************************************************************************
if
(
sql_ex
.
empty_flags
&
FIELD_TERM_EMPTY
)
*****************************************************************************
ex
.
field_term
->
length
(
0
);
ex
.
skip_lines
=
skip_lines
;
Slave_log_event methods
List
<
Item
>
fields
;
set_fields
(
fields
);
*****************************************************************************
thd
->
slave_proxy_id
=
thd
->
thread_id
;
****************************************************************************/
if
(
net
)
{
/*****************************************************************************
// mysql_load will use thd->net to read the file
thd
->
net
.
vio
=
net
->
vio
;
Slave_log_event::pack_info()
/*
Make sure the client does not get confused about the packet sequence
****************************************************************************/
*/
#ifndef MYSQL_CLIENT
thd
->
net
.
pkt_nr
=
net
->
pkt_nr
;
void
Slave_log_event
::
pack_info
(
String
*
packet
)
}
{
if
(
mysql_load
(
thd
,
&
ex
,
&
tables
,
fields
,
handle_dup
,
net
!=
0
,
char
buf1
[
256
],
buf
[
22
],
*
end
;
TL_WRITE
))
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
thd
->
query_error
=
1
;
tmp
.
length
(
0
);
if
(
thd
->
cuted_fields
)
tmp
.
append
(
"host="
);
sql_print_error
(
"Slave: load data infile at position %s in log \
tmp
.
append
(
master_host
);
'%s' produced %d warning(s)"
,
llstr
(
rli
->
master_log_pos
,
llbuff
),
RPL_LOG_NAME
,
tmp
.
append
(
",port="
);
thd
->
cuted_fields
);
end
=
int10_to_str
((
long
)
master_port
,
buf
,
10
);
if
(
net
)
tmp
.
append
(
buf
,
(
uint32
)
(
end
-
buf
));
net
->
pkt_nr
=
thd
->
net
.
pkt_nr
;
tmp
.
append
(
",log="
);
}
tmp
.
append
(
master_log
);
}
tmp
.
append
(
",pos="
);
else
tmp
.
append
(
llstr
(
master_pos
,
buf
));
{
net_store_data
(
packet
,
tmp
.
ptr
(),
tmp
.
length
());
/*
}
We will just ask the master to send us /dev/null if we do not
#endif // !MYSQL_CLIENT
want to load the data.
TODO: this a bug - needs to be done in I/O thread
/*****************************************************************************
*/
if
(
net
)
Slave_log_event::Slave_log_event()
skip_load_data_infile
(
net
);
}
****************************************************************************/
#ifndef MYSQL_CLIENT
thd
->
net
.
vio
=
0
;
Slave_log_event
::
Slave_log_event
(
THD
*
thd_arg
,
thd
->
db
=
0
;
// prevent db from being freed
struct
st_relay_log_info
*
rli
)
:
close_thread_tables
(
thd
);
Log_event
(
thd_arg
),
mem_pool
(
0
),
master_host
(
0
)
if
(
thd
->
query_error
)
{
DBUG_ENTER
(
"Slave_log_event"
);
if
(
!
rli
->
inited
)
// QQ When can this happen ?
DBUG_VOID_RETURN
;
MASTER_INFO
*
mi
=
rli
->
mi
;
// TODO: re-write this better without holding both locks at the same time
pthread_mutex_lock
(
&
mi
->
data_lock
);
pthread_mutex_lock
(
&
rli
->
data_lock
);
master_host_len
=
strlen
(
mi
->
host
);
master_log_len
=
strlen
(
rli
->
master_log_name
);
// on OOM, just do not initialize the structure and print the error
if
((
mem_pool
=
(
char
*
)
my_malloc
(
get_data_size
()
+
1
,
MYF
(
MY_WME
))))
{
{
int
sql_error
=
thd
->
net
.
last_errno
;
master_host
=
mem_pool
+
SL_MASTER_HOST_OFFSET
;
if
(
!
sql_error
)
memcpy
(
master_host
,
mi
->
host
,
master_host_len
+
1
);
sql_error
=
ER_UNKNOWN_ERROR
;
master_log
=
master_host
+
master_host_len
+
1
;
memcpy
(
master_log
,
rli
->
master_log_name
,
master_log_len
+
1
);
slave_print_error
(
rli
,
sql_error
,
master_port
=
mi
->
port
;
"Slave: Error '%s' running load data infile "
,
master_pos
=
rli
->
master_log_pos
;
ER_SAFE
(
sql_error
));
DBUG_PRINT
(
"info"
,
(
"master_log: %s pos: %d"
,
master_log
,
free_root
(
&
thd
->
mem_root
,
0
);
(
ulong
)
master_pos
));
return
1
;
}
}
free_root
(
&
thd
->
mem_root
,
0
);
else
sql_print_error
(
"Out of memory while recording slave event"
);
if
(
thd
->
fatal_error
)
pthread_mutex_unlock
(
&
rli
->
data_lock
);
pthread_mutex_unlock
(
&
mi
->
data_lock
);
DBUG_VOID_RETURN
;
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Slave_log_event dtor
****************************************************************************/
Slave_log_event
::~
Slave_log_event
()
{
my_free
(
mem_pool
,
MYF
(
MY_ALLOW_ZERO_PTR
));
}
/*****************************************************************************
Slave_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Slave_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
char
llbuff
[
22
];
if
(
short_form
)
return
;
print_header
(
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"Slave: master_host: '%s' master_port: %d \
master_log: '%s' master_pos: %s
\n
"
,
master_host
,
master_port
,
master_log
,
llstr
(
master_pos
,
llbuff
));
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Slave_log_event::get_data_size()
****************************************************************************/
int
Slave_log_event
::
get_data_size
()
{
return
master_host_len
+
master_log_len
+
1
+
SL_MASTER_HOST_OFFSET
;
}
/*****************************************************************************
Slave_log_event::write_data()
****************************************************************************/
int
Slave_log_event
::
write_data
(
IO_CACHE
*
file
)
{
int8store
(
mem_pool
+
SL_MASTER_POS_OFFSET
,
master_pos
);
int2store
(
mem_pool
+
SL_MASTER_PORT_OFFSET
,
master_port
);
// log and host are already there
return
my_b_safe_write
(
file
,
(
byte
*
)
mem_pool
,
get_data_size
());
}
/*****************************************************************************
Slave_log_event::init_from_mem_pool()
****************************************************************************/
void
Slave_log_event
::
init_from_mem_pool
(
int
data_size
)
{
master_pos
=
uint8korr
(
mem_pool
+
SL_MASTER_POS_OFFSET
);
master_port
=
uint2korr
(
mem_pool
+
SL_MASTER_PORT_OFFSET
);
master_host
=
mem_pool
+
SL_MASTER_HOST_OFFSET
;
master_host_len
=
strlen
(
master_host
);
// safety
master_log
=
master_host
+
master_host_len
+
1
;
if
(
master_log
>
mem_pool
+
data_size
)
{
{
sql_print_error
(
"Slave: Fatal error running LOAD DATA INFILE "
)
;
master_host
=
0
;
return
1
;
return
;
}
}
master_log_len
=
strlen
(
master_log
);
}
return
Log_event
::
exec_event
(
rli
);
/*****************************************************************************
Slave_log_event::Slave_log_event()
****************************************************************************/
Slave_log_event
::
Slave_log_event
(
const
char
*
buf
,
int
event_len
)
:
Log_event
(
buf
,
0
),
mem_pool
(
0
),
master_host
(
0
)
{
event_len
-=
LOG_EVENT_HEADER_LEN
;
if
(
event_len
<
0
)
return
;
if
(
!
(
mem_pool
=
(
char
*
)
my_malloc
(
event_len
+
1
,
MYF
(
MY_WME
))))
return
;
memcpy
(
mem_pool
,
buf
+
LOG_EVENT_HEADER_LEN
,
event_len
);
mem_pool
[
event_len
]
=
0
;
init_from_mem_pool
(
event_len
);
}
}
/*****************************************************************************
/*
Slave_log_event::exec_event()
The master started
IMPLEMENTATION
****************************************************************************/
- To handle the case where the master died without a stop event,
#ifndef MYSQL_CLIENT
we clean up all temporary tables + locks that we got.
int
Slave_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
if
(
mysql_bin_log
.
is_open
())
mysql_bin_log
.
write
(
this
);
return
Log_event
::
exec_event
(
rli
);
}
#endif // !MYSQL_CLIENT
TODO
- Remove all active user locks
- If we have an active transaction at this point, the master died
in the middle while writing the transaction to the binary log.
In this case we should stop the slave.
*/
int
Start_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
/*****************************************************************************
{
*****************************************************************************
/* All temporary tables was deleted on the master */
close_temporary_tables
(
thd
);
Stop_log_event methods
/*
If we have old format, load_tmpdir is cleaned up by the I/O thread
*****************************************************************************
*/
****************************************************************************/
if
(
!
rli
->
mi
->
old_format
)
cleanup_load_tmpdir
();
/*****************************************************************************
return
Log_event
::
exec_event
(
rli
);
Stop_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Stop_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
if
(
short_form
)
return
;
print_header
(
file
);
fprintf
(
file
,
"
\t
Stop
\n
"
);
fflush
(
file
);
}
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Stop_log_event::exec_event()
/*
The master stopped. Clean up all temporary tables + locks that the
The master stopped. Clean up all temporary tables + locks that the
master may have set.
master may have set.
TODO
TODO
- Remove all active user locks
- Remove all active user locks
*/
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Stop_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
int
Stop_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
// do not clean up immediately after rotate event
// do not clean up immediately after rotate event
...
@@ -1931,70 +2103,156 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
...
@@ -1931,70 +2103,156 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
flush_relay_log_info
(
rli
);
flush_relay_log_info
(
rli
);
return
0
;
return
0
;
}
}
#endif // !MYSQL_CLIENT
/*
/*
****************************************************************************
Got a rotate log even from the master
*****************************************************************************
IMPLEMENTATION
Create_file_log_event methods
This is mainly used so that we can later figure out the logname and
position for the master.
We can't rotate the slave as this will cause infinitive rotations
*****************************************************************************
in a A -> B -> A setup.
****************************************************************************/
RETURN VALUES
/*****************************************************************************
0 ok
*/
int
Rotate_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
Create_file_log_event ctor
****************************************************************************/
#ifndef MYSQL_CLIENT
Create_file_log_event
::
Create_file_log_event
(
THD
*
thd_arg
,
sql_exchange
*
ex
,
const
char
*
db_arg
,
const
char
*
table_name_arg
,
List
<
Item
>&
fields_arg
,
enum
enum_duplicates
handle_dup
,
char
*
block_arg
,
uint
block_len_arg
)
:
Load_log_event
(
thd_arg
,
ex
,
db_arg
,
table_name_arg
,
fields_arg
,
handle_dup
),
fake_base
(
0
),
block
(
block_arg
),
block_len
(
block_len_arg
),
file_id
(
thd_arg
->
file_id
=
mysql_bin_log
.
next_file_id
())
{
{
char
*
log_name
=
rli
->
master_log_name
;
sql_ex
.
force_new_format
();
DBUG_ENTER
(
"Rotate_log_event::exec_event"
);
}
#endif // !MYSQL_CLIENT
pthread_mutex_lock
(
&
rli
->
data_lock
);
/*****************************************************************************
memcpy
(
log_name
,
new_log_ident
,
ident_len
+
1
);
rli
->
master_log_pos
=
pos
;
Create_file_log_event::write_data_body()
rli
->
relay_log_pos
+=
get_event_len
();
DBUG_PRINT
(
"info"
,
(
"master_log_pos: %d"
,
(
ulong
)
rli
->
master_log_pos
));
****************************************************************************/
pthread_mutex_unlock
(
&
rli
->
data_lock
);
int
Create_file_log_event
::
write_data_body
(
IO_CACHE
*
file
)
pthread_cond_broadcast
(
&
rli
->
data_cond
);
{
flush_relay_log_info
(
rli
);
int
res
;
DBUG_RETURN
(
0
);
if
((
res
=
Load_log_event
::
write_data_body
(
file
))
||
fake_base
)
return
res
;
return
(
my_b_safe_write
(
file
,
(
byte
*
)
""
,
1
)
||
my_b_safe_write
(
file
,
(
byte
*
)
block
,
block_len
));
}
}
/*****************************************************************************
Create_file_log_event::write_data_header()
int
Intvar_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
****************************************************************************/
int
Create_file_log_event
::
write_data_header
(
IO_CACHE
*
file
)
{
{
switch
(
type
)
{
int
res
;
case
LAST_INSERT_ID_EVENT
:
if
((
res
=
Load_log_event
::
write_data_header
(
file
))
||
fake_base
)
thd
->
last_insert_id_used
=
1
;
return
res
;
thd
->
last_insert_id
=
val
;
byte
buf
[
CREATE_FILE_HEADER_LEN
];
break
;
int4store
(
buf
+
CF_FILE_ID_OFFSET
,
file_id
);
case
INSERT_ID_EVENT
:
return
my_b_safe_write
(
file
,
buf
,
CREATE_FILE_HEADER_LEN
);
thd
->
next_insert_id
=
val
;
}
break
;
/*****************************************************************************
Create_file_log_event::write_base()
****************************************************************************/
int
Create_file_log_event
::
write_base
(
IO_CACHE
*
file
)
{
int
res
;
fake_base
=
1
;
// pretend we are Load event
res
=
write
(
file
);
fake_base
=
0
;
return
res
;
}
/*****************************************************************************
Create_file_log_event ctor
****************************************************************************/
Create_file_log_event
::
Create_file_log_event
(
const
char
*
buf
,
int
len
,
bool
old_format
)
:
Load_log_event
(
buf
,
0
,
old_format
),
fake_base
(
0
),
block
(
0
),
inited_from_old
(
0
)
{
int
block_offset
;
if
(
copy_log_event
(
buf
,
len
,
old_format
))
return
;
if
(
!
old_format
)
{
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
+
LOAD_HEADER_LEN
+
CF_FILE_ID_OFFSET
);
// + 1 for \0 terminating fname
block_offset
=
(
LOG_EVENT_HEADER_LEN
+
Load_log_event
::
get_data_size
()
+
CREATE_FILE_HEADER_LEN
+
1
);
if
(
len
<
block_offset
)
return
;
block
=
(
char
*
)
buf
+
block_offset
;
block_len
=
len
-
block_offset
;
}
else
{
sql_ex
.
force_new_format
();
inited_from_old
=
1
;
}
}
rli
->
inc_pending
(
get_event_len
());
return
0
;
}
}
int
Rand_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
/*****************************************************************************
Create_file_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Create_file_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
{
thd
->
rand
.
seed1
=
seed1
;
if
(
short_form
)
thd
->
rand
.
seed2
=
seed2
;
return
;
rli
->
inc_pending
(
get_event_len
()
);
Load_log_event
::
print
(
file
,
1
,
last_db
);
return
0
;
fprintf
(
file
,
" file_id: %d block_len: %d
\n
"
,
file_id
,
block_len
)
;
}
}
#endif // MYSQL_CLIENT
int
Slave_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
/*****************************************************************************
Create_file_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Create_file_log_event
::
pack_info
(
String
*
packet
)
{
{
if
(
mysql_bin_log
.
is_open
())
char
buf1
[
256
],
buf
[
22
],
*
end
;
mysql_bin_log
.
write
(
this
);
String
tmp
(
buf1
,
sizeof
(
buf1
),
system_charset_info
);
return
Log_event
::
exec_event
(
rli
);
tmp
.
length
(
0
);
tmp
.
append
(
"db="
);
tmp
.
append
(
db
,
db_len
);
tmp
.
append
(
";table="
);
tmp
.
append
(
table_name
,
table_name_len
);
tmp
.
append
(
";file_id="
);
end
=
int10_to_str
((
long
)
file_id
,
buf
,
10
);
tmp
.
append
(
buf
,
(
uint32
)
(
end
-
buf
));
tmp
.
append
(
";block_len="
);
end
=
int10_to_str
((
long
)
block_len
,
buf
,
10
);
tmp
.
append
(
buf
,
(
uint32
)
(
end
-
buf
));
net_store_data
(
packet
,
(
char
*
)
tmp
.
ptr
(),
tmp
.
length
());
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Create_file_log_event::exec_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Create_file_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
int
Create_file_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
char
fname_buf
[
FN_REFLEN
+
10
];
char
fname_buf
[
FN_REFLEN
+
10
];
...
@@ -2051,20 +2309,100 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
...
@@ -2051,20 +2309,100 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
my_close
(
fd
,
MYF
(
0
));
my_close
(
fd
,
MYF
(
0
));
return
error
?
1
:
Log_event
::
exec_event
(
rli
);
return
error
?
1
:
Log_event
::
exec_event
(
rli
);
}
}
#endif // !MYSQL_CLIENT
int
Delete_file_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
/*****************************************************************************
*****************************************************************************
Append_block_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Append_block_log_event ctor
****************************************************************************/
#ifndef MYSQL_CLIENT
Append_block_log_event
::
Append_block_log_event
(
THD
*
thd_arg
,
char
*
block_arg
,
uint
block_len_arg
)
:
Log_event
(
thd_arg
),
block
(
block_arg
),
block_len
(
block_len_arg
),
file_id
(
thd_arg
->
file_id
)
{
{
char
fname
[
FN_REFLEN
+
10
];
char
*
p
=
slave_load_file_stem
(
fname
,
file_id
,
server_id
);
memcpy
(
p
,
".data"
,
6
);
(
void
)
my_delete
(
fname
,
MYF
(
MY_WME
));
memcpy
(
p
,
".info"
,
6
);
(
void
)
my_delete
(
fname
,
MYF
(
MY_WME
));
if
(
mysql_bin_log
.
is_open
())
mysql_bin_log
.
write
(
this
);
return
Log_event
::
exec_event
(
rli
);
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Append_block_log_event ctor
****************************************************************************/
Append_block_log_event
::
Append_block_log_event
(
const
char
*
buf
,
int
len
)
:
Log_event
(
buf
,
0
),
block
(
0
)
{
if
((
uint
)
len
<
APPEND_BLOCK_EVENT_OVERHEAD
)
return
;
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
AB_FILE_ID_OFFSET
);
block
=
(
char
*
)
buf
+
APPEND_BLOCK_EVENT_OVERHEAD
;
block_len
=
len
-
APPEND_BLOCK_EVENT_OVERHEAD
;
}
/*****************************************************************************
Append_block_log_event::write_data()
****************************************************************************/
int
Append_block_log_event
::
write_data
(
IO_CACHE
*
file
)
{
byte
buf
[
APPEND_BLOCK_HEADER_LEN
];
int4store
(
buf
+
AB_FILE_ID_OFFSET
,
file_id
);
return
(
my_b_safe_write
(
file
,
buf
,
APPEND_BLOCK_HEADER_LEN
)
||
my_b_safe_write
(
file
,
(
byte
*
)
block
,
block_len
));
}
/*****************************************************************************
Append_block_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Append_block_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
if
(
short_form
)
return
;
print_header
(
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"#Append_block: file_id: %d block_len: %d
\n
"
,
file_id
,
block_len
);
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Append_block_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Append_block_log_event
::
pack_info
(
String
*
packet
)
{
char
buf
[
256
];
uint
length
;
length
=
(
uint
)
my_sprintf
(
buf
,
(
buf
,
";file_id=%u;block_len=%u"
,
file_id
,
block_len
));
net_store_data
(
packet
,
buf
,
(
int32
)
length
);
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Append_block_log_event::exec_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Append_block_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
int
Append_block_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
char
fname
[
FN_REFLEN
+
10
];
char
fname
[
FN_REFLEN
+
10
];
...
@@ -2092,7 +2430,191 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
...
@@ -2092,7 +2430,191 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
my_close
(
fd
,
MYF
(
0
));
my_close
(
fd
,
MYF
(
0
));
return
error
?
error
:
Log_event
::
exec_event
(
rli
);
return
error
?
error
:
Log_event
::
exec_event
(
rli
);
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
Delete_file_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Delete_file_log_event ctor
****************************************************************************/
#ifndef MYSQL_CLIENT
Delete_file_log_event
::
Delete_file_log_event
(
THD
*
thd_arg
)
:
Log_event
(
thd_arg
),
file_id
(
thd_arg
->
file_id
)
{
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Delete_file_log_event ctor
****************************************************************************/
Delete_file_log_event
::
Delete_file_log_event
(
const
char
*
buf
,
int
len
)
:
Log_event
(
buf
,
0
),
file_id
(
0
)
{
if
((
uint
)
len
<
DELETE_FILE_EVENT_OVERHEAD
)
return
;
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
AB_FILE_ID_OFFSET
);
}
/*****************************************************************************
Delete_file_log_event::write_data()
****************************************************************************/
int
Delete_file_log_event
::
write_data
(
IO_CACHE
*
file
)
{
byte
buf
[
DELETE_FILE_HEADER_LEN
];
int4store
(
buf
+
DF_FILE_ID_OFFSET
,
file_id
);
return
my_b_safe_write
(
file
,
buf
,
DELETE_FILE_HEADER_LEN
);
}
/*****************************************************************************
Delete_file_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Delete_file_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
if
(
short_form
)
return
;
print_header
(
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"#Delete_file: file_id=%u
\n
"
,
file_id
);
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Delete_file_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Delete_file_log_event
::
pack_info
(
String
*
packet
)
{
char
buf
[
64
];
uint
length
;
length
=
(
uint
)
my_sprintf
(
buf
,
(
buf
,
";file_id=%u"
,
(
uint
)
file_id
));
net_store_data
(
packet
,
buf
,
(
int32
)
length
);
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Delete_file_log_event::exec_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Delete_file_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
char
fname
[
FN_REFLEN
+
10
];
char
*
p
=
slave_load_file_stem
(
fname
,
file_id
,
server_id
);
memcpy
(
p
,
".data"
,
6
);
(
void
)
my_delete
(
fname
,
MYF
(
MY_WME
));
memcpy
(
p
,
".info"
,
6
);
(
void
)
my_delete
(
fname
,
MYF
(
MY_WME
));
if
(
mysql_bin_log
.
is_open
())
mysql_bin_log
.
write
(
this
);
return
Log_event
::
exec_event
(
rli
);
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
Execute_load_log_event methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
Execute_load_log_event ctor
****************************************************************************/
#ifndef MYSQL_CLIENT
Execute_load_log_event
::
Execute_load_log_event
(
THD
*
thd_arg
)
:
Log_event
(
thd_arg
),
file_id
(
thd_arg
->
file_id
)
{
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Execute_load_log_event ctor
****************************************************************************/
Execute_load_log_event
::
Execute_load_log_event
(
const
char
*
buf
,
int
len
)
:
Log_event
(
buf
,
0
),
file_id
(
0
)
{
if
((
uint
)
len
<
EXEC_LOAD_EVENT_OVERHEAD
)
return
;
file_id
=
uint4korr
(
buf
+
LOG_EVENT_HEADER_LEN
+
EL_FILE_ID_OFFSET
);
}
/*****************************************************************************
Execute_load_log_event::write_data()
****************************************************************************/
int
Execute_load_log_event
::
write_data
(
IO_CACHE
*
file
)
{
byte
buf
[
EXEC_LOAD_HEADER_LEN
];
int4store
(
buf
+
EL_FILE_ID_OFFSET
,
file_id
);
return
my_b_safe_write
(
file
,
buf
,
EXEC_LOAD_HEADER_LEN
);
}
/*****************************************************************************
Execute_load_log_event::print()
****************************************************************************/
#ifdef MYSQL_CLIENT
void
Execute_load_log_event
::
print
(
FILE
*
file
,
bool
short_form
,
char
*
last_db
)
{
if
(
short_form
)
return
;
print_header
(
file
);
fputc
(
'\n'
,
file
);
fprintf
(
file
,
"#Exec_load: file_id=%d
\n
"
,
file_id
);
}
#endif // MYSQL_CLIENT
/*****************************************************************************
Execute_load_log_event::pack_info()
****************************************************************************/
#ifndef MYSQL_CLIENT
void
Execute_load_log_event
::
pack_info
(
String
*
packet
)
{
char
buf
[
64
];
uint
length
;
length
=
(
uint
)
my_sprintf
(
buf
,
(
buf
,
";file_id=%u"
,
(
uint
)
file_id
));
net_store_data
(
packet
,
buf
,
(
int32
)
length
);
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
Execute_load_log_event::exec_event()
****************************************************************************/
#ifndef MYSQL_CLIENT
int
Execute_load_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
int
Execute_load_log_event
::
exec_event
(
struct
st_relay_log_info
*
rli
)
{
{
char
fname
[
FN_REFLEN
+
10
];
char
fname
[
FN_REFLEN
+
10
];
...
@@ -2151,5 +2673,100 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
...
@@ -2151,5 +2673,100 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
}
}
return
error
?
error
:
Log_event
::
exec_event
(
rli
);
return
error
?
error
:
Log_event
::
exec_event
(
rli
);
}
}
#endif // !MYSQL_CLIENT
/*****************************************************************************
*****************************************************************************
sql_ex_info methods
*****************************************************************************
****************************************************************************/
/*****************************************************************************
sql_ex_info::write_data()
****************************************************************************/
int
sql_ex_info
::
write_data
(
IO_CACHE
*
file
)
{
if
(
new_format
())
{
return
(
write_str
(
file
,
field_term
,
field_term_len
)
||
write_str
(
file
,
enclosed
,
enclosed_len
)
||
write_str
(
file
,
line_term
,
line_term_len
)
||
write_str
(
file
,
line_start
,
line_start_len
)
||
write_str
(
file
,
escaped
,
escaped_len
)
||
my_b_safe_write
(
file
,(
byte
*
)
&
opt_flags
,
1
));
}
else
{
old_sql_ex
old_ex
;
old_ex
.
field_term
=
*
field_term
;
old_ex
.
enclosed
=
*
enclosed
;
old_ex
.
line_term
=
*
line_term
;
old_ex
.
line_start
=
*
line_start
;
old_ex
.
escaped
=
*
escaped
;
old_ex
.
opt_flags
=
opt_flags
;
old_ex
.
empty_flags
=
empty_flags
;
return
my_b_safe_write
(
file
,
(
byte
*
)
&
old_ex
,
sizeof
(
old_ex
));
}
}
/*****************************************************************************
sql_ex_info::init()
****************************************************************************/
char
*
sql_ex_info
::
init
(
char
*
buf
,
char
*
buf_end
,
bool
use_new_format
)
{
cached_new_format
=
use_new_format
;
if
(
use_new_format
)
{
empty_flags
=
0
;
/*
The code below assumes that buf will not disappear from
under our feet during the lifetime of the event. This assumption
holds true in the slave thread if the log is in new format, but is not
the case when we have old format because we will be reusing net buffer
to read the actual file before we write out the Create_file event.
*/
if
(
read_str
(
buf
,
buf_end
,
field_term
,
field_term_len
)
||
read_str
(
buf
,
buf_end
,
enclosed
,
enclosed_len
)
||
read_str
(
buf
,
buf_end
,
line_term
,
line_term_len
)
||
read_str
(
buf
,
buf_end
,
line_start
,
line_start_len
)
||
read_str
(
buf
,
buf_end
,
escaped
,
escaped_len
))
return
0
;
opt_flags
=
*
buf
++
;
}
else
{
field_term_len
=
enclosed_len
=
line_term_len
=
line_start_len
=
escaped_len
=
1
;
field_term
=
buf
++
;
// Use first byte in string
enclosed
=
buf
++
;
line_term
=
buf
++
;
line_start
=
buf
++
;
escaped
=
buf
++
;
opt_flags
=
*
buf
++
;
empty_flags
=
*
buf
++
;
if
(
empty_flags
&
FIELD_TERM_EMPTY
)
field_term_len
=
0
;
if
(
empty_flags
&
ENCLOSED_EMPTY
)
enclosed_len
=
0
;
if
(
empty_flags
&
LINE_TERM_EMPTY
)
line_term_len
=
0
;
if
(
empty_flags
&
LINE_START_EMPTY
)
line_start_len
=
0
;
if
(
empty_flags
&
ESCAPED_EMPTY
)
escaped_len
=
0
;
}
return
buf
;
}
#endif
/* !MYSQL_CLIENT */
sql/log_event.h
View file @
26a1d888
...
@@ -54,6 +54,11 @@
...
@@ -54,6 +54,11 @@
#define LINE_START_EMPTY 0x8
#define LINE_START_EMPTY 0x8
#define ESCAPED_EMPTY 0x10
#define ESCAPED_EMPTY 0x10
/*****************************************************************************
old_sql_ex struct
****************************************************************************/
struct
old_sql_ex
struct
old_sql_ex
{
{
char
field_term
;
char
field_term
;
...
@@ -67,6 +72,11 @@ struct old_sql_ex
...
@@ -67,6 +72,11 @@ struct old_sql_ex
#define NUM_LOAD_DELIM_STRS 5
#define NUM_LOAD_DELIM_STRS 5
/*****************************************************************************
sql_ex_info struct
****************************************************************************/
struct
sql_ex_info
struct
sql_ex_info
{
{
char
*
field_term
;
char
*
field_term
;
...
@@ -99,13 +109,19 @@ struct sql_ex_info
...
@@ -99,13 +109,19 @@ struct sql_ex_info
}
}
};
};
/*
/*****************************************************************************
Binary log consists of events. Each event has a fixed length header,
followed by possibly variable ( depending on the type of event) length
MySQL Binary Log
data body. The data body consists of an optional fixed length segment
(post-header), and an optional variable length segment. See #defines and
This log consists of events. Each event has a fixed-length header,
comments below for the format specifics
possibly followed by a variable length data body.
*/
The data body consists of an optional fixed length segment (post-header)
and an optional variable length segment.
See the #defines below for the format specifics.
****************************************************************************/
/* event-specific post-header sizes */
/* event-specific post-header sizes */
#define LOG_EVENT_HEADER_LEN 19
#define LOG_EVENT_HEADER_LEN 19
...
@@ -221,6 +237,13 @@ class THD;
...
@@ -221,6 +237,13 @@ class THD;
struct
st_relay_log_info
;
struct
st_relay_log_info
;
/*****************************************************************************
Log_event class
This is the abstract base class for binary log events.
****************************************************************************/
class
Log_event
class
Log_event
{
{
public:
public:
...
@@ -303,6 +326,13 @@ class Log_event
...
@@ -303,6 +326,13 @@ class Log_event
};
};
/*****************************************************************************
Query Log Event class
Logs SQL queries
****************************************************************************/
class
Query_log_event
:
public
Log_event
class
Query_log_event
:
public
Log_event
{
{
protected:
protected:
...
@@ -355,6 +385,11 @@ class Query_log_event: public Log_event
...
@@ -355,6 +385,11 @@ class Query_log_event: public Log_event
};
};
/*****************************************************************************
Slave Log Event class
****************************************************************************/
class
Slave_log_event
:
public
Log_event
class
Slave_log_event
:
public
Log_event
{
{
protected:
protected:
...
@@ -384,6 +419,12 @@ class Slave_log_event: public Log_event
...
@@ -384,6 +419,12 @@ class Slave_log_event: public Log_event
int
write_data
(
IO_CACHE
*
file
);
int
write_data
(
IO_CACHE
*
file
);
};
};
/*****************************************************************************
Load Log Event class
****************************************************************************/
class
Load_log_event
:
public
Log_event
class
Load_log_event
:
public
Log_event
{
{
protected:
protected:
...
@@ -446,6 +487,11 @@ class Load_log_event: public Log_event
...
@@ -446,6 +487,11 @@ class Load_log_event: public Log_event
extern
char
server_version
[
SERVER_VERSION_LENGTH
];
extern
char
server_version
[
SERVER_VERSION_LENGTH
];
/*****************************************************************************
Start Log Event class
****************************************************************************/
class
Start_log_event
:
public
Log_event
class
Start_log_event
:
public
Log_event
{
{
public:
public:
...
@@ -477,6 +523,13 @@ class Start_log_event: public Log_event
...
@@ -477,6 +523,13 @@ class Start_log_event: public Log_event
};
};
/*****************************************************************************
Intvar Log Event class
Logs special variables such as auto_increment values
****************************************************************************/
class
Intvar_log_event
:
public
Log_event
class
Intvar_log_event
:
public
Log_event
{
{
public:
public:
...
@@ -503,9 +556,11 @@ class Intvar_log_event: public Log_event
...
@@ -503,9 +556,11 @@ class Intvar_log_event: public Log_event
};
};
/*****************************************************************************
/*****************************************************************************
*
* Rand log event class
Rand Log Event class
*
Logs random seed used by the next RAND()
****************************************************************************/
****************************************************************************/
class
Rand_log_event
:
public
Log_event
class
Rand_log_event
:
public
Log_event
{
{
...
@@ -531,6 +586,12 @@ class Rand_log_event: public Log_event
...
@@ -531,6 +586,12 @@ class Rand_log_event: public Log_event
bool
is_valid
()
{
return
1
;
}
bool
is_valid
()
{
return
1
;
}
};
};
/*****************************************************************************
Stop Log Event class
****************************************************************************/
class
Stop_log_event
:
public
Log_event
class
Stop_log_event
:
public
Log_event
{
{
public:
public:
...
@@ -551,6 +612,13 @@ class Stop_log_event: public Log_event
...
@@ -551,6 +612,13 @@ class Stop_log_event: public Log_event
};
};
/*****************************************************************************
Rotate Log Event class
This will be depricated when we move to using sequence ids.
****************************************************************************/
class
Rotate_log_event
:
public
Log_event
class
Rotate_log_event
:
public
Log_event
{
{
public:
public:
...
@@ -585,6 +653,11 @@ class Rotate_log_event: public Log_event
...
@@ -585,6 +653,11 @@ class Rotate_log_event: public Log_event
/* the classes below are for the new LOAD DATA INFILE logging */
/* the classes below are for the new LOAD DATA INFILE logging */
/*****************************************************************************
Create File Log Event class
****************************************************************************/
class
Create_file_log_event
:
public
Load_log_event
class
Create_file_log_event
:
public
Load_log_event
{
{
protected:
protected:
...
@@ -641,6 +714,11 @@ class Create_file_log_event: public Load_log_event
...
@@ -641,6 +714,11 @@ class Create_file_log_event: public Load_log_event
};
};
/*****************************************************************************
Append Block Log Event class
****************************************************************************/
class
Append_block_log_event
:
public
Log_event
class
Append_block_log_event
:
public
Log_event
{
{
public:
public:
...
@@ -665,7 +743,11 @@ class Append_block_log_event: public Log_event
...
@@ -665,7 +743,11 @@ class Append_block_log_event: public Log_event
int
write_data
(
IO_CACHE
*
file
);
int
write_data
(
IO_CACHE
*
file
);
};
};
/*****************************************************************************
Delete File Log Event class
****************************************************************************/
class
Delete_file_log_event
:
public
Log_event
class
Delete_file_log_event
:
public
Log_event
{
{
public:
public:
...
@@ -687,6 +769,11 @@ class Delete_file_log_event: public Log_event
...
@@ -687,6 +769,11 @@ class Delete_file_log_event: public Log_event
int
write_data
(
IO_CACHE
*
file
);
int
write_data
(
IO_CACHE
*
file
);
};
};
/*****************************************************************************
Execute Load Log Event class
****************************************************************************/
class
Execute_load_log_event
:
public
Log_event
class
Execute_load_log_event
:
public
Log_event
{
{
public:
public:
...
...
sql/sql_derived.cc
View file @
26a1d888
...
@@ -70,7 +70,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
...
@@ -70,7 +70,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
if
(
tables_is_opened
||
!
(
res
=
open_and_lock_tables
(
thd
,
tables
)))
if
(
tables_is_opened
||
!
(
res
=
open_and_lock_tables
(
thd
,
tables
)))
{
{
if
(
tables
&&
setup_fields
(
thd
,
tables
,
item_list
,
0
,
0
,
1
))
if
(
setup_fields
(
thd
,
tables
,
item_list
,
0
,
0
,
1
))
{
{
res
=-
1
;
res
=-
1
;
goto
exit
;
goto
exit
;
...
@@ -113,6 +113,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
...
@@ -113,6 +113,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
t
->
table
=
table
;
t
->
table
=
table
;
table
->
derived_select_number
=
sl
->
select_number
;
table
->
derived_select_number
=
sl
->
select_number
;
sl
->
exclude
();
sl
->
exclude
();
t
->
db
=
(
tables
&&
tables
->
db
&&
tables
->
db
[
0
])
?
t
->
db
:
thd
->
db
;
t
->
derived
=
(
SELECT_LEX
*
)
0
;
// just in case ...
t
->
derived
=
(
SELECT_LEX
*
)
0
;
// just in case ...
}
}
}
}
...
...
sql/sql_parse.cc
View file @
26a1d888
...
@@ -1388,10 +1388,14 @@ mysql_execute_command(THD *thd)
...
@@ -1388,10 +1388,14 @@ mysql_execute_command(THD *thd)
for
(
TABLE_LIST
*
cursor
=
tables
;
for
(
TABLE_LIST
*
cursor
=
tables
;
cursor
;
cursor
;
cursor
=
cursor
->
next
)
cursor
=
cursor
->
next
)
if
(
cursor
->
derived
&&
mysql_derived
(
thd
,
lex
,
if
(
cursor
->
derived
&&
(
res
=
mysql_derived
(
thd
,
lex
,
(
SELECT_LEX_UNIT
*
)
cursor
->
derived
,
(
SELECT_LEX_UNIT
*
)
cursor
->
derived
,
cursor
,
0
))
cursor
,
0
)))
{
if
(
res
<
0
)
send_error
(
thd
,
thd
->
killed
?
ER_SERVER_SHUTDOWN
:
0
);
DBUG_VOID_RETURN
;
DBUG_VOID_RETURN
;
}
}
}
if
((
lex
->
select_lex
.
next_select_in_list
()
&&
if
((
lex
->
select_lex
.
next_select_in_list
()
&&
lex
->
unit
.
create_total_list
(
thd
,
lex
,
&
tables
))
||
lex
->
unit
.
create_total_list
(
thd
,
lex
,
&
tables
))
||
...
@@ -2781,7 +2785,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
...
@@ -2781,7 +2785,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
found
=
1
;
found
=
1
;
}
}
}
}
else
if
(
check_access
(
thd
,
want_access
,
tables
->
db
,
&
tables
->
grant
.
privilege
,
else
if
(
tables
->
db
&&
check_access
(
thd
,
want_access
,
tables
->
db
,
&
tables
->
grant
.
privilege
,
0
,
no_errors
))
0
,
no_errors
))
return
TRUE
;
return
TRUE
;
}
}
...
...
sql/sql_test.cc
View file @
26a1d888
...
@@ -26,6 +26,23 @@
...
@@ -26,6 +26,23 @@
/* Intern key cache variables */
/* Intern key cache variables */
extern
"C"
pthread_mutex_t
THR_LOCK_keycache
;
extern
"C"
pthread_mutex_t
THR_LOCK_keycache
;
static
const
char
*
lock_descriptions
[]
=
{
"No lock"
,
"Low priority read lock"
,
"Shared Read lock"
,
"High priority read lock"
,
"Read lock without concurrent inserts"
,
"Write lock that allows other writers"
,
"Write lock, but allow reading"
,
"Concurrent insert lock"
,
"Lock Used by delayed insert"
,
"Low priority write lock"
,
"High priority write lock"
,
"Highest priority write lock"
};
#ifndef DBUG_OFF
#ifndef DBUG_OFF
void
void
...
@@ -45,29 +62,11 @@ print_where(COND *cond,const char *info)
...
@@ -45,29 +62,11 @@ print_where(COND *cond,const char *info)
DBUG_UNLOCK_FILE
;
DBUG_UNLOCK_FILE
;
}
}
}
}
/* This is for debugging purposes */
/* This is for debugging purposes */
extern
HASH
open_cache
;
extern
HASH
open_cache
;
extern
TABLE
*
unused_tables
;
extern
TABLE
*
unused_tables
;
static
const
char
*
lock_descriptions
[]
=
{
"No lock"
,
"Low priority read lock"
,
"Shared Read lock"
,
"High priority read lock"
,
"Read lock without concurrent inserts"
,
"Write lock that allows other writers"
,
"Write lock, but allow reading"
,
"Concurrent insert lock"
,
"Lock Used by delayed insert"
,
"Low priority write lock"
,
"High priority write lock"
,
"Highest priority write lock"
};
void
print_cached_tables
(
void
)
void
print_cached_tables
(
void
)
{
{
uint
idx
,
count
,
unused
;
uint
idx
,
count
,
unused
;
...
@@ -203,6 +202,99 @@ TEST_join(JOIN *join)
...
@@ -203,6 +202,99 @@ TEST_join(JOIN *join)
#endif
#endif
typedef
struct
st_debug_lock
{
ulong
thread_id
;
char
table_name
[
FN_REFLEN
];
bool
waiting
;
const
char
*
lock_text
;
enum
thr_lock_type
type
;
}
TABLE_LOCK_INFO
;
static
int
dl_compare
(
TABLE_LOCK_INFO
*
a
,
TABLE_LOCK_INFO
*
b
)
{
if
(
a
->
thread_id
>
b
->
thread_id
)
return
1
;
if
(
a
->
thread_id
<
b
->
thread_id
)
return
-
1
;
if
(
a
->
waiting
==
b
->
waiting
)
return
0
;
else
if
(
a
->
waiting
)
return
-
1
;
return
1
;
}
static
void
push_locks_into_array
(
DYNAMIC_ARRAY
*
ar
,
THR_LOCK_DATA
*
data
,
bool
wait
,
const
char
*
text
)
{
if
(
data
)
{
TABLE
*
table
=
(
TABLE
*
)
data
->
debug_print_param
;
if
(
table
&&
table
->
tmp_table
==
NO_TMP_TABLE
)
{
TABLE_LOCK_INFO
table_lock_info
;
table_lock_info
.
thread_id
=
table
->
in_use
->
thread_id
;
memcpy
(
table_lock_info
.
table_name
,
table
->
table_cache_key
,
table
->
key_length
);
table_lock_info
.
table_name
[
strlen
(
table_lock_info
.
table_name
)]
=
'.'
;
table_lock_info
.
waiting
=
wait
;
table_lock_info
.
lock_text
=
text
;
table_lock_info
.
type
=
table
->
reginfo
.
lock_type
;
// obtainable also from THR_LOCK_DATA
VOID
(
push_dynamic
(
ar
,(
gptr
)
&
table_lock_info
));
}
}
}
/*
Regarding MERGE tables:
For now, the best option is to use the common TABLE *pointer for all
cases; The drawback is that for MERGE tables we will see many locks
for the merge tables even if some of them are for individual tables.
The way to solve this is to add to 'THR_LOCK' structure a pointer to
the filename and use this when printing the data.
(We can for now ignore this and just print the same name for all merge
table parts; Please add the above as a comment to the display_lock
function so that we can easily add this if we ever need this.
*/
static
void
display_table_locks
(
void
)
{
LIST
*
list
;
DYNAMIC_ARRAY
saved_table_locks
;
VOID
(
my_init_dynamic_array
(
&
saved_table_locks
,
sizeof
(
TABLE_LOCK_INFO
),
open_cache
.
records
+
20
,
50
));
VOID
(
pthread_mutex_lock
(
&
THR_LOCK_lock
));
for
(
list
=
thr_lock_thread_list
;
list
;
list
=
rest
(
list
))
{
THR_LOCK
*
lock
=
(
THR_LOCK
*
)
list
->
data
;
VOID
(
pthread_mutex_lock
(
&
lock
->
mutex
));
push_locks_into_array
(
&
saved_table_locks
,
lock
->
write
.
data
,
false
,
"Locked - write"
);
push_locks_into_array
(
&
saved_table_locks
,
lock
->
write_wait
.
data
,
true
,
"Waiting - write"
);
push_locks_into_array
(
&
saved_table_locks
,
lock
->
read
.
data
,
false
,
"Locked - read"
);
push_locks_into_array
(
&
saved_table_locks
,
lock
->
read_wait
.
data
,
true
,
"Waiting - read"
);
VOID
(
pthread_mutex_unlock
(
&
lock
->
mutex
));
}
VOID
(
pthread_mutex_unlock
(
&
THR_LOCK_lock
));
if
(
!
saved_table_locks
.
elements
)
goto
end
;
qsort
((
gptr
)
dynamic_element
(
&
saved_table_locks
,
0
,
TABLE_LOCK_INFO
*
),
saved_table_locks
.
elements
,
sizeof
(
TABLE_LOCK_INFO
),(
qsort_cmp
)
dl_compare
);
freeze_size
(
&
saved_table_locks
);
puts
(
"
\n
Thread database.table_name Locked/Waiting Lock_type
\n
"
);
for
(
uint
i
=
0
;
i
<
saved_table_locks
.
elements
;
i
++
)
{
TABLE_LOCK_INFO
*
dl_ptr
=
dynamic_element
(
&
saved_table_locks
,
i
,
TABLE_LOCK_INFO
*
);
printf
(
"%-8ld%-28.28s%-22s%s
\n
"
,
dl_ptr
->
thread_id
,
dl_ptr
->
table_name
,
dl_ptr
->
lock_text
,
lock_descriptions
[(
int
)
dl_ptr
->
type
]);
}
puts
(
"
\n\n
"
);
end:
delete_dynamic
(
&
saved_table_locks
);
}
void
mysql_print_status
(
THD
*
thd
)
void
mysql_print_status
(
THD
*
thd
)
{
{
char
current_dir
[
FN_REFLEN
];
char
current_dir
[
FN_REFLEN
];
...
@@ -268,6 +360,7 @@ Next alarm time: %lu\n",
...
@@ -268,6 +360,7 @@ Next alarm time: %lu\n",
alarm_info
.
max_used_alarms
,
alarm_info
.
max_used_alarms
,
alarm_info
.
next_alarm_time
);
alarm_info
.
next_alarm_time
);
#endif
#endif
display_table_locks
();
fflush
(
stdout
);
fflush
(
stdout
);
if
(
thd
)
if
(
thd
)
thd
->
proc_info
=
"malloc"
;
thd
->
proc_info
=
"malloc"
;
...
...
sql/sql_yacc.yy
View file @
26a1d888
...
@@ -1449,20 +1449,6 @@ slave:
...
@@ -1449,20 +1449,6 @@ slave:
lex->sql_command = SQLCOM_SLAVE_STOP;
lex->sql_command = SQLCOM_SLAVE_STOP;
lex->type = 0;
lex->type = 0;
};
};
|
SLAVE START_SYM slave_thread_opts
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_START;
lex->type = 0;
}
|
SLAVE STOP_SYM slave_thread_opts
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_STOP;
lex->type = 0;
};
slave_thread_opts:
slave_thread_opts:
slave_thread_opt
slave_thread_opt
...
...
strings/longlong2str-x86.s
View file @
26a1d888
...
@@ -64,7 +64,7 @@ longlong2str:
...
@@ -64,7 +64,7 @@ longlong2str:
jne
.
L150
jne
.
L150
movb
$
48
,(%
edi
)
movb
$
48
,(%
edi
)
incl
%
edi
incl
%
edi
jmp
.
L1
64
jmp
.
L1
0_end
.
align
4
.
align
4
.
L150
:
.
L150
:
...
@@ -81,9 +81,9 @@ longlong2str:
...
@@ -81,9 +81,9 @@ longlong2str:
movl
%
eax
,%
ebp
movl
%
eax
,%
ebp
movl
%
esi
,%
eax
movl
%
esi
,%
eax
divl
%
ebx
divl
%
ebx
decl
%
ecx
movl
%
eax
,%
esi
#
quotent
in
ebp
:
esi
movl
%
eax
,%
esi
#
quotent
in
ebp
:
esi
movb
_dig_vec
(%
edx
),%
al
#
al
is
faster
than
dl
movb
_dig_vec
(%
edx
),%
al
#
al
is
faster
than
dl
decl
%
ecx
movb
%
al
,(%
ecx
)
#
store
value
in
buff
movb
%
al
,(%
ecx
)
#
store
value
in
buff
.
align
4
.
align
4
.
L155
:
.
L155
:
...
@@ -91,7 +91,7 @@ longlong2str:
...
@@ -91,7 +91,7 @@ longlong2str:
ja
.
L153
ja
.
L153
testl
%
esi
,%
esi
#
rest
value
testl
%
esi
,%
esi
#
rest
value
jl
.
L153
jl
.
L153
je
.
L1
60
#
Ready
je
.
L1
0_mov
#
Ready
movl
%
esi
,%
eax
movl
%
esi
,%
eax
movl
$
_dig_vec
,%
ebp
movl
$
_dig_vec
,%
ebp
.
align
4
.
align
4
...
@@ -105,14 +105,14 @@ longlong2str:
...
@@ -105,14 +105,14 @@ longlong2str:
movb
%
dl
,(%
ecx
)
movb
%
dl
,(%
ecx
)
jne
.
L154
jne
.
L154
.
L1
60
:
.
L1
0_mov
:
movl
%
ecx
,%
esi
movl
%
ecx
,%
esi
leal
92
(%
esp
),%
ecx
#
End
of
buffer
leal
92
(%
esp
),%
ecx
#
End
of
buffer
subl
%
esi
,%
ecx
subl
%
esi
,%
ecx
rep
rep
movsb
movsb
.
L1
64
:
.
L1
0_end
:
movl
%
edi
,%
eax
#
Pointer
to
end
null
movl
%
edi
,%
eax
#
Pointer
to
end
null
movb
$
0
,(%
edi
)
#
Store
the
end
null
movb
$
0
,(%
edi
)
#
Store
the
end
null
...
@@ -131,10 +131,93 @@ longlong2str:
...
@@ -131,10 +131,93 @@ longlong2str:
.
Lfe3
:
.
Lfe3
:
.
size
longlong2str
,
.
Lfe3
-
longlong2str
.
size
longlong2str
,
.
Lfe3
-
longlong2str
#
#
This
is
almost
equal
to
the
above
,
except
that
we
can
do
the
final
#
loop
much
more
efficient
#
.
align
4
.
Ltmp
:
.
long
0xcccccccd
.
align
4
.
globl
longlong10_to_str
.
globl
longlong10_to_str
.
type
longlong10_str
,
@
function
.
type
longlong10_str
,
@
function
longlong10_to_str
:
longlong10_to_str
:
jmp
longlong2str
subl
$
80
,%
esp
pushl
%
ebp
pushl
%
esi
pushl
%
edi
pushl
%
ebx
movl
100
(%
esp
),%
esi
#
Lower
part
of
val
movl
104
(%
esp
),%
ebp
#
Higher
part
of
val
movl
108
(%
esp
),%
edi
#
get
dst
movl
112
(%
esp
),%
ebx
#
Radix
(
10
or
-
10
)
testl
%
ebx
,%
ebx
jge
.
L10_10
#
Positive
radix
negl
%
ebx
#
Change
radix
to
positive
(=
10
)
testl
%
ebp
,%
ebp
#
Test
if
negative
value
jge
.
L10_10
movb
$
45
,(%
edi
)
#
Add
sign
incl
%
edi
negl
%
esi
#
Change
sign
of
val
(
ebp
:
esi
)
adcl
$
0
,%
ebp
negl
%
ebp
.
align
4
.
L10_10
:
leal
92
(%
esp
),%
ecx
#
End
of
buffer
movl
%
esi
,%
eax
#
Test
if
zero
(
for
easy
loop
)
orl
%
ebp
,%
eax
jne
.
L10_30
#
Not
zero
#
Here
when
value
is
zero
movb
$
48
,(%
edi
)
incl
%
edi
jmp
.
L10_end
.
align
4
.
L10_20
:
#
val
is
stored
in
in
ebp
:
esi
movl
%
ebp
,%
eax
#
High
part
of
value
xorl
%
edx
,%
edx
divl
%
ebx
#
Divide
by
10
movl
%
eax
,%
ebp
movl
%
esi
,%
eax
divl
%
ebx
#
Divide
by
10
decl
%
ecx
movl
%
eax
,%
esi
#
quotent
in
ebp
:
esi
addl
$
48
,%
edx
#
Convert
to
ascii
movb
%
dl
,(%
ecx
)
#
store
value
in
buff
.
L10_30
:
testl
%
ebp
,%
ebp
ja
.
L10_20
testl
%
esi
,%
esi
#
rest
value
jl
.
L10_20
#
Unsigned
,
do
ulonglong
div
once
more
je
.
L10_mov
#
Ready
movl
%
esi
,%
ebx
#
Move
val
to
%
ebx
#
The
following
code
uses
some
tricks
to
change
division
by
10
to
#
multiplication
and
shifts
movl
.
Ltmp
,%
esi
#
set
%
esi
to
0xcccccccd
.
L10_40
:
movl
%
ebx
,%
eax
mull
%
esi
decl
%
ecx
shrl
$
3
,%
edx
leal
(%
edx
,%
edx
,
4
),%
eax
addl
%
eax
,%
eax
subb
%
al
,%
bl
#
%
bl
now
contains
val
%
10
addb
$
48
,%
bl
movb
%
bl
,(%
ecx
)
movl
%
edx
,%
ebx
testl
%
ebx
,%
ebx
jne
.
L10_40
jmp
.
L10_mov
#
Shared
end
with
longlong10_to_str
.
L10end
:
.
L10end
:
.
size
longlong10_to_str
,
.
L10end
-
longlong10_to_str
.
size
longlong10_to_str
,
.
L10end
-
longlong10_to_str
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment