mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Mainly resolving Guilhem's 4.1 patch to 5.0
This commit is contained in:
@ -14,11 +14,28 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
/*
|
||||
|
||||
TODO: print the catalog (some USE catalog.db ????).
|
||||
|
||||
Standalone program to read a MySQL binary log (or relay log);
|
||||
can read files produced by 3.23, 4.x, 5.0 servers.
|
||||
|
||||
Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0.
|
||||
Should be able to read any file of these categories, even with
|
||||
--start-position.
|
||||
An important fact: the Format_desc event of the log is at most the 3rd event
|
||||
of the log; if it is the 3rd then there is this combination:
|
||||
Format_desc_of_slave, Rotate_of_master, Format_desc_of_master.
|
||||
*/
|
||||
|
||||
#define MYSQL_CLIENT
|
||||
#undef MYSQL_SERVER
|
||||
#include "client_priv.h"
|
||||
#include <my_time.h>
|
||||
#include "log_event.h"
|
||||
/* That one is necessary for defines of OPTION_NO_FOREIGN_KEY_CHECKS etc */
|
||||
#include "mysql_priv.h"
|
||||
|
||||
#define BIN_LOG_HEADER_SIZE 4
|
||||
#define PROBE_HEADER_LEN (EVENT_LEN_OFFSET+4)
|
||||
@ -66,6 +83,14 @@ static MYSQL* mysql = NULL;
|
||||
static const char* dirname_for_local_load= 0;
|
||||
static bool stop_passed= 0;
|
||||
|
||||
/*
|
||||
check_header() will set the pointer below.
|
||||
Why do we need here a pointer on an event instead of an event ?
|
||||
This is because the event will be created (alloced) in read_log_event()
|
||||
(which returns a pointer) in check_header().
|
||||
*/
|
||||
Format_description_log_event* description_event;
|
||||
|
||||
static int dump_local_log_entries(const char* logname);
|
||||
static int dump_remote_log_entries(const char* logname);
|
||||
static int dump_log_entries(const char* logname);
|
||||
@ -305,8 +330,8 @@ int Load_log_processor::process(Append_block_log_event *ae)
|
||||
|
||||
/*
|
||||
There is no Create_file event (a bad binlog or a big
|
||||
--position). Assuming it's a big --position, we just do nothing and
|
||||
print a warning.
|
||||
--start-position). Assuming it's a big --start-position, we just do
|
||||
nothing and print a warning.
|
||||
*/
|
||||
fprintf(stderr,"Warning: ignoring Append_block as there is no \
|
||||
Create_file event for file_id: %u\n",ae->file_id);
|
||||
@ -316,7 +341,13 @@ Create_file event for file_id: %u\n",ae->file_id);
|
||||
|
||||
Load_log_processor load_processor;
|
||||
|
||||
|
||||
/*
|
||||
Process an event
|
||||
|
||||
SYNOPSIS
|
||||
process_event()
|
||||
|
||||
RETURN
|
||||
0 ok and continue
|
||||
1 error and terminate
|
||||
@ -325,21 +356,34 @@ Load_log_processor load_processor;
|
||||
TODO
|
||||
This function returns 0 even in some error cases. This should be changed.
|
||||
*/
|
||||
int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
|
||||
|
||||
|
||||
|
||||
int process_event(LAST_EVENT_INFO *last_event_info, Log_event *ev,
|
||||
my_off_t pos)
|
||||
{
|
||||
char ll_buff[21];
|
||||
Log_event_type ev_type= ev->get_type_code();
|
||||
DBUG_ENTER("process_event");
|
||||
|
||||
/*
|
||||
Format events are not concerned by --offset and such, we always need to
|
||||
read them to be able to process the wanted events.
|
||||
*/
|
||||
if ((rec_count >= offset) &&
|
||||
((my_time_t)(ev->when) >= start_datetime))
|
||||
((my_time_t)(ev->when) >= start_datetime) ||
|
||||
(ev_type == FORMAT_DESCRIPTION_EVENT))
|
||||
{
|
||||
if (ev_type != FORMAT_DESCRIPTION_EVENT)
|
||||
{
|
||||
/*
|
||||
We have found an event after start_datetime, from now on print
|
||||
everything (in case the binlog has timestamps increasing and decreasing,
|
||||
we do this to avoid cutting the middle).
|
||||
everything (in case the binlog has timestamps increasing and
|
||||
decreasing, we do this to avoid cutting the middle).
|
||||
*/
|
||||
start_datetime= 0;
|
||||
offset= 0; // print everything and protect against cycling rec_count
|
||||
}
|
||||
if (((my_time_t)(ev->when) >= stop_datetime)
|
||||
|| (pos >= stop_position_mot))
|
||||
{
|
||||
@ -349,7 +393,7 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
|
||||
if (!short_form)
|
||||
fprintf(result_file, "# at %s\n",llstr(pos,ll_buff));
|
||||
|
||||
switch (ev->get_type_code()) {
|
||||
switch (ev_type) {
|
||||
case QUERY_EVENT:
|
||||
if (one_database)
|
||||
{
|
||||
@ -357,7 +401,7 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
|
||||
if ((log_dbname != NULL) && (strcmp(log_dbname, database)))
|
||||
goto end;
|
||||
}
|
||||
ev->print(result_file, short_form, last_db);
|
||||
ev->print(result_file, short_form, last_event_info);
|
||||
break;
|
||||
case CREATE_FILE_EVENT:
|
||||
{
|
||||
@ -381,8 +425,9 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
|
||||
filename and use LOCAL), prepared in the 'case EXEC_LOAD_EVENT'
|
||||
below.
|
||||
*/
|
||||
ce->print(result_file, short_form, last_db, TRUE);
|
||||
if (!old_format)
|
||||
ce->print(result_file, short_form, last_event_info, TRUE);
|
||||
// If this binlog is not 3.23 ; why this test??
|
||||
if (description_event->binlog_version >= 3)
|
||||
{
|
||||
if (load_processor.process(ce))
|
||||
break; // Error
|
||||
@ -391,23 +436,23 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
|
||||
break;
|
||||
}
|
||||
case APPEND_BLOCK_EVENT:
|
||||
ev->print(result_file, short_form, last_db);
|
||||
ev->print(result_file, short_form, last_event_info);
|
||||
if (load_processor.process((Append_block_log_event*) ev))
|
||||
break; // Error
|
||||
break;
|
||||
case EXEC_LOAD_EVENT:
|
||||
{
|
||||
ev->print(result_file, short_form, last_db);
|
||||
ev->print(result_file, short_form, last_event_info);
|
||||
Execute_load_log_event *exv= (Execute_load_log_event*)ev;
|
||||
Create_file_log_event *ce= load_processor.grab_event(exv->file_id);
|
||||
/*
|
||||
if ce is 0, it probably means that we have not seen the Create_file
|
||||
event (a bad binlog, or most probably --position is after the
|
||||
event (a bad binlog, or most probably --start-position is after the
|
||||
Create_file event). Print a warning comment.
|
||||
*/
|
||||
if (ce)
|
||||
{
|
||||
ce->print(result_file, short_form, last_db, TRUE);
|
||||
ce->print(result_file, short_form, last_event_info, TRUE);
|
||||
my_free((char*)ce->fname,MYF(MY_WME));
|
||||
delete ce;
|
||||
}
|
||||
@ -416,8 +461,20 @@ int process_event(char *last_db, Log_event *ev, my_off_t pos, int old_format)
|
||||
Create_file event for file_id: %u\n",exv->file_id);
|
||||
break;
|
||||
}
|
||||
case FORMAT_DESCRIPTION_EVENT:
|
||||
delete description_event;
|
||||
description_event= (Format_description_log_event*) ev;
|
||||
ev->print(result_file, short_form, last_event_info);
|
||||
/*
|
||||
We don't want this event to be deleted now, so let's hide it (I
|
||||
(Guilhem) should later see if this triggers a non-serious Valgrind
|
||||
error). Not serious error, because we will free description_event
|
||||
later.
|
||||
*/
|
||||
ev= 0;
|
||||
break;
|
||||
default:
|
||||
ev->print(result_file, short_form, last_db);
|
||||
ev->print(result_file, short_form, last_event_info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -558,7 +615,7 @@ static void die(const char* fmt, ...)
|
||||
|
||||
static void print_version()
|
||||
{
|
||||
printf("%s Ver 3.0 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
|
||||
printf("%s Ver 3.1 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
|
||||
NETWARE_SET_SCREEN_MODE(1);
|
||||
}
|
||||
|
||||
@ -701,12 +758,17 @@ static int dump_log_entries(const char* logname)
|
||||
}
|
||||
|
||||
|
||||
static int check_master_version(MYSQL* mysql)
|
||||
/*
|
||||
This is not as smart as check_header() (used for local log); it will not work
|
||||
for a binlog which mixes format. TODO: fix this.
|
||||
*/
|
||||
static int check_master_version(MYSQL* mysql,
|
||||
Format_description_log_event
|
||||
**description_event)
|
||||
{
|
||||
MYSQL_RES* res = 0;
|
||||
MYSQL_ROW row;
|
||||
const char* version;
|
||||
int old_format = 0;
|
||||
|
||||
if (mysql_query(mysql, "SELECT VERSION()") ||
|
||||
!(res = mysql_store_result(mysql)))
|
||||
@ -731,11 +793,18 @@ static int check_master_version(MYSQL* mysql)
|
||||
|
||||
switch (*version) {
|
||||
case '3':
|
||||
old_format = 1;
|
||||
*description_event= new Format_description_log_event(1);
|
||||
break;
|
||||
case '4':
|
||||
*description_event= new Format_description_log_event(3);
|
||||
case '5':
|
||||
old_format = 0;
|
||||
/*
|
||||
The server is soon going to send us its Format_description log
|
||||
event, unless it is a 5.0 server with 3.23 or 4.0 binlogs.
|
||||
So we first assume that this is 4.0 (which is enough to read the
|
||||
Format_desc event if one comes).
|
||||
*/
|
||||
*description_event= new Format_description_log_event(3);
|
||||
break;
|
||||
default:
|
||||
sql_print_error("Master reported unrecognized MySQL version '%s'",
|
||||
@ -745,18 +814,17 @@ static int check_master_version(MYSQL* mysql)
|
||||
return 1;
|
||||
}
|
||||
mysql_free_result(res);
|
||||
return old_format;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int dump_remote_log_entries(const char* logname)
|
||||
|
||||
{
|
||||
char buf[128];
|
||||
char last_db[FN_REFLEN+1] = "";
|
||||
ulong len;
|
||||
uint logname_len;
|
||||
LAST_EVENT_INFO last_event_info;
|
||||
uint len, logname_len;
|
||||
NET* net;
|
||||
int old_format;
|
||||
int error= 0;
|
||||
my_off_t old_off= start_position_mot;
|
||||
char fname[FN_REFLEN+1];
|
||||
@ -769,7 +837,18 @@ static int dump_remote_log_entries(const char* logname)
|
||||
*/
|
||||
mysql= safe_connect();
|
||||
net= &mysql->net;
|
||||
old_format = check_master_version(mysql);
|
||||
|
||||
if (check_master_version(mysql, &description_event))
|
||||
{
|
||||
fprintf(stderr, "Could not find server version");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (!description_event || !description_event->is_valid())
|
||||
{
|
||||
fprintf(stderr, "Invalid Format_description log event; \
|
||||
could be out of memory");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
COM_BINLOG_DUMP accepts only 4 bytes for the position, so we are forced to
|
||||
@ -798,6 +877,8 @@ static int dump_remote_log_entries(const char* logname)
|
||||
for (;;)
|
||||
{
|
||||
const char *error_msg;
|
||||
Log_event *ev;
|
||||
|
||||
len = net_safe_read(mysql);
|
||||
if (len == packet_error)
|
||||
{
|
||||
@ -810,9 +891,9 @@ static int dump_remote_log_entries(const char* logname)
|
||||
break; // end of data
|
||||
DBUG_PRINT("info",( "len= %u, net->read_pos[5] = %d\n",
|
||||
len, net->read_pos[5]));
|
||||
Log_event *ev = Log_event::read_log_event((const char*) net->read_pos + 1 ,
|
||||
len - 1, &error_msg, old_format);
|
||||
if (!ev)
|
||||
if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
|
||||
len - 1, &error_msg,
|
||||
description_event)))
|
||||
{
|
||||
fprintf(stderr, "Could not construct log event object\n");
|
||||
error= 1;
|
||||
@ -820,25 +901,27 @@ static int dump_remote_log_entries(const char* logname)
|
||||
}
|
||||
|
||||
Log_event_type type= ev->get_type_code();
|
||||
if (!old_format || ( type != LOAD_EVENT && type != CREATE_FILE_EVENT))
|
||||
if (description_event->binlog_version >= 3 ||
|
||||
(type != LOAD_EVENT && type != CREATE_FILE_EVENT))
|
||||
{
|
||||
if (ev->get_type_code() == ROTATE_EVENT)
|
||||
/*
|
||||
If this is a Rotate event, maybe it's the end of the requested binlog;
|
||||
in this case we are done (stop transfer).
|
||||
This is suitable for binlogs, not relay logs (but for now we don't read
|
||||
relay logs remotely because the server is not able to do that). If one
|
||||
day we read relay logs remotely, then we will have a problem with the
|
||||
detection below: relay logs contain Rotate events which are about the
|
||||
binlogs, so which would trigger the end-detection below.
|
||||
*/
|
||||
if (type == ROTATE_EVENT)
|
||||
{
|
||||
Rotate_log_event *rev= (Rotate_log_event *)ev;
|
||||
/*
|
||||
mysqld is sending us all its binlogs after the requested one, but we
|
||||
don't want them.
|
||||
If this is a fake Rotate event, and not about our log, we can stop
|
||||
transfer. If this a real Rotate event (so it's not about our log,
|
||||
it's in our log describing the next log), we print it (because it's
|
||||
part of our log) and then we will stop when we receive the fake one
|
||||
soon.
|
||||
This is suitable for binlogs, not relay logs (but for now we don't
|
||||
read relay logs remotely because the server is not able to do
|
||||
that). If one day we read relay logs remotely, then we will have a
|
||||
problem with the detection below: relay logs contain Rotate events
|
||||
which are about the binlogs, so which would trigger the end-detection
|
||||
below.
|
||||
*/
|
||||
if (rev->when == 0)
|
||||
{
|
||||
@ -861,7 +944,7 @@ static int dump_remote_log_entries(const char* logname)
|
||||
len= 1; // fake Rotate, so don't increment old_off
|
||||
}
|
||||
}
|
||||
if ((error= process_event(last_db,ev,old_off,old_format)))
|
||||
if ((error= process_event(&last_event_info,ev,old_off)))
|
||||
{
|
||||
error= ((error < 0) ? 0 : 1);
|
||||
goto err;
|
||||
@ -880,57 +963,128 @@ static int dump_remote_log_entries(const char* logname)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((error= process_event(last_db,ev,old_off,old_format)))
|
||||
if ((error= process_event(&last_event_info,ev,old_off)))
|
||||
{
|
||||
my_close(file,MYF(MY_WME));
|
||||
error= ((error < 0) ? 0 : 1);
|
||||
goto err;
|
||||
}
|
||||
if (load_processor.load_old_format_file(net,old_fname,old_len,file))
|
||||
{
|
||||
error= load_processor.load_old_format_file(net,old_fname,old_len,file);
|
||||
my_close(file,MYF(MY_WME));
|
||||
if (error)
|
||||
{
|
||||
error= 1;
|
||||
goto err;
|
||||
}
|
||||
my_close(file,MYF(MY_WME));
|
||||
}
|
||||
|
||||
/*
|
||||
Let's adjust offset for remote log as for local log to produce
|
||||
similar text.
|
||||
*/
|
||||
old_off+= len-1;
|
||||
}
|
||||
|
||||
err:
|
||||
mysql_close(mysql);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
static int check_header(IO_CACHE* file)
|
||||
static void check_header(IO_CACHE* file,
|
||||
Format_description_log_event **description_event)
|
||||
{
|
||||
byte header[BIN_LOG_HEADER_SIZE];
|
||||
byte buf[PROBE_HEADER_LEN];
|
||||
int old_format=0;
|
||||
DBUG_ENTER("check_header");
|
||||
my_off_t tmp_pos, pos;
|
||||
|
||||
my_off_t pos = my_b_tell(file);
|
||||
*description_event= new Format_description_log_event(3);
|
||||
pos= my_b_tell(file);
|
||||
my_b_seek(file, (my_off_t)0);
|
||||
if (my_b_read(file, header, sizeof(header)))
|
||||
die("Failed reading header; Probably an empty file");
|
||||
if (memcmp(header, BINLOG_MAGIC, sizeof(header)))
|
||||
die("File is not a binary log file");
|
||||
if (!my_b_read(file, buf, sizeof(buf)))
|
||||
|
||||
/*
|
||||
Imagine we are running with --start-position=1000. We still need
|
||||
to know the binlog format's. So we still need to find, if there is
|
||||
one, the Format_desc event, or to know if this is a 3.23
|
||||
binlog. So we need to first read the first events of the log,
|
||||
those around offset 4. Even if we are reading a 3.23 binlog from
|
||||
the start (no --start-position): we need to know the header length
|
||||
(which is 13 in 3.23, 19 in 4.x) to be able to successfully print
|
||||
the first event (Start_log_event_v3). So even in this case, we
|
||||
need to "probe" the first bytes of the log *before* we do a real
|
||||
read_log_event(). Because read_log_event() needs to know the
|
||||
header's length to work fine.
|
||||
*/
|
||||
for(;;)
|
||||
{
|
||||
if (buf[4] == START_EVENT)
|
||||
tmp_pos= my_b_tell(file); /* should be 4 the first time */
|
||||
if (my_b_read(file, buf, sizeof(buf)))
|
||||
{
|
||||
uint event_len;
|
||||
event_len = uint4korr(buf + EVENT_LEN_OFFSET);
|
||||
old_format = (event_len < (LOG_EVENT_HEADER_LEN + START_HEADER_LEN));
|
||||
if (file->error)
|
||||
die("\
|
||||
Could not read entry at offset %lu : Error in log format or read error",
|
||||
tmp_pos);
|
||||
/*
|
||||
Otherwise this is just EOF : this log currently contains 0-2
|
||||
events. Maybe it's going to be filled in the next
|
||||
milliseconds; then we are going to have a problem if this a
|
||||
3.23 log (imagine we are locally reading a 3.23 binlog which
|
||||
is being written presently): we won't know it in
|
||||
read_log_event() and will fail(). Similar problems could
|
||||
happen with hot relay logs if --start-position is used (but a
|
||||
--start-position which is posterior to the current size of the log).
|
||||
These are rare problems anyway (reading a hot log + when we
|
||||
read the first events there are not all there yet + when we
|
||||
read a bit later there are more events + using a strange
|
||||
--start-position).
|
||||
*/
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info",("buf[4]=%d", buf[4]));
|
||||
/* always test for a Start_v3, even if no --start-position */
|
||||
if (buf[4] == START_EVENT_V3) /* This is 3.23 or 4.x */
|
||||
{
|
||||
if (uint4korr(buf + EVENT_LEN_OFFSET) <
|
||||
(LOG_EVENT_MINIMAL_HEADER_LEN + START_V3_HEADER_LEN))
|
||||
{
|
||||
/* This is 3.23 (format 1) */
|
||||
delete *description_event;
|
||||
*description_event= new Format_description_log_event(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (tmp_pos >= start_position)
|
||||
break;
|
||||
else if (buf[4] == FORMAT_DESCRIPTION_EVENT) /* This is 5.0 */
|
||||
{
|
||||
my_b_seek(file, tmp_pos); /* seek back to event's start */
|
||||
if (!(*description_event= (Format_description_log_event*)
|
||||
Log_event::read_log_event(file, *description_event)))
|
||||
/* EOF can't be hit here normally, so it's a real error */
|
||||
die("Could not read a Format_description_log_event event \
|
||||
at offset %lu ; this could be a log format error or read error",
|
||||
tmp_pos);
|
||||
DBUG_PRINT("info",("Setting description_event"));
|
||||
}
|
||||
else if (buf[4] == ROTATE_EVENT)
|
||||
{
|
||||
my_b_seek(file, tmp_pos); /* seek back to event's start */
|
||||
if (!Log_event::read_log_event(file, *description_event))
|
||||
/* EOF can't be hit here normally, so it's a real error */
|
||||
die("Could not read a Rotate_log_event event \
|
||||
at offset %lu ; this could be a log format error or read error",
|
||||
tmp_pos);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
my_b_seek(file, pos);
|
||||
DBUG_RETURN(old_format);
|
||||
}
|
||||
|
||||
|
||||
@ -938,13 +1092,10 @@ static int dump_local_log_entries(const char* logname)
|
||||
{
|
||||
File fd = -1;
|
||||
IO_CACHE cache,*file= &cache;
|
||||
char last_db[FN_REFLEN+1];
|
||||
LAST_EVENT_INFO last_event_info;
|
||||
byte tmp_buff[BIN_LOG_HEADER_SIZE];
|
||||
bool old_format = 0;
|
||||
int error= 0;
|
||||
|
||||
last_db[0]= 0;
|
||||
|
||||
if (logname && logname[0] != '-')
|
||||
{
|
||||
if ((fd = my_open(logname, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
|
||||
@ -953,16 +1104,16 @@ static int dump_local_log_entries(const char* logname)
|
||||
MYF(MY_WME | MY_NABP)))
|
||||
{
|
||||
my_close(fd, MYF(MY_WME));
|
||||
exit(1);
|
||||
return 1;
|
||||
}
|
||||
old_format = check_header(file);
|
||||
check_header(file, &description_event);
|
||||
}
|
||||
else
|
||||
else // reading from stdin; TODO: check that it works
|
||||
{
|
||||
if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
|
||||
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
|
||||
return 1;
|
||||
old_format = check_header(file);
|
||||
check_header(file, &description_event);
|
||||
if (start_position)
|
||||
{
|
||||
/* skip 'start_position' characters from stdout */
|
||||
@ -982,22 +1133,20 @@ static int dump_local_log_entries(const char* logname)
|
||||
file->seek_not_done=0;
|
||||
}
|
||||
|
||||
if (!start_position)
|
||||
{
|
||||
// Skip header
|
||||
if (my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
|
||||
if (!description_event || !description_event->is_valid())
|
||||
die("Invalid Format_description log event; could be out of memory");
|
||||
|
||||
if (!start_position && my_b_read(file, tmp_buff, BIN_LOG_HEADER_SIZE))
|
||||
{
|
||||
error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char llbuff[21];
|
||||
my_off_t old_off = my_b_tell(file);
|
||||
|
||||
Log_event* ev = Log_event::read_log_event(file, old_format);
|
||||
Log_event* ev = Log_event::read_log_event(file, description_event);
|
||||
if (!ev)
|
||||
{
|
||||
if (file->error)
|
||||
@ -1011,7 +1160,7 @@ static int dump_local_log_entries(const char* logname)
|
||||
// file->error == 0 means EOF, that's OK, we break in this case
|
||||
break;
|
||||
}
|
||||
if ((error= process_event(last_db,ev,old_off,false)))
|
||||
if ((error= process_event(&last_event_info,ev,old_off)))
|
||||
{
|
||||
if (error < 0)
|
||||
error= 0;
|
||||
@ -1023,6 +1172,7 @@ end:
|
||||
if (fd >= 0)
|
||||
my_close(fd, MYF(MY_WME));
|
||||
end_io_cache(file);
|
||||
delete description_event;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,8 @@ static uint opt_protocol= 0;
|
||||
static char *default_charset= (char*) MYSQL_UNIVERSAL_CLIENT_CHARSET;
|
||||
static CHARSET_INFO *charset_info= &my_charset_latin1;
|
||||
const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
|
||||
/* do we met VIEWs during tables scaning */
|
||||
my_bool was_views= 0;
|
||||
|
||||
const char *compatible_mode_names[]=
|
||||
{
|
||||
@ -367,6 +369,8 @@ static int dump_databases(char **);
|
||||
static int dump_all_databases();
|
||||
static char *quote_name(const char *name, char *buff, my_bool force);
|
||||
static const char *check_if_ignore_table(const char *table_name);
|
||||
static my_bool getViewStructure(char *table, char* db);
|
||||
static my_bool dump_all_views_in_db(char *database);
|
||||
|
||||
#include <help_start.h>
|
||||
|
||||
@ -1035,6 +1039,7 @@ static uint getTableStructure(char *table, char* db)
|
||||
{
|
||||
/* Make an sql-file, if path was given iow. option -T was given */
|
||||
char buff[20+FN_REFLEN];
|
||||
MYSQL_FIELD *field;
|
||||
|
||||
sprintf(buff,"show create table %s", result_table);
|
||||
if (mysql_query_with_error_report(sock, 0, buff))
|
||||
@ -1068,8 +1073,16 @@ static uint getTableStructure(char *table, char* db)
|
||||
check_io(sql_file);
|
||||
}
|
||||
|
||||
tableRes=mysql_store_result(sock);
|
||||
row=mysql_fetch_row(tableRes);
|
||||
tableRes= mysql_store_result(sock);
|
||||
field= mysql_fetch_field_direct(tableRes, 0);
|
||||
if (strcmp(field->name, "View") == 0)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf(stderr, "-- It's a view, skipped\n");
|
||||
was_views= 1;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
row= mysql_fetch_row(tableRes);
|
||||
fprintf(sql_file, "%s;\n", row[1]);
|
||||
check_io(sql_file);
|
||||
mysql_free_result(tableRes);
|
||||
@ -1213,6 +1226,14 @@ static uint getTableStructure(char *table, char* db)
|
||||
sprintf(buff,"show keys from %s", result_table);
|
||||
if (mysql_query_with_error_report(sock, &tableRes, buff))
|
||||
{
|
||||
if (mysql_errno(sock) == ER_WRONG_OBJECT)
|
||||
{
|
||||
/* it is VIEW */
|
||||
fputs("\t\t<options Comment=\"view\" />\n", sql_file);
|
||||
goto continue_xml;
|
||||
}
|
||||
fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
|
||||
my_progname, result_table, mysql_error(sock));
|
||||
if (path)
|
||||
my_fclose(sql_file, MYF(MY_WME));
|
||||
safe_exit(EX_MYSQLERR);
|
||||
@ -1316,6 +1337,7 @@ static uint getTableStructure(char *table, char* db)
|
||||
}
|
||||
mysql_free_result(tableRes); /* Is always safe to free */
|
||||
}
|
||||
continue_xml:
|
||||
if (!opt_xml)
|
||||
fputs(";\n", sql_file);
|
||||
else
|
||||
@ -1845,6 +1867,21 @@ static int dump_all_databases()
|
||||
if (dump_all_tables_in_db(row[0]))
|
||||
result=1;
|
||||
}
|
||||
if (was_views)
|
||||
{
|
||||
if (mysql_query(sock, "SHOW DATABASES") ||
|
||||
!(tableres = mysql_store_result(sock)))
|
||||
{
|
||||
my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
|
||||
MYF(0), mysql_error(sock));
|
||||
return 1;
|
||||
}
|
||||
while ((row = mysql_fetch_row(tableres)))
|
||||
{
|
||||
if (dump_all_views_in_db(row[0]))
|
||||
result=1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/* dump_all_databases */
|
||||
@ -1853,11 +1890,20 @@ static int dump_all_databases()
|
||||
static int dump_databases(char **db_names)
|
||||
{
|
||||
int result=0;
|
||||
for ( ; *db_names ; db_names++)
|
||||
char **db;
|
||||
for (db= db_names ; *db ; db++)
|
||||
{
|
||||
if (dump_all_tables_in_db(*db_names))
|
||||
if (dump_all_tables_in_db(*db))
|
||||
result=1;
|
||||
}
|
||||
if (!result && was_views)
|
||||
{
|
||||
for (db= db_names ; *db ; db++)
|
||||
{
|
||||
if (dump_all_views_in_db(*db))
|
||||
result=1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} /* dump_databases */
|
||||
|
||||
@ -1965,11 +2011,64 @@ static int dump_all_tables_in_db(char *database)
|
||||
return 0;
|
||||
} /* dump_all_tables_in_db */
|
||||
|
||||
/*
|
||||
dump structure of views of database
|
||||
|
||||
SYNOPSIS
|
||||
dump_all_views_in_db()
|
||||
database database name
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 ERROR
|
||||
*/
|
||||
|
||||
static my_bool dump_all_views_in_db(char *database)
|
||||
{
|
||||
char *table;
|
||||
uint numrows;
|
||||
char table_buff[NAME_LEN*2+3];
|
||||
|
||||
if (init_dumping(database))
|
||||
return 1;
|
||||
if (opt_xml)
|
||||
print_xml_tag1(md_result_file, "", "database name=", database, "\n");
|
||||
if (lock_tables)
|
||||
{
|
||||
DYNAMIC_STRING query;
|
||||
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
|
||||
for (numrows= 0 ; (table= getTableName(1)); numrows++)
|
||||
{
|
||||
dynstr_append(&query, quote_name(table, table_buff, 1));
|
||||
dynstr_append(&query, " READ /*!32311 LOCAL */,");
|
||||
}
|
||||
if (numrows && mysql_real_query(sock, query.str, query.length-1))
|
||||
DBerror(sock, "when using LOCK TABLES");
|
||||
/* We shall continue here, if --force was given */
|
||||
dynstr_free(&query);
|
||||
}
|
||||
if (flush_logs)
|
||||
{
|
||||
if (mysql_refresh(sock, REFRESH_LOG))
|
||||
DBerror(sock, "when doing refresh");
|
||||
/* We shall continue here, if --force was given */
|
||||
}
|
||||
while ((table= getTableName(0)))
|
||||
getViewStructure(table, database);
|
||||
if (opt_xml)
|
||||
{
|
||||
fputs("</database>\n", md_result_file);
|
||||
check_io(md_result_file);
|
||||
}
|
||||
if (lock_tables)
|
||||
mysql_query(sock,"UNLOCK TABLES");
|
||||
return 0;
|
||||
} /* dump_all_tables_in_db */
|
||||
|
||||
static int dump_selected_tables(char *db, char **table_names, int tables)
|
||||
{
|
||||
uint numrows;
|
||||
int i;
|
||||
char table_buff[NAME_LEN*+3];
|
||||
|
||||
if (init_dumping(db))
|
||||
@ -1977,7 +2076,6 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
|
||||
if (lock_tables)
|
||||
{
|
||||
DYNAMIC_STRING query;
|
||||
int i;
|
||||
|
||||
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
|
||||
for (i=0 ; i < tables ; i++)
|
||||
@ -1998,11 +2096,16 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
|
||||
}
|
||||
if (opt_xml)
|
||||
print_xml_tag1(md_result_file, "", "database name=", db, "\n");
|
||||
for (; tables > 0 ; tables-- , table_names++)
|
||||
for (i=0 ; i < tables ; i++)
|
||||
{
|
||||
numrows = getTableStructure(*table_names, db);
|
||||
numrows = getTableStructure(table_names[i], db);
|
||||
if (!dFlag && numrows > 0)
|
||||
dumpTable(numrows, *table_names);
|
||||
dumpTable(numrows, table_names[i]);
|
||||
}
|
||||
if (was_views)
|
||||
{
|
||||
for (i=0 ; i < tables ; i++)
|
||||
getViewStructure(table_names[i], db);
|
||||
}
|
||||
if (opt_xml)
|
||||
{
|
||||
@ -2197,14 +2300,113 @@ static const char *check_if_ignore_table(const char *table_name)
|
||||
mysql_free_result(res);
|
||||
return 0; /* assume table is ok */
|
||||
}
|
||||
if (!(row[1]))
|
||||
result= "VIEW";
|
||||
else
|
||||
{
|
||||
if (strcmp(row[1], (result= "MRG_MyISAM")) &&
|
||||
strcmp(row[1], (result= "MRG_ISAM")))
|
||||
result= 0;
|
||||
}
|
||||
mysql_free_result(res);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Getting VIEW structure
|
||||
|
||||
SYNOPSIS
|
||||
getViewStructure()
|
||||
table view name
|
||||
db db name
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
1 ERROR
|
||||
*/
|
||||
|
||||
static my_bool getViewStructure(char *table, char* db)
|
||||
{
|
||||
MYSQL_RES *tableRes;
|
||||
MYSQL_ROW row;
|
||||
MYSQL_FIELD *field;
|
||||
char *result_table, *opt_quoted_table;
|
||||
char table_buff[NAME_LEN*2+3];
|
||||
char table_buff2[NAME_LEN*2+3];
|
||||
char buff[20+FN_REFLEN];
|
||||
FILE *sql_file = md_result_file;
|
||||
DBUG_ENTER("getViewStructure");
|
||||
|
||||
if (tFlag)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
if (verbose)
|
||||
fprintf(stderr, "-- Retrieving view structure for table %s...\n", table);
|
||||
|
||||
sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d",
|
||||
(opt_quoted || opt_keywords));
|
||||
result_table= quote_name(table, table_buff, 1);
|
||||
opt_quoted_table= quote_name(table, table_buff2, 0);
|
||||
|
||||
sprintf(buff,"show create table %s", result_table);
|
||||
if (mysql_query(sock, buff))
|
||||
{
|
||||
fprintf(stderr, "%s: Can't get CREATE TABLE for view %s (%s)\n",
|
||||
my_progname, result_table, mysql_error(sock));
|
||||
safe_exit(EX_MYSQLERR);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (path)
|
||||
{
|
||||
char filename[FN_REFLEN], tmp_path[FN_REFLEN];
|
||||
convert_dirname(tmp_path,path,NullS);
|
||||
sql_file= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
|
||||
O_WRONLY, MYF(MY_WME));
|
||||
if (!sql_file) /* If file couldn't be opened */
|
||||
{
|
||||
safe_exit(EX_MYSQLERR);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
write_header(sql_file, db);
|
||||
}
|
||||
tableRes= mysql_store_result(sock);
|
||||
field= mysql_fetch_field_direct(tableRes, 0);
|
||||
if (strcmp(field->name, "View") != 0)
|
||||
{
|
||||
if (verbose)
|
||||
fprintf(stderr, "-- It's base table, skipped\n");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (!opt_xml && opt_comments)
|
||||
{
|
||||
fprintf(sql_file, "\n--\n-- View structure for view %s\n--\n\n",
|
||||
result_table);
|
||||
check_io(sql_file);
|
||||
}
|
||||
if (opt_drop)
|
||||
{
|
||||
fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table);
|
||||
check_io(sql_file);
|
||||
}
|
||||
|
||||
row= mysql_fetch_row(tableRes);
|
||||
fprintf(sql_file, "%s;\n", row[1]);
|
||||
check_io(sql_file);
|
||||
mysql_free_result(tableRes);
|
||||
|
||||
if (sql_file != md_result_file)
|
||||
{
|
||||
fputs("\n", sql_file);
|
||||
write_footer(sql_file);
|
||||
my_fclose(sql_file, MYF(MY_WME));
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
compatible_mode_normal_str[0]= 0;
|
||||
|
195
sql/handler.cc
195
sql/handler.cc
@ -54,11 +54,7 @@
|
||||
|
||||
static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
|
||||
|
||||
ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
|
||||
ha_read_key_count, ha_read_next_count, ha_read_prev_count,
|
||||
ha_read_first_count, ha_read_last_count,
|
||||
ha_commit_count, ha_rollback_count,
|
||||
ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count;
|
||||
ulong ha_read_count, ha_discover_count;
|
||||
|
||||
static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
|
||||
|
||||
@ -114,7 +110,7 @@ uint known_extensions_id= 0;
|
||||
|
||||
enum db_type ha_resolve_by_name(const char *name, uint namelen)
|
||||
{
|
||||
THD *thd=current_thd;
|
||||
THD *thd= current_thd;
|
||||
if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) {
|
||||
return (enum db_type) thd->variables.table_type;
|
||||
}
|
||||
@ -145,6 +141,7 @@ const char *ha_get_storage_engine(enum db_type db_type)
|
||||
enum db_type ha_checktype(enum db_type database_type)
|
||||
{
|
||||
show_table_type_st *types;
|
||||
THD *thd= current_thd;
|
||||
for (types= sys_table_types; types->type; types++)
|
||||
{
|
||||
if ((database_type == types->db_type) &&
|
||||
@ -163,12 +160,11 @@ enum db_type ha_checktype(enum db_type database_type)
|
||||
break;
|
||||
}
|
||||
|
||||
return
|
||||
DB_TYPE_UNKNOWN != (enum db_type) current_thd->variables.table_type ?
|
||||
(enum db_type) current_thd->variables.table_type :
|
||||
DB_TYPE_UNKNOWN != (enum db_type) global_system_variables.table_type ?
|
||||
(enum db_type) global_system_variables.table_type :
|
||||
DB_TYPE_MYISAM;
|
||||
return ((enum db_type) thd->variables.table_type != DB_TYPE_UNKNOWN ?
|
||||
(enum db_type) thd->variables.table_type :
|
||||
(enum db_type) global_system_variables.table_type !=
|
||||
DB_TYPE_UNKNOWN ?
|
||||
(enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM);
|
||||
} /* ha_checktype */
|
||||
|
||||
|
||||
@ -565,7 +561,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
|
||||
thd->variables.tx_isolation=thd->session_tx_isolation;
|
||||
if (operation_done)
|
||||
{
|
||||
statistic_increment(ha_commit_count,&LOCK_status);
|
||||
statistic_increment(thd->status_var.ha_commit_count,&LOCK_status);
|
||||
thd->transaction.cleanup();
|
||||
}
|
||||
if (need_start_waiters)
|
||||
@ -734,7 +730,7 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
|
||||
operation_done=1;
|
||||
#endif
|
||||
if (operation_done)
|
||||
statistic_increment(ha_rollback_count,&LOCK_status);
|
||||
statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
|
||||
}
|
||||
#endif /* USING_TRANSACTIONS */
|
||||
|
||||
@ -816,10 +812,14 @@ bool ha_flush_logs()
|
||||
|
||||
int ha_delete_table(enum db_type table_type, const char *path)
|
||||
{
|
||||
handler *file;
|
||||
char tmp_path[FN_REFLEN];
|
||||
handler *file=get_new_handler((TABLE*) 0, table_type);
|
||||
if (!file)
|
||||
|
||||
/* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
|
||||
if (table_type == DB_TYPE_UNKNOWN ||
|
||||
! (file=get_new_handler((TABLE*) 0, table_type)))
|
||||
return ENOENT;
|
||||
|
||||
if (lower_case_table_names == 2 && !(file->table_flags() & HA_FILE_BASED))
|
||||
{
|
||||
/* Ensure that table handler get path in lower case */
|
||||
@ -948,7 +948,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
|
||||
register int error;
|
||||
DBUG_ENTER("handler::read_first_row");
|
||||
|
||||
statistic_increment(ha_read_first_count,&LOCK_status);
|
||||
statistic_increment(current_thd->status_var.ha_read_first_count,&LOCK_status);
|
||||
|
||||
/*
|
||||
If there is very few deleted rows in the table, find the first row by
|
||||
@ -972,41 +972,163 @@ int handler::read_first_row(byte * buf, uint primary_key)
|
||||
|
||||
|
||||
/*
|
||||
Updates field with field_type NEXT_NUMBER according to following:
|
||||
if field = 0 change field to the next free key in database.
|
||||
Generate the next auto-increment number based on increment and offset
|
||||
|
||||
In most cases increment= offset= 1, in which case we get:
|
||||
1,2,3,4,5,...
|
||||
If increment=10 and offset=5 and previous number is 1, we get:
|
||||
1,5,15,25,35,...
|
||||
*/
|
||||
|
||||
inline ulonglong
|
||||
next_insert_id(ulonglong nr,struct system_variables *variables)
|
||||
{
|
||||
nr= (((nr+ variables->auto_increment_increment -
|
||||
variables->auto_increment_offset)) /
|
||||
(ulonglong) variables->auto_increment_increment);
|
||||
return (nr* (ulonglong) variables->auto_increment_increment +
|
||||
variables->auto_increment_offset);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Updates columns with type NEXT_NUMBER if:
|
||||
|
||||
- If column value is set to NULL (in which case
|
||||
auto_increment_field_not_null is 0)
|
||||
- If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not
|
||||
set. In the future we will only set NEXT_NUMBER fields if one sets them
|
||||
to NULL (or they are not included in the insert list).
|
||||
|
||||
|
||||
There are two different cases when the above is true:
|
||||
|
||||
- thd->next_insert_id == 0 (This is the normal case)
|
||||
In this case we set the set the column for the first row to the value
|
||||
next_insert_id(get_auto_increment(column))) which is normally
|
||||
max-used-column-value +1.
|
||||
|
||||
We call get_auto_increment() only for the first row in a multi-row
|
||||
statement. For the following rows we generate new numbers based on the
|
||||
last used number.
|
||||
|
||||
- thd->next_insert_id != 0. This happens when we have read a statement
|
||||
from the binary log or when one has used SET LAST_INSERT_ID=#.
|
||||
|
||||
In this case we will set the column to the value of next_insert_id.
|
||||
The next row will be given the id
|
||||
next_insert_id(next_insert_id)
|
||||
|
||||
The idea is that generated auto_increment values are predictable and
|
||||
independent of the column values in the table. This is needed to be
|
||||
able to replicate into a table that already has rows with a higher
|
||||
auto-increment value than the one that is inserted.
|
||||
|
||||
After we have already generated an auto-increment number and the user
|
||||
inserts a column with a higher value than the last used one, we will
|
||||
start counting from the inserted value.
|
||||
|
||||
thd->next_insert_id is cleared after it's been used for a statement.
|
||||
*/
|
||||
|
||||
void handler::update_auto_increment()
|
||||
{
|
||||
longlong nr;
|
||||
THD *thd;
|
||||
ulonglong nr;
|
||||
THD *thd= table->in_use;
|
||||
struct system_variables *variables= &thd->variables;
|
||||
DBUG_ENTER("handler::update_auto_increment");
|
||||
if (table->next_number_field->val_int() != 0 ||
|
||||
|
||||
/*
|
||||
We must save the previous value to be able to restore it if the
|
||||
row was not inserted
|
||||
*/
|
||||
thd->prev_insert_id= thd->next_insert_id;
|
||||
|
||||
if ((nr= table->next_number_field->val_int()) != 0 ||
|
||||
table->auto_increment_field_not_null &&
|
||||
current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
|
||||
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
|
||||
{
|
||||
/* Clear flag for next row */
|
||||
table->auto_increment_field_not_null= FALSE;
|
||||
/* Mark that we didn't generate a new value **/
|
||||
auto_increment_column_changed=0;
|
||||
|
||||
/* Update next_insert_id if we have already generated a value */
|
||||
if (thd->clear_next_insert_id && nr >= thd->next_insert_id)
|
||||
{
|
||||
if (variables->auto_increment_increment != 1)
|
||||
nr= next_insert_id(nr, variables);
|
||||
else
|
||||
nr++;
|
||||
thd->next_insert_id= nr;
|
||||
DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
table->auto_increment_field_not_null= FALSE;
|
||||
thd=current_thd;
|
||||
if ((nr=thd->next_insert_id))
|
||||
thd->next_insert_id=0; // Clear after use
|
||||
else
|
||||
nr=get_auto_increment();
|
||||
if (!table->next_number_field->store(nr))
|
||||
if (!(nr= thd->next_insert_id))
|
||||
{
|
||||
nr= get_auto_increment();
|
||||
if (variables->auto_increment_increment != 1)
|
||||
nr= next_insert_id(nr-1, variables);
|
||||
/*
|
||||
Update next row based on the found value. This way we don't have to
|
||||
call the handler for every generated auto-increment value on a
|
||||
multi-row statement
|
||||
*/
|
||||
thd->next_insert_id= nr;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr));
|
||||
|
||||
/* Mark that we should clear next_insert_id before next stmt */
|
||||
thd->clear_next_insert_id= 1;
|
||||
|
||||
if (!table->next_number_field->store((longlong) nr))
|
||||
thd->insert_id((ulonglong) nr);
|
||||
else
|
||||
thd->insert_id(table->next_number_field->val_int());
|
||||
|
||||
/*
|
||||
We can't set next_insert_id if the auto-increment key is not the
|
||||
first key part, as there is no guarantee that the first parts will be in
|
||||
sequence
|
||||
*/
|
||||
if (!table->next_number_key_offset)
|
||||
{
|
||||
/*
|
||||
Set next insert id to point to next auto-increment value to be able to
|
||||
handle multi-row statements
|
||||
This works even if auto_increment_increment > 1
|
||||
*/
|
||||
thd->next_insert_id= next_insert_id(nr, variables);
|
||||
}
|
||||
else
|
||||
thd->next_insert_id= 0;
|
||||
|
||||
/* Mark that we generated a new value */
|
||||
auto_increment_column_changed=1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
restore_auto_increment
|
||||
|
||||
longlong handler::get_auto_increment()
|
||||
In case of error on write, we restore the last used next_insert_id value
|
||||
because the previous value was not used.
|
||||
*/
|
||||
|
||||
void handler::restore_auto_increment()
|
||||
{
|
||||
longlong nr;
|
||||
THD *thd= table->in_use;
|
||||
if (thd->next_insert_id)
|
||||
thd->next_insert_id= thd->prev_insert_id;
|
||||
}
|
||||
|
||||
|
||||
ulonglong handler::get_auto_increment()
|
||||
{
|
||||
ulonglong nr;
|
||||
int error;
|
||||
|
||||
(void) extra(HA_EXTRA_KEYREAD);
|
||||
@ -1018,7 +1140,8 @@ longlong handler::get_auto_increment()
|
||||
else
|
||||
{
|
||||
byte key[MAX_KEY_LENGTH];
|
||||
key_copy(key,table,table->next_number_index,
|
||||
key_copy(key, table->record[0],
|
||||
table->key_info + table->next_number_index,
|
||||
table->next_number_key_offset);
|
||||
error=index_read(table->record[1], key, table->next_number_key_offset,
|
||||
HA_READ_PREFIX_LAST);
|
||||
@ -1027,8 +1150,8 @@ longlong handler::get_auto_increment()
|
||||
if (error)
|
||||
nr=1;
|
||||
else
|
||||
nr=(longlong) table->next_number_field->
|
||||
val_int_offset(table->rec_buff_length)+1;
|
||||
nr=((ulonglong) table->next_number_field->
|
||||
val_int_offset(table->rec_buff_length)+1);
|
||||
index_end();
|
||||
(void) extra(HA_EXTRA_NO_KEYREAD);
|
||||
return nr;
|
||||
@ -1271,7 +1394,7 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
|
||||
char name_buff[FN_REFLEN];
|
||||
DBUG_ENTER("ha_create_table");
|
||||
|
||||
if (openfrm(name,"",0,(uint) READ_ALL, 0, &table))
|
||||
if (openfrm(current_thd, name,"",0,(uint) READ_ALL, 0, &table))
|
||||
DBUG_RETURN(1);
|
||||
if (update_create_info)
|
||||
{
|
||||
@ -1336,7 +1459,7 @@ int ha_create_table_from_engine(THD* thd,
|
||||
if ((error = writefrm(path, frmblob, frmlen)))
|
||||
goto err_end;
|
||||
|
||||
if (openfrm(path,"",0,(uint) READ_ALL, 0, &table))
|
||||
if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
update_create_info_from_table(&create_info, &table);
|
||||
|
71
sql/lex.h
71
sql/lex.h
@ -65,6 +65,7 @@ static SYMBOL symbols[] = {
|
||||
{ "AGAINST", SYM(AGAINST)},
|
||||
{ "AGGREGATE", SYM(AGGREGATE_SYM)},
|
||||
{ "ALL", SYM(ALL)},
|
||||
{ "ALGORITHM", SYM(ALGORITHM_SYM)},
|
||||
{ "ALTER", SYM(ALTER)},
|
||||
{ "ANALYZE", SYM(ANALYZE_SYM)},
|
||||
{ "AND", SYM(AND_SYM)},
|
||||
@ -72,6 +73,7 @@ static SYMBOL symbols[] = {
|
||||
{ "AS", SYM(AS)},
|
||||
{ "ASC", SYM(ASC)},
|
||||
{ "ASCII", SYM(ASCII_SYM)},
|
||||
{ "ASENSITIVE", SYM(ASENSITIVE_SYM)},
|
||||
{ "AUTO_INCREMENT", SYM(AUTO_INC)},
|
||||
{ "AVG", SYM(AVG_SYM)},
|
||||
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH)},
|
||||
@ -93,7 +95,9 @@ static SYMBOL symbols[] = {
|
||||
{ "BY", SYM(BY)},
|
||||
{ "BYTE", SYM(BYTE_SYM)},
|
||||
{ "CACHE", SYM(CACHE_SYM)},
|
||||
{ "CALL", SYM(CALL_SYM)},
|
||||
{ "CASCADE", SYM(CASCADE)},
|
||||
{ "CASCADED", SYM(CASCADED)},
|
||||
{ "CASE", SYM(CASE_SYM)},
|
||||
{ "CHANGE", SYM(CHANGE)},
|
||||
{ "CHANGED", SYM(CHANGED)},
|
||||
@ -114,8 +118,12 @@ static SYMBOL symbols[] = {
|
||||
{ "COMMITTED", SYM(COMMITTED_SYM)},
|
||||
{ "COMPRESSED", SYM(COMPRESSED_SYM)},
|
||||
{ "CONCURRENT", SYM(CONCURRENT)},
|
||||
{ "CONDITION", SYM(CONDITION_SYM)},
|
||||
{ "CONNECTION", SYM(CONNECTION_SYM)},
|
||||
{ "CONSISTENT", SYM(CONSISTENT_SYM)},
|
||||
{ "CONSTRAINT", SYM(CONSTRAINT)},
|
||||
{ "CONTAINS", SYM(CONTAINS_SYM)},
|
||||
{ "CONTINUE", SYM(CONTINUE_SYM)},
|
||||
{ "CONVERT", SYM(CONVERT_SYM)},
|
||||
{ "CREATE", SYM(CREATE)},
|
||||
{ "CROSS", SYM(CROSS)},
|
||||
@ -124,6 +132,7 @@ static SYMBOL symbols[] = {
|
||||
{ "CURRENT_TIME", SYM(CURTIME)},
|
||||
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM)},
|
||||
{ "CURRENT_USER", SYM(CURRENT_USER)},
|
||||
{ "CURSOR", SYM(CURSOR_SYM)},
|
||||
{ "DATA", SYM(DATA_SYM)},
|
||||
{ "DATABASE", SYM(DATABASE)},
|
||||
{ "DATABASES", SYM(DATABASES)},
|
||||
@ -137,13 +146,16 @@ static SYMBOL symbols[] = {
|
||||
{ "DEALLOCATE", SYM(DEALLOCATE_SYM)},
|
||||
{ "DEC", SYM(DECIMAL_SYM)},
|
||||
{ "DECIMAL", SYM(DECIMAL_SYM)},
|
||||
{ "DECLARE", SYM(DECLARE_SYM)},
|
||||
{ "DEFAULT", SYM(DEFAULT)},
|
||||
{ "DEFINER", SYM(DEFINER_SYM)},
|
||||
{ "DELAYED", SYM(DELAYED_SYM)},
|
||||
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM)},
|
||||
{ "DELETE", SYM(DELETE_SYM)},
|
||||
{ "DESC", SYM(DESC)},
|
||||
{ "DESCRIBE", SYM(DESCRIBE)},
|
||||
{ "DES_KEY_FILE", SYM(DES_KEY_FILE)},
|
||||
{ "DETERMINISTIC", SYM(DETERMINISTIC_SYM)},
|
||||
{ "DIRECTORY", SYM(DIRECTORY_SYM)},
|
||||
{ "DISABLE", SYM(DISABLE_SYM)},
|
||||
{ "DISCARD", SYM(DISCARD)},
|
||||
@ -157,7 +169,9 @@ static SYMBOL symbols[] = {
|
||||
{ "DUMPFILE", SYM(DUMPFILE)},
|
||||
{ "DUPLICATE", SYM(DUPLICATE_SYM)},
|
||||
{ "DYNAMIC", SYM(DYNAMIC_SYM)},
|
||||
{ "EACH", SYM(EACH_SYM)},
|
||||
{ "ELSE", SYM(ELSE)},
|
||||
{ "ELSEIF", SYM(ELSEIF_SYM)},
|
||||
{ "ENABLE", SYM(ENABLE_SYM)},
|
||||
{ "ENCLOSED", SYM(ENCLOSED)},
|
||||
{ "END", SYM(END)},
|
||||
@ -170,11 +184,13 @@ static SYMBOL symbols[] = {
|
||||
{ "EVENTS", SYM(EVENTS_SYM)},
|
||||
{ "EXECUTE", SYM(EXECUTE_SYM)},
|
||||
{ "EXISTS", SYM(EXISTS)},
|
||||
{ "EXIT", SYM(EXIT_SYM)},
|
||||
{ "EXPANSION", SYM(EXPANSION_SYM)},
|
||||
{ "EXPLAIN", SYM(DESCRIBE)},
|
||||
{ "EXTENDED", SYM(EXTENDED_SYM)},
|
||||
{ "FALSE", SYM(FALSE_SYM)},
|
||||
{ "FAST", SYM(FAST_SYM)},
|
||||
{ "FETCH", SYM(FETCH_SYM)},
|
||||
{ "FIELDS", SYM(COLUMNS)},
|
||||
{ "FILE", SYM(FILE_SYM)},
|
||||
{ "FIRST", SYM(FIRST_SYM)},
|
||||
@ -186,14 +202,17 @@ static SYMBOL symbols[] = {
|
||||
{ "FOR", SYM(FOR_SYM)},
|
||||
{ "FORCE", SYM(FORCE_SYM)},
|
||||
{ "FOREIGN", SYM(FOREIGN)},
|
||||
{ "FOUND", SYM(FOUND_SYM)},
|
||||
{ "FRAC_SECOND", SYM(FRAC_SECOND_SYM)},
|
||||
{ "FROM", SYM(FROM)},
|
||||
{ "FULL", SYM(FULL)},
|
||||
{ "FULLTEXT", SYM(FULLTEXT_SYM)},
|
||||
{ "FUNCTION", SYM(UDF_SYM)},
|
||||
{ "FUNCTION", SYM(FUNCTION_SYM)},
|
||||
{ "GEOMETRY", SYM(GEOMETRY_SYM)},
|
||||
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)},
|
||||
{ "GET_FORMAT", SYM(GET_FORMAT)},
|
||||
{ "GLOBAL", SYM(GLOBAL_SYM)},
|
||||
{ "GOTO", SYM(GOTO_SYM)},
|
||||
{ "GRANT", SYM(GRANT)},
|
||||
{ "GRANTS", SYM(GRANTS)},
|
||||
{ "GROUP", SYM(GROUP)},
|
||||
@ -218,6 +237,8 @@ static SYMBOL symbols[] = {
|
||||
{ "INNER", SYM(INNER_SYM)},
|
||||
{ "INNOBASE", SYM(INNOBASE_SYM)},
|
||||
{ "INNODB", SYM(INNOBASE_SYM)},
|
||||
{ "INOUT", SYM(INOUT_SYM)},
|
||||
{ "INSENSITIVE", SYM(INSENSITIVE_SYM)},
|
||||
{ "INSERT", SYM(INSERT)},
|
||||
{ "INSERT_METHOD", SYM(INSERT_METHOD)},
|
||||
{ "INT", SYM(INT_SYM)},
|
||||
@ -233,12 +254,17 @@ static SYMBOL symbols[] = {
|
||||
{ "IS", SYM(IS)},
|
||||
{ "ISOLATION", SYM(ISOLATION)},
|
||||
{ "ISSUER", SYM(ISSUER_SYM)},
|
||||
{ "ITERATE", SYM(ITERATE_SYM)},
|
||||
{ "INVOKER", SYM(INVOKER_SYM)},
|
||||
{ "JOIN", SYM(JOIN_SYM)},
|
||||
{ "KEY", SYM(KEY_SYM)},
|
||||
{ "KEYS", SYM(KEYS)},
|
||||
{ "KILL", SYM(KILL_SYM)},
|
||||
{ "LABEL", SYM(LABEL_SYM)},
|
||||
{ "LANGUAGE", SYM(LANGUAGE_SYM)},
|
||||
{ "LAST", SYM(LAST_SYM)},
|
||||
{ "LEADING", SYM(LEADING)},
|
||||
{ "LEAVE", SYM(LEAVE_SYM)},
|
||||
{ "LEAVES", SYM(LEAVES)},
|
||||
{ "LEFT", SYM(LEFT)},
|
||||
{ "LEVEL", SYM(LEVEL_SYM)},
|
||||
@ -256,6 +282,7 @@ static SYMBOL symbols[] = {
|
||||
{ "LONG", SYM(LONG_SYM)},
|
||||
{ "LONGBLOB", SYM(LONGBLOB)},
|
||||
{ "LONGTEXT", SYM(LONGTEXT)},
|
||||
{ "LOOP", SYM(LOOP_SYM)},
|
||||
{ "LOW_PRIORITY", SYM(LOW_PRIORITY)},
|
||||
{ "MASTER", SYM(MASTER_SYM)},
|
||||
{ "MASTER_CONNECT_RETRY", SYM(MASTER_CONNECT_RETRY_SYM)},
|
||||
@ -281,6 +308,7 @@ static SYMBOL symbols[] = {
|
||||
{ "MEDIUMBLOB", SYM(MEDIUMBLOB)},
|
||||
{ "MEDIUMINT", SYM(MEDIUMINT)},
|
||||
{ "MEDIUMTEXT", SYM(MEDIUMTEXT)},
|
||||
{ "MERGE", SYM(MERGE_SYM)},
|
||||
{ "MICROSECOND", SYM(MICROSECOND_SYM)},
|
||||
{ "MIDDLEINT", SYM(MEDIUMINT)}, /* For powerbuilder */
|
||||
{ "MINUTE", SYM(MINUTE_SYM)},
|
||||
@ -289,11 +317,13 @@ static SYMBOL symbols[] = {
|
||||
{ "MIN_ROWS", SYM(MIN_ROWS)},
|
||||
{ "MOD", SYM(MOD_SYM)},
|
||||
{ "MODE", SYM(MODE_SYM)},
|
||||
{ "MODIFIES", SYM(MODIFIES_SYM)},
|
||||
{ "MODIFY", SYM(MODIFY_SYM)},
|
||||
{ "MONTH", SYM(MONTH_SYM)},
|
||||
{ "MULTILINESTRING", SYM(MULTILINESTRING)},
|
||||
{ "MULTIPOINT", SYM(MULTIPOINT)},
|
||||
{ "MULTIPOLYGON", SYM(MULTIPOLYGON)},
|
||||
{ "NAME", SYM(NAME_SYM)},
|
||||
{ "NAMES", SYM(NAMES_SYM)},
|
||||
{ "NATIONAL", SYM(NATIONAL_SYM)},
|
||||
{ "NATURAL", SYM(NATURAL)},
|
||||
@ -319,6 +349,7 @@ static SYMBOL symbols[] = {
|
||||
{ "OPTIONALLY", SYM(OPTIONALLY)},
|
||||
{ "OR", SYM(OR_SYM)},
|
||||
{ "ORDER", SYM(ORDER_SYM)},
|
||||
{ "OUT", SYM(OUT_SYM)},
|
||||
{ "OUTER", SYM(OUTER)},
|
||||
{ "OUTFILE", SYM(OUTFILE)},
|
||||
{ "PACK_KEYS", SYM(PACK_KEYS_SYM)},
|
||||
@ -335,6 +366,7 @@ static SYMBOL symbols[] = {
|
||||
{ "PROCESS" , SYM(PROCESS)},
|
||||
{ "PROCESSLIST", SYM(PROCESSLIST_SYM)},
|
||||
{ "PURGE", SYM(PURGE)},
|
||||
{ "QUARTER", SYM(QUARTER_SYM)},
|
||||
{ "QUERY", SYM(QUERY_SYM)},
|
||||
{ "QUICK", SYM(QUICK)},
|
||||
{ "RAID0", SYM(RAID_0_SYM)},
|
||||
@ -342,6 +374,7 @@ static SYMBOL symbols[] = {
|
||||
{ "RAID_CHUNKSIZE", SYM(RAID_CHUNKSIZE)},
|
||||
{ "RAID_TYPE", SYM(RAID_TYPE)},
|
||||
{ "READ", SYM(READ_SYM)},
|
||||
{ "READS", SYM(READS_SYM)},
|
||||
{ "REAL", SYM(REAL)},
|
||||
{ "REFERENCES", SYM(REFERENCES)},
|
||||
{ "REGEXP", SYM(REGEXP)},
|
||||
@ -354,11 +387,13 @@ static SYMBOL symbols[] = {
|
||||
{ "REPEATABLE", SYM(REPEATABLE_SYM)},
|
||||
{ "REPLACE", SYM(REPLACE)},
|
||||
{ "REPLICATION", SYM(REPLICATION)},
|
||||
{ "REPEAT", SYM(REPEAT_SYM)},
|
||||
{ "REQUIRE", SYM(REQUIRE_SYM)},
|
||||
{ "RESET", SYM(RESET_SYM)},
|
||||
{ "RESTORE", SYM(RESTORE_SYM)},
|
||||
{ "RESTRICT", SYM(RESTRICT)},
|
||||
{ "RETURNS", SYM(UDF_RETURNS_SYM)},
|
||||
{ "RETURN", SYM(RETURN_SYM)},
|
||||
{ "RETURNS", SYM(RETURNS_SYM)},
|
||||
{ "REVOKE", SYM(REVOKE)},
|
||||
{ "RIGHT", SYM(RIGHT)},
|
||||
{ "RLIKE", SYM(REGEXP)}, /* Like in mSQL2 */
|
||||
@ -369,9 +404,13 @@ static SYMBOL symbols[] = {
|
||||
{ "ROW_FORMAT", SYM(ROW_FORMAT_SYM)},
|
||||
{ "RTREE", SYM(RTREE_SYM)},
|
||||
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
|
||||
{ "SCHEMA", SYM(DATABASE)},
|
||||
{ "SCHEMAS", SYM(DATABASES)},
|
||||
{ "SECOND", SYM(SECOND_SYM)},
|
||||
{ "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM)},
|
||||
{ "SECURITY", SYM(SECURITY_SYM)},
|
||||
{ "SELECT", SYM(SELECT_SYM)},
|
||||
{ "SENSITIVE", SYM(SENSITIVE_SYM)},
|
||||
{ "SEPARATOR", SYM(SEPARATOR_SYM)},
|
||||
{ "SERIAL", SYM(SERIAL_SYM)},
|
||||
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM)},
|
||||
@ -389,6 +428,11 @@ static SYMBOL symbols[] = {
|
||||
{ "SONAME", SYM(UDF_SONAME_SYM)},
|
||||
{ "SOUNDS", SYM(SOUNDS_SYM)},
|
||||
{ "SPATIAL", SYM(SPATIAL_SYM)},
|
||||
{ "SPECIFIC", SYM(SPECIFIC_SYM)},
|
||||
{ "SQL", SYM(SQL_SYM)},
|
||||
{ "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM)},
|
||||
{ "SQLSTATE", SYM(SQLSTATE_SYM)},
|
||||
{ "SQLWARNING", SYM(SQLWARNING_SYM)},
|
||||
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT)},
|
||||
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT)},
|
||||
{ "SQL_CACHE", SYM(SQL_CACHE_SYM)},
|
||||
@ -396,6 +440,15 @@ static SYMBOL symbols[] = {
|
||||
{ "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM)},
|
||||
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT)},
|
||||
{ "SQL_THREAD", SYM(SQL_THREAD)},
|
||||
{ "SQL_TSI_FRAC_SECOND", SYM(FRAC_SECOND_SYM)},
|
||||
{ "SQL_TSI_SECOND", SYM(SECOND_SYM)},
|
||||
{ "SQL_TSI_MINUTE", SYM(MINUTE_SYM)},
|
||||
{ "SQL_TSI_HOUR", SYM(HOUR_SYM)},
|
||||
{ "SQL_TSI_DAY", SYM(DAY_SYM)},
|
||||
{ "SQL_TSI_WEEK", SYM(WEEK_SYM)},
|
||||
{ "SQL_TSI_MONTH", SYM(MONTH_SYM)},
|
||||
{ "SQL_TSI_QUARTER", SYM(QUARTER_SYM)},
|
||||
{ "SQL_TSI_YEAR", SYM(YEAR_SYM)},
|
||||
{ "SSL", SYM(SSL_SYM)},
|
||||
{ "START", SYM(START_SYM)},
|
||||
{ "STARTING", SYM(STARTING)},
|
||||
@ -411,22 +464,28 @@ static SYMBOL symbols[] = {
|
||||
{ "TABLES", SYM(TABLES)},
|
||||
{ "TABLESPACE", SYM(TABLESPACE)},
|
||||
{ "TEMPORARY", SYM(TEMPORARY)},
|
||||
{ "TEMPTABLE", SYM(TEMPTABLE_SYM)},
|
||||
{ "TERMINATED", SYM(TERMINATED)},
|
||||
{ "TEXT", SYM(TEXT_SYM)},
|
||||
{ "THEN", SYM(THEN_SYM)},
|
||||
{ "TIME", SYM(TIME_SYM)},
|
||||
{ "TIMESTAMP", SYM(TIMESTAMP)},
|
||||
{ "TIMESTAMPADD", SYM(TIMESTAMP_ADD)},
|
||||
{ "TIMESTAMPDIFF", SYM(TIMESTAMP_DIFF)},
|
||||
{ "TINYBLOB", SYM(TINYBLOB)},
|
||||
{ "TINYINT", SYM(TINYINT)},
|
||||
{ "TINYTEXT", SYM(TINYTEXT)},
|
||||
{ "TO", SYM(TO_SYM)},
|
||||
{ "TRAILING", SYM(TRAILING)},
|
||||
{ "TRANSACTION", SYM(TRANSACTION_SYM)},
|
||||
{ "TRIGGER", SYM(TRIGGER_SYM)},
|
||||
{ "TRUE", SYM(TRUE_SYM)},
|
||||
{ "TRUNCATE", SYM(TRUNCATE_SYM)},
|
||||
{ "TYPE", SYM(TYPE_SYM)},
|
||||
{ "TYPES", SYM(TYPES_SYM)},
|
||||
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM)},
|
||||
{ "UNDEFINED", SYM(UNDEFINED_SYM)},
|
||||
{ "UNDO", SYM(UNDO_SYM)},
|
||||
{ "UNICODE", SYM(UNICODE_SYM)},
|
||||
{ "UNION", SYM(UNION_SYM)},
|
||||
{ "UNIQUE", SYM(UNIQUE_SYM)},
|
||||
@ -451,8 +510,11 @@ static SYMBOL symbols[] = {
|
||||
{ "VARIABLES", SYM(VARIABLES)},
|
||||
{ "VARYING", SYM(VARYING)},
|
||||
{ "WARNINGS", SYM(WARNINGS)},
|
||||
{ "WEEK", SYM(WEEK_SYM)},
|
||||
{ "WHEN", SYM(WHEN_SYM)},
|
||||
{ "WHERE", SYM(WHERE)},
|
||||
{ "WHILE", SYM(WHILE_SYM)},
|
||||
{ "VIEW", SYM(VIEW_SYM)},
|
||||
{ "WITH", SYM(WITH)},
|
||||
{ "WORK", SYM(WORK_SYM)},
|
||||
{ "WRITE", SYM(WRITE_SYM)},
|
||||
@ -499,7 +561,6 @@ static SYMBOL sql_functions[] = {
|
||||
{ "CONCAT", SYM(CONCAT)},
|
||||
{ "CONCAT_WS", SYM(CONCAT_WS)},
|
||||
{ "CONNECTION_ID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
|
||||
{ "CONTAINS", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_contains)},
|
||||
{ "CONV", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
|
||||
{ "CONVERT_TZ", SYM(CONVERT_TZ_SYM)},
|
||||
{ "COUNT", SYM(COUNT_SYM)},
|
||||
@ -636,14 +697,13 @@ static SYMBOL sql_functions[] = {
|
||||
{ "POSITION", SYM(POSITION_SYM)},
|
||||
{ "POW", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
|
||||
{ "POWER", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
|
||||
{ "QUARTER", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_quarter)},
|
||||
{ "QUOTE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_quote)},
|
||||
{ "RADIANS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_radians)},
|
||||
{ "RAND", SYM(RAND)},
|
||||
{ "RELEASE_LOCK", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_release_lock)},
|
||||
{ "REPEAT", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_repeat)},
|
||||
{ "REVERSE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_reverse)},
|
||||
{ "ROUND", SYM(ROUND)},
|
||||
{ "ROW_COUNT", SYM(ROW_COUNT_SYM)},
|
||||
{ "RPAD", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_rpad)},
|
||||
{ "RTRIM", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_rtrim)},
|
||||
{ "SEC_TO_TIME", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sec_to_time)},
|
||||
@ -686,7 +746,6 @@ static SYMBOL sql_functions[] = {
|
||||
{ "UUID", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_uuid)},
|
||||
{ "VARIANCE", SYM(VARIANCE_SYM)},
|
||||
{ "VERSION", F_SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
|
||||
{ "WEEK", SYM(WEEK_SYM)},
|
||||
{ "WEEKDAY", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)},
|
||||
{ "WEEKOFYEAR", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekofyear)},
|
||||
{ "WITHIN", F_SYM(FUNC_ARG2),0,CREATE_FUNC_GEOM(create_func_within)},
|
||||
|
153
sql/log.cc
153
sql/log.cc
@ -35,7 +35,7 @@
|
||||
#include "message.h"
|
||||
#endif
|
||||
|
||||
MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
|
||||
MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log;
|
||||
ulong sync_binlog_counter= 0;
|
||||
|
||||
static bool test_if_number(const char *str,
|
||||
@ -129,7 +129,8 @@ static int find_uniq_filename(char *name)
|
||||
MYSQL_LOG::MYSQL_LOG()
|
||||
:bytes_written(0), last_time(0), query_start(0), name(0),
|
||||
file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0),
|
||||
need_start_event(1)
|
||||
need_start_event(1), description_event_for_exec(0),
|
||||
description_event_for_queue(0)
|
||||
{
|
||||
/*
|
||||
We don't want to initialize LOCK_Log here as such initialization depends on
|
||||
@ -157,6 +158,8 @@ void MYSQL_LOG::cleanup()
|
||||
{
|
||||
inited= 0;
|
||||
close(LOG_CLOSE_INDEX);
|
||||
delete description_event_for_queue;
|
||||
delete description_event_for_exec;
|
||||
(void) pthread_mutex_destroy(&LOCK_log);
|
||||
(void) pthread_mutex_destroy(&LOCK_index);
|
||||
(void) pthread_cond_destroy(&update_cond);
|
||||
@ -226,7 +229,8 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
|
||||
const char *new_name, const char *index_file_name_arg,
|
||||
enum cache_type io_cache_type_arg,
|
||||
bool no_auto_events_arg,
|
||||
ulong max_size_arg)
|
||||
ulong max_size_arg,
|
||||
bool null_created_arg)
|
||||
{
|
||||
char buff[512];
|
||||
File file= -1, index_file_nr= -1;
|
||||
@ -324,8 +328,8 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
|
||||
if (my_b_safe_write(&log_file, (byte*) BINLOG_MAGIC,
|
||||
BIN_LOG_HEADER_SIZE))
|
||||
goto err;
|
||||
bytes_written += BIN_LOG_HEADER_SIZE;
|
||||
write_file_name_to_index_file=1;
|
||||
bytes_written+= BIN_LOG_HEADER_SIZE;
|
||||
write_file_name_to_index_file= 1;
|
||||
}
|
||||
|
||||
if (!my_b_inited(&index_file))
|
||||
@ -355,10 +359,50 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
|
||||
}
|
||||
if (need_start_event && !no_auto_events)
|
||||
{
|
||||
need_start_event=0;
|
||||
Start_log_event s;
|
||||
s.set_log_pos(this);
|
||||
s.write(&log_file);
|
||||
/*
|
||||
In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event
|
||||
even if this is not the very first binlog.
|
||||
*/
|
||||
Format_description_log_event s(BINLOG_VERSION);
|
||||
if (!s.is_valid())
|
||||
goto err;
|
||||
if (null_created_arg)
|
||||
s.created= 0;
|
||||
if (s.write(&log_file))
|
||||
goto err;
|
||||
bytes_written+= s.data_written;
|
||||
}
|
||||
if (description_event_for_queue &&
|
||||
description_event_for_queue->binlog_version>=4)
|
||||
{
|
||||
/*
|
||||
This is a relay log written to by the I/O slave thread.
|
||||
Write the event so that others can later know the format of this relay
|
||||
log.
|
||||
Note that this event is very close to the original event from the
|
||||
master (it has binlog version of the master, event types of the
|
||||
master), so this is suitable to parse the next relay log's event. It
|
||||
has been produced by
|
||||
Format_description_log_event::Format_description_log_event(char*
|
||||
buf,).
|
||||
Why don't we want to write the description_event_for_queue if this
|
||||
event is for format<4 (3.23 or 4.x): this is because in that case, the
|
||||
description_event_for_queue describes the data received from the
|
||||
master, but not the data written to the relay log (*conversion*),
|
||||
which is in format 4 (slave's).
|
||||
*/
|
||||
/*
|
||||
Set 'created' to 0, so that in next relay logs this event does not
|
||||
trigger cleaning actions on the slave in
|
||||
Format_description_log_event::exec_event().
|
||||
*/
|
||||
description_event_for_queue->created= 0;
|
||||
/* Don't set log_pos in event header */
|
||||
description_event_for_queue->artificial_event=1;
|
||||
|
||||
if (description_event_for_queue->write(&log_file))
|
||||
goto err;
|
||||
bytes_written+= description_event_for_queue->data_written;
|
||||
}
|
||||
if (flush_io_cache(&log_file) ||
|
||||
my_sync(log_file.file, MYF(MY_WME)))
|
||||
@ -654,7 +698,7 @@ bool MYSQL_LOG::reset_logs(THD* thd)
|
||||
if (!thd->slave_thread)
|
||||
need_start_event=1;
|
||||
open(save_name, save_log_type, 0, index_file_name,
|
||||
io_cache_type, no_auto_events, max_size);
|
||||
io_cache_type, no_auto_events, max_size, 0);
|
||||
my_free((gptr) save_name, MYF(0));
|
||||
|
||||
err:
|
||||
@ -836,22 +880,18 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
||||
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
|
||||
!log_in_use(log_info.log_file_name))
|
||||
{
|
||||
ulong tmp;
|
||||
LINT_INIT(tmp);
|
||||
ulong file_size= 0;
|
||||
if (decrease_log_space) //stat the file we want to delete
|
||||
{
|
||||
MY_STAT s;
|
||||
if (my_stat(log_info.log_file_name,&s,MYF(0)))
|
||||
tmp= s.st_size;
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
If we could not stat, we can't know the amount
|
||||
of space that deletion will free. In most cases,
|
||||
deletion won't work either, so it's not a problem.
|
||||
*/
|
||||
tmp= 0;
|
||||
}
|
||||
if (my_stat(log_info.log_file_name,&s,MYF(0)))
|
||||
file_size= s.st_size;
|
||||
}
|
||||
/*
|
||||
It's not fatal if we can't delete a log file ;
|
||||
@ -859,7 +899,7 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
||||
*/
|
||||
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
|
||||
if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space)
|
||||
*decrease_log_space-= tmp;
|
||||
*decrease_log_space-= file_size;
|
||||
if (find_next_log(&log_info, 0) || exit_loop)
|
||||
break;
|
||||
}
|
||||
@ -1024,9 +1064,8 @@ void MYSQL_LOG::new_file(bool need_lock)
|
||||
*/
|
||||
THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
|
||||
Rotate_log_event r(thd,new_name+dirname_length(new_name));
|
||||
r.set_log_pos(this);
|
||||
r.write(&log_file);
|
||||
bytes_written += r.get_event_len();
|
||||
bytes_written += r.data_written;
|
||||
}
|
||||
/*
|
||||
Update needs to be signalled even if there is no rotate event
|
||||
@ -1044,8 +1083,17 @@ void MYSQL_LOG::new_file(bool need_lock)
|
||||
Note that at this point, log_type != LOG_CLOSED (important for is_open()).
|
||||
*/
|
||||
|
||||
/*
|
||||
new_file() is only used for rotation (in FLUSH LOGS or because size >
|
||||
max_binlog_size or max_relay_log_size).
|
||||
If this is a binary log, the Format_description_log_event at the beginning of
|
||||
the new file should have created=0 (to distinguish with the
|
||||
Format_description_log_event written at server startup, which should
|
||||
trigger temp tables deletion on slaves.
|
||||
*/
|
||||
|
||||
open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type,
|
||||
no_auto_events, max_size);
|
||||
no_auto_events, max_size, 1);
|
||||
if (this == &mysql_bin_log)
|
||||
report_pos_in_innodb();
|
||||
my_free(old_name,MYF(0));
|
||||
@ -1076,7 +1124,7 @@ bool MYSQL_LOG::append(Log_event* ev)
|
||||
error=1;
|
||||
goto err;
|
||||
}
|
||||
bytes_written += ev->get_event_len();
|
||||
bytes_written+= ev->data_written;
|
||||
DBUG_PRINT("info",("max_size: %lu",max_size));
|
||||
if ((uint) my_b_append_tell(&log_file) > max_size)
|
||||
{
|
||||
@ -1129,7 +1177,7 @@ err:
|
||||
|
||||
/*
|
||||
Write to normal (not rotable) log
|
||||
This is the format for the 'normal', 'slow' and 'update' logs.
|
||||
This is the format for the 'normal' log.
|
||||
*/
|
||||
|
||||
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
|
||||
@ -1220,11 +1268,15 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
|
||||
|
||||
inline bool sync_binlog(IO_CACHE *cache)
|
||||
{
|
||||
return (sync_binlog_period &&
|
||||
(sync_binlog_period == ++sync_binlog_counter) &&
|
||||
(sync_binlog_counter= 0, my_sync(cache->file, MYF(MY_WME))));
|
||||
if (sync_binlog_period == ++sync_binlog_counter && sync_binlog_period)
|
||||
{
|
||||
sync_binlog_counter= 0;
|
||||
return my_sync(cache->file, MYF(MY_WME));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Write an event to the binary log
|
||||
*/
|
||||
@ -1292,7 +1344,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
|
||||
|
||||
if (thd)
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 50000
|
||||
/* NOTE: CHARSET AND TZ REPL WILL BE REWRITTEN SHORTLY */
|
||||
/*
|
||||
To make replication of charsets working in 4.1 we are writing values
|
||||
of charset related variables before every statement in the binlog,
|
||||
@ -1318,7 +1370,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
(uint) thd->variables.collation_database->number,
|
||||
(uint) thd->variables.collation_server->number);
|
||||
Query_log_event e(thd, buf, written, 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1334,31 +1385,26 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
thd->variables.time_zone->get_name()->ptr(),
|
||||
"'", NullS);
|
||||
Query_log_event e(thd, buf, buf_end - buf, 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (thd->last_insert_id_used)
|
||||
{
|
||||
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
|
||||
thd->current_insert_id);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
if (thd->insert_id_used)
|
||||
{
|
||||
Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
if (thd->rand_used)
|
||||
{
|
||||
Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1374,7 +1420,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
user_var_event->length,
|
||||
user_var_event->type,
|
||||
user_var_event->charset_number);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1386,48 +1431,17 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
p= strmov(strmov(buf, "SET CHARACTER SET "),
|
||||
thd->variables.convert_set->name);
|
||||
Query_log_event e(thd, buf, (ulong) (p - buf), 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
If the user has set FOREIGN_KEY_CHECKS=0 we wrap every SQL
|
||||
command in the binlog inside:
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
<command>;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
*/
|
||||
|
||||
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
|
||||
{
|
||||
Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=0", 24, 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the SQL command */
|
||||
|
||||
event_info->set_log_pos(this);
|
||||
if (event_info->write(file))
|
||||
goto err;
|
||||
|
||||
/* Write log events to reset the 'run environment' of the SQL command */
|
||||
|
||||
if (thd)
|
||||
{
|
||||
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS)
|
||||
{
|
||||
Query_log_event e(thd, "SET FOREIGN_KEY_CHECKS=1", 24, 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Tell for transactional table handlers up to which position in the
|
||||
binlog file we wrote. The table handler can store this info, and
|
||||
@ -1604,7 +1618,6 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
|
||||
master's binlog, which would result in wrong positions being shown to
|
||||
the user, MASTER_POS_WAIT undue waiting etc.
|
||||
*/
|
||||
qinfo.set_log_pos(this);
|
||||
if (qinfo.write(&log_file))
|
||||
goto err;
|
||||
}
|
||||
@ -1630,7 +1643,6 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
|
||||
commit_or_rollback ? "COMMIT" : "ROLLBACK",
|
||||
commit_or_rollback ? 6 : 8,
|
||||
TRUE);
|
||||
qinfo.set_log_pos(this);
|
||||
if (qinfo.write(&log_file) || flush_io_cache(&log_file) ||
|
||||
sync_binlog(&log_file))
|
||||
goto err;
|
||||
@ -1692,8 +1704,7 @@ err:
|
||||
|
||||
|
||||
/*
|
||||
Write update log in a format suitable for incremental backup
|
||||
This is also used by the slow query log.
|
||||
Write to the slow query log.
|
||||
*/
|
||||
|
||||
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
|
||||
@ -1877,8 +1888,8 @@ void MYSQL_LOG::close(uint exiting)
|
||||
(exiting & LOG_CLOSE_STOP_EVENT))
|
||||
{
|
||||
Stop_log_event s;
|
||||
s.set_log_pos(this);
|
||||
s.write(&log_file);
|
||||
bytes_written+= s.data_written;
|
||||
signal_update();
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
1580
sql/log_event.cc
1580
sql/log_event.cc
File diff suppressed because it is too large
Load Diff
1639
sql/sql_parse.cc
1639
sql/sql_parse.cc
File diff suppressed because it is too large
Load Diff
2235
sql/sql_yacc.yy
2235
sql/sql_yacc.yy
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user