summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/convert.cc2
-rw-r--r--sql/field.cc25
-rw-r--r--sql/filesort.cc5
-rw-r--r--sql/ha_innodb.cc685
-rw-r--r--sql/ha_innodb.h8
-rw-r--r--sql/ha_isam.cc2
-rw-r--r--sql/ha_myisam.cc44
-rw-r--r--sql/ha_myisammrg.cc4
-rw-r--r--sql/handler.cc62
-rw-r--r--sql/handler.h13
-rw-r--r--sql/item.cc23
-rw-r--r--sql/item.h15
-rw-r--r--sql/item_cmpfunc.cc5
-rw-r--r--sql/item_func.cc12
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_strfunc.cc17
-rw-r--r--sql/item_sum.h3
-rw-r--r--sql/item_timefunc.cc2
-rw-r--r--sql/item_timefunc.h1
-rw-r--r--sql/lex.h11
-rw-r--r--sql/lock.cc7
-rw-r--r--sql/log.cc42
-rw-r--r--sql/log_event.cc68
-rw-r--r--sql/log_event.h11
-rw-r--r--sql/my_lock.c17
-rw-r--r--sql/mysql_priv.h37
-rw-r--r--sql/mysqld.cc358
-rw-r--r--sql/net_pkg.cc8
-rw-r--r--sql/net_serv.cc15
-rw-r--r--sql/nt_servc.cc4
-rw-r--r--sql/opt_range.cc15
-rw-r--r--sql/opt_range.h3
-rw-r--r--sql/repl_failsafe.cc1
-rw-r--r--sql/share/Makefile.am1
-rw-r--r--sql/slave.cc402
-rw-r--r--sql/slave.h17
-rw-r--r--sql/sql_acl.cc41
-rw-r--r--sql/sql_base.cc25
-rw-r--r--sql/sql_cache.cc177
-rw-r--r--sql/sql_cache.h26
-rw-r--r--sql/sql_class.cc107
-rw-r--r--sql/sql_class.h53
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_delete.cc6
-rw-r--r--sql/sql_insert.cc10
-rw-r--r--sql/sql_lex.cc4
-rw-r--r--sql/sql_lex.h5
-rw-r--r--sql/sql_load.cc9
-rw-r--r--sql/sql_parse.cc173
-rw-r--r--sql/sql_rename.cc10
-rw-r--r--sql/sql_repl.cc61
-rw-r--r--sql/sql_select.cc417
-rw-r--r--sql/sql_show.cc14
-rw-r--r--sql/sql_table.cc124
-rw-r--r--sql/sql_union.cc65
-rw-r--r--sql/sql_update.cc6
-rw-r--r--sql/sql_yacc.yy123
-rw-r--r--sql/table.cc5
-rw-r--r--sql/table.h15
-rw-r--r--sql/unireg.cc4
-rw-r--r--sql/unireg.h5
61 files changed, 2163 insertions, 1276 deletions
diff --git a/sql/convert.cc b/sql/convert.cc
index 7a06208759c..75af13e0939 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -456,7 +456,7 @@ bool CONVERT::store(String *packet,const char *from,uint length)
packet->realloc(packet_length+5+length))
return 1;
char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
- length);
+ (ulonglong)length);
for (const char *end=from+length ; from != end ; from++)
*to++= to_map[(uchar) *from];
diff --git a/sql/field.cc b/sql/field.cc
index 2a0d0160d00..32679f549ba 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1713,6 +1713,11 @@ void Field_float::store(double nr)
float j;
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
+ if (unsigned_flag && nr < 0)
+ {
+ current_thd->cuted_fields++;
+ nr=0;
+ }
if (nr < -FLT_MAX)
{
j= -FLT_MAX;
@@ -1739,6 +1744,11 @@ void Field_float::store(double nr)
void Field_float::store(longlong nr)
{
float j= (float) nr;
+ if (unsigned_flag && j < 0)
+ {
+ current_thd->cuted_fields++;
+ j=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1945,6 +1955,11 @@ void Field_double::store(const char *from,uint len)
double j= atof(tmp_str.c_ptr());
if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
current_thd->cuted_fields++;
+ if (unsigned_flag && j < 0)
+ {
+ current_thd->cuted_fields++;
+ j=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1960,6 +1975,11 @@ void Field_double::store(double nr)
{
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
+ if (unsigned_flag && nr < 0)
+ {
+ current_thd->cuted_fields++;
+ nr=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1974,6 +1994,11 @@ void Field_double::store(double nr)
void Field_double::store(longlong nr)
{
double j= (double) nr;
+ if (unsigned_flag && j < 0)
+ {
+ current_thd->cuted_fields++;
+ j=0;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
diff --git a/sql/filesort.cc b/sql/filesort.cc
index a5f42d5731e..7e3d1c96f57 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -452,10 +452,7 @@ static void make_sortkey(register SORTPARAM *param,
{
if (field->is_null())
{
- if (sort_field->reverse)
- bfill(to,sort_field->length+1,(char) 255);
- else
- bzero((char*) to,sort_field->length+1);
+ bzero((char*) to,sort_field->length+1);
to+= sort_field->length+1;
continue;
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index f99e677913e..aa8ce0f3c18 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & InnoDB Oy
+/* Copyright (C) 2000 MySQL AB & InnoDB Oy
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -76,25 +76,40 @@ bool innodb_skip = 0;
uint innobase_init_flags = 0;
ulong innobase_cache_size = 0;
+/* The default values for the following, type long, start-up parameters
+are declared in mysqld.cc: */
+
long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_file_size, innobase_log_buffer_size,
innobase_buffer_pool_size, innobase_additional_mem_pool_size,
innobase_file_io_threads, innobase_lock_wait_timeout,
- innobase_thread_concurrency, innobase_force_recovery;
+ innobase_thread_concurrency, innobase_force_recovery;
+
+/* The default values for the following char* start-up parameters
+are determined in innobase_init below: */
+
+char* innobase_data_home_dir = NULL;
+char* innobase_log_group_home_dir = NULL;
+char* innobase_log_arch_dir = NULL;
+char* innobase_unix_file_flush_method = NULL;
+
+/* Below we have boolean-valued start-up parameters, and their default
+values */
-char *innobase_data_home_dir;
-char *innobase_log_group_home_dir, *innobase_log_arch_dir;
-char *innobase_unix_file_flush_method;
-bool innobase_flush_log_at_trx_commit, innobase_log_archive,
- innobase_use_native_aio, innobase_fast_shutdown;
+my_bool innobase_flush_log_at_trx_commit = FALSE;
+my_bool innobase_log_archive = FALSE;
+my_bool innobase_use_native_aio = FALSE;
+my_bool innobase_fast_shutdown = TRUE;
/*
- Set default InnoDB size to 64M, to let users use InnoDB without having
- to specify any startup options.
+ Set default InnoDB size to 64M and let it be auto-extending. Thus users
+ can use InnoDB without having to specify any startup options.
*/
-char *innobase_data_file_path= (char*) "ibdata1:64M";
-char *internal_innobase_data_file_path=0;
+/* innobase_data_file_path=ibdata:15,idata2:1,... */
+
+char *innobase_data_file_path= (char*) "ibdata1:64M:autoextend";
+static char *internal_innobase_data_file_path=0;
/* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call
@@ -235,7 +250,7 @@ convert_error_code_to_mysql(
extern "C" {
/*****************************************************************
Prints info of a THD object (== user session thread) to the
-standatd output. NOTE that mysql/innobase/trx/trx0trx.c must contain
+standard output. NOTE that mysql/innobase/trx/trx0trx.c must contain
the prototype for this function! */
void
@@ -304,6 +319,8 @@ check_trx_exists(
thd->transaction.stmt.innobase_tid =
(void*)&innodb_dummy_stmt_trx_handle;
+ } else {
+ ut_a(trx->magic_n == TRX_MAGIC_N);
}
return(trx);
@@ -336,227 +353,6 @@ ha_innobase::update_thd(
}
/*************************************************************************
-Reads the data files and their sizes from a character string given in
-the .cnf file. */
-static
-bool
-innobase_parse_data_file_paths_and_sizes(void)
-/*==========================================*/
- /* out: TRUE if ok, FALSE if parsing
- error */
-{
- char* str;
- char* endp;
- char* path;
- ulint size;
- ulint i = 0;
-
- str = internal_innobase_data_file_path;
-
- /* First calculate the number of data files and check syntax:
- path:size[M];path:size[M]... . Note that a Windows path may
- contain a drive name and a ':'. */
-
- while (*str != '\0') {
- path = str;
-
- while ((*str != ':' && *str != '\0')
- || (*str == ':'
- && (*(str + 1) == '\\' || *(str + 1) == '/'))) {
- str++;
- }
-
- if (*str == '\0') {
- return(FALSE);
- }
-
- str++;
-
- size = strtoul(str, &endp, 10);
-
- str = endp;
-
- if ((*str != 'M') && (*str != 'G')) {
- size = size / (1024 * 1024);
- } else if (*str == 'G') {
- size = size * 1024;
- str++;
- } else {
- str++;
- }
-
- if (strlen(str) >= 6
- && *str == 'n'
- && *(str + 1) == 'e'
- && *(str + 2) == 'w') {
- str += 3;
- }
-
- if (strlen(str) >= 3
- && *str == 'r'
- && *(str + 1) == 'a'
- && *(str + 2) == 'w') {
- str += 3;
- }
-
- if (size == 0) {
- return(FALSE);
- }
-
- i++;
-
- if (*str == ';') {
- str++;
- } else if (*str != '\0') {
-
- return(FALSE);
- }
- }
-
- srv_data_file_names = (char**)ut_malloc(i * sizeof(void*));
- srv_data_file_sizes = (ulint*)ut_malloc(i * sizeof(ulint));
- srv_data_file_is_raw_partition = (ulint*)ut_malloc(i * sizeof(ulint));
-
- srv_n_data_files = i;
-
- /* Then store the actual values to our arrays */
-
- str = internal_innobase_data_file_path;
- i = 0;
-
- while (*str != '\0') {
- path = str;
-
- /* Note that we must ignore the ':' in a Windows path */
-
- while ((*str != ':' && *str != '\0')
- || (*str == ':'
- && (*(str + 1) == '\\' || *(str + 1) == '/'))) {
- str++;
- }
-
- if (*str == ':') {
- /* Make path a null-terminated string */
- *str = '\0';
- str++;
- }
-
- size = strtoul(str, &endp, 10);
-
- str = endp;
-
- if ((*str != 'M') && (*str != 'G')) {
- size = size / (1024 * 1024);
- } else if (*str == 'G') {
- size = size * 1024;
- str++;
- } else {
- str++;
- }
-
- srv_data_file_is_raw_partition[i] = 0;
-
- if (strlen(str) >= 6
- && *str == 'n'
- && *(str + 1) == 'e'
- && *(str + 2) == 'w') {
- str += 3;
- srv_data_file_is_raw_partition[i] = SRV_NEW_RAW;
- }
-
- if (strlen(str) >= 3
- && *str == 'r'
- && *(str + 1) == 'a'
- && *(str + 2) == 'w') {
- str += 3;
-
- if (srv_data_file_is_raw_partition[i] == 0) {
- srv_data_file_is_raw_partition[i] = SRV_OLD_RAW;
- }
- }
-
- srv_data_file_names[i] = path;
- srv_data_file_sizes[i] = size;
-
- i++;
-
- if (*str == ';') {
- str++;
- }
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
-Reads log group home directories from a character string given in
-the .cnf file. */
-static
-bool
-innobase_parse_log_group_home_dirs(void)
-/*====================================*/
- /* out: TRUE if ok, FALSE if parsing
- error */
-{
- char* str;
- char* path;
- ulint i = 0;
-
- str = innobase_log_group_home_dir;
-
- /* First calculate the number of directories and check syntax:
- path;path;... */
-
- while (*str != '\0') {
- path = str;
-
- while (*str != ';' && *str != '\0') {
- str++;
- }
-
- i++;
-
- if (*str == ';') {
- str++;
- } else if (*str != '\0') {
-
- return(FALSE);
- }
- }
-
- if (i != (ulint) innobase_mirrored_log_groups) {
-
- return(FALSE);
- }
-
- srv_log_group_home_dirs = (char**) ut_malloc(i * sizeof(void*));
-
- /* Then store the actual values to our array */
-
- str = innobase_log_group_home_dir;
- i = 0;
-
- while (*str != '\0') {
- path = str;
-
- while (*str != ';' && *str != '\0') {
- str++;
- }
-
- if (*str == ';') {
- *str = '\0';
- str++;
- }
-
- srv_log_group_home_dirs[i] = path;
-
- i++;
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
Opens an InnoDB database. */
bool
@@ -579,9 +375,9 @@ innobase_init(void)
else
{
/* It's better to use current lib, to keep path's short */
- current_lib[0]=FN_CURLIB;
- current_lib[1]=FN_LIBCHAR;
- current_lib[2]=0;
+ current_lib[0] = FN_CURLIB;
+ current_lib[1] = FN_LIBCHAR;
+ current_lib[2] = 0;
default_path=current_lib;
}
@@ -603,12 +399,17 @@ innobase_init(void)
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
default_path);
- srv_logs_home = (char*) "";
srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir :
default_path);
- ret = innobase_parse_data_file_paths_and_sizes();
-
+ ret = (bool)
+ srv_parse_data_file_paths_and_sizes(internal_innobase_data_file_path,
+ &srv_data_file_names,
+ &srv_data_file_sizes,
+ &srv_data_file_is_raw_partition,
+ &srv_n_data_files,
+ &srv_auto_extend_last_data_file,
+ &srv_last_file_size_max);
if (ret == FALSE) {
sql_print_error("InnoDB: syntax error in innodb_data_file_path");
DBUG_RETURN(TRUE);
@@ -616,12 +417,18 @@ innobase_init(void)
if (!innobase_log_group_home_dir)
innobase_log_group_home_dir= default_path;
- ret = innobase_parse_log_group_home_dirs();
- if (ret == FALSE) {
- DBUG_RETURN(TRUE);
- }
+ ret = (bool)
+ srv_parse_log_group_home_dirs(innobase_log_group_home_dir,
+ &srv_log_group_home_dirs);
+
+ if (ret == FALSE || innobase_mirrored_log_groups != 1) {
+ fprintf(stderr,
+ "InnoDB: syntax error in innodb_log_group_home_dir\n"
+ "InnoDB: or a wrong number of mirrored log groups\n");
+ DBUG_RETURN(TRUE);
+ }
srv_unix_file_flush_method_str = (innobase_unix_file_flush_method ?
innobase_unix_file_flush_method :
(char*)"fdatasync");
@@ -662,10 +469,11 @@ innobase_init(void)
if (err != DB_SUCCESS) {
- DBUG_RETURN(1);
+ DBUG_RETURN(1);
}
+
(void) hash_init(&innobase_open_tables,32,0,0,
- (hash_get_key) innobase_get_key,0,0);
+ (hash_get_key) innobase_get_key,0,0);
pthread_mutex_init(&innobase_mutex,MY_MUTEX_INIT_FAST);
DBUG_RETURN(0);
}
@@ -841,6 +649,7 @@ innobase_close_connection(
whose transaction should be rolled back */
{
if (NULL != thd->transaction.all.innobase_tid) {
+
trx_rollback_for_mysql((trx_t*)
(thd->transaction.all.innobase_tid));
trx_free_for_mysql((trx_t*)
@@ -984,7 +793,10 @@ ha_innobase::open(
/* Get pointer to a table object in InnoDB dictionary cache */
- if (NULL == (ib_table = dict_table_get(norm_name, NULL))) {
+ ib_table = dict_table_get_and_increment_handle_count(
+ norm_name, NULL);
+
+ if (NULL == ib_table) {
sql_print_error("InnoDB error:\n\
Cannot find table %s from the internal data dictionary\n\
@@ -1347,33 +1159,43 @@ build_template(
clust_index = dict_table_get_first_index_noninline(prebuilt->table);
- if (!prebuilt->in_update_remember_pos) {
+ if (!prebuilt->hint_no_need_to_fetch_extra_cols) {
+ /* We have a hint that we should at least fetch all
+ columns in the key, or all columns in the table */
+
if (prebuilt->read_just_key) {
+ /* MySQL has instructed us that it is enough to
+ fetch the columns in the key */
+
fetch_all_in_key = TRUE;
} else {
/* We are building a temporary table: fetch all
- columns */
+ columns; the reason is that MySQL may use the
+ clustered index key to store rows, but the mechanism
+ we use below to detect required columns does not
+ reveal that. Actually, it might be enough to
+ fetch only all in the key also in this case! */
templ_type = ROW_MYSQL_WHOLE_ROW;
}
}
if (prebuilt->select_lock_type == LOCK_X) {
- /* TODO: should fix the code in sql_update so that we could do
- with fetching only the needed columns */
+ /* We always retrieve the whole clustered index record if we
+ use exclusive row level locks, for example, if the read is
+ done in an UPDATE statement. */
templ_type = ROW_MYSQL_WHOLE_ROW;
}
if (templ_type == ROW_MYSQL_REC_FIELDS) {
+ /* In versions < 3.23.50 we always retrieved the clustered
+ index record if prebuilt->select_lock_type == LOCK_S,
+ but there is really not need for that, and in some cases
+ performance could be seriously degraded because the MySQL
+ optimizer did not know about our convention! */
- if (prebuilt->select_lock_type != LOCK_NONE) {
- /* Let index be the clustered index */
-
- index = clust_index;
- } else {
- index = prebuilt->index;
- }
+ index = prebuilt->index;
} else {
index = clust_index;
}
@@ -1469,12 +1291,6 @@ skip_field:
(index->table->cols + templ->col_no)->clust_pos;
}
}
-
- if (templ_type == ROW_MYSQL_REC_FIELDS
- && prebuilt->select_lock_type != LOCK_NONE) {
-
- prebuilt->need_to_access_clustered = TRUE;
- }
}
/************************************************************************
@@ -1507,7 +1323,9 @@ ha_innobase::write_row(
}
if (table->next_number_field && record == table->record[0]) {
-
+ /* This is the case where the table has an
+ auto-increment column */
+
/* Fetch the value the user possibly has set in the
autoincrement field */
@@ -1591,12 +1409,6 @@ ha_innobase::write_row(
}
}
- /* Set the 'in_update_remember_pos' flag to FALSE to
- make sure all columns are fetched in the select done by
- update_auto_increment */
-
- prebuilt->in_update_remember_pos = FALSE;
-
update_auto_increment();
if (auto_inc == 0) {
@@ -1620,7 +1432,7 @@ ha_innobase::write_row(
}
/* We have to set sql_stat_start to TRUE because
- update_auto_increment has called a select, and
+ update_auto_increment may have called a select, and
has reset that flag; row_insert_for_mysql has to
know to set the IX intention lock on the table, something
it only does at the start of each statement */
@@ -1860,9 +1672,7 @@ ha_innobase::update_row(
/* This is not a delete */
prebuilt->upd_node->is_delete = FALSE;
- if (!prebuilt->in_update_remember_pos) {
- assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
- }
+ assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
srv_conc_enter_innodb(prebuilt->trx);
@@ -1908,7 +1718,6 @@ ha_innobase::delete_row(
/* This is a delete */
prebuilt->upd_node->is_delete = TRUE;
- prebuilt->in_update_remember_pos = TRUE;
srv_conc_enter_innodb(prebuilt->trx);
@@ -2111,26 +1920,28 @@ ha_innobase::change_active_index(
InnoDB */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- KEY* key;
+ KEY* key=0;
statistic_increment(ha_read_key_count, &LOCK_status);
DBUG_ENTER("change_active_index");
active_index = keynr;
- if (keynr != MAX_KEY && table->keys > 0)
- {
+ if (keynr != MAX_KEY && table->keys > 0) {
key = table->key_info + active_index;
- prebuilt->index=dict_table_get_index_noninline(prebuilt->table, key->name);
- if (!prebuilt->index)
- {
- sql_print_error("Innodb could not find key n:o %u with name %s from dict cache for table %s", keynr, key->name, prebuilt->table->name);
- return(1);
- }
+ prebuilt->index = dict_table_get_index_noninline(
+ prebuilt->table,
+ key->name);
+ } else {
+ prebuilt->index = dict_table_get_first_index_noninline(
+ prebuilt->table);
+ }
+
+ if (!prebuilt->index) {
+ sql_print_error("Innodb could not find key n:o %u with name %s from dict cache for table %s", keynr, key ? key->name : "NULL", prebuilt->table->name);
+ DBUG_RETURN(1);
}
- else
- prebuilt->index = dict_table_get_first_index_noninline(prebuilt->table);
assert(prebuilt->search_tuple != 0);
@@ -2402,7 +2213,7 @@ ha_innobase::rnd_pos(
int error;
uint keynr = active_index;
DBUG_ENTER("rnd_pos");
- DBUG_DUMP("key", pos, ref_stored_len);
+ DBUG_DUMP("key", (char*) pos, ref_stored_len);
statistic_increment(ha_read_rnd_count, &LOCK_status);
@@ -2465,44 +2276,6 @@ ha_innobase::position(
ref_stored_len = len;
}
-/***********************************************************************
-Tells something additional to the handler about how to do things. */
-
-int
-ha_innobase::extra(
-/*===============*/
- /* out: 0 or error number */
- enum ha_extra_function operation)
- /* in: HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE */
-{
- row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
-
- switch (operation) {
- case HA_EXTRA_RESET:
- case HA_EXTRA_RESET_STATE:
- prebuilt->read_just_key = 0;
- break;
- case HA_EXTRA_NO_KEYREAD:
- prebuilt->read_just_key = 0;
- break;
- case HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE:
- prebuilt->in_update_remember_pos = FALSE;
- break;
- case HA_EXTRA_KEYREAD:
- prebuilt->read_just_key = 1;
- break;
- default:/* Do nothing */
- ;
- }
-
- return(0);
-}
-
-int ha_innobase::reset(void)
-{
- return(0);
-}
-
/*********************************************************************
Creates a table definition to an InnoDB database. */
@@ -2665,7 +2438,6 @@ ha_innobase::create(
dict_table_t* innobase_table;
trx_t* trx;
int primary_key_no;
- KEY* key;
uint i;
char name2[FN_REFLEN];
char norm_name[FN_REFLEN];
@@ -2680,7 +2452,9 @@ ha_innobase::create(
/* Create the table definition in InnoDB */
- if ((error = create_table_def(trx, form, norm_name))) {
+ error = create_table_def(trx, form, norm_name);
+
+ if (error) {
trx_commit_for_mysql(trx);
@@ -2866,7 +2640,9 @@ innobase_drop_database(
memcpy(namebuf, ptr, len);
namebuf[len] = '/';
namebuf[len + 1] = '\0';
-
+#ifdef __WIN__
+ casedn_str(namebuf);
+#endif
trx = trx_allocate_for_mysql();
error = row_drop_database_for_mysql(namebuf, trx);
@@ -2981,9 +2757,9 @@ ha_innobase::records_in_range(
DBUG_ENTER("records_in_range");
- if (prebuilt->trx) {
- prebuilt->trx->op_info = (char*) "estimating range size";
- }
+ /* Warning: since it is not sure that MySQL calls external_lock
+ before calling this function, the trx field in prebuilt can be
+ obsolete! */
active_index = keynr;
@@ -3017,10 +2793,6 @@ ha_innobase::records_in_range(
my_free((char*) key_val_buff2, MYF(0));
- if (prebuilt->trx) {
- prebuilt->trx->op_info = (char*) "";
- }
-
DBUG_RETURN((ha_rows) n_rows);
}
@@ -3041,10 +2813,9 @@ ha_innobase::estimate_number_of_rows(void)
ulonglong estimate;
ulonglong data_file_length;
- if (prebuilt->trx) {
- prebuilt->trx->op_info =
- (char*) "estimating upper bound of table size";
- }
+ /* Warning: since it is not sure that MySQL calls external_lock
+ before calling this function, the trx field in prebuilt can be
+ obsolete! */
DBUG_ENTER("info");
@@ -3061,10 +2832,6 @@ ha_innobase::estimate_number_of_rows(void)
estimate = 2 * data_file_length / dict_index_calc_min_rec_len(index);
- if (prebuilt->trx) {
- prebuilt->trx->op_info = (char*) "";
- }
-
DBUG_RETURN((ha_rows) estimate);
}
@@ -3080,10 +2847,12 @@ ha_innobase::scan_time()
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- /* In the following formula we assume that scanning 10 pages
- takes the same time as a disk seek: */
-
- return((double) (prebuilt->table->stat_clustered_index_size / 10));
+ /* Since MySQL seems to favor table scans too much over index
+ searches, we pretend that a sequential read takes the same time
+ as a random disk read, that is, we do not divide the following
+ by 10, which would be physically realistic. */
+
+ return((double) (prebuilt->table->stat_clustered_index_size));
}
/*************************************************************************
@@ -3104,9 +2873,9 @@ ha_innobase::info(
DBUG_ENTER("info");
- if (prebuilt->trx) {
- prebuilt->trx->op_info = (char*) "calculating table stats";
- }
+ /* Warning: since it is not sure that MySQL calls external_lock
+ before calling this function, the trx field in prebuilt can be
+ obsolete! */
ib_table = prebuilt->table;
@@ -3154,25 +2923,17 @@ ha_innobase::info(
index->stat_n_diff_key_vals[j + 1]);
}
+ /* Since MySQL seems to favor table scans
+ too much over index searches, we pretend
+ index selectivity is 2 times better than
+ our estimate: */
+
+ rec_per_key = rec_per_key / 2;
+
if (rec_per_key == 0) {
rec_per_key = 1;
}
- /* Since the MySQL optimizer is often too
- pessimistic in the assumption that a table
- does not fit in the buffer pool, we
- increase the attractiveness of indexes
- by assuming the selectivity of any prefix
- of an index is 1 / 100 or better.
- (Actually, we should look at the table
- size, and if the table is smaller than
- the buffer pool, we should uniformly
- increase the attractiveness of indexes,
- regardless of the estimated selectivity.) */
-
- if (rec_per_key > records / 100) {
- rec_per_key = records / 100;
- }
table->key_info[i].rec_per_key[j]
= rec_per_key;
}
@@ -3188,15 +2949,13 @@ ha_innobase::info(
pointer and cause a seg fault. */
if (flag & HA_STATUS_ERRKEY) {
+ ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
+
errkey = (unsigned int) row_get_mysql_key_number_for_index(
(dict_index_t*)
trx_get_error_info(prebuilt->trx));
}
- if (prebuilt->trx) {
- prebuilt->trx->op_info = (char*) "";
- }
-
DBUG_VOID_RETURN;
}
@@ -3217,6 +2976,8 @@ ha_innobase::check(
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
ulint ret;
+ ut_a(prebuilt->trx && prebuilt->trx->magic_n == TRX_MAGIC_N);
+
if (prebuilt->mysql_template == NULL) {
/* Build the template; we will use a dummy template
in index scans done in checking */
@@ -3250,6 +3011,10 @@ ha_innobase::update_table_comment(
char* str = my_malloc(length + 550, MYF(0));
char* pos;
+ /* Warning: since it is not sure that MySQL calls external_lock
+ before calling this function, the trx field in prebuilt can be
+ obsolete! */
+
if (!str) {
return((char*)comment);
}
@@ -3264,11 +3029,104 @@ ha_innobase::update_table_comment(
pos += sprintf(pos, "InnoDB free: %lu kB",
(ulong) innobase_get_free_space());
- /* We assume 150 bytes of space to print info */
+ /* We assume 450 - length bytes of space to print info */
+
+ if (length < 450) {
+ dict_print_info_on_foreign_keys(FALSE, pos, 450 - length,
+ prebuilt->table);
+ }
+
+ return(str);
+}
+
+/***********************************************************************
+Gets the foreign key create info for a table stored in InnoDB. */
+
+char*
+ha_innobase::get_foreign_key_create_info(void)
+/*==========================================*/
+ /* out, own: character string in the form which
+ can be inserted to the CREATE TABLE statement,
+ MUST be freed with ::free_foreign_key_create_info */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ char* str;
+
+ if (prebuilt == NULL) {
+ fprintf(stderr,
+"InnoDB: Error: cannot get create info for foreign keys\n");
+
+ return(NULL);
+ }
+
+ str = (char*)ut_malloc(10000);
- dict_print_info_on_foreign_keys(pos, 500, prebuilt->table);
+ str[0] = '\0';
+
+ dict_print_info_on_foreign_keys(TRUE, str, 9000, prebuilt->table);
return(str);
+}
+
+/***********************************************************************
+Frees the foreign key create info for a table stored in InnoDB, if it is
+non-NULL. */
+
+void
+ha_innobase::free_foreign_key_create_info(
+/*======================================*/
+ char* str) /* in, own: create info string to free */
+{
+ if (str) {
+ ut_free(str);
+ }
+}
+
+/***********************************************************************
+Tells something additional to the handler about how to do things. */
+
+int
+ha_innobase::extra(
+/*===============*/
+ /* out: 0 or error number */
+ enum ha_extra_function operation)
+ /* in: HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE */
+{
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+
+ /* Warning: since it is not sure that MySQL calls external_lock
+ before calling this function, the trx field in prebuilt can be
+ obsolete! */
+
+ switch (operation) {
+ case HA_EXTRA_RESET:
+ case HA_EXTRA_RESET_STATE:
+ prebuilt->read_just_key = 0;
+ break;
+ case HA_EXTRA_NO_KEYREAD:
+ prebuilt->read_just_key = 0;
+ break;
+ case HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE:
+ prebuilt->hint_no_need_to_fetch_extra_cols = FALSE;
+ break;
+ case HA_EXTRA_KEYREAD:
+ prebuilt->read_just_key = 1;
+ break;
+ default:/* Do nothing */
+ ;
+ }
+
+ return(0);
+}
+
+/**********************************************************************
+????????????? */
+
+int
+ha_innobase::reset(void)
+/*====================*/
+{
+ return(0);
}
/**********************************************************************
@@ -3296,7 +3154,7 @@ ha_innobase::external_lock(
trx = prebuilt->trx;
prebuilt->sql_stat_start = TRUE;
- prebuilt->in_update_remember_pos = TRUE;
+ prebuilt->hint_no_need_to_fetch_extra_cols = TRUE;
prebuilt->read_just_key = 0;
@@ -3315,6 +3173,16 @@ ha_innobase::external_lock(
thd->transaction.all.innodb_active_trans = 1;
trx->n_mysql_tables_in_use++;
+ if (thd->tx_isolation == ISO_SERIALIZABLE
+ && prebuilt->select_lock_type == LOCK_NONE) {
+
+ /* To get serializable execution we let InnoDB
+ conceptually add 'LOCK IN SHARE MODE' to all SELECTs
+ which otherwise would have been consistent reads */
+
+ prebuilt->select_lock_type = LOCK_S;
+ }
+
if (prebuilt->select_lock_type != LOCK_NONE) {
trx->mysql_n_tables_locked++;
@@ -3422,8 +3290,8 @@ ha_innobase::store_lock(
lock_type == TL_READ_NO_INSERT) {
/* This is a SELECT ... IN SHARE MODE, or
we are doing a complex SQL statement like
- INSERT INTO ... SELECT ... and the logical logging
- requires the use of a locking read */
+ INSERT INTO ... SELECT ... and the logical logging (MySQL
+ binlog) requires the use of a locking read */
prebuilt->select_lock_type = LOCK_S;
} else {
@@ -3463,38 +3331,59 @@ ha_innobase::get_auto_increment()
/*=============================*/
/* out: the next auto-increment column value */
{
- row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- longlong nr;
- int error;
+ row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
+ longlong nr;
+ int error;
- (void) extra(HA_EXTRA_KEYREAD);
- index_init(table->next_number_index);
+ /* Also SHOW TABLE STATUS calls this function. Previously, when we did
+ always read the max autoinc key value, setting x-locks, users were
+ surprised that SHOW TABLE STATUS could end up in a deadlock with
+ ordinary SQL queries. We avoid these deadlocks if the auto-inc
+ counter for the table has been initialized by fetching the value
+ from the table struct in dictionary cache. */
- /* We use an exclusive lock when we read the max key value from the
- auto-increment column index. This is because then build_template will
- advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
- id of the auto-increment column is not changed, and previously InnoDB
- did not fetch it, causing SHOW TABLE STATUS to show wrong values
- for the autoinc column. */
+ assert(prebuilt->table);
+
+ nr = dict_table_autoinc_read(prebuilt->table);
- prebuilt->select_lock_type = LOCK_X;
- prebuilt->trx->mysql_n_tables_locked += 1;
+ if (nr != 0) {
- error=index_last(table->record[1]);
+ return(nr + 1);
+ }
- if (error) {
- nr = 1;
- } else {
- nr = (longlong) table->next_number_field->
- val_int_offset(table->rec_buff_length) + 1;
- }
+ (void) extra(HA_EXTRA_KEYREAD);
+ index_init(table->next_number_index);
- (void) extra(HA_EXTRA_NO_KEYREAD);
+ /* We use an exclusive lock when we read the max key value from the
+ auto-increment column index. This is because then build_template will
+ advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
+ id of the auto-increment column is not changed, and previously InnoDB
+ did not fetch it, causing SHOW TABLE STATUS to show wrong values
+ for the autoinc column. */
- index_end();
+ prebuilt->select_lock_type = LOCK_X;
- return(nr);
-}
+ /* Play safe and also give in another way the hint to fetch
+ all columns in the key: */
+
+ prebuilt->hint_no_need_to_fetch_extra_cols = FALSE;
+
+ prebuilt->trx->mysql_n_tables_locked += 1;
+
+ error = index_last(table->record[1]);
+
+ if (error) {
+ nr = 1;
+ } else {
+ nr = (longlong) table->next_number_field->
+ val_int_offset(table->rec_buff_length) + 1;
+ }
+
+ (void) extra(HA_EXTRA_NO_KEYREAD);
+ index_end();
+
+ return(nr);
+}
#endif /* HAVE_INNOBASE_DB */
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index f926f303b26..a0f3ea28d2c 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -158,7 +158,8 @@ class ha_innobase: public handler
int rename_table(const char* from, const char* to);
int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment);
-
+ char* get_foreign_key_create_info();
+ void free_foreign_key_create_info(char* str);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
longlong get_auto_increment();
@@ -178,8 +179,9 @@ extern long innobase_force_recovery, innobase_thread_concurrency;
extern char *innobase_data_home_dir, *innobase_data_file_path;
extern char *innobase_log_group_home_dir, *innobase_log_arch_dir;
extern char *innobase_unix_file_flush_method;
-extern bool innobase_flush_log_at_trx_commit, innobase_log_archive,
- innobase_use_native_aio, innobase_fast_shutdown;
+/* The following variables have to be my_bool for SHOW VARIABLES to work */
+extern my_bool innobase_flush_log_at_trx_commit, innobase_log_archive,
+ innobase_use_native_aio, innobase_fast_shutdown;
extern TYPELIB innobase_lock_typelib;
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index 4b8c40f8fe6..7c9c7a64c9d 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -201,7 +201,7 @@ void ha_isam::info(uint flag)
sortkey = info.sortkey;
block_size=nisam_block_size;
table->keys = min(table->keys,info.keys);
- table->keys_in_use= (((key_map) 1) << table->keys)- (key_map) 1;
+ table->keys_in_use= set_bits(key_map,table->keys);
table->db_options_in_use= info.options;
table->db_record_offset=
(table->db_options_in_use &
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 78ac9f3b309..df55cdd0033 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -289,7 +289,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
error = chk_key(&param, file);
if (!error)
{
- if ((!check_opt->quick &&
+ if ((!(param.testflag & T_QUICK) &&
((share->options &
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ||
(param.testflag & (T_EXTEND | T_MEDIUM)))) ||
@@ -330,7 +330,6 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
mi_mark_crashed(file);
file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
- check_opt->retry_without_quick=param.retry_without_quick;
thd->proc_info=old_proc_info;
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
@@ -397,8 +396,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
}
tmp_check_opt.init();
- tmp_check_opt.quick = 1;
- tmp_check_opt.flags |= T_VERY_SILENT | T_CALC_CHECKSUM;
+ tmp_check_opt.flags |= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
DBUG_RETURN(repair(thd, &tmp_check_opt));
err:
@@ -488,24 +486,23 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
myisamchk_init(&param);
param.thd = thd;
param.op_name = (char*) "repair";
- param.testflag = ((check_opt->flags & ~(T_EXTEND)) |
+ param.testflag = ((check_opt->flags & ~(T_EXTEND)) |
T_SILENT | T_FORCE_CREATE |
(check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT));
- if (check_opt->quick)
- param.opt_rep_quick++;
param.sort_buffer_length= check_opt->sort_buffer_size;
start_records=file->state->records;
while ((error=repair(thd,param,0)) && param.retry_repair)
{
param.retry_repair=0;
- if (param.retry_without_quick && param.opt_rep_quick)
+ if ((param.testflag & T_RETRY_WITHOUT_QUICK) &&
+ (param.testflag & T_QUICK))
{
- param.opt_rep_quick=0;
+ param.testflag&= ~T_RETRY_WITHOUT_QUICK;
sql_print_error("Warning: Retrying repair of: '%s' without quick",
table->path);
continue;
}
- param.opt_rep_quick=0; // Safety
+ param.testflag&= ~T_QUICK;
if ((param.testflag & T_REP_BY_SORT))
{
param.testflag= (param.testflag & ~T_REP_BY_SORT) | T_REP;
@@ -537,8 +534,6 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt)
param.op_name = (char*) "optimize";
param.testflag = (check_opt->flags | T_SILENT | T_FORCE_CREATE |
T_REP_BY_SORT | T_STATISTICS | T_SORT_INDEX);
- if (check_opt->quick)
- param.opt_rep_quick++;
param.sort_buffer_length= check_opt->sort_buffer_size;
return repair(thd,param,1);
}
@@ -573,7 +568,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
if (!optimize ||
((file->state->del || share->state.split != file->state->records) &&
- (!param.opt_rep_quick ||
+ (!(param.testflag & T_QUICK) ||
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
{
ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
@@ -587,13 +582,15 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
param.testflag|= T_STATISTICS; // We get this for free
thd->proc_info="Repair by sorting";
statistics_done=1;
- error = mi_repair_by_sort(&param, file, fixed_name, param.opt_rep_quick);
+ error = mi_repair_by_sort(&param, file, fixed_name,
+ param.testflag & T_QUICK);
}
else
{
thd->proc_info="Repair with keycache";
param.testflag &= ~T_REP_BY_SORT;
- error= mi_repair(&param, file, fixed_name, param.opt_rep_quick);
+ error= mi_repair(&param, file, fixed_name,
+ param.testflag & T_QUICK);
}
param.testflag=testflag;
optimize_done=1;
@@ -691,17 +688,16 @@ bool ha_myisam::activate_all_index(THD *thd)
mi_extra(file, HA_EXTRA_BULK_INSERT_END);
if (enable_activate_all_index &&
- share->state.key_map != ((ulonglong) 1L << share->base.keys)-1)
+ share->state.key_map != set_bits(ulonglong, share->base.keys))
{
const char *save_proc_info=thd->proc_info;
thd->proc_info="Creating index";
myisamchk_init(&param);
param.op_name = (char*) "recreating_index";
- param.testflag = (T_SILENT | T_REP_BY_SORT |
+ param.testflag = (T_SILENT | T_REP_BY_SORT | T_QUICK |
T_CREATE_MISSING_KEYS | T_TRUST_HEADER);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= myisam_sort_buffer_size;
- param.opt_rep_quick++; // Don't copy data file
param.tmpdir=mysql_tmpdir;
error=repair(thd,param,0) != HA_ADMIN_OK;
thd->proc_info=save_proc_info;
@@ -723,16 +719,16 @@ bool ha_myisam::check_and_repair(THD *thd)
check_opt.flags= T_MEDIUM | T_AUTO_REPAIR;
// Don't use quick if deleted rows
if (!file->state->del && (myisam_recover_options & HA_RECOVER_QUICK))
- check_opt.quick=1;
+ check_opt.flags|=T_QUICK;
sql_print_error("Warning: Checking table: '%s'",table->path);
if ((marked_crashed=mi_is_crashed(file)) || check(thd, &check_opt))
{
sql_print_error("Warning: Recovering table: '%s'",table->path);
- check_opt.quick= !check_opt.retry_without_quick && !marked_crashed;
- check_opt.flags=(((myisam_recover_options & HA_RECOVER_BACKUP) ?
- T_BACKUP_DATA : 0) |
- (!(myisam_recover_options & HA_RECOVER_FORCE) ?
- T_SAFE_REPAIR : 0)) | T_AUTO_REPAIR;
+ check_opt.flags=
+ ((myisam_recover_options & HA_RECOVER_BACKUP ? T_BACKUP_DATA : 0) |
+ (marked_crashed ? 0 : T_QUICK) |
+ (myisam_recover_options & HA_RECOVER_FORCE ? 0 : T_SAFE_REPAIR) |
+ T_AUTO_REPAIR);
if (repair(thd, &check_opt))
error=1;
}
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 63a23fb708f..4e09c87f341 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -46,7 +46,7 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
return (my_errno ? my_errno : -1);
}
DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc..."))
- myrg_extrafunc(file, &query_cache_invalidate_by_MyISAM_filename);
+ myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK);
@@ -189,7 +189,7 @@ void ha_myisammrg::info(uint flag)
deleted = (ha_rows) info.deleted;
data_file_length=info.data_file_length;
errkey = info.errkey;
- table->keys_in_use=(((key_map) 1) << table->keys)- (key_map) 1;
+ table->keys_in_use= set_bits(key_map, table->keys);
table->db_options_in_use = info.options;
table->is_view=1;
mean_rec_length=info.reclength;
diff --git a/sql/handler.cc b/sql/handler.cc
index 1e879c55b5e..178f631569d 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -45,6 +45,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;
const char *ha_table_type[] = {
@@ -221,28 +222,31 @@ int ha_autocommit_or_rollback(THD *thd, int error)
DBUG_RETURN(error);
}
-/* This function is called when MySQL writes the log segment of a transaction
-to the binlog. It is called when the LOCK_log mutex is reserved. Here we
-communicate to transactional table handlers whta binlog position corresponds
-to the current transaction. The handler can store it and in recovery print
-to the user, so that the user knows from what position in the binlog to
-start possible roll-forward, for example, if the crashed server was a slave
-in replication. This function also calls the commit of the table handler,
-because the order of trasnactions in the log of the table handler must be
-the same as in the binlog. */
+/*
+ This function is called when MySQL writes the log segment of a
+ transaction to the binlog. It is called when the LOCK_log mutex is
+ reserved. Here we communicate to transactional table handlers what
+ binlog position corresponds to the current transaction. The handler
+ can store it and in recovery print to the user, so that the user
+ knows from what position in the binlog to start possible
+ roll-forward, for example, if the crashed server was a slave in
+ replication. This function also calls the commit of the table
+ handler, because the order of transactions in the log of the table
+ handler must be the same as in the binlog.
+
+ arguments:
+ log_file_name: latest binlog file name
+ end_offset: the offset in the binlog file up to which we wrote
+*/
-int ha_report_binlog_offset_and_commit(
- THD *thd, /* in: user thread */
- char *log_file_name, /* in: latest binlog file name */
- my_off_t end_offset) /* in: the offset in the binlog file
- up to which we wrote */
+int ha_report_binlog_offset_and_commit(THD *thd,
+ char *log_file_name,
+ my_off_t end_offset)
{
+ int error= 0;
+#ifdef HAVE_INNOBASE_DB
THD_TRANS *trans;
- int error = 0;
-
trans = &thd->transaction.all;
-
-#ifdef HAVE_INNOBASE_DB
if (trans->innobase_tid)
{
if ((error=innobase_report_binlog_offset_and_commit(thd,
@@ -256,7 +260,6 @@ int ha_report_binlog_offset_and_commit(
trans->innodb_active_trans=0;
}
#endif
-
return error;
}
@@ -267,6 +270,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
+ bool operation_done= 0;
+ bool transaction_commited= 0;
/* Update the binary log if we have cached some queries */
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
my_b_tell(&thd->transaction.trans_log))
@@ -284,6 +289,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
my_error(ER_ERROR_DURING_COMMIT, MYF(0), error);
error=1;
}
+ else
+ transaction_commited= 1;
trans->bdb_tid=0;
}
#endif
@@ -297,12 +304,19 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
}
trans->innodb_active_trans=0;
if (trans == &thd->transaction.all)
- query_cache.invalidate(Query_cache_table::INNODB);
+ operation_done= transaction_commited= 1;
+
}
#endif
+#ifdef HAVE_QUERY_CACHE
+ if (transaction_commited)
+ query_cache.invalidate(thd->transaction.changed_tables);
+#endif /*HAVE_QUERY_CACHE*/
if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
sql_print_error("Error: Got error during commit; Binlog is not up to date!");
thd->tx_isolation=thd->session_tx_isolation;
+ if (operation_done)
+ statistic_increment(ha_commit_count,&LOCK_status);
}
#endif // using transactions
DBUG_RETURN(error);
@@ -316,6 +330,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
+ bool operation_done=0;
#ifdef HAVE_BERKELEY_DB
if (trans->bdb_tid)
{
@@ -325,6 +340,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
error=1;
}
trans->bdb_tid=0;
+ operation_done=1;
}
#endif
#ifdef HAVE_INNOBASE_DB
@@ -336,6 +352,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
error=1;
}
trans->innodb_active_trans=0;
+ operation_done=1;
}
#endif
if (trans == &thd->transaction.all)
@@ -343,6 +360,8 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
WRITE_CACHE, (my_off_t) 0, 0, 1);
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
thd->tx_isolation=thd->session_tx_isolation;
+ if (operation_done)
+ statistic_increment(ha_rollback_count,&LOCK_status);
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
@@ -527,7 +546,8 @@ int handler::read_first_row(byte * buf, uint primary_key)
If there is very few deleted rows in the table, find the first row by
scanning the table.
*/
- if (deleted < 10 || primary_key >= MAX_KEY)
+ if (deleted < 10 || primary_key >= MAX_KEY ||
+ !(option_flag() & HA_READ_ORDER))
{
(void) rnd_init();
while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
diff --git a/sql/handler.h b/sql/handler.h
index b083465afc5..868badf4d49 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -174,14 +174,11 @@ extern ulong myisam_sort_buffer_size;
typedef struct st_ha_check_opt
{
ulong sort_buffer_size;
- uint flags;
- bool quick;
- bool changed_files;
- bool optimize;
- bool retry_without_quick;
+ uint flags; /* isam layer flags (e.g. for myisamchk) */
+ uint sql_flags; /* sql layer flags - for something myisamchk cannot do */
inline void init()
{
- flags= 0; quick= optimize= retry_without_quick=0;
+ flags= sql_flags= 0;
sort_buffer_size = myisam_sort_buffer_size;
}
} HA_CHECK_OPT;
@@ -311,7 +308,9 @@ public:
virtual char *update_table_comment(const char * comment)
{ return (char*) comment;}
virtual void append_create_info(String *packet) {}
-
+ virtual char* get_foreign_key_create_info()
+ { return(NULL);} /* gets foreign key create string from InnoDB */
+ virtual void free_foreign_key_create_info(char* str) {}
/* The following can be called without an open handler */
virtual const char *table_type() const =0;
virtual const char **bas_ext() const =0;
diff --git a/sql/item.cc b/sql/item.cc
index c081fd9dd5f..dac10eafafb 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -59,12 +59,28 @@ void Item::set_name(char *str,uint length)
}
}
-bool Item::eq(const Item *item) const // Only doing this on conds
+/*
+ This function is only called when comparing items in the WHERE clause
+*/
+
+bool Item::eq(const Item *item, bool binary_cmp) const
{
return type() == item->type() && name && item->name &&
!my_strcasecmp(name,item->name);
}
+bool Item_string::eq(const Item *item, bool binary_cmp) const
+{
+ if (type() == item->type())
+ {
+ if (binary_cmp)
+ return !stringcmp(&str_value, &item->str_value);
+ return !sortcmp(&str_value, &item->str_value);
+ }
+ return 0;
+}
+
+
/*
Get the value of the function as a TIME structure.
As a extra convenience the time structure is reset on error!
@@ -203,7 +219,7 @@ longlong Item_field::val_int_result()
return result_field->val_int();
}
-bool Item_field::eq(const Item *item) const
+bool Item_field::eq(const Item *item, bool binary_cmp) const
{
return item->type() == FIELD_ITEM && ((Item_field*) item)->field == field;
}
@@ -262,7 +278,8 @@ void Item_string::print(String *str)
str->append('\'');
}
-bool Item_null::eq(const Item *item) const { return item->type() == type(); }
+bool Item_null::eq(const Item *item, bool binary_cmp) const
+{ return item->type() == type(); }
double Item_null::val() { null_value=1; return 0.0; }
longlong Item_null::val_int() { null_value=1; return 0; }
/* ARGSUSED */
diff --git a/sql/item.h b/sql/item.h
index 5028f25c6b8..575af197e7d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -57,7 +57,7 @@ public:
virtual void save_org_in_field(Field *field)
{ (void) save_in_field(field); }
virtual bool send(THD *thd, String *str);
- virtual bool eq(const Item *) const;
+ virtual bool eq(const Item *, bool binary_cmp) const;
virtual Item_result result_type () const { return REAL_RESULT; }
virtual enum Type type() const =0;
virtual double val()=0;
@@ -111,7 +111,7 @@ public:
{}
Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; }
- bool eq(const Item *item) const;
+ bool eq(const Item *item, bool binary_cmp) const;
double val();
longlong val_int();
String *val_str(String*);
@@ -141,7 +141,7 @@ public:
Item_null(char *name_par=0)
{ maybe_null=null_value=TRUE; name= name_par ? name_par : (char*) "NULL";}
enum Type type() const { return NULL_ITEM; }
- bool eq(const Item *item) const;
+ bool eq(const Item *item, bool binary_cmp) const;
double val();
longlong val_int();
String *val_str(String *str);
@@ -264,6 +264,7 @@ public:
void make_field(Send_field *field);
enum Item_result result_type () const { return STRING_RESULT; }
bool basic_const_item() const { return 1; }
+ bool eq(const Item *item, bool binary_cmp) const;
Item *new_item() { return new Item_string(name,str_value.ptr(),max_length); }
String *const_string() { return &str_value; }
inline void append(char *str,uint length) { str_value.append(str,length); }
@@ -323,7 +324,8 @@ public:
Item_ref(Item **item, char *table_name_par,char *field_name_par)
:Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
enum Type type() const { return REF_ITEM; }
- bool eq(const Item *item) const { return (*ref)->eq(item); }
+ bool eq(const Item *item, bool binary_cmp) const
+ { return (*ref)->eq(item, binary_cmp); }
~Item_ref() { if (ref) delete *ref; }
double val()
{
@@ -343,6 +345,11 @@ public:
null_value=(*ref)->null_value;
return tmp;
}
+ bool is_null()
+ {
+ (void) (*ref)->val_int_result();
+ return (*ref)->null_value;
+ }
bool get_date(TIME *ltime,bool fuzzydate)
{
return (null_value=(*ref)->get_date(ltime,fuzzydate));
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 0c83698e60a..bb773af1ddf 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -790,8 +790,9 @@ String *Item_func_coalesce::val_str(String *str)
null_value=0;
for (uint i=0 ; i < arg_count ; i++)
{
- if (args[i]->val_str(str) != NULL)
- return args[i]->val_str(str);
+ String *res;
+ if ((res=args[i]->val_str(str)))
+ return res;
}
null_value=1;
return 0;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 1818a755a43..90e7a5a6477 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -148,7 +148,7 @@ void Item_func::print_op(String *str)
str->append(')');
}
-bool Item_func::eq(const Item *item) const
+bool Item_func::eq(const Item *item, bool binary_cmp) const
{
/* Assume we don't have rtti */
if (this == item)
@@ -160,7 +160,7 @@ bool Item_func::eq(const Item *item) const
func_name() != item_func->func_name())
return 0;
for (uint i=0; i < arg_count ; i++)
- if (!args[i]->eq(item_func->args[i]))
+ if (!args[i]->eq(item_func->args[i], binary_cmp))
return 0;
return 1;
}
@@ -1975,7 +1975,7 @@ void Item_func_get_user_var::print(String *str)
str->append(')');
}
-bool Item_func_get_user_var::eq(const Item *item) const
+bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
{
/* Assume we don't have rtti */
if (this == item)
@@ -2108,12 +2108,14 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
key=NO_SUCH_KEY;
const_item_cache=0;
table=((Item_field *)fields.head())->field->table;
+ table->fulltext_searched=1;
record=table->record[0];
if (key == NO_SUCH_KEY && mode != FT_BOOL)
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
return 1;
}
+
return 0;
}
@@ -2197,7 +2199,7 @@ err:
return 1;
}
-bool Item_func_match::eq(const Item *item) const
+bool Item_func_match::eq(const Item *item, bool binary_cmp) const
{
if (item->type() != FUNC_ITEM)
return 0;
@@ -2208,7 +2210,7 @@ bool Item_func_match::eq(const Item *item) const
Item_func_match *ifm=(Item_func_match*) item;
if (key == ifm->key && table == ifm->table &&
- key_item()->eq(ifm->key_item()))
+ key_item()->eq(ifm->key_item(), binary_cmp))
return 1;
return 0;
diff --git a/sql/item_func.h b/sql/item_func.h
index 823bfb44a96..c3e437712ee 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -98,7 +98,7 @@ public:
void make_field(Send_field *field);
table_map used_tables() const;
void update_used_tables();
- bool eq(const Item *item) const;
+ bool eq(const Item *item, bool binary_cmp) const;
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
virtual bool have_rev_func() const { return 0; }
virtual Item *key_item() const { return args[0]; }
@@ -889,7 +889,7 @@ public:
bool const_item() const { return const_var_flag; }
table_map used_tables() const
{ return const_var_flag ? 0 : RAND_TABLE_BIT; }
- bool eq(const Item *item) const;
+ bool eq(const Item *item, bool binary_cmp) const;
};
@@ -930,13 +930,14 @@ public:
ft_handler=0;
if(join_key)
table->file->ft_handler=0;
+ table->fulltext_searched=0;
}
if (concat) delete concat;
}
enum Functype functype() const { return FT_FUNC; }
void update_used_tables() {}
bool fix_fields(THD *thd,struct st_table_list *tlist);
- bool eq(const Item *) const;
+ bool eq(const Item *, bool binary_cmp) const;
longlong val_int() { return val()!=0.0; }
double val();
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index c64fdc7a049..602cd7e38be 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1921,18 +1921,21 @@ String* Item_func_inet_ntoa::val_str(String* str)
uchar buf[8], *p;
ulonglong n = (ulonglong) args[0]->val_int();
char num[4];
- // we do not know if args[0] is NULL until we have called
- // some val function on it if args[0] is not a constant!
+ /*
+ we do not know if args[0] is NULL until we have called
+ some val function on it if args[0] is not a constant!
+ */
if ((null_value=args[0]->null_value))
return 0; // Null value
+
str->length(0);
int8store(buf,n);
- // now we can assume little endian
- // we handle the possibility of an 8-byte IP address
- // however, we do not want to confuse those who are just using
- // 4 byte ones
-
+ /*
+ Now we can assume little endian.
+ We handle the possibility of an 8-byte IP address however, we do
+ not want to confuse those who are just using 4 byte ones
+ */
for (p= buf + 8; p > buf+4 && p[-1] == 0 ; p-- ) ;
num[3]='.';
while (p-- > buf)
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 4840ae8298d..a963799b6a7 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -64,6 +64,7 @@ public:
{ return new Item_field(field);}
table_map used_tables() const { return ~(table_map) 0; } /* Not used */
bool const_item() const { return 0; }
+ bool is_null() { return null_value; }
void update_used_tables() { }
void make_field(Send_field *field);
void print(String *str);
@@ -202,6 +203,7 @@ public:
enum Type type() const { return FIELD_AVG_ITEM; }
double val();
longlong val_int() { return (longlong) val(); }
+ bool is_null() { (void) val_int(); return null_value; }
String *val_str(String*);
void make_field(Send_field *field);
void fix_length_and_dec() {}
@@ -239,6 +241,7 @@ public:
double val();
longlong val_int() { return (longlong) val(); }
String *val_str(String*);
+ bool is_null() { (void) val_int(); return null_value; }
void make_field(Send_field *field);
void fix_length_and_dec() {}
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 8f55a02b020..9a003b79609 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -672,7 +672,7 @@ String *Item_func_date_format::val_str(String *str)
else
size=format_length(format);
if (format == str)
- str= &str_value; // Save result here
+ str= &value; // Save result here
if (str->alloc(size))
{
null_value=1;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 32b85e7f028..aa4140192ab 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -333,6 +333,7 @@ class Item_func_date_format :public Item_str_func
{
int fixed_length;
const bool date_or_time;
+ String value;
public:
Item_func_date_format(Item *a,Item *b,bool date_or_time_arg)
:Item_str_func(a,b),date_or_time(date_or_time_arg) {}
diff --git a/sql/lex.h b/sql/lex.h
index 6bee4152e48..8c7beb64b9b 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -62,8 +62,8 @@ static SYMBOL symbols[] = {
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
{ "AUTOCOMMIT", SYM(AUTOCOMMIT),0,0},
- { "BACKUP", SYM(BACKUP_SYM),0,0},
- { "BEGIN", SYM(BEGIN_SYM),0,0},
+ { "BACKUP", SYM(BACKUP_SYM),0,0},
+ { "BEGIN", SYM(BEGIN_SYM),0,0},
{ "BERKELEYDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BETWEEN", SYM(BETWEEN_SYM),0,0},
@@ -191,6 +191,7 @@ static SYMBOL symbols[] = {
{ "INT4", SYM(INT_SYM),0,0},
{ "INT8", SYM(BIGINT),0,0},
{ "INTO", SYM(INTO),0,0},
+ { "IO_THREAD", SYM(IO_THREAD),0,0},
{ "IF", SYM(IF),0,0},
{ "IS", SYM(IS),0,0},
{ "ISOLATION", SYM(ISOLATION),0,0},
@@ -279,6 +280,8 @@ static SYMBOL symbols[] = {
{ "READ", SYM(READ_SYM),0,0},
{ "REAL", SYM(REAL),0,0},
{ "REFERENCES", SYM(REFERENCES),0,0},
+ { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM),0,0},
+ { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM),0,0},
{ "RELOAD", SYM(RELOAD),0,0},
{ "REGEXP", SYM(REGEXP),0,0},
{ "RENAME", SYM(RENAME),0,0},
@@ -320,13 +323,14 @@ static SYMBOL symbols[] = {
{ "SQL_LOG_UPDATE", SYM(SQL_LOG_UPDATE),0,0},
{ "SQL_LOW_PRIORITY_UPDATES", SYM(SQL_LOW_PRIORITY_UPDATES),0,0},
{ "SQL_MAX_JOIN_SIZE",SYM(SQL_MAX_JOIN_SIZE), 0, 0},
- { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
+ { "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
{ "SQL_QUERY_CACHE_TYPE",SYM(SQL_QUERY_CACHE_TYPE_SYM), 0, 0},
{ "SQL_QUOTE_SHOW_CREATE",SYM(SQL_QUOTE_SHOW_CREATE), 0, 0},
{ "SQL_SAFE_UPDATES", SYM(SQL_SAFE_UPDATES),0,0},
{ "SQL_SELECT_LIMIT", SYM(SQL_SELECT_LIMIT),0,0},
{ "SQL_SLAVE_SKIP_COUNTER", SYM(SQL_SLAVE_SKIP_COUNTER),0,0},
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0},
+ { "SQL_THREAD", SYM(SQL_THREAD),0,0},
{ "SQL_WARNINGS", SYM(SQL_WARNINGS),0,0},
{ "SSL", SYM(SSL_SYM),0,0},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0},
@@ -359,6 +363,7 @@ static SYMBOL symbols[] = {
{ "UNLOCK", SYM(UNLOCK_SYM),0,0},
{ "UNSIGNED", SYM(UNSIGNED),0,0},
{ "USE", SYM(USE_SYM),0,0},
+ { "USE_FRM", SYM(USE_FRM),0,0},
{ "USING", SYM(USING),0,0},
{ "UPDATE", SYM(UPDATE_SYM),0,0},
{ "USAGE", SYM(USAGE),0,0},
diff --git a/sql/lock.cc b/sql/lock.cc
index 5d2856278b6..db849757741 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -88,6 +88,13 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
thd->locked=0;
break;
}
+ else if (!thd->open_tables)
+ {
+ // Only using temporary tables, no need to unlock
+ thd->some_tables_deleted=0;
+ thd->locked=0;
+ break;
+ }
/* some table was altered or deleted. reopen tables marked deleted */
mysql_unlock_tables(thd,sql_lock);
diff --git a/sql/log.cc b/sql/log.cc
index 892780d3882..c393d2eb413 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -83,7 +83,7 @@ static int find_uniq_filename(char *name)
MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1),
name(0), log_type(LOG_CLOSED),write_error(0),
inited(0), file_id(1),no_rotate(0),
- need_start_event(1)
+ need_start_event(1),bytes_written(0)
{
/*
We don't want to intialize LOCK_Log here as the thread system may
@@ -99,6 +99,7 @@ MYSQL_LOG::~MYSQL_LOG()
{
(void) pthread_mutex_destroy(&LOCK_log);
(void) pthread_mutex_destroy(&LOCK_index);
+ (void) pthread_cond_destroy(&update_cond);
}
}
@@ -233,17 +234,14 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
}
else if (log_type == LOG_BIN)
{
- bool error;
- /*
- Explanation of the boolean black magic:
- if we are supposed to write magic number try write
- clean up if failed
- then if index_file has not been previously opened, try to open it
- clean up if failed
- */
- if ((do_magic && my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4)) ||
+ bool error;
+ if (do_magic)
+ {
+ if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, 4) ||
open_index(O_APPEND | O_RDWR | O_CREAT))
- goto err;
+ goto err;
+ bytes_written += 4;
+ }
if (need_start_event && !no_auto_events)
{
@@ -461,12 +459,30 @@ err:
my_delete(fname, MYF(0)); // do not report error if the file is not there
else
{
+ MY_STAT s;
my_close(index_file, MYF(MY_WME));
+ if (!my_stat(rli->relay_log_name,&s,MYF(0)))
+ {
+ sql_print_error("The first log %s failed to stat during purge",
+ rli->relay_log_name);
+ error=1;
+ goto err;
+ }
if (my_rename(fname,index_file_name,MYF(MY_WME)) ||
(index_file=my_open(index_file_name,O_BINARY|O_RDWR|O_APPEND,
MYF(MY_WME)))<0 ||
my_delete(rli->relay_log_name, MYF(MY_WME)))
error=1;
+
+ pthread_mutex_lock(&rli->log_space_lock);
+ rli->log_space_total -= s.st_size;
+ fprintf(stderr,"purge_first_log: %ld\n", rli->log_space_total);
+ pthread_mutex_unlock(&rli->log_space_lock);
+ // ok to broadcast after the critical region as there is no risk of
+ // the mutex being destroyed by this thread later - this helps save
+ // context switches
+ pthread_cond_broadcast(&rli->log_space_cond);
+
if ((error=find_first_log(&rli->linfo,"",0/*no mutex*/)))
{
char buff[22];
@@ -478,6 +494,7 @@ err:
rli->relay_log_pos = 4;
strnmov(rli->relay_log_name,rli->linfo.log_file_name,
sizeof(rli->relay_log_name));
+ flush_relay_log_info(rli);
}
/*
No need to free io_buf because we allocated both fname and io_buf in
@@ -693,6 +710,7 @@ void MYSQL_LOG::new_file(bool inside_mutex)
if (thd && thd->slave_thread)
r.flags |= LOG_EVENT_FORCED_ROTATE_F;
r.write(&log_file);
+ bytes_written += r.get_event_len();
}
// update needs to be signaled even if there is no rotate event
// log rotation should give the waiting thread a signal to
@@ -726,6 +744,7 @@ bool MYSQL_LOG::append(Log_event* ev)
error=1;
goto err;
}
+ bytes_written += ev->get_event_len();
if ((uint)my_b_append_tell(&log_file) > max_binlog_size)
{
new_file(1);
@@ -752,6 +771,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
error = 1;
break;
}
+ bytes_written += len;
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
if ((uint) my_b_append_tell(&log_file) > max_binlog_size)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 648e9175e13..fd04f8dbbaa 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -556,6 +556,8 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
ev = new Query_log_event(buf, event_len, old_format);
break;
case LOAD_EVENT:
+ ev = new Create_file_log_event(buf, event_len, old_format);
+ break;
case NEW_LOAD_EVENT:
ev = new Load_log_event(buf, event_len, old_format);
break;
@@ -566,7 +568,7 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
ev = new Slave_log_event(buf, event_len);
break;
case CREATE_FILE_EVENT:
- ev = new Create_file_log_event(buf, event_len);
+ ev = new Create_file_log_event(buf, event_len, old_format);
break;
case APPEND_BLOCK_EVENT:
ev = new Append_block_log_event(buf, event_len);
@@ -959,6 +961,12 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool 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) ||
@@ -970,11 +978,11 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
else
{
field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
- *field_term=*buf++;
- *enclosed= *buf++;
- *line_term= *buf++;
- *line_start=*buf++;
- *escaped= *buf++;
+ field_term = buf++;
+ enclosed= buf++;
+ line_term= buf++;
+ line_start= buf++;
+ escaped= buf++;
opt_flags = *buf++;
empty_flags=*buf++;
if (empty_flags & FIELD_TERM_EMPTY)
@@ -1095,7 +1103,9 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
db_len = (uint)data_head[L_DB_LEN_OFFSET];
num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET);
- int body_offset = get_data_body_offset();
+ int body_offset = (buf[EVENT_TYPE_OFFSET] == LOAD_EVENT) ?
+ LOAD_HEADER_LEN + OLD_HEADER_LEN : get_data_body_offset();
+
if ((int) event_len < body_offset)
return 1;
//sql_ex.init() on success returns the pointer to the first byte after
@@ -1117,7 +1127,6 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
table_name = fields + field_block_len;
db = table_name + table_name_len + 1;
fname = db + db_len + 1;
- int type_code = get_type_code();
fname_len = strlen(fname);
// null termination is accomplished by the caller doing buf[event_len]=0
return 0;
@@ -1367,20 +1376,29 @@ int Create_file_log_event::write_base(IO_CACHE* file)
return res;
}
-Create_file_log_event::Create_file_log_event(const char* buf, int len):
- Load_log_event(buf,0,0),fake_base(0),block(0)
+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,0))
- return;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
- + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
- block_offset = LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
- CREATE_FILE_HEADER_LEN + 1; // 1 for \0 terminating fname
- if (len < block_offset)
+ if (copy_log_event(buf,len,old_format))
return;
- block = (char*)buf + block_offset;
- block_len = len - block_offset;
+ if (!old_format)
+ {
+ file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
+ + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
+ block_offset = LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
+ CREATE_FILE_HEADER_LEN + 1; // 1 for \0 terminating fname
+ 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;
+ }
}
@@ -1568,6 +1586,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
int expected_error,actual_error = 0;
init_sql_alloc(&thd->mem_root, 8192,0);
thd->db = rewrite_db((char*)db);
+ DBUG_ASSERT(q_len == strlen(query));
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->query = (char*)query;
@@ -1588,7 +1607,9 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
{
mysql_parse(thd, thd->query, q_len);
if (expected_error !=
- (actual_error = thd->net.last_errno) && 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)";
@@ -1739,11 +1760,12 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
int Start_log_event::exec_event(struct st_relay_log_info* rli)
{
+ close_temporary_tables(thd);
+ // if we have old format, load_tmpdir is cleaned up by the I/O thread
+ // TODO: cleanup_load_tmpdir() needs to remove only the files associated
+ // with the server id that has just started
if (!rli->mi->old_format)
- {
- close_temporary_tables(thd);
cleanup_load_tmpdir();
- }
return Log_event::exec_event(rli);
}
diff --git a/sql/log_event.h b/sql/log_event.h
index 089d9589763..a29c3952d46 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -64,6 +64,8 @@ struct old_sql_ex
char empty_flags;
};
+#define NUM_LOAD_DELIM_STRS 5
+
struct sql_ex_info
{
@@ -153,8 +155,8 @@ struct sql_ex_info
#define L_THREAD_ID_OFFSET 0
#define L_EXEC_TIME_OFFSET 4
#define L_SKIP_LINES_OFFSET 8
-#define L_DB_LEN_OFFSET 12
-#define L_TBL_LEN_OFFSET 13
+#define L_TBL_LEN_OFFSET 12
+#define L_DB_LEN_OFFSET 13
#define L_NUM_FIELDS_OFFSET 14
#define L_SQL_EX_OFFSET 18
#define L_DATA_OFFSET LOAD_HEADER_LEN
@@ -570,6 +572,7 @@ public:
char* block;
uint block_len;
uint file_id;
+ bool inited_from_old;
#ifndef MYSQL_CLIENT
Create_file_log_event(THD* thd, sql_exchange* ex, const char* db_arg,
const char* table_name_arg,
@@ -578,7 +581,7 @@ public:
char* block_arg, uint block_len_arg);
#endif
- Create_file_log_event(const char* buf, int event_len);
+ Create_file_log_event(const char* buf, int event_len, bool old_format);
~Create_file_log_event()
{
}
@@ -591,7 +594,7 @@ public:
4 + 1 + block_len;}
int get_data_body_offset() { return fake_base ? LOAD_EVENT_OVERHEAD:
LOAD_EVENT_OVERHEAD + CREATE_FILE_HEADER_LEN; }
- bool is_valid() { return block != 0; }
+ bool is_valid() { return inited_from_old || block != 0; }
int write_data_header(IO_CACHE* file);
int write_data_body(IO_CACHE* file);
int write_base(IO_CACHE* file); // cut out Create_file extentions and
diff --git a/sql/my_lock.c b/sql/my_lock.c
index 9b4ac502e57..4d451fcff22 100644
--- a/sql/my_lock.c
+++ b/sql/my_lock.c
@@ -26,10 +26,6 @@
#include <thr_alarm.h>
#include <errno.h>
-#ifdef HAVE_FCNTL
-static struct flock lock; /* Must be static for sun-sparc */
-#endif
-
/* Lock a part of a file */
int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags)
@@ -37,24 +33,25 @@ int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags)
thr_alarm_t alarmed;
ALARM alarm_buff;
uint wait_for_alarm;
+ struct flock m_lock;
DBUG_ENTER("my_lock");
DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
fd,locktype,(ulong) start,(ulong) length,MyFlags));
if (my_disable_locking)
DBUG_RETURN(0); /* purecov: inspected */
- lock.l_type=(short) locktype;
- lock.l_whence=0L;
- lock.l_start=(long) start;
- lock.l_len=(long) length;
+ m_lock.l_type=(short) locktype;
+ m_lock.l_whence=0L;
+ m_lock.l_start=(long) start;
+ m_lock.l_len=(long) length;
wait_for_alarm=(MyFlags & MY_DONT_WAIT ? MY_HOW_OFTEN_TO_ALARM :
(uint) 12*60*60);
- if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
+ if (fcntl(fd,F_SETLK,&m_lock) != -1) /* Check if we can lock */
DBUG_RETURN(0); /* Ok, file locked */
DBUG_PRINT("info",("Was locked, trying with alarm"));
if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff))
{
int value;
- while ((value=fcntl(fd,F_SETLKW,&lock)) && !thr_got_alarm(&alarmed) &&
+ while ((value=fcntl(fd,F_SETLKW,&m_lock)) && !thr_got_alarm(&alarmed) &&
errno == EINTR) ;
thr_end_alarm(&alarmed);
if (value != -1)
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 81604a7ecfd..12249d2292c 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -48,6 +48,7 @@ char *sql_strmake(const char *str,uint len);
gptr sql_memdup(const void * ptr,unsigned size);
void sql_element_free(void *ptr);
void kill_one_thread(THD *thd, ulong id);
+int net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
@@ -159,8 +160,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define OPTION_LOW_PRIORITY_UPDATES 8192
#define OPTION_WARNINGS 16384
#define OPTION_AUTO_IS_NULL 32768
-#define OPTION_ANSI_MODE 65536L
-#define OPTION_SAFE_UPDATES OPTION_ANSI_MODE*2
+#define OPTION_FOUND_COMMENT 65536L
+#define OPTION_SAFE_UPDATES OPTION_FOUND_COMMENT*2
#define OPTION_BUFFER_RESULT OPTION_SAFE_UPDATES*2
#define OPTION_BIN_LOG OPTION_BUFFER_RESULT*2
#define OPTION_NOT_AUTO_COMMIT OPTION_BIN_LOG*2
@@ -180,7 +181,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define SELECT_NO_UNLOCK (QUERY_NO_GOOD_INDEX_USED*2)
#define TMP_TABLE_ALL_COLUMNS (SELECT_NO_UNLOCK*2)
-
+/* Bits for different SQL modes modes (including ANSI mode) */
#define MODE_REAL_AS_FLOAT 1
#define MODE_PIPES_AS_CONCAT 2
#define MODE_ANSI_QUOTES 4
@@ -250,7 +251,33 @@ inline THD *_current_thd(void)
#include "item.h"
#include "sql_class.h"
#include "opt_range.h"
+
+#ifdef HAVE_QUERY_CACHE
#include "sql_cache.h"
+#define query_cache_store_query(A, B) query_cache.store_query(A, B)
+#define query_cache_destroy() query_cache.destroy()
+#define query_cache_result_size_limit(A) query_cache.result_size_limit(A)
+#define query_cache_resize(A) query_cache.resize(A)
+#define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C)
+#define query_cache_invalidate1(A) query_cache.invalidate(A)
+#define query_cache_send_result_to_client(A, B, C) \
+ query_cache.send_result_to_client(A, B, C)
+#define query_cache_invalidate_by_MyISAM_filename_ref \
+ &query_cache_invalidate_by_MyISAM_filename
+#else
+#define query_cache_store_query(A, B)
+#define query_cache_destroy()
+#define query_cache_result_size_limit(A)
+#define query_cache_resize(A)
+#define query_cache_invalidate3(A, B, C)
+#define query_cache_invalidate1(A)
+#define query_cache_send_result_to_client(A, B, C) 0
+#define query_cache_invalidate_by_MyISAM_filename_ref NULL
+
+#define query_cache_abort(A)
+#define query_cache_end_of_result(A)
+#define query_cache_invalidate_by_MyISAM_filename_ref NULL
+#endif /*HAVE_QUERY_CACHE*/
int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
@@ -582,11 +609,13 @@ extern pthread_cond_t COND_refresh,COND_thread_count;
extern pthread_attr_t connection_attrib;
extern bool opt_endinfo, using_udf_functions, locked_in_memory,
opt_using_transactions, use_temp_pool, mysql_embedded;
+extern bool opt_local_infile;
extern char f_fyllchar;
extern 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_read_rnd_count, ha_read_rnd_next_count;
+ ha_read_rnd_count, ha_read_rnd_next_count,
+ ha_commit_count, ha_rollback_count;
extern MY_BITMAP temp_pool;
extern uchar *days_in_month;
extern DATE_FORMAT dayord;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d5c3e6f1c6f..f787181174a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -38,7 +38,17 @@
#define ONE_THREAD
#endif
-/* do stack traces are only supported on linux intel */
+#ifdef SAFEMALLOC
+#define SHUTDOWN_THD shutdown_th=pthread_self();
+#define MAIN_THD main_th=pthread_self();
+#define SIGNAL_THD signal_th=pthread_self();
+#else
+#define SHUTDOWN_THD
+#define MAIN_THD
+#define SIGNAL_THD
+#endif
+
+/* stack traces are only supported on linux intel */
#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK)
#define HAVE_STACK_TRACE_ON_SEGV
#include "../pstack/pstack.h"
@@ -162,6 +172,7 @@ static SECURITY_DESCRIPTOR sdPipeDescriptor;
static HANDLE hPipe = INVALID_HANDLE_VALUE;
static pthread_cond_t COND_handler_count;
static uint handler_count;
+static bool opt_enable_named_pipe = 0;
#endif
#ifdef __WIN__
static bool opt_console=0,start_mode=0;
@@ -209,7 +220,11 @@ SHOW_COMP_OPTION have_openssl=SHOW_OPTION_YES;
SHOW_COMP_OPTION have_openssl=SHOW_OPTION_NO;
#endif
SHOW_COMP_OPTION have_symlink=SHOW_OPTION_YES;
-
+#ifdef HAVE_QUERY_CACHE
+SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_YES;
+#else
+SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO;
+#endif
bool opt_skip_slave_start = 0; // If set, slave is not autostarted
static bool opt_do_pstack = 0;
@@ -276,7 +291,11 @@ ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
ulong com_stat[(uint) SQLCOM_END], com_other;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
-ulong query_cache_size=0, query_cache_limit=0, query_cache_startup_type=1;
+#ifdef HAVE_QUERY_CACHE
+ulong query_cache_size=0, query_cache_limit=0, query_cache_startup_type=1;
+Query_cache query_cache;
+#endif
+
volatile ulong cached_thread_count=0;
// replication parameters, if master_host is not NULL, we are a slave
@@ -297,6 +316,7 @@ ulong bytes_sent = 0L, bytes_received = 0L;
bool opt_endinfo,using_udf_functions,low_priority_updates, locked_in_memory;
bool opt_using_transactions, using_update_log, opt_warnings=0;
+bool opt_local_infile=1;
bool volatile abort_loop,select_thread_in_use,grant_option;
bool volatile ready_to_exit,shutdown_in_progress;
ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */
@@ -369,8 +389,6 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_server_id,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
-Query_cache query_cache;
-
pthread_cond_t COND_refresh,COND_thread_count,COND_binlog_update,
COND_slave_stopped, COND_slave_start;
pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
@@ -481,13 +499,27 @@ static void close_connections(void)
}
}
#ifdef __NT__
- if ( hPipe != INVALID_HANDLE_VALUE )
+ if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
- HANDLE hTempPipe = &hPipe;
+ HANDLE temp;
DBUG_PRINT( "quit", ("Closing named pipes") );
- hPipe = INVALID_HANDLE_VALUE;
- DisconnectNamedPipe( hTempPipe );
- CloseHandle( hTempPipe );
+
+ /* Create connection to the handle named pipe handler to break the loop */
+ if ((temp = CreateFile(szPipeName,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL )) != INVALID_HANDLE_VALUE)
+ {
+ WaitNamedPipe(szPipeName, 1000);
+ DWORD dwMode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ SetNamedPipeHandleState(temp, &dwMode, NULL, NULL);
+ CancelIo(temp);
+ DisconnectNamedPipe(temp);
+ CloseHandle(temp);
+ }
}
#endif
#ifdef HAVE_SYS_UN_H
@@ -679,6 +711,7 @@ static void __cdecl kill_server(int sig_ptr)
sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */
#if defined(USE_ONE_SIGNAL_HAND) && !defined(__WIN__) && !defined(OS2)
+ SHUTDOWN_THD;
my_thread_init(); // If this is a new thread
#endif
close_connections();
@@ -694,6 +727,7 @@ static void __cdecl kill_server(int sig_ptr)
#ifdef USE_ONE_SIGNAL_HAND
static pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
{
+ SHUTDOWN_THD;
my_thread_init(); // Initialize new thread
kill_server(0);
my_thread_end(); // Normally never reached
@@ -708,8 +742,9 @@ static pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
static sig_handler print_signal_warning(int sig)
{
- sql_print_error("Warning: Got signal %d from thread %d",
- sig,my_thread_id());
+ if (opt_warnings)
+ sql_print_error("Warning: Got signal %d from thread %d",
+ sig,my_thread_id());
#ifdef DONT_REMEMBER_SIGNAL
sigset(sig,print_signal_warning); /* int. thread system calls */
#endif
@@ -749,7 +784,7 @@ void clean_up(bool print_message)
bitmap_free(&slave_error_mask);
acl_free(1);
grant_free();
- query_cache.destroy();
+ query_cache_destroy();
table_cache_free();
hostname_cache_free();
item_user_lock_free();
@@ -769,8 +804,10 @@ void clean_up(bool print_message)
my_free(opt_ssl_ca,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_ssl_capath,MYF(MY_ALLOW_ZERO_PTR));
my_free(opt_ssl_cipher,MYF(MY_ALLOW_ZERO_PTR));
+ my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
opt_ssl_key=opt_ssl_cert=opt_ssl_ca=opt_ssl_capath=0;
#endif /* HAVE_OPENSSL */
+
free_defaults(defaults_argv);
my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR));
my_free(allocated_mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
@@ -856,20 +893,33 @@ static void set_user(const char *user)
if (!strcmp(user,"root"))
return; // Avoid problem with dynamic libraries
+ uid_t uid;
if (!(ent = getpwnam(user)))
{
- fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
- unireg_abort(1);
+ // allow a numeric uid to be used
+ const char *pos;
+ for (pos=user; isdigit(*pos); pos++) ;
+ if (*pos) // Not numeric id
+ {
+ fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
+ unireg_abort(1);
+ }
+ uid=atoi(user); // Use numberic uid
}
+ else
+ {
#ifdef HAVE_INITGROUPS
- initgroups((char*) user,ent->pw_gid);
+ initgroups((char*) user,ent->pw_gid);
#endif
- if (setgid(ent->pw_gid) == -1)
- {
- sql_perror("setgid");
- unireg_abort(1);
+ if (setgid(ent->pw_gid) == -1)
+ {
+ sql_perror("setgid");
+ unireg_abort(1);
+ }
+ uid=ent->pw_uid;
}
- if (setuid(ent->pw_uid) == -1)
+
+ if (setuid(uid) == -1)
{
sql_perror("setuid");
unireg_abort(1);
@@ -939,18 +989,21 @@ static void server_init(void)
unireg_abort(1);
}
if (listen(ip_sock,(int) back_log) < 0)
- sql_print_error("Warning: listen() on TCP/IP failed with error %d",
+ {
+ sql_print_error("Error: listen() on TCP/IP failed with error %d",
socket_errno);
+ unireg_abort(1);
+ }
}
if (mysqld_chroot)
set_root(mysqld_chroot);
-
- set_user(mysqld_user); // set_user now takes care of mysqld_user==NULL
+ set_user(mysqld_user); // Works also with mysqld_user==NULL
#ifdef __NT__
/* create named pipe */
- if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap)
+ if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap &&
+ opt_enable_named_pipe)
{
sprintf( szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port );
ZeroMemory( &saPipeSecurity, sizeof(saPipeSecurity) );
@@ -1221,6 +1274,7 @@ static void init_signals(void)
signal(SIGALRM, SIG_IGN);
signal(SIGBREAK,SIG_IGN);
signal_thread = pthread_self();
+ SIGNAL_THD;
}
static void start_signal_handler(void)
@@ -1346,6 +1400,7 @@ static void init_signals(void)
sigaction(SIGBUS, &sa, NULL);
#endif
sigaction(SIGILL, &sa, NULL);
+ sigaction(SIGFPE, &sa, NULL);
}
(void) sigemptyset(&set);
#ifdef THREAD_SPECIFIC_SIGPIPE
@@ -1413,7 +1468,7 @@ static void *signal_hand(void *arg __attribute__((unused)))
int sig;
my_thread_init(); // Init new thread
DBUG_ENTER("signal_hand");
-
+ SIGNAL_THD;
/* Setup alarm handler */
init_thr_alarm(max_connections+max_insert_delayed_threads);
#if SIGINT != THR_KILL_SIGNAL
@@ -1468,7 +1523,10 @@ static void *signal_hand(void *arg __attribute__((unused)))
else
while ((error=my_sigwait(&set,&sig)) == EINTR) ;
if (cleanup_done)
+ {
+ my_thread_end();
pthread_exit(0); // Safety
+ }
switch (sig) {
case SIGTERM:
case SIGQUIT:
@@ -1562,6 +1620,7 @@ int uname(struct utsname *a)
pthread_handler_decl(handle_shutdown,arg)
{
MSG msg;
+ SHUTDOWN_THD;
my_thread_init();
/* this call should create the message queue for this thread */
@@ -1588,6 +1647,7 @@ int __stdcall handle_kill(ulong ctrl_type)
#ifdef OS2
pthread_handler_decl(handle_shutdown,arg)
{
+ SHUTDOWN_THD;
my_thread_init();
// wait semaphore
@@ -1659,6 +1719,7 @@ int main(int argc, char **argv)
my_umask=0660; // Default umask for new files
my_umask_dir=0700; // Default umask for new directories
+ MAIN_THD;
MY_INIT(argv[0]); // init my_sys library & pthreads
tzset(); // Set tzname
@@ -1689,7 +1750,7 @@ int main(int argc, char **argv)
if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
strmov(glob_hostname,"mysql");
- strmov(pidfile_name,glob_hostname);
+ strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5);
strmov(strcend(pidfile_name,'.'),".pid"); // Add extension
#ifndef DBUG_OFF
strxmov(strend(server_version),MYSQL_SERVER_SUFFIX,"-debug",NullS);
@@ -1760,7 +1821,8 @@ int main(int argc, char **argv)
if (opt_use_ssl)
{
ssl_acceptor_fd = new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert,
- opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher);
+ opt_ssl_ca, opt_ssl_capath,
+ opt_ssl_cipher);
DBUG_PRINT("info",("ssl_acceptor_fd: %p",ssl_acceptor_fd));
if (!ssl_acceptor_fd)
opt_use_ssl = 0;
@@ -1832,8 +1894,8 @@ int main(int argc, char **argv)
server_init();
table_cache_init();
hostname_cache_init();
- query_cache.result_size_limit(query_cache_limit);
- query_cache.resize(query_cache_size);
+ query_cache_result_size_limit(query_cache_limit);
+ query_cache_resize(query_cache_size);
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
@@ -1849,48 +1911,17 @@ int main(int argc, char **argv)
using_update_log=1;
}
- init_slave();
-
- if (opt_bin_log && !server_id)
- {
- server_id= !master_host ? 1 : 2;
- switch (server_id) {
-#ifdef EXTRA_DEBUG
- case 1:
- sql_print_error("\
-Warning: You have enabled the binary log, but you haven't set server-id:\n\
-Updates will be logged to the binary log, but connections to slaves will\n\
-not be accepted.");
- break;
-#endif
- case 2:
- sql_print_error("\
-Warning: You should set server-id to a non-0 value if master_host is set.\n\
-The server will not act as a slave.");
- break;
- }
- }
- if (opt_bin_log)
- {
- if (!opt_bin_logname)
- {
- char tmp[FN_REFLEN];
- /* TODO: The following should be using fn_format(); We just need to
- first change fn_format() to cut the file name if it's too long.
- */
- strmake(tmp,glob_hostname,FN_REFLEN-5);
- strmov(strcend(tmp,'.'),"-bin");
- opt_bin_logname=my_strdup(tmp,MYF(MY_WME));
- }
- mysql_bin_log.set_index_file_name(opt_binlog_index_name);
- open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
- LOG_BIN);
- using_update_log=1;
- }
-
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
LOG_NORMAL);
+#ifdef __WIN__
+#define MYSQL_ERR_FILE "mysql.err"
+ if (!opt_console)
+ {
+ freopen(MYSQL_ERR_FILE,"a+",stdout);
+ freopen(MYSQL_ERR_FILE,"a+",stderr);
+ }
+#endif
if (ha_init())
{
sql_print_error("Can't init databases");
@@ -1916,13 +1947,8 @@ The server will not act as a slave.");
ft_init_stopwords(ft_precompiled_stopwords);
#ifdef __WIN__
-#define MYSQL_ERR_FILE "mysql.err"
if (!opt_console)
- {
- freopen(MYSQL_ERR_FILE,"a+",stdout);
- freopen(MYSQL_ERR_FILE,"a+",stderr);
FreeConsole(); // Remove window
- }
#endif
/*
@@ -1955,6 +1981,46 @@ The server will not act as a slave.");
if (!opt_noacl)
udf_init();
#endif
+ /* init_slave() must be called after the thread keys are created */
+ init_slave();
+
+ if (opt_bin_log && !server_id)
+ {
+ server_id= !master_host ? 1 : 2;
+ switch (server_id) {
+#ifdef EXTRA_DEBUG
+ case 1:
+ sql_print_error("\
+Warning: You have enabled the binary log, but you haven't set server-id:\n\
+Updates will be logged to the binary log, but connections to slaves will\n\
+not be accepted.");
+ break;
+#endif
+ case 2:
+ sql_print_error("\
+Warning: You should set server-id to a non-0 value if master_host is set.\n\
+The server will not act as a slave.");
+ break;
+ }
+ }
+ if (opt_bin_log)
+ {
+ if (!opt_bin_logname)
+ {
+ char tmp[FN_REFLEN];
+ /* TODO: The following should be using fn_format(); We just need to
+ first change fn_format() to cut the file name if it's too long.
+ */
+ strmake(tmp,glob_hostname,FN_REFLEN-5);
+ strmov(strcend(tmp,'.'),"-bin");
+ opt_bin_logname=my_strdup(tmp,MYF(MY_WME));
+ }
+ mysql_bin_log.set_index_file_name(opt_binlog_index_name);
+ open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
+ LOG_BIN);
+ using_update_log=1;
+ }
+
if (opt_bootstrap)
{
@@ -2006,9 +2072,11 @@ The server will not act as a slave.");
fflush(stdout);
#ifdef __NT__
- if (hPipe == INVALID_HANDLE_VALUE && !have_tcpip)
+ if (hPipe == INVALID_HANDLE_VALUE &&
+ (!have_tcpip || opt_disable_networking))
{
- sql_print_error("TCP/IP must be installed on Win98 platforms");
+ sql_print_error("TCP/IP or --enable-named-pipe should be configured on NT OS");
+ unireg_abort(1);
}
else
{
@@ -2017,7 +2085,7 @@ The server will not act as a slave.");
{
pthread_t hThread;
handler_count=0;
- if ( hPipe != INVALID_HANDLE_VALUE )
+ if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
handler_count++;
if (pthread_create(&hThread,&connection_attrib,
@@ -2067,42 +2135,26 @@ The server will not act as a slave.");
#ifdef EXTRA_DEBUG2
sql_print_error("After lock_thread_count");
#endif
-#else
-#if !defined(EMBEDDED_LIBRARY)
- if (Service.IsNT())
- {
- if(start_mode)
- {
- if (WaitForSingleObject(hEventShutdown,1000)==WAIT_TIMEOUT)
- Service.Stop();
- }
- else
- {
- Service.SetShutdownEvent(0);
- if(hEventShutdown) CloseHandle(hEventShutdown);
- }
- }
- else
- {
- Service.SetShutdownEvent(0);
- if(hEventShutdown) CloseHandle(hEventShutdown);
- }
-#endif
-#endif
-#ifdef HAVE_OPENSSL
- my_free((gptr)ssl_acceptor_fd,MYF(MY_ALLOW_ZERO_PTR));
-#endif /* HAVE_OPENSSL */
+#endif /* __WIN__ */
+
/* Wait until cleanup is done */
(void) pthread_mutex_lock(&LOCK_thread_count);
- DBUG_PRINT("quit", ("Got thread_count mutex for clean up wait"));
-
while (!ready_to_exit)
{
- DBUG_PRINT("quit", ("not yet ready to exit"));
pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
}
- DBUG_PRINT("quit", ("ready to exit"));
(void) pthread_mutex_unlock(&LOCK_thread_count);
+
+#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
+ if (Service.IsNT() && start_mode)
+ Service.Stop();
+ else
+ {
+ Service.SetShutdownEvent(0);
+ if (hEventShutdown)
+ CloseHandle(hEventShutdown);
+ }
+#endif
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(0);
return(0); /* purecov: deadcode */
@@ -2441,6 +2493,7 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
struct request_info req;
signal(SIGCHLD, SIG_DFL);
request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL);
+#ifndef __linux__
fromhost(&req);
if (!hosts_access(&req))
{
@@ -2450,6 +2503,12 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
clean_exit() - same stupid thing ...
*/
syslog(deny_severity, "refused connect from %s", eval_client(&req));
+#else
+ fromhost();
+ if (!hosts_access())
+ {
+ syslog(deny_severity, "refused connect from %s", eval_client());
+#endif
if (req.sink)
((void (*)(int))req.sink)(req.fd);
@@ -2543,9 +2602,9 @@ pthread_handler_decl(handle_connections_namedpipes,arg)
fConnected = ConnectNamedPipe( hPipe, NULL );
if (abort_loop)
break;
- if ( !fConnected )
+ if (!fConnected)
fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
- if ( !fConnected )
+ if (!fConnected)
{
CloseHandle( hPipe );
if ((hPipe = CreateNamedPipe(szPipeName,
@@ -2583,7 +2642,7 @@ pthread_handler_decl(handle_connections_namedpipes,arg)
continue; // We have to try again
}
- if ( !(thd = new THD))
+ if (!(thd = new THD))
{
DisconnectNamedPipe( hConnectedPipe );
CloseHandle( hConnectedPipe );
@@ -2667,13 +2726,14 @@ enum options {
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
+ OPT_HAVE_NAMED_PIPE,
OPT_DO_PSTACK, OPT_REPORT_HOST,
OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
OPT_SHOW_SLAVE_AUTH_INFO, OPT_OLD_RPL_COMPAT,
OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE,
OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE,
- OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE
+ OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE, OPT_LOCAL_INFILE
};
static struct option long_options[] = {
@@ -2707,6 +2767,7 @@ static struct option long_options[] = {
{"delay-key-write-for-all-tables",
no_argument, 0, (int) OPT_DELAY_KEY_WRITE},
{"enable-locking", no_argument, 0, (int) OPT_ENABLE_LOCK},
+ {"enable-named-pipe", no_argument, 0, (int) OPT_HAVE_NAMED_PIPE},
{"enable-pstack", no_argument, 0, (int) OPT_DO_PSTACK},
{"exit-info", optional_argument, 0, 'T'},
{"flush", no_argument, 0, (int) OPT_FLUSH},
@@ -2735,6 +2796,7 @@ static struct option long_options[] = {
{"init-file", required_argument, 0, (int) OPT_INIT_FILE},
{"log", optional_argument, 0, 'l'},
{"language", required_argument, 0, 'L'},
+ {"local-infile", optional_argument, 0, (int) OPT_LOCAL_INFILE},
{"log-bin", optional_argument, 0, (int) OPT_BIN_LOG},
{"log-bin-index", required_argument, 0, (int) OPT_BIN_LOG_INDEX},
{"log-isam", optional_argument, 0, (int) OPT_ISAM_LOG},
@@ -2970,16 +3032,20 @@ CHANGEABLE_VAR changeable_vars[] = {
0, 0, 65535, 0, 1},
{ "query_buffer_size", (long*) &query_buff_size,
0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
+#ifdef HAVE_QUERY_CACHE
{ "query_cache_limit", (long*) &query_cache_limit,
1024*1024L, 0, ULONG_MAX, 0, 1},
{ "query_cache_size", (long*) &query_cache_size,
0, 0, ULONG_MAX, 0, 1},
{ "query_cache_startup_type",(long*) &query_cache_startup_type,
1, 0, 2, 0, 1},
+#endif /*HAVE_QUERY_CACHE*/
{ "record_buffer", (long*) &my_default_record_cache_size,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
{ "record_rnd_buffer", (long*) &record_rnd_cache_size,
0, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
+ { "relay_log_space_limit", (long*) &relay_log_space_limit, 0L, 0L,ULONG_MAX,
+ 0, 1},
{ "slave_net_timeout", (long*) &slave_net_timeout,
SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
{ "slow_launch_time", (long*) &slow_launch_time,
@@ -3037,6 +3103,7 @@ struct show_var_st init_vars[]= {
{"have_raid", (char*) &have_raid, SHOW_HAVE},
{"have_symlink", (char*) &have_symlink, SHOW_HAVE},
{"have_openssl", (char*) &have_openssl, SHOW_HAVE},
+ {"have_query_cache", (char*) &have_query_cache, SHOW_HAVE},
{"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR},
#ifdef HAVE_INNOBASE_DB
{"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG },
@@ -3070,7 +3137,7 @@ struct show_var_st init_vars[]= {
{"log_update", (char*) &opt_update_log, SHOW_BOOL},
{"log_bin", (char*) &opt_bin_log, SHOW_BOOL},
{"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_BOOL},
- {"log_long_queries", (char*) &opt_slow_log, SHOW_BOOL},
+ {"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL},
{"long_query_time", (char*) &long_query_time, SHOW_LONG},
{"low_priority_updates", (char*) &low_priority_updates, SHOW_BOOL},
{"lower_case_table_names", (char*) &lower_case_table_names, SHOW_LONG},
@@ -3092,6 +3159,9 @@ struct show_var_st init_vars[]= {
{"myisam_max_sort_file_size",(char*) &myisam_max_sort_file_size, SHOW_LONG},
{"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR},
{"myisam_sort_buffer_size", (char*) &myisam_sort_buffer_size, SHOW_LONG},
+#ifdef __NT__
+ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_BOOL},
+#endif
{"net_buffer_length", (char*) &net_buffer_length, SHOW_LONG},
{"net_read_timeout", (char*) &net_read_timeout, SHOW_LONG},
{"net_retry_count", (char*) &mysqld_net_retry_count, SHOW_LONG},
@@ -3104,9 +3174,11 @@ struct show_var_st init_vars[]= {
{"record_rnd_buffer", (char*) &record_rnd_cache_size, SHOW_LONG},
{"rpl_recovery_rank", (char*) &rpl_recovery_rank, SHOW_LONG},
{"query_buffer_size", (char*) &query_buff_size, SHOW_LONG},
+#ifdef HAVE_QUERY_CACHE
{"query_cache_limit", (char*) &query_cache.query_cache_limit, SHOW_LONG},
{"query_cache_size", (char*) &query_cache.query_cache_size, SHOW_LONG},
{"query_cache_startup_type",(char*) &query_cache_startup_type, SHOW_LONG},
+#endif /*HAVE_QUERY_CACHE*/
{"safe_show_database", (char*) &opt_safe_show_db, SHOW_BOOL},
{"server_id", (char*) &server_id, SHOW_LONG},
{"slave_net_timeout", (char*) &slave_net_timeout, SHOW_LONG},
@@ -3213,6 +3285,7 @@ struct show_var_st status_vars[]= {
{"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG},
{"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG},
{"Flush_commands", (char*) &refresh_version, SHOW_LONG_CONST},
+ {"Handler_commit", (char*) &ha_commit_count, SHOW_LONG},
{"Handler_delete", (char*) &ha_delete_count, SHOW_LONG},
{"Handler_read_first", (char*) &ha_read_first_count, SHOW_LONG},
{"Handler_read_key", (char*) &ha_read_key_count, SHOW_LONG},
@@ -3220,6 +3293,7 @@ struct show_var_st status_vars[]= {
{"Handler_read_prev", (char*) &ha_read_prev_count, SHOW_LONG},
{"Handler_read_rnd", (char*) &ha_read_rnd_count, SHOW_LONG},
{"Handler_read_rnd_next", (char*) &ha_read_rnd_next_count, SHOW_LONG},
+ {"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG},
{"Handler_update", (char*) &ha_update_count, SHOW_LONG},
{"Handler_write", (char*) &ha_write_count, SHOW_LONG},
{"Key_blocks_used", (char*) &_my_blocks_used, SHOW_LONG_CONST},
@@ -3235,6 +3309,7 @@ struct show_var_st status_vars[]= {
{"Open_streams", (char*) &my_stream_opened, SHOW_INT_CONST},
{"Opened_tables", (char*) &opened_tables, SHOW_LONG},
{"Questions", (char*) 0, SHOW_QUESTION},
+#ifdef HAVE_QUERY_CACHE
{"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST},
{"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG},
{"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
@@ -3245,6 +3320,7 @@ struct show_var_st status_vars[]= {
SHOW_LONG_CONST},
{"Qcache_total_blocks", (char*) &query_cache.total_blocks,
SHOW_LONG_CONST},
+#endif /*HAVE_QUERY_CACHE*/
{"Rpl_status", (char*) 0, SHOW_RPL_STATUS},
{"Select_full_join", (char*) &select_full_join_count, SHOW_LONG},
{"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG},
@@ -3309,10 +3385,11 @@ static void use_help(void)
static void usage(void)
{
print_version();
- puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB, by Monty and others");
- puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
- puts("and you are welcome to modify and redistribute it under the GPL license\n");
- puts("Starts the MySQL server\n");
+ puts("\
+Copyright (C) 2000 MySQL AB, by Monty and others\n\
+This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
+and you are welcome to modify and redistribute it under the GPL license\n\
+Starts the MySQL server\n");
printf("Usage: %s [OPTIONS]\n", my_progname);
puts("\n\
@@ -3358,6 +3435,7 @@ static void usage(void)
--init-file=file Read SQL commands from this file at startup\n\
-L, --language=... Client error messages in given language. May be\n\
given as a full path\n\
+ --local-infile=[1|0] Enable/disable LOAD DATA LOCAL INFILE\n\
-l, --log[=file] Log connections and queries to file\n\
--log-bin[=file] Log queries in new binary format (for replication)\n\
--log-bin-index=file File that holds the names for last binary log files\n\
@@ -3422,10 +3500,12 @@ static void usage(void)
-W, --warnings Log some not critical warnings to the log file\n");
#ifdef __WIN__
puts("NT and Win32 specific options:\n\
- --console Don't remove the console window\n\
- --install Install mysqld as a service (NT)\n\
- --remove Remove mysqld from the service list (NT)\n\
- --standalone Dummy option to start as a standalone program (NT)\
+ --console Don't remove the console window\n\
+ --install Install the default service (NT)\n\
+ --install-manual Install the default service started manually (NT)\n\
+ --remove Remove the default service from the service list (NT)\n\
+ --enable-named-pipe Enable the named pipe (NT)\n\
+ --standalone Dummy option to start as a standalone program (NT)\
");
#ifdef USE_SYMDIR
puts("--use-symbolic-links Enable symbolic link support");
@@ -3512,9 +3592,10 @@ static void set_options(void)
opt_specialflag |= SPECIAL_NO_PRIOR;
#endif
- (void) strmov( default_charset, MYSQL_CHARSET);
- (void) strmov( language, LANGUAGE);
- (void) strmov( mysql_real_data_home, get_relative_path(DATADIR));
+ (void) strmake(default_charset, MYSQL_CHARSET, sizeof(default_charset)-1);
+ (void) strmake(language, LANGUAGE, sizeof(language)-1);
+ (void) strmake(mysql_real_data_home, get_relative_path(DATADIR),
+ sizeof(mysql_real_data_home-1));
#ifdef __WIN__
/* Allow Win32 users to move MySQL anywhere */
{
@@ -3525,9 +3606,9 @@ static void set_options(void)
}
#else
const char *tmpenv;
- if ( !(tmpenv = getenv("MY_BASEDIR_VERSION")))
+ if (!(tmpenv = getenv("MY_BASEDIR_VERSION")))
tmpenv = DEFAULT_MYSQL_HOME;
- (void) strmov( mysql_home, tmpenv );
+ (void) strmake(mysql_home, tmpenv, sizeof(mysql_home)-1);
#endif
#if defined( HAVE_mit_thread ) || defined( __WIN__ ) || defined( HAVE_LINUXTHREADS )
@@ -3573,17 +3654,17 @@ static void get_options(int argc,char **argv)
default_tx_isolation= ISO_SERIALIZABLE;
break;
case 'b':
- strmov(mysql_home,optarg);
+ strmake(mysql_home,optarg,sizeof(mysql_home)-1);
break;
case 'l':
opt_log=1;
opt_logname=optarg; // Use hostname.log if null
break;
case 'h':
- strmov(mysql_real_data_home,optarg);
+ strmake(mysql_real_data_home,optarg, sizeof(mysql_real_data_home)-1);
break;
case 'L':
- strmov(language,optarg);
+ strmake(language, optarg, sizeof(language)-1);
break;
case 'n':
opt_specialflag|= SPECIAL_NEW_FUNC;
@@ -3601,6 +3682,9 @@ static void get_options(int argc,char **argv)
case 'P':
mysql_port= (unsigned int) atoi(optarg);
break;
+ case OPT_LOCAL_INFILE:
+ opt_local_infile= test(!optarg || atoi(optarg) != 0);
+ break;
case OPT_SLAVE_SKIP_ERRORS:
init_slave_skip_errors(optarg);
break;
@@ -3845,7 +3929,9 @@ static void get_options(int argc,char **argv)
my_use_symdir=0;
have_symlink=SHOW_OPTION_DISABLED;
ha_open_options&= ~HA_OPEN_ABORT_IF_CRASHED;
+#ifdef HAVE_QUERY_CACHE
query_cache_size=0;
+#endif
break;
case (int) OPT_SAFE:
opt_specialflag|= SPECIAL_SAFE_MODE;
@@ -3938,11 +4024,16 @@ static void get_options(int argc,char **argv)
}
break;
case (int) OPT_PID_FILE:
- strmov(pidfile_name,optarg);
+ strmake(pidfile_name, optarg, sizeof(pidfile_name)-1);
break;
case (int) OPT_INIT_FILE:
opt_init_file=optarg;
break;
+ case (int) OPT_HAVE_NAMED_PIPE:
+#if __NT__
+ opt_enable_named_pipe=1;
+#endif
+ break;
#ifdef __WIN__
case (int) OPT_STANDALONE: /* Dummy option for NT */
break;
@@ -3988,10 +4079,10 @@ static void get_options(int argc,char **argv)
myisam_delay_key_write=0;
break;
case 'C':
- strmov(default_charset,optarg);
+ strmake(default_charset, optarg, sizeof(default_charset)-1);
break;
case OPT_CHARSETS_DIR:
- strmov(mysql_charsets_dir, optarg);
+ strmake(mysql_charsets_dir, optarg, sizeof(mysql_charsets_dir)-1);
charsets_dir = mysql_charsets_dir;
break;
#ifdef TO_BE_DONE
@@ -4263,16 +4354,17 @@ static void fix_paths(void)
char buff[FN_REFLEN],*sharedir=get_relative_path(SHAREDIR);
if (test_if_hard_path(sharedir))
- strmov(buff,sharedir); /* purecov: tested */
+ strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */
else
- strxmov(buff,mysql_home,sharedir,NullS);
+ strxnmov(buff,sizeof(buff)-1,mysql_home,sharedir,NullS);
convert_dirname(buff,buff,NullS);
(void) my_load_path(language,language,buff);
/* If --character-sets-dir isn't given, use shared library dir */
if (charsets_dir != mysql_charsets_dir)
{
- strmov(strmov(mysql_charsets_dir,buff),CHARSET_DIR);
+ strxnmov(mysql_charsets_dir, sizeof(mysql_charsets_dir)-1, buff,
+ CHARSET_DIR, NullS);
charsets_dir=mysql_charsets_dir;
}
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index 64c1b07a493..1ab3e18424f 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -108,7 +108,13 @@ net_printf(NET *net, uint errcode, ...)
thd->query_error = 1; // if we are here, something is wrong :-)
query_cache_abort(net); // Safety
va_start(args,errcode);
- format=ER(errcode);
+ /*
+ The following is needed to make net_printf() work with 0 argument for
+ errorcode and use the argument after that as the format string. This
+ is useful for rare errors that are not worth the hassle to put in
+ errmsg.sys, but at the same time, the message is not fixed text
+ */
+ format=errcode ? ER(errcode) : va_arg(args,char*);
offset= net->return_errno ? 2 : 0;
text_pos=(char*) net->buff+head_length+offset+1;
(void) vsprintf(my_const_cast(char*) (text_pos),format,args);
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 7a1d25e980d..9884adf9b46 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -329,10 +329,12 @@ net_real_write(NET *net,const char *packet,ulong len)
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
-#ifdef MYSQL_SERVER
+#ifdef MYSQL_SERVER
+#ifdef HAVE_QUERY_CACHE
if (net->query_cache_query != 0)
query_cache_insert(net, packet, len);
#endif
+#endif
if (net->error == 2)
DBUG_RETURN(-1); /* socket can't be used */
@@ -814,3 +816,14 @@ my_net_read(NET *net)
#endif /* HAVE_COMPRESS */
return len;
}
+
+int net_request_file(NET* net, const char* fname)
+{
+ char tmp [FN_REFLEN+1],*end;
+ DBUG_ENTER("net_request_file");
+ tmp[0] = (char) 251; /* NULL_LENGTH */
+ end=strnmov(tmp+1,fname,sizeof(tmp)-2);
+ DBUG_RETURN(my_net_write(net,tmp,(uint) (end-tmp)) ||
+ net_flush(net));
+}
+
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index 6930800982e..8c705a94f55 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -28,7 +28,7 @@ NTService::NTService()
//time-out variables
nStartTimeOut = 15000;
- nStopTimeOut = 15000;
+ nStopTimeOut = 86400000;
nPauseTimeOut = 5000;
nResumeTimeOut = 5000;
@@ -253,7 +253,7 @@ void NTService::ServiceMain(DWORD argc, LPTSTR *argv)
WaitForSingleObject (pService->hExitEvent, INFINITE);
// wait for thread to exit
- if (WaitForSingleObject (pService->hThreadHandle, 1000) == WAIT_TIMEOUT)
+ if (WaitForSingleObject (pService->hThreadHandle, INFINITE) == WAIT_TIMEOUT)
CloseHandle(pService->hThreadHandle);
pService->Exit(0);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index c3f4c91b718..20f198182f4 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2523,13 +2523,13 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
/*
- * This is a hack: we inherit from QUICK_SELECT so that we can use the
- * get_next() interface, but we have to hold a pointer to the original
- * QUICK_SELECT because its data are used all over the place. What
- * should be done is to factor out the data that is needed into a base
- * class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
- * which handle the ranges and implement the get_next() function. But
- * for now, this seems to work right at least.
+ This is a hack: we inherit from QUICK_SELECT so that we can use the
+ get_next() interface, but we have to hold a pointer to the original
+ QUICK_SELECT because its data are used all over the place. What
+ should be done is to factor out the data that is needed into a base
+ class (QUICK_SELECT), and then have two subclasses (_ASC and _DESC)
+ which handle the ranges and implement the get_next() function. But
+ for now, this seems to work right at least.
*/
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts)
@@ -2538,6 +2538,7 @@ QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts)
bool not_read_after_key = file->option_flag() & HA_NOT_READ_AFTER_KEY;
QUICK_RANGE *r;
+ it.rewind();
for (r = it++; r; r = it++)
{
rev_ranges.push_front(r);
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 83eb10235ea..f48a3936a17 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -77,6 +77,7 @@ public:
void reset(void) { next=0; it.rewind(); }
int init() { return error=file->index_init(index); }
virtual int get_next();
+ virtual bool reverse_sorted() { return 0; }
int cmp_next(QUICK_RANGE *range);
bool unique_key_range();
};
@@ -87,6 +88,7 @@ class QUICK_SELECT_DESC: public QUICK_SELECT
public:
QUICK_SELECT_DESC(QUICK_SELECT *q, uint used_key_parts);
int get_next();
+ bool reverse_sorted() { return 1; }
private:
int cmp_prev(QUICK_RANGE *range);
bool range_reads_after_key(QUICK_RANGE *range);
@@ -96,6 +98,7 @@ private:
List_iterator<QUICK_RANGE> rev_it;
};
+
class SQL_SELECT :public Sql_alloc {
public:
QUICK_SELECT *quick; // If quick-select used
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 6cc7ef7404b..257418d1682 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -828,6 +828,7 @@ int load_master_data(THD* thd)
active_mi->rli.master_log_pos = active_mi->master_log_pos;
strnmov(active_mi->rli.master_log_name,active_mi->master_log_name,
sizeof(active_mi->rli.master_log_name));
+ flush_relay_log_info(&active_mi->rli);
pthread_cond_broadcast(&active_mi->rli.data_cond);
pthread_mutex_unlock(&active_mi->rli.data_lock);
thd->proc_info = "starting slave";
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index cb3056b5f5a..c70ac9ccf57 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -5,6 +5,7 @@ dist-hook:
test -d $(distdir)/$$dir || mkdir $(distdir)/$$dir; \
$(INSTALL_DATA) $(srcdir)/$$dir/*.* $(distdir)/$$dir; \
done; \
+ sleep 1 ; touch $(srcdir)/*/errmsg.sys
$(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets
$(INSTALL_DATA) $(srcdir)/charsets/Index $(distdir)/charsets
diff --git a/sql/slave.cc b/sql/slave.cc
index 8884e5de778..25b29732000 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -29,6 +29,8 @@
bool use_slave_mask = 0;
MY_BITMAP slave_error_mask;
+typedef bool (*CHECK_KILLED_FUNC)(THD*,void*);
+
volatile bool slave_sql_running = 0, slave_io_running = 0;
char* slave_load_tmpdir = 0;
MASTER_INFO main_mi;
@@ -40,6 +42,8 @@ bool do_table_inited = 0, ignore_table_inited = 0;
bool wild_do_table_inited = 0, wild_ignore_table_inited = 0;
bool table_rules_on = 0;
static TABLE* save_temporary_tables = 0;
+ulong relay_log_space_limit = 0; /* TODO: fix variables to access ulonglong
+ values and make it ulonglong */
// when slave thread exits, we need to remember the temporary tables so we
// can re-use them on slave start
@@ -55,16 +59,20 @@ typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
void skip_load_data_infile(NET* net);
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev);
+static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev);
static int queue_old_event(MASTER_INFO* mi, const char* buf,
uint event_len);
-static inline bool slave_killed(THD* thd,MASTER_INFO* mi);
-static inline bool slave_killed(THD* thd,RELAY_LOG_INFO* rli);
+static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli);
+static inline bool io_slave_killed(THD* thd,MASTER_INFO* mi);
+static inline bool sql_slave_killed(THD* thd,RELAY_LOG_INFO* rli);
+static int count_relay_log_space(RELAY_LOG_INFO* rli);
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type);
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi);
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
bool reconnect);
-static int safe_sleep(THD* thd, MASTER_INFO* mi, int sec);
+static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
+ void* thread_killed_arg);
static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name);
@@ -162,6 +170,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
ulonglong pos, bool need_data_lock,
const char** errmsg)
{
+ *errmsg=0;
if (rli->log_pos_current)
return 0;
pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
@@ -259,8 +268,9 @@ void init_slave_skip_errors(char* arg)
// are not running
int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg)
{
+ DBUG_ENTER("purge_relay_logs");
if (!rli->inited)
- return 0; /* successfully do nothing */
+ DBUG_RETURN(0); /* successfully do nothing */
DBUG_ASSERT(rli->slave_running == 0);
DBUG_ASSERT(rli->mi->slave_running == 0);
int error=0;
@@ -277,14 +287,20 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg)
goto err;
}
strnmov(rli->relay_log_name,rli->linfo.log_file_name,
- sizeof(rli->relay_log_name));
+ sizeof(rli->relay_log_name)-1);
+ rli->log_space_total=4; //just first log with magic number and nothing else
rli->relay_log_pos=4;
+ rli->relay_log.reset_bytes_written();
rli->log_pos_current=0;
if (!just_reset)
error = init_relay_log_pos(rli,0,0,0/*do not need data lock*/,errmsg);
-err:
+err:
+#ifndef DBUG_OFF
+ char buf[22];
+#endif
+ DBUG_PRINT("info",("log_space_total=%s",llstr(rli->log_space_total,buf)));
pthread_mutex_unlock(&rli->data_lock);
- return error;
+ DBUG_RETURN(error);
}
int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
@@ -341,7 +357,14 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
}
}
DBUG_ASSERT(thd != 0);
- KICK_SLAVE(thd);
+ /* is is criticate to test if the slave is running. Otherwise, we might
+ be referening freed memory trying to kick it
+ */
+ THD_CHECK_SENTRY(thd);
+ if (*slave_running)
+ {
+ KICK_SLAVE(thd);
+ }
while (*slave_running)
{
/* there is a small chance that slave thread might miss the first
@@ -360,9 +383,12 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
abstime.tv_sec=tv.tv_sec+2;
abstime.tv_nsec=tv.tv_usec*1000;
#endif
+ DBUG_ASSERT_LOCK(cond_lock);
pthread_cond_timedwait(term_cond, cond_lock, &abstime);
if (*slave_running)
+ {
KICK_SLAVE(thd);
+ }
}
if (term_lock)
pthread_mutex_unlock(term_lock);
@@ -603,14 +629,14 @@ void end_slave()
free_string_array(&replicate_wild_ignore_table);
}
-static inline bool slave_killed(THD* thd, MASTER_INFO* mi)
+static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
{
DBUG_ASSERT(mi->io_thd == thd);
DBUG_ASSERT(mi->slave_running == 1); // tracking buffer overrun
return mi->abort_slave || abort_loop || thd->killed;
}
-static inline bool slave_killed(THD* thd, RELAY_LOG_INFO* rli)
+static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
{
DBUG_ASSERT(rli->sql_thd == thd);
DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
@@ -654,7 +680,7 @@ char* rewrite_db(char* db)
int db_ok(const char* db, I_List<i_string> &do_list,
I_List<i_string> &ignore_list )
{
- if(do_list.is_empty() && ignore_list.is_empty())
+ if (do_list.is_empty() && ignore_list.is_empty())
return 1; // ok to replicate if the user puts no constraints
// if the user has specified restrictions on which databases to replicate
@@ -854,8 +880,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
}
check_opt.init();
- check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM;
- check_opt.quick = 1;
+ check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK;
thd->proc_info = "Rebuilding the index on master dump table";
// we do not want repair() to spam us with messages
// just send them to the error log, and report the failure in case of
@@ -939,14 +964,14 @@ void end_master_info(MASTER_INFO* mi)
int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
{
+ DBUG_ENTER("init_relay_log_info");
if (rli->inited)
- return 0;
+ DBUG_RETURN(0);
MY_STAT stat_area;
char fname[FN_REFLEN+128];
int info_fd;
const char* msg = 0;
int error = 0;
-
fn_format(fname, info_fname,
mysql_data_home, "", 4+32);
pthread_mutex_lock(&rli->data_lock);
@@ -955,6 +980,10 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
rli->cur_log_fd = -1;
rli->slave_skip_counter=0;
rli->log_pos_current=0;
+ rli->abort_pos_wait=0;
+ rli->skip_log_purge=0;
+ rli->log_space_limit = relay_log_space_limit;
+ rli->log_space_total = 0;
// TODO: make this work with multi-master
if (!opt_relay_logname)
{
@@ -986,7 +1015,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
my_close(info_fd, MYF(0));
rli->info_fd=-1;
pthread_mutex_unlock(&rli->data_lock);
- return 1;
+ DBUG_RETURN(1);
}
if (init_relay_log_pos(rli,"",4,0/*no data mutex*/,&msg))
goto err;
@@ -1006,7 +1035,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
my_close(info_fd, MYF(0));
rli->info_fd=-1;
pthread_mutex_unlock(&rli->data_lock);
- return 1;
+ DBUG_RETURN(1);
}
rli->info_fd = info_fd;
@@ -1037,8 +1066,13 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
// before flush_relay_log_info
reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
error=test(flush_relay_log_info(rli));
+ if (count_relay_log_space(rli))
+ {
+ msg="Error counting relay log space";
+ goto err;
+ }
pthread_mutex_unlock(&rli->data_lock);
- return error;
+ DBUG_RETURN(error);
err:
sql_print_error(msg);
@@ -1046,9 +1080,66 @@ err:
my_close(info_fd, MYF(0));
rli->info_fd=-1;
pthread_mutex_unlock(&rli->data_lock);
- return 1;
+ DBUG_RETURN(1);
+}
+
+static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo)
+{
+ MY_STAT s;
+ DBUG_ENTER("add_relay_log");
+ if (!my_stat(linfo->log_file_name,&s,MYF(0)))
+ {
+ sql_print_error("log %s listed in the index, but failed to stat",
+ linfo->log_file_name);
+ DBUG_RETURN(1);
+ }
+ rli->log_space_total += s.st_size;
+#ifndef DBUG_OFF
+ char buf[22];
+#endif
+ DBUG_PRINT("info",("log_space_total: %s", llstr(rli->log_space_total,buf)));
+ DBUG_RETURN(0);
}
+static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
+{
+ bool slave_killed;
+ MASTER_INFO* mi = rli->mi;
+ const char* save_proc_info;
+ THD* thd = mi->io_thd;
+ DBUG_ENTER("wait_for_relay_log_space");
+ pthread_mutex_lock(&rli->log_space_lock);
+ save_proc_info = thd->proc_info;
+ thd->proc_info = "Waiting for relay log space to free";
+ while (rli->log_space_limit < rli->log_space_total &&
+ !(slave_killed=io_slave_killed(thd,mi)))
+ {
+ pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
+ }
+ thd->proc_info = save_proc_info;
+ pthread_mutex_unlock(&rli->log_space_lock);
+ DBUG_RETURN(slave_killed);
+}
+
+static int count_relay_log_space(RELAY_LOG_INFO* rli)
+{
+ LOG_INFO linfo;
+ DBUG_ENTER("count_relay_log_space");
+ rli->log_space_total = 0;
+ if (rli->relay_log.find_first_log(&linfo,""))
+ {
+ sql_print_error("Could not find first log while counting relay log space");
+ DBUG_RETURN(1);
+ }
+ if (add_relay_log(rli,&linfo))
+ DBUG_RETURN(1);
+ while (!rli->relay_log.find_next_log(&linfo))
+ {
+ if (add_relay_log(rli,&linfo))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname)
@@ -1058,6 +1149,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
if (init_relay_log_info(&mi->rli, slave_info_fname))
return 1;
mi->rli.mi = mi;
+ mi->mysql=0;
+ mi->file_id=1;
mi->ignore_stop_event=0;
int fd,error;
MY_STAT stat_area;
@@ -1225,6 +1318,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
field_list.push_back(new Item_empty_string("Last_error", 20));
field_list.push_back(new Item_empty_string("Skip_counter", 12));
field_list.push_back(new Item_empty_string("Exec_master_log_pos", 12));
+ field_list.push_back(new Item_empty_string("Relay_log_space", 12));
if(send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
@@ -1251,6 +1345,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
net_store_data(packet, mi->rli.last_slave_error);
net_store_data(packet, mi->rli.slave_skip_counter);
net_store_data(packet, (longlong) mi->rli.master_log_pos);
+ net_store_data(packet, (longlong) mi->rli.log_space_total);
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
@@ -1283,9 +1378,16 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
bool pos_reached = 0;
int event_count = 0;
pthread_mutex_lock(&data_lock);
- while (!thd->killed)
+ abort_pos_wait=0; // abort only if master info changes during wait
+ while (!thd->killed || !abort_pos_wait)
{
int cmp_result;
+ if (abort_pos_wait)
+ {
+ abort_pos_wait=0;
+ pthread_mutex_unlock(&data_lock);
+ return -1;
+ }
DBUG_ASSERT(*master_log_name || master_log_pos == 0);
if (*master_log_name)
{
@@ -1337,10 +1439,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->thread_id = thread_id++;
pthread_mutex_unlock(&LOCK_thread_count);
- if (init_thr_lock() ||
- my_pthread_setspecific_ptr(THR_THD, thd) ||
- my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root) ||
- my_pthread_setspecific_ptr(THR_NET, &thd->net))
+ if (init_thr_lock() || thd->store_globals())
{
end_thread(thd,0);
DBUG_RETURN(-1);
@@ -1354,7 +1453,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
- thd->mem_root.free=thd->mem_root.used=0; // Probably not needed
if (thd->max_join_size == (ulong) ~0L)
thd->options |= OPTION_BIG_SELECTS;
@@ -1368,11 +1466,11 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
}
thd->version=refresh_version;
thd->set_time();
-
DBUG_RETURN(0);
}
-static int safe_sleep(THD* thd, MASTER_INFO* mi, int sec)
+static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
+ void* thread_killed_arg)
{
thr_alarm_t alarmed;
thr_alarm_init(&alarmed);
@@ -1395,7 +1493,7 @@ static int safe_sleep(THD* thd, MASTER_INFO* mi, int sec)
if (thr_alarm_in_use(&alarmed))
thr_end_alarm(&alarmed);
- if (slave_killed(thd,mi))
+ if ((*thread_killed)(thd,thread_killed_arg))
return 1;
start_time=time((time_t*) 0);
}
@@ -1525,7 +1623,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
DBUG_ASSERT(rli->sql_thd==thd);
Log_event * ev = next_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
- if (slave_killed(thd,rli))
+ if (sql_slave_killed(thd,rli))
return 1;
if (ev)
{
@@ -1535,10 +1633,6 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
if (ev->server_id == ::server_id ||
(rli->slave_skip_counter && type_code != ROTATE_EVENT))
{
- /*
- TODO: I/O thread must handle skipping file delivery for
- old load data infile events
- */
/* TODO: I/O thread should not even log events with the same server id */
rli->inc_pos(ev->get_event_len(),
type_code != STOP_EVENT ? ev->log_pos : LL(0),
@@ -1601,6 +1695,7 @@ slave_begin:
my_thread_init();
thd = new THD; // note that contructor of THD uses DBUG_ !
DBUG_ENTER("handle_slave_io");
+ THD_CHECK_SENTRY(thd);
pthread_detach_this_thread();
if (init_slave_thread(thd, SLAVE_THD_IO))
@@ -1621,7 +1716,7 @@ slave_begin:
DBUG_PRINT("info",("master info: log_file_name=%s, position=%s",
mi->master_log_name, llstr(mi->master_log_pos,llbuff)));
- if (!(mysql = mc_mysql_init(NULL)))
+ if (!(mi->mysql = mysql = mc_mysql_init(NULL)))
{
sql_print_error("Slave I/O thread: error in mc_mysql_init()");
goto err;
@@ -1662,13 +1757,13 @@ connected:
goto err;
}
- while (!slave_killed(thd,mi))
+ while (!io_slave_killed(thd,mi))
{
thd->proc_info = "Requesting binlog dump";
if (request_dump(mysql, mi))
{
sql_print_error("Failed on request_dump()");
- if(slave_killed(thd,mi))
+ if(io_slave_killed(thd,mi))
{
sql_print_error("Slave I/O thread killed while requesting master \
dump");
@@ -1683,11 +1778,12 @@ dump");
hopefuly the admin can fix the problem sometime
*/
if (retried_once)
- safe_sleep(thd, mi, mi->connect_retry);
+ safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
+ (void*)mi);
else
retried_once = 1;
- if (slave_killed(thd,mi))
+ if (io_slave_killed(thd,mi))
{
sql_print_error("Slave I/O thread killed while retrying master \
dump");
@@ -1698,7 +1794,7 @@ dump");
sql_print_error("Slave I/O thread: failed dump request, \
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
llstr(mi->master_log_pos,llbuff));
- if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
+ if (safe_reconnect(thd, mysql, mi) || io_slave_killed(thd,mi))
{
sql_print_error("Slave I/O thread killed during or \
after reconnect");
@@ -1708,11 +1804,11 @@ after reconnect");
goto connected;
}
- while (!slave_killed(thd,mi))
+ while (!io_slave_killed(thd,mi))
{
thd->proc_info = "Reading master update";
ulong event_len = read_event(mysql, mi);
- if (slave_killed(thd,mi))
+ if (io_slave_killed(thd,mi))
{
sql_print_error("Slave I/O thread killed while reading event");
goto err;
@@ -1732,11 +1828,12 @@ is correct, restart the server with a higher value of max_allowed_packet",
thd->proc_info = "Waiting to reconnect after a failed read";
mc_end_server(mysql);
if (retried_once) // punish repeat offender with sleep
- safe_sleep(thd,mi,mi->connect_retry);
+ safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
+ (void*)mi);
else
retried_once = 1;
- if (slave_killed(thd,mi))
+ if (io_slave_killed(thd,mi))
{
sql_print_error("Slave I/O thread killed while waiting to \
reconnect after a failed read");
@@ -1746,7 +1843,7 @@ reconnect after a failed read");
sql_print_error("Slave I/O thread: Failed reading log event, \
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
llstr(mi->master_log_pos, llbuff));
- if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
+ if (safe_reconnect(thd, mysql, mi) || io_slave_killed(thd,mi))
{
sql_print_error("Slave I/O thread killed during or after a \
reconnect done to recover from failed read");
@@ -1763,6 +1860,15 @@ reconnect done to recover from failed read");
from master");
goto err;
}
+ flush_master_info(mi);
+ if (mi->rli.log_space_limit && mi->rli.log_space_limit <
+ mi->rli.log_space_total)
+ if (wait_for_relay_log_space(&mi->rli))
+ {
+ sql_print_error("Slave I/O thread aborted while waiting for relay \
+log space");
+ goto err;
+ }
// TODO: check debugging abort code
#ifndef DBUG_OFF
if (abort_slave_event_count && !--events_till_abort)
@@ -1771,8 +1877,8 @@ from master");
goto err;
}
#endif
- } // while(!slave_killed(thd,mi)) - read/exec loop
- } // while(!slave_killed(thd,mi)) - slave loop
+ }
+ }
// error = 0;
err:
@@ -1780,8 +1886,11 @@ err:
sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s",
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
thd->query = thd->db = 0; // extra safety
- if(mysql)
+ if (mysql)
+ {
mc_mysql_close(mysql);
+ mi->mysql=0;
+ }
thd->proc_info = "Waiting for slave mutex on exit";
pthread_mutex_lock(&mi->run_lock);
mi->slave_running = 0;
@@ -1790,13 +1899,14 @@ err:
change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
mi->abort_slave = 0; // TODO: check if this is needed
DBUG_ASSERT(thd->net.buff != 0);
- net_end(&thd->net); // destructor will not free it, because we are weird
+ net_end(&thd->net); // destructor will not free it, because net.vio is 0
pthread_mutex_lock(&LOCK_thread_count);
+ THD_CHECK_SENTRY(thd);
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
+ my_thread_end(); // clean-up before broadcast
pthread_cond_broadcast(&mi->stop_cond); // tell the world we are done
pthread_mutex_unlock(&mi->run_lock);
- my_thread_end();
#ifndef DBUG_OFF
if(abort_slave_event_count && !events_till_abort)
goto slave_begin;
@@ -1832,7 +1942,8 @@ slave_begin:
my_thread_init();
thd = new THD; // note that contructor of THD uses DBUG_ !
DBUG_ENTER("handle_slave_sql");
-
+ THD_CHECK_SENTRY(thd);
+
pthread_detach_this_thread();
if (init_slave_thread(thd, SLAVE_THD_SQL))
{
@@ -1845,6 +1956,7 @@ slave_begin:
sql_print_error("Failed during slave thread initialization");
goto err;
}
+ THD_CHECK_SENTRY(thd);
thd->thread_stack = (char*)&thd; // remember where our stack is
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
threads.append(thd);
@@ -1871,14 +1983,15 @@ slave_begin:
log '%s' at position %s,relay log: name='%s',pos='%s'", RPL_LOG_NAME,
llstr(rli->master_log_pos,llbuff),rli->relay_log_name,
llstr(rli->relay_log_pos,llbuff1));
- while (!slave_killed(thd,rli))
+ while (!sql_slave_killed(thd,rli))
{
thd->proc_info = "Processing master log event";
DBUG_ASSERT(rli->sql_thd == thd);
+ THD_CHECK_SENTRY(thd);
if (exec_relay_log_event(thd,rli))
{
// do not scare the user if SQL thread was simply killed or stopped
- if (!slave_killed(thd,rli))
+ if (!sql_slave_killed(thd,rli))
sql_print_error("\
Error running query, slave SQL thread aborted. Fix the problem, and restart \
the slave SQL thread with \"SLAVE START\". We stopped at log \
@@ -1886,7 +1999,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
goto err;
}
- } // while(!slave_killed(thd,rli)) - read/exec loop
+ } // while(!sql_slave_killed(thd,rli)) - read/exec loop
// error = 0;
err:
@@ -1910,14 +2023,16 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because we are weird
DBUG_ASSERT(rli->sql_thd == thd);
+ THD_CHECK_SENTRY(thd);
rli->sql_thd = 0;
pthread_mutex_lock(&LOCK_thread_count);
+ THD_CHECK_SENTRY(thd);
delete thd;
pthread_mutex_unlock(&LOCK_thread_count);
+ my_thread_end(); // clean-up before broadcasting termination
pthread_cond_broadcast(&rli->stop_cond);
// tell the world we are done
pthread_mutex_unlock(&rli->run_lock);
- my_thread_end();
#ifndef DBUG_OFF // TODO: reconsider the code below
if (abort_slave_event_count && !rli->events_till_abort)
goto slave_begin;
@@ -1926,11 +2041,104 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_RETURN(0); // Can't return anything here
}
+static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
+{
+ int error = 1;
+ ulong num_bytes;
+ bool cev_not_written;
+ THD* thd;
+ NET* net = &mi->mysql->net;
+
+ if (unlikely(!cev->is_valid()))
+ return 1;
+ /*
+ TODO: fix to honor table rules, not only db rules
+ */
+ if (!db_ok(cev->db, replicate_do_db, replicate_ignore_db))
+ {
+ skip_load_data_infile(net);
+ return 0;
+ }
+ DBUG_ASSERT(cev->inited_from_old);
+ thd = mi->io_thd;
+ thd->file_id = cev->file_id = mi->file_id++;
+ thd->server_id = cev->server_id;
+ cev_not_written = 1;
+
+ if (unlikely(net_request_file(net,cev->fname)))
+ {
+ sql_print_error("Slave I/O: failed requesting download of '%s'",
+ cev->fname);
+ goto err;
+ }
+
+ /* this dummy block is so we could instantiate Append_block_log_event
+ once and then modify it slightly instead of doing it multiple times
+ in the loop
+ */
+ {
+ Append_block_log_event aev(thd,0,0);
+
+ for (;;)
+ {
+ if (unlikely((num_bytes=my_net_read(net)) == packet_error))
+ {
+ sql_print_error("Network read error downloading '%s' from master",
+ cev->fname);
+ goto err;
+ }
+ if (unlikely(!num_bytes)) /* eof */
+ {
+ send_ok(net); /* 3.23 master wants it */
+ Execute_load_log_event xev(thd);
+ xev.log_pos = mi->master_log_pos;
+ if (unlikely(mi->rli.relay_log.append(&xev)))
+ {
+ sql_print_error("Slave I/O: error writing Exec_load event to \
+relay log");
+ goto err;
+ }
+ mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
+ break;
+ }
+ if (unlikely(cev_not_written))
+ {
+ cev->block = (char*)net->read_pos;
+ cev->block_len = num_bytes;
+ cev->log_pos = mi->master_log_pos;
+ if (unlikely(mi->rli.relay_log.append(cev)))
+ {
+ sql_print_error("Slave I/O: error writing Create_file event to \
+relay log");
+ goto err;
+ }
+ cev_not_written=0;
+ mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
+ }
+ else
+ {
+ aev.block = (char*)net->read_pos;
+ aev.block_len = num_bytes;
+ aev.log_pos = mi->master_log_pos;
+ if (unlikely(mi->rli.relay_log.append(&aev)))
+ {
+ sql_print_error("Slave I/O: error writing Append_block event to \
+relay log");
+ goto err;
+ }
+ mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total) ;
+ }
+ }
+ }
+ error=0;
+err:
+ return error;
+}
// We assume we already locked mi->data_lock
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev)
{
- if (!rev->is_valid())
+ if (unlikely(!rev->is_valid()))
return 1;
DBUG_ASSERT(rev->ident_len<sizeof(mi->master_log_name));
memcpy(mi->master_log_name,rev->new_log_ident,
@@ -1961,6 +2169,21 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
const char *errmsg = 0;
bool inc_pos = 1;
bool processed_stop_event = 0;
+ char* tmp_buf = 0;
+ /* if we get Load event, we need to pass a non-reusable buffer
+ to read_log_event, so we do a trick
+ */
+ if (buf[EVENT_TYPE_OFFSET] == LOAD_EVENT)
+ {
+ if (unlikely(!(tmp_buf=(char*)my_malloc(event_len+1,MYF(MY_WME)))))
+ {
+ sql_print_error("Slave I/O: out of memory for Load event");
+ return 1;
+ }
+ memcpy(tmp_buf,buf,event_len);
+ tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer
+ buf = (const char*)tmp_buf;
+ }
Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
1 /*old format*/ );
if (unlikely(!ev))
@@ -1968,6 +2191,7 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
sql_print_error("Read invalid event from master: '%s',\
master could be corrupt but a more likely cause of this is a bug",
errmsg);
+ my_free((char*)tmp_buf, MYF(MY_ALLOW_ZERO_PTR));
return 1;
}
pthread_mutex_lock(&mi->data_lock);
@@ -1978,6 +2202,7 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
{
delete ev;
pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(!tmp_buf);
return 1;
}
mi->ignore_stop_event=1;
@@ -1986,12 +2211,16 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
case STOP_EVENT:
processed_stop_event=1;
break;
- case LOAD_EVENT:
- // TODO: actually process it
- mi->master_log_pos += event_len;
+ case CREATE_FILE_EVENT:
+ {
+ int error = process_io_create_file(mi,(Create_file_log_event*)ev);
delete ev;
+ mi->master_log_pos += event_len;
pthread_mutex_unlock(&mi->data_lock);
- return 0;
+ DBUG_ASSERT(tmp_buf);
+ my_free((char*)tmp_buf, MYF(0));
+ return error;
+ }
default:
mi->ignore_stop_event=0;
break;
@@ -2002,8 +2231,10 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
{
delete ev;
pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(!tmp_buf);
return 1;
}
+ mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
}
delete ev;
if (likely(inc_pos))
@@ -2011,6 +2242,7 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
if (unlikely(processed_stop_event))
mi->ignore_stop_event=1;
pthread_mutex_unlock(&mi->data_lock);
+ DBUG_ASSERT(!tmp_buf);
return 0;
}
@@ -2056,6 +2288,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
{
if (likely(inc_pos))
mi->master_log_pos += event_len;
+ mi->rli.relay_log.harvest_bytes_written(&mi->rli.log_space_total);
}
if (unlikely(processed_stop_event))
mi->ignore_stop_event=1;
@@ -2108,7 +2341,7 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
#ifndef DBUG_OFF
events_till_disconnect = disconnect_slave_event_count;
#endif
- while (!(slave_was_killed = slave_killed(thd,mi)) &&
+ while (!(slave_was_killed = io_slave_killed(thd,mi)) &&
(reconnect ? mc_mysql_reconnect(mysql) != 0 :
!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, 0)))
@@ -2122,7 +2355,8 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
mc_mysql_error(mysql), last_errno=mc_mysql_errno(mysql),
mi->connect_retry);
}
- safe_sleep(thd,mi,mi->connect_retry);
+ safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
+ (void*)mi);
/*
By default we try forever. The reason is that failure will trigger
master election, so if the user did not set master_retry_count we
@@ -2173,7 +2407,7 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
int flush_relay_log_info(RELAY_LOG_INFO* rli)
{
- IO_CACHE* file = &rli->info_file;
+ register IO_CACHE* file = &rli->info_file;
char lbuf[22],lbuf1[22];
my_b_seek(file, 0L);
@@ -2217,7 +2451,7 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
*/
pthread_mutex_lock(&rli->data_lock);
- for (; !(was_killed=slave_killed(thd,rli)) ;)
+ for (; !(was_killed=sql_slave_killed(thd,rli)) ;)
{
/*
We can have two kinds of log reading:
@@ -2251,7 +2485,10 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
}
DBUG_ASSERT(my_b_tell(cur_log) >= 4);
DBUG_ASSERT(my_b_tell(cur_log) == rli->relay_log_pos + rli->pending);
- if ((ev=Log_event::read_log_event(cur_log,0,rli->mi->old_format)))
+ /* relay log is always in new format - if the master is 3.23, the
+ I/O thread will convert the format for us
+ */
+ if ((ev=Log_event::read_log_event(cur_log,0,(bool)0/*new format*/)))
{
DBUG_ASSERT(thd==rli->sql_thd);
if (hot_log)
@@ -2296,13 +2533,35 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
end_io_cache(cur_log);
DBUG_ASSERT(rli->cur_log_fd >= 0);
my_close(rli->cur_log_fd, MYF(MY_WME));
- rli->cur_log_fd = -1;
+ rli->cur_log_fd = -1;
- // purge_first_log will properly set up relay log coordinates in rli
- if (rli->relay_log.purge_first_log(rli))
+ // TODO: make skip_log_purge a start-up option. At this point this
+ // is not critical priority
+ if (!rli->skip_log_purge)
{
- errmsg = "Error purging processed log";
- goto err;
+ // purge_first_log will properly set up relay log coordinates in rli
+ if (rli->relay_log.purge_first_log(rli))
+ {
+ errmsg = "Error purging processed log";
+ goto err;
+ }
+ }
+ else
+ {
+ // TODO: verify that no lock is ok here. At this point, if we
+ // get this wrong, this is actually no big deal - the only time
+ // this code will ever be executed is if we are recovering from
+ // a bug when a full reload of the slave is not feasible or
+ // desirable.
+ if (rli->relay_log.find_next_log(&rli->linfo,0/*no lock*/))
+ {
+ errmsg = "error switching to the next log";
+ goto err;
+ }
+ rli->relay_log_pos = 4;
+ strnmov(rli->relay_log_name,rli->linfo.log_file_name,
+ sizeof(rli->relay_log_name));
+ flush_relay_log_info(rli);
}
// next log is hot
@@ -2344,9 +2603,12 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
sql_print_error("Slave SQL thread: I/O error reading \
event(errno=%d,cur_log->error=%d)",
my_errno,cur_log->error);
+ // set read position to the beginning of the event
+ my_b_seek(cur_log,rli->relay_log_pos+rli->pending);
// no need to hog the mutex while we sleep
pthread_mutex_unlock(&rli->data_lock);
- safe_sleep(rli->sql_thd,rli->mi,1);
+ safe_sleep(rli->sql_thd,1,(CHECK_KILLED_FUNC)sql_slave_killed,
+ (void*)rli);
pthread_mutex_lock(&rli->data_lock);
}
}
diff --git a/sql/slave.h b/sql/slave.h
index f60f2ce2954..354fc46e99d 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -31,6 +31,7 @@ extern char* slave_load_tmpdir;
extern my_string master_info_file,relay_log_info_file;
extern my_string opt_relay_logname, opt_relaylog_index_name;
extern bool opt_skip_slave_start;
+extern ulong relay_log_space_limit;
struct st_master_info;
/*
@@ -151,25 +152,36 @@ typedef struct st_relay_log_info
char last_slave_error[MAX_SLAVE_ERRMSG];
THD* sql_thd;
bool log_pos_current;
+ bool abort_pos_wait;
+ bool skip_log_purge;
+ ulonglong log_space_limit,log_space_total;
+ pthread_mutex_t log_space_lock;
+ pthread_cond_t log_space_cond;
st_relay_log_info():info_fd(-1),cur_log_fd(-1),inited(0),
cur_log_init_count(0),
- log_pos_current(0)
+ log_pos_current(0),abort_pos_wait(0),
+ skip_log_purge(0)
{
relay_log_name[0] = master_log_name[0] = 0;
+ bzero(&info_file,sizeof(info_file));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
pthread_cond_init(&data_cond, NULL);
pthread_cond_init(&start_cond, NULL);
pthread_cond_init(&stop_cond, NULL);
+ pthread_cond_init(&log_space_cond, NULL);
}
~st_relay_log_info()
{
pthread_mutex_destroy(&run_lock);
pthread_mutex_destroy(&data_lock);
+ pthread_mutex_destroy(&log_space_lock);
pthread_cond_destroy(&data_cond);
pthread_cond_destroy(&start_cond);
pthread_cond_destroy(&stop_cond);
+ pthread_cond_destroy(&log_space_cond);
}
inline void inc_pending(ulonglong val)
{
@@ -254,6 +266,8 @@ typedef struct st_master_info
pthread_mutex_t data_lock,run_lock;
pthread_cond_t data_cond,start_cond,stop_cond;
THD *io_thd;
+ MYSQL* mysql;
+ uint32 file_id; // for 3.23 load data infile
RELAY_LOG_INFO rli;
uint port;
uint connect_retry;
@@ -269,6 +283,7 @@ typedef struct st_master_info
st_master_info():fd(-1), io_thd(0), inited(0), old_format(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
+ bzero(&file,sizeof(file));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
pthread_cond_init(&data_cond, NULL);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 577084a650a..104b431bdbb 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -221,6 +221,8 @@ int acl_init(bool dont_read_acl_tables)
user.x509_issuer=get_field(&mem, table, 19);
user.x509_subject=get_field(&mem, table, 20);
}
+ else
+ user.ssl_type=SSL_TYPE_NONE;
#endif /* HAVE_OPENSSL */
if (user.password && (length=(uint) strlen(user.password)) == 8 &&
protocol_version == PROTOCOL_VERSION)
@@ -920,14 +922,10 @@ bool acl_check_host(const char *host, const char *ip)
bool change_password(THD *thd, const char *host, const char *user,
char *new_password)
{
+ uint length=0;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("thd=%x, host='%s', user='%s', new_password='%s'",thd,host,user,new_password));
- uint length=0;
- if (!user[0])
- {
- send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER);
- DBUG_RETURN(1);
- }
+
if (!initialized)
{
send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */
@@ -939,16 +937,21 @@ bool change_password(THD *thd, const char *host, const char *user,
length=(uint) strlen(new_password);
new_password[length & 16]=0;
- if (!thd || (!thd->slave_thread && ( strcmp(thd->user,user) ||
- my_strcasecmp(host,thd->host ? thd->host : thd->ip))))
+ if (!thd->slave_thread &&
+ (strcmp(thd->user,user) ||
+ my_strcasecmp(host,thd->host ? thd->host : thd->ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
DBUG_RETURN(1);
}
+ if (!thd->slave_thread && !thd->user[0])
+ {
+ send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER);
+ DBUG_RETURN(1);
+ }
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
- DBUG_PRINT("info",("host=%s, user=%s",host,user));
- if (!(acl_user= find_acl_user(host,user)) || !acl_user->user)
+ if (!(acl_user= find_acl_user(host,user)))
{
send_error(&thd->net, ER_PASSWORD_NO_MATCH);
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -956,7 +959,8 @@ bool change_password(THD *thd, const char *host, const char *user,
}
if (update_user_table(thd,
acl_user->host.hostname ? acl_user->host.hostname : "",
- acl_user->user, new_password))
+ acl_user->user ? acl_user->user : "",
+ new_password))
{
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
send_error(&thd->net,0); /* purecov: deadcode */
@@ -976,7 +980,7 @@ bool change_password(THD *thd, const char *host, const char *user,
qinfo.q_len =
my_sprintf(buff,
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
- acl_user->user,
+ acl_user->user ? acl_user->user : "",
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
mysql_update_log.write(thd,buff,qinfo.q_len);
@@ -1201,7 +1205,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
/* We write down SSL related ACL stuff */
DBUG_PRINT("info",("table->fields=%d",table->fields));
if (table->fields >= 21) /* From 4.0.0 we have more fields */
- {
+ {
table->field[18]->store("",0);
table->field[19]->store("",0);
table->field[20]->store("",0);
@@ -2687,6 +2691,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
#endif /* HAVE_OPENSSL */
if (want_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18);
+ else if (acl_user->questions)
+ {
+ char buff[65], *p; // just as in int2str
+ global.append(" WITH MAX_QUERIES_PER_HOUR = ",29);
+ p=int2str(acl_user->questions,buff,10);
+ global.append(buff,p-buff);
+ }
thd->packet.length(0);
net_store_data(&thd->packet,global.ptr(),global.length());
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
@@ -2734,9 +2745,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
}
- db.append (" ON ",4);
+ db.append (" ON '",5);
db.append(acl_db->db);
- db.append (".* TO '",7);
+ db.append ("'.* TO '",8);
db.append(lex_user->user.str,lex_user->user.length);
db.append ("'@'",3);
db.append(lex_user->host.str, lex_user->host.length);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a5116fa0e20..88854396ae3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -430,6 +430,7 @@ void close_thread_tables(THD *thd, bool locked)
while (thd->open_tables)
found_old_table|=close_thread_table(thd, &thd->open_tables);
+ thd->some_tables_deleted=0;
/* Free tables to hold down open files */
while (open_cache.records > table_cache_size && unused_tables)
@@ -708,11 +709,11 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
if (open_unireg_entry(thd, table, db, table_name, table_name, 1) ||
!(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
key_length)))
- {
- closefrm(table);
- pthread_mutex_unlock(&LOCK_open);
- DBUG_RETURN(0);
- }
+ {
+ closefrm(table);
+ pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(0);
+ }
table->key_length=key_length;
table->version=0;
@@ -1692,7 +1693,7 @@ find_item_in_list(Item *find,List<Item> &items)
{
if (found)
{
- if ((*found)->eq(item))
+ if ((*found)->eq(item,0))
continue; // Same field twice (Access?)
if (current_thd->where)
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
@@ -1708,7 +1709,7 @@ find_item_in_list(Item *find,List<Item> &items)
}
}
}
- else if (!table_name && (item->eq(find) ||
+ else if (!table_name && (item->eq(find,0) ||
find->name &&
!my_strcasecmp(item->name,find->name)))
{
@@ -2175,8 +2176,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
int setup_ftfuncs(THD *thd)
{
- List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list),
- lj(thd->lex.select_lex.ftfunc_list);
+ List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list),
+ lj(thd->lex.select->ftfunc_list);
Item_func_match *ftf, *ftf2;
while ((ftf=li++))
@@ -2186,7 +2187,7 @@ int setup_ftfuncs(THD *thd)
lj.rewind();
while ((ftf2=lj++) != ftf)
{
- if (ftf->eq(ftf2) && !ftf2->master)
+ if (ftf->eq(ftf2,1) && !ftf2->master)
ftf2->master=ftf;
}
}
@@ -2196,9 +2197,9 @@ int setup_ftfuncs(THD *thd)
int init_ftfuncs(THD *thd, bool no_order)
{
- if (thd->lex.select_lex.ftfunc_list.elements)
+ if (thd->lex.select->ftfunc_list.elements)
{
- List_iterator<Item_func_match> li(thd->lex.select_lex.ftfunc_list);
+ List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list);
Item_func_match *ifm;
DBUG_PRINT("info",("Performing FULLTEXT search"));
thd->proc_info="FULLTEXT initialization";
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index c5ebeead05a..588d60462b0 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -271,8 +271,6 @@ If join_results allocated new block(s) then we need call pack_cache again.
TODO list:
- - Invalidate queries that use innoDB tables changed in transaction & remove
- invalidation by table type
- Delayed till after-parsing qache answer (for column rights processing)
- Optimize cache resizing
- if new_size < old_size then pack & shrink
@@ -280,11 +278,10 @@ TODO list:
- Move MRG_MYISAM table type processing to handlers, something like:
tables_used->table->file->register_used_filenames(callback,
first_argument);
- - In Query_cache::insert_table eliminate strlen(). To do this we have to
- add db_len to the TABLE_LIST and TABLE structures.
*/
#include "mysql_priv.h"
+#ifdef HAVE_QUERY_CACHE
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
@@ -1030,7 +1027,8 @@ err:
Remove all cached queries that uses any of the tables in the list
*/
-void Query_cache::invalidate(TABLE_LIST *tables_used)
+void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
+ my_bool using_transactions)
{
DBUG_ENTER("Query_cache::invalidate (table list)");
if (query_cache_size > 0)
@@ -1039,54 +1037,76 @@ void Query_cache::invalidate(TABLE_LIST *tables_used)
if (query_cache_size > 0)
{
DUMP(this);
+
+ using_transactions = using_transactions &&
+ (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN));
for ( ; tables_used; tables_used=tables_used->next)
- invalidate_table(tables_used);
+ {
+ DBUG_ASSERT(!using_transactions || tables_used->table!=0);
+ if (using_transactions &&
+ tables_used->table->file->has_transactions())
+ /*
+ Tables_used->table can't be 0 in transaction.
+ Only 'drop' invalidate not opened table, but 'drop'
+ force transaction finish.
+ */
+ thd->add_changed_table(tables_used->table);
+ else
+ invalidate_table(tables_used);
+ }
}
STRUCT_UNLOCK(&structure_guard_mutex);
}
DBUG_VOID_RETURN;
}
-/*
- Remove all cached queries that uses the given table
-*/
-
-void Query_cache::invalidate(TABLE *table)
+void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
{
- DBUG_ENTER("Query_cache::invalidate (table)");
- if (query_cache_size > 0)
+ DBUG_ENTER("Query_cache::invalidate (changed table list)");
+ if (query_cache_size > 0 && tables_used)
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
- invalidate_table(table);
+ {
+ DUMP(this);
+ for ( ; tables_used; tables_used=tables_used->next)
+ {
+ invalidate_table(tables_used->key, tables_used->key_length);
+ DBUG_PRINT("qcache", (" db %s, table %s", tables_used->key,
+ tables_used->table_name));
+ }
+ }
STRUCT_UNLOCK(&structure_guard_mutex);
}
DBUG_VOID_RETURN;
}
/*
- Remove all cached queries that uses the given table type.
+ Remove all cached queries that uses the given table
*/
-void Query_cache::invalidate(Query_cache_table::query_cache_table_type type)
+void Query_cache::invalidate(THD *thd, TABLE *table,
+ my_bool using_transactions)
{
- DBUG_ENTER("Query_cache::invalidate (type)");
+ DBUG_ENTER("Query_cache::invalidate (table)");
+
if (query_cache_size > 0)
{
STRUCT_LOCK(&structure_guard_mutex);
- DUMP(this);
if (query_cache_size > 0)
{
- /* invalidate_table reduce list while only root of list remain */
- while (tables_blocks[type] != 0)
- invalidate_table(tables_blocks[type]);
+ using_transactions = using_transactions &&
+ (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN));
+ if (using_transactions && table->file->has_transactions())
+ thd->add_changed_table(table);
+ else
+ invalidate_table(table);
}
STRUCT_UNLOCK(&structure_guard_mutex);
}
DBUG_VOID_RETURN;
}
-
/*
Remove all cached queries that uses the given database
*/
@@ -1100,12 +1120,9 @@ void Query_cache::invalidate(char *db)
if (query_cache_size > 0)
{
DUMP(this);
- for (int i=0 ; i < (int) Query_cache_table::TYPES_NUMBER; i++)
- {
/* invalidate_table reduce list while only root of list remain */
- while (tables_blocks[i] !=0 )
- invalidate_table(tables_blocks[i]);
- }
+ while (tables_blocks !=0 )
+ invalidate_table(tables_blocks);
}
STRUCT_UNLOCK(&structure_guard_mutex);
}
@@ -1120,7 +1137,8 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
{
/* Calculate the key outside the lock to make the lock shorter */
char key[MAX_DBKEY_LENGTH];
- uint key_length= filename_2_table_key(key, filename);
+ uint32 db_length;
+ uint key_length= filename_2_table_key(key, filename, &db_length);
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0) // Safety if cache removed
{
@@ -1801,10 +1819,14 @@ void Query_cache::invalidate_table(TABLE_LIST *table_list)
void Query_cache::invalidate_table(TABLE *table)
{
+ invalidate_table((byte*) table->table_cache_key, table->key_length);
+}
+
+void Query_cache::invalidate_table(byte * key, uint32 key_length)
+{
Query_cache_block *table_block;
if ((table_block = ((Query_cache_block*)
- hash_search(&tables, (byte*) table->table_cache_key,
- table->key_length))))
+ hash_search(&tables, key, key_length))))
invalidate_table(table_block);
}
@@ -1842,8 +1864,7 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
block_table->n=n;
if (!insert_table(tables_used->table->key_length,
tables_used->table->table_cache_key, block_table,
- Query_cache_table::type_convertion(tables_used->table->
- db_type)))
+ tables_used->db_length))
break;
if (tables_used->table->db_type == DB_TYPE_MRG_MYISAM)
@@ -1855,10 +1876,12 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
table++)
{
char key[MAX_DBKEY_LENGTH];
- uint key_length =filename_2_table_key(key, table->table->filename);
+ uint32 db_length;
+ uint key_length =filename_2_table_key(key, table->table->filename,
+ &db_length);
(++block_table)->n= ++n;
if (!insert_table(key_length, key, block_table,
- Query_cache_table::type_convertion(DB_TYPE_MYISAM)))
+ db_length))
goto err;
}
}
@@ -1885,7 +1908,7 @@ err:
my_bool
Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *node,
- Query_cache_table::query_cache_table_type type)
+ uint32 db_length)
{
DBUG_ENTER("Query_cache::insert_table");
DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
@@ -1909,9 +1932,8 @@ Query_cache::insert_table(uint key_len, char *key,
DBUG_RETURN(0);
}
Query_cache_table *header = table_block->table();
- header->type(type);
double_linked_list_simple_include(table_block,
- &tables_blocks[type]);
+ &tables_blocks);
Query_cache_block_table *list_root = table_block->table(0);
list_root->n = 0;
list_root->next = list_root->prev = list_root;
@@ -1923,7 +1945,7 @@ Query_cache::insert_table(uint key_len, char *key,
DBUG_RETURN(0);
}
char *db = header->db();
- header->table(db + strlen(db) + 1);
+ header->table(db + db_length + 1);
}
Query_cache_block_table *list_root = table_block->table(0);
@@ -1947,7 +1969,7 @@ void Query_cache::unlink_table(Query_cache_block_table *node)
// list is empty (neighbor is root of list)
Query_cache_block *table_block = neighbour->block();
double_linked_list_exclude(table_block,
- &tables_blocks[table_block->table()->type()]);
+ &tables_blocks);
hash_delete(&tables,(byte *) table_block);
free_memory_block(table_block);
}
@@ -2033,7 +2055,7 @@ Query_cache::get_free_block(ulong len, my_bool not_less, ulong min)
block=block->prev;
n++;
}
- if(block->length < len)
+ if (block->length < len)
block=block->next;
}
}
@@ -2513,8 +2535,8 @@ my_bool Query_cache::move_by_type(byte **border,
new_block->n_tables=1;
memmove((char*) new_block->data(), data, len-new_block->headers_len());
relink(block, new_block, next, prev, pnext, pprev);
- if (tables_blocks[new_block->table()->type()] == block)
- tables_blocks[new_block->table()->type()] = new_block;
+ if (tables_blocks == block)
+ tables_blocks = new_block;
Query_cache_block_table *nlist_root = new_block->table(0);
nlist_root->n = 0;
@@ -2771,10 +2793,10 @@ my_bool Query_cache::join_results(ulong join_limit)
}
-uint Query_cache::filename_2_table_key (char *key, const char *path)
+uint Query_cache::filename_2_table_key (char *key, const char *path,
+ uint32 *db_length)
{
char tablename[FN_REFLEN+2], *filename, *dbname;
- uint db_length;
DBUG_ENTER("Query_cache::filename_2_table_key");
/* Safety if filename didn't have a directory name */
@@ -2785,10 +2807,10 @@ uint Query_cache::filename_2_table_key (char *key, const char *path)
filename= tablename + dirname_length(tablename + 2) + 2;
/* Find start of databasename */
for (dbname= filename - 2 ; dbname[-1] != FN_LIBCHAR ; dbname--) ;
- db_length= (filename - dbname) - 1;
- DBUG_PRINT("qcache", ("table '%-.*s.%s'", db_length, dbname, filename));
+ *db_length= (filename - dbname) - 1;
+ DBUG_PRINT("qcache", ("table '%-.*s.%s'", *db_length, dbname, filename));
- DBUG_RETURN((uint) (strmov(strmake(key, dbname, db_length) + 1,
+ DBUG_RETURN((uint) (strmov(strmake(key, dbname, *db_length) + 1,
filename) -key) + 1);
}
@@ -2975,22 +2997,18 @@ void Query_cache::tables_dump()
DBUG_PRINT("qcache", ("--------------------"));
DBUG_PRINT("qcache", ("TABLES"));
DBUG_PRINT("qcache", ("--------------------"));
- for (int i=0; i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ if (tables_blocks != 0)
{
- DBUG_PRINT("qcache", ("--- type %u", i));
- if (tables_blocks[i] != 0)
+ Query_cache_block *table_block = tables_blocks;
+ do
{
- Query_cache_block *table_block = tables_blocks[i];
- do
- {
- Query_cache_table *table = table_block->table();
- DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
- table_block = table_block->next;
- } while ( table_block != tables_blocks[i]);
- }
- else
- DBUG_PRINT("qcache", ("no tables in list"));
+ Query_cache_table *table = table_block->table();
+ DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
+ table_block = table_block->next;
+ } while ( table_block != tables_blocks);
}
+ else
+ DBUG_PRINT("qcache", ("no tables in list"));
DBUG_PRINT("qcache", ("--------------------"));
}
@@ -3082,7 +3100,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
break;
}
case Query_cache_block::TABLE:
- if (in_list(tables_blocks[block->table()->type()], block, "tables"))
+ if (in_list(tables_blocks, block, "tables"))
result = 1;
if (in_table_list(block->table(0), block->table(0), "table list root"))
result = 1;
@@ -3197,28 +3215,25 @@ my_bool Query_cache::check_integrity(bool not_locked)
}
DBUG_PRINT("qcache", ("check tables ..."));
- for (i=0 ; (int) i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ if ((block = tables_blocks))
{
- if ((block = tables_blocks[i]))
+ do
{
- do
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_table_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&tables, key, length);
+ if (((gptr)block) != val)
{
- DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
- (ulong) block, (uint) block->type));
- uint length;
- byte *key = query_cache_table_get_key((byte*) block, &length, 0);
- gptr val = hash_search(&tables, key, length);
- if (((gptr)block) != val)
- {
- DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
- (ulong) block, (ulong) val));
- }
-
- if (in_blocks(block))
- result = 1;
- block=block->next;
- } while (block != tables_blocks[i]);
- }
+ DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+
+ if (in_blocks(block))
+ result = 1;
+ block=block->next;
+ } while (block != tables_blocks);
}
DBUG_PRINT("qcache", ("check free blocks"));
@@ -3446,3 +3461,5 @@ err2:
}
#endif /* DBUG_OFF */
+
+#endif /*HAVE_QUERY_CACHE*/
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index b1d8eb23198..81ea80669b8 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -148,17 +148,8 @@ struct Query_cache_query
struct Query_cache_table
{
- enum query_cache_table_type {OTHER=0, INNODB=1, TYPES_NUMBER=2};
- inline static query_cache_table_type type_convertion(db_type type)
- {
- return (type == DB_TYPE_INNODB ? INNODB : OTHER);
- }
-
char *tbl;
- query_cache_table_type tp;
- inline query_cache_table_type type() { return tp; }
- inline void type(query_cache_table_type t) { tp = t;}
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
inline void table(char *table) { tbl = table; }
@@ -248,7 +239,7 @@ protected:
byte *cache; // cache memory
Query_cache_block *first_block; // physical location block list
Query_cache_block *queries_blocks; // query list (LIFO)
- Query_cache_block *tables_blocks[Query_cache_table::TYPES_NUMBER];
+ Query_cache_block *tables_blocks;
Query_cache_memory_bin *bins; // free block lists
Query_cache_memory_bin_step *steps; // bins spacing info
@@ -270,7 +261,8 @@ protected:
Query_cache_block *tail_head);
/* Table key generation */
- static uint filename_2_table_key (char *key, const char *filename);
+ static uint filename_2_table_key (char *key, const char *filename,
+ uint32 *db_langth);
/* The following functions require that structure_guard_mutex is locked */
void flush_cache();
@@ -282,13 +274,14 @@ protected:
my_bool first_block);
void invalidate_table(TABLE_LIST *table);
void invalidate_table(TABLE *table);
+ void invalidate_table(byte *key, uint32 key_length);
void invalidate_table(Query_cache_block *table_block);
my_bool register_all_tables(Query_cache_block *block,
TABLE_LIST *tables_used,
TABLE_COUNTER_TYPE tables);
my_bool insert_table(uint key_len, char *key,
Query_cache_block_table *node,
- Query_cache_table::query_cache_table_type type);
+ uint32 db_length);
void unlink_table(Query_cache_block_table *node);
Query_cache_block *get_free_block (ulong len, my_bool not_less,
ulong min);
@@ -369,11 +362,10 @@ protected:
int send_result_to_client(THD *thd, char *query, uint query_length);
/* Remove all queries that uses any of the listed following tables */
- void invalidate(TABLE_LIST *tables_used);
- void invalidate(TABLE *table);
-
- /* Remove all queries that uses tables of pointed type*/
- void invalidate(Query_cache_table::query_cache_table_type type);
+ void invalidate(THD* thd, TABLE_LIST *tables_used,
+ my_bool using_transactions);
+ void invalidate(CHANGED_TABLE_LIST *tables_used);
+ void invalidate(THD* thd, TABLE *table, my_bool using_transactions);
/* Remove all queries that uses any of the tables in following database */
void invalidate(char *db);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 795e7bcef00..03bb8ae2c97 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -34,6 +34,8 @@
#ifdef __WIN__
#include <io.h>
#endif
+#include <mysys_err.h>
+#include <assert.h>
/*****************************************************************************
** Instansiate templates
@@ -102,9 +104,13 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
cond_count=0;
convert_set=0;
mysys_var=0;
+#ifndef DBUG_OFF
+ dbug_sentry=THD_SENTRY_MAGIC;
+#endif
net.vio=0;
ull=0;
system_thread=cleanup_done=0;
+ transaction.changed_tables = 0;
#ifdef __WIN__
real_id = 0;
#endif
@@ -119,10 +125,14 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
server_id = ::server_id;
slave_net = 0;
log_pos = 0;
- server_status=SERVER_STATUS_AUTOCOMMIT;
+ server_status= SERVER_STATUS_AUTOCOMMIT;
update_lock_default= low_priority_updates ? TL_WRITE_LOW_PRIORITY : TL_WRITE;
- options=thd_startup_options;
- query_cache_type = (byte) query_cache_startup_type;
+ options= thd_startup_options;
+#ifdef HAVE_QUERY_CACHE
+ query_cache_type= (byte) query_cache_startup_type;
+#else
+ query_cache_type= 0; //Safety
+#endif
sql_mode=(uint) opt_sql_mode;
inactive_timeout=net_wait_timeout;
open_options=ha_open_options;
@@ -136,12 +146,13 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
/* Initialize sub structures */
bzero((char*) &mem_root,sizeof(mem_root));
+ bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
+ user_connect=(UC *)0;
hash_init(&user_vars, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(void (*)(void*)) free_var,0);
#ifdef USING_TRANSACTIONS
bzero((char*) &transaction,sizeof(transaction));
- user_connect=(UC *)0;
if (opt_using_transactions)
{
if (open_cached_file(&transaction.trans_log,
@@ -183,6 +194,7 @@ void THD::cleanup(void)
THD::~THD()
{
+ THD_CHECK_SENTRY(this);
DBUG_ENTER("~THD()");
/* Close connection */
if (net.vio)
@@ -211,15 +223,20 @@ THD::~THD()
safeFree(db);
safeFree(ip);
free_root(&mem_root,MYF(0));
+ free_root(&transaction.mem_root,MYF(0));
mysys_var=0; // Safety (shouldn't be needed)
#ifdef SIGNAL_WITH_VIO_CLOSE
pthread_mutex_destroy(&active_vio_lock);
+#endif
+#ifndef DBUG_OFF
+ dbug_sentry = THD_SENTRY_GONE;
#endif
DBUG_VOID_RETURN;
}
void THD::awake(bool prepare_to_die)
{
+ THD_CHECK_SENTRY(this);
if (prepare_to_die)
killed = 1;
thr_alarm_kill(real_id);
@@ -255,6 +272,88 @@ bool THD::store_globals()
my_pthread_setspecific_ptr(THR_NET, &net));
}
+/* routings to adding tables to list of changed in transaction tables */
+
+inline static void list_include(CHANGED_TABLE_LIST** prev,
+ CHANGED_TABLE_LIST* curr,
+ CHANGED_TABLE_LIST* new_table)
+{
+ if (new_table)
+ {
+ *prev = new_table;
+ (*prev)->next = curr;
+ }
+}
+
+/* add table to list of changed in transaction tables */
+void THD::add_changed_table(TABLE *table)
+{
+ DBUG_ENTER("THD::add_changed_table (table)");
+
+ DBUG_ASSERT((options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)) &&
+ table->file->has_transactions());
+
+ CHANGED_TABLE_LIST** prev = &transaction.changed_tables;
+ CHANGED_TABLE_LIST* curr = transaction.changed_tables;
+
+ for(; curr; prev = &(curr->next), curr = curr->next)
+ {
+ int cmp = (long)curr->key_length - (long)table->key_length;
+ if (cmp < 0)
+ {
+ list_include(prev, curr, changed_table_dup(table));
+ DBUG_PRINT("info",
+ ("key_length %u %u", table->key_length, (*prev)->key_length));
+ DBUG_VOID_RETURN;
+ }
+ else if (cmp == 0)
+ {
+ cmp = memcmp(curr->key ,table->table_cache_key, curr->key_length);
+ if (cmp < 0)
+ {
+ list_include(prev, curr, changed_table_dup(table));
+ DBUG_PRINT("info",
+ ("key_length %u %u", table->key_length, (*prev)->key_length));
+ DBUG_VOID_RETURN;
+ }
+ else if (cmp == 0)
+ {
+ DBUG_PRINT("info", ("already in list"));
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+ *prev = changed_table_dup(table);
+ DBUG_PRINT("info", ("key_length %u %u", table->key_length, (*prev)->key_length));
+ DBUG_VOID_RETURN;
+}
+
+CHANGED_TABLE_LIST* THD::changed_table_dup(TABLE *table)
+{
+ CHANGED_TABLE_LIST* new_table =
+ (CHANGED_TABLE_LIST*) trans_alloc(ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST))+
+ table->key_length + 1);
+ if (!new_table)
+ {
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
+ ALIGN_SIZE(sizeof(TABLE_LIST)) + table->key_length + 1);
+ killed= 1;
+ return 0;
+ }
+
+ new_table->key = (char *) (((byte*)new_table)+
+ ALIGN_SIZE(sizeof(CHANGED_TABLE_LIST)));
+ new_table->next = 0;
+ new_table->key_length = table->key_length;
+ uint32 db_len = ((new_table->table_name =
+ ::strmake(new_table->key, table->table_cache_key,
+ table->key_length) + 1) - new_table->key);
+ ::memcpy(new_table->key + db_len, table->table_cache_key + db_len,
+ table->key_length - db_len);
+ return new_table;
+}
+
+
/*****************************************************************************
** Functions to provide a interface to select results
*****************************************************************************/
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a1423cfcdf1..d8824e80686 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -78,12 +78,29 @@ class MYSQL_LOG {
bool need_start_event;
pthread_cond_t update_cond;
bool no_auto_events; // for relay binlog
+ ulonglong bytes_written;
friend class Log_event;
public:
MYSQL_LOG();
~MYSQL_LOG();
pthread_mutex_t* get_log_lock() { return &LOCK_log; }
+ void reset_bytes_written()
+ {
+ bytes_written = 0;
+ }
+ void harvest_bytes_written(ulonglong* counter)
+ {
+#ifndef DBUG_OFF
+ char buf1[22],buf2[22];
+#endif
+ DBUG_ENTER("harvest_bytes_written");
+ (*counter)+=bytes_written;
+ DBUG_PRINT("info",("counter=%s,bytes_written=%s", llstr(*counter,buf1),
+ llstr(bytes_written,buf2)));
+ bytes_written=0;
+ DBUG_VOID_RETURN;
+ }
IO_CACHE* get_log_file() { return &log_file; }
void signal_update() { pthread_cond_broadcast(&update_cond);}
void wait_for_update(THD* thd);
@@ -251,6 +268,11 @@ public:
class delayed_insert;
+#define THD_SENTRY_MAGIC 0xfeedd1ff
+#define THD_SENTRY_GONE 0xdeadbeef
+
+#define THD_CHECK_SENTRY(thd) DBUG_ASSERT(thd->dbug_sentry == THD_SENTRY_MAGIC)
+
/* For each client connection we create a separate thread with THD serving as
a thread/connection descriptor */
@@ -258,7 +280,7 @@ class THD :public ilink {
public:
NET net; // client connection descriptor
LEX lex; // parse tree descriptor
- MEM_ROOT mem_root; // memory allocation pool
+ MEM_ROOT mem_root; // 1 command-life memory allocation pool
HASH user_vars; // hash for user variables
String packet; // dynamic string buffer used for network I/O
struct sockaddr_in remote; // client socket address
@@ -312,6 +334,9 @@ public:
// TODO: document the variables below
MYSQL_LOCK *lock,*locked_tables;
ULL *ull;
+#ifndef DBUG_OFF
+ uint dbug_sentry; // watch out for memory corruption
+#endif
struct st_my_thread_var *mysys_var;
enum enum_server_command command;
uint32 server_id;
@@ -326,6 +351,19 @@ public:
THD_TRANS all; // Trans since BEGIN WORK
THD_TRANS stmt; // Trans for current statement
uint bdb_lock_count;
+
+ /*
+ Tables changed in transaction (that must be invalidated in query cache).
+ List contain only transactional tables, that not invalidated in query
+ cache (instead of full list of changed in transaction tables).
+ */
+ CHANGED_TABLE_LIST* changed_tables;
+ MEM_ROOT mem_root; // Transaction-life memory allocation pool
+ void cleanup()
+ {
+ changed_tables = 0;
+ free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
+ }
} transaction;
Item *free_list, *handler_items;
CONVERT *convert_set;
@@ -374,7 +412,7 @@ public:
ulong slave_proxy_id;
NET* slave_net; // network connection from slave -> m.
my_off_t log_pos;
-
+
THD();
~THD();
void cleanup(void);
@@ -471,9 +509,18 @@ public:
memcpy(ptr,str,size);
return ptr;
}
+ inline gptr trans_alloc(unsigned int size)
+ {
+ return alloc_root(&transaction.mem_root,size);
+ }
+ void add_changed_table(TABLE *table);
+ CHANGED_TABLE_LIST * changed_table_dup(TABLE *table);
};
-
+/*
+ Used to hold information about file and file structure in exchainge
+ via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
+*/
class sql_exchange :public Sql_alloc
{
public:
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index dd8ed634011..9f521ac5ffd 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -159,7 +159,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if ((deleted=mysql_rm_known_files(thd, dirp, db, path,0)) >= 0 && thd)
{
ha_drop_database(path);
- query_cache.invalidate(db);
+ query_cache_invalidate1(db);
if (!silent)
{
if (!thd->query)
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index a155abc522b..89e30f31fd5 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -182,7 +182,7 @@ cleanup:
thd->lock=0;
}
if (deleted)
- query_cache.invalidate(table_list);
+ query_cache_invalidate3(thd, table_list, 1);
delete select;
if (error >= 0) // Fatal error
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
@@ -470,7 +470,7 @@ bool multi_delete::send_eof()
VOID(ha_autocommit_or_rollback(thd,error > 0));
}
if (deleted)
- query_cache.invalidate(delete_tables);
+ query_cache_invalidate3(thd, delete_tables, 1);
::send_ok(&thd->net,deleted);
return 0;
}
@@ -548,7 +548,7 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
bzero((char*) &create_info,sizeof(create_info));
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1) ? -1 : 0;
- query_cache.invalidate(table_list);
+ query_cache_invalidate3(thd, table_list, 0);
if (!dont_send_ok)
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 0898ad4bffb..235adcc02c1 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -311,7 +311,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
thd->proc_info="end";
if (info.copied || info.deleted)
- query_cache.invalidate(table_list);
+ query_cache_invalidate3(thd, table_list, 1);
table->time_stamp=save_time_stamp; // Restore auto timestamp ptr
table->next_number_field=0;
thd->count_cuted_fields=0;
@@ -1217,7 +1217,7 @@ bool delayed_insert::handle_inserts(void)
sql_print_error("%s",thd.net.last_error);
goto err;
}
- query_cache.invalidate(table);
+ query_cache_invalidate3(&thd, table, 1);
if (thr_reschedule_write_lock(*thd.lock->locks))
{
/* This should never happen */
@@ -1242,7 +1242,7 @@ bool delayed_insert::handle_inserts(void)
sql_print_error("%s",thd.net.last_error);
goto err;
}
- query_cache.invalidate(table);
+ query_cache_invalidate3(&thd, table, 1);
pthread_mutex_lock(&mutex);
DBUG_RETURN(0);
@@ -1330,7 +1330,7 @@ void select_insert::send_error(uint errcode,const char *err)
table->file->activate_all_index(thd);
ha_rollback_stmt(thd);
if (info.copied || info.deleted)
- query_cache.invalidate(table);
+ query_cache_invalidate3(thd, table, 1);
}
@@ -1343,7 +1343,7 @@ bool select_insert::send_eof()
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
error=error2;
if (info.copied || info.deleted)
- query_cache.invalidate(table);
+ query_cache_invalidate3(thd, table, 1);
if (error)
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d61e47d0883..42a8a700da3 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -150,6 +150,8 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->convert_set=(lex->thd=thd)->convert_set;
lex->yacc_yyss=lex->yacc_yyvs=0;
lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE);
+ lex->slave_thd_opt=0;
+ bzero(&lex->mi,sizeof(lex->mi));
return lex;
}
@@ -768,6 +770,7 @@ int yylex(void *arg)
return(TEXT_STRING);
case STATE_COMMENT: // Comment
+ lex->select_lex.options|= OPTION_FOUND_COMMENT;
while ((c = yyGet()) != '\n' && c) ;
yyUnget(); // Safety against eof
state = STATE_START; // Try again
@@ -779,6 +782,7 @@ int yylex(void *arg)
break;
}
yySkip(); // Skip '*'
+ lex->select_lex.options|= OPTION_FOUND_COMMENT;
if (yyPeek() == '!') // MySQL command in comment
{
ulong version=MYSQL_VERSION_ID;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6a966336ad7..6961ab8c712 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -57,6 +57,7 @@ enum enum_sql_command {
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
+ SQLCOM_EMPTY_QUERY,
SQLCOM_END
};
@@ -97,6 +98,8 @@ typedef struct st_lex_master_info
uint port, connect_retry;
ulonglong pos;
ulong server_id;
+ char* relay_log_name;
+ ulong relay_log_pos;
} LEX_MASTER_INFO;
@@ -185,7 +188,7 @@ typedef struct st_lex {
thr_lock_type lock_option;
bool drop_primary,drop_if_exists,local_file;
bool in_comment,ignore_space,verbose,simple_alter, option_type;
-
+ uint slave_thd_opt;
} LEX;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index abc9fa5a121..419e3fccabd 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -145,14 +145,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (read_file_from_client && handle_duplicates == DUP_ERROR)
handle_duplicates=DUP_IGNORE;
- if (read_file_from_client && (thd->client_capabilities & CLIENT_LOCAL_FILES))
+ if (read_file_from_client)
{
- char tmp [FN_REFLEN+1],*end;
- DBUG_PRINT("info",("reading local file"));
- tmp[0] = (char) 251; /* NULL_LENGTH */
- end=strnmov(tmp+1,ex->file_name,sizeof(tmp)-2);
- (void) my_net_write(&thd->net,tmp,(uint) (end-tmp));
- (void) net_flush(&thd->net);
+ (void)net_request_file(&thd->net,ex->file_name);
file = -1;
}
else
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index cf84c815973..dc89888a1a5 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -48,6 +48,10 @@
#endif /* HAVE_OPENSSL */
#define SCRAMBLE_LENGTH 8
+#define MEM_ROOT_BLOCK_SIZE 8192
+#define MEM_ROOT_PREALLOC 8192
+#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
+#define TRANS_MEM_ROOT_PREALLOC 4096
extern int yyparse(void);
extern "C" pthread_mutex_t THR_LOCK_keycache;
@@ -120,8 +124,9 @@ inline bool end_active_trans(THD *thd)
static HASH hash_user_connections;
extern pthread_mutex_t LOCK_user_conn;
-static int get_or_create_user_conn(THD *thd, const char *user, const char *host,
- uint max_questions)
+static int get_or_create_user_conn(THD *thd, const char *user,
+ const char *host,
+ uint max_questions)
{
int return_val=0;
uint temp_len;
@@ -134,19 +139,18 @@ static int get_or_create_user_conn(THD *thd, const char *user, const char *host,
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host,
NullS) - temp_user);
(void) pthread_mutex_lock(&LOCK_user_conn);
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- if (!uc)
+ if (!(uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
{
- uc= ((struct user_conn*)
- my_malloc(sizeof(struct user_conn) + temp_len+1,
- MYF(MY_WME)));
- if (!uc)
+ /* First connection for user; Create a user connection object */
+ if (!(uc= ((struct user_conn*)
+ my_malloc(sizeof(struct user_conn) + temp_len+1,
+ MYF(MY_WME)))))
{
send_error(&current_thd->net, 0, NullS); // Out of memory
return_val=1;
goto end;
- }
+ }
uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1);
uc->len = temp_len;
@@ -233,8 +237,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
db ? db : (char*) "");
thd->db_access=0;
/* Don't allow user to connect if he has done too many queries */
- if ((max_questions || max_user_connections) &&
- get_or_create_user_conn(thd,user,thd->host_or_ip,max_questions))
+ if ((max_questions || max_user_connections) && get_or_create_user_conn(thd,user,thd->host_or_ip,max_questions))
return -1;
if (max_user_connections && thd->user_connect &&
check_for_max_user_connections(thd->user_connect))
@@ -280,9 +283,6 @@ static int check_for_max_user_connections(UC *uc)
{
int error=0;
DBUG_ENTER("check_for_max_user_connections");
-// DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
-
- DBUG_ASSERT(uc != 0);
if (max_user_connections <= (uint) uc->connections)
{
@@ -303,8 +303,6 @@ static void decrease_user_connections(UC *uc)
return;
DBUG_ENTER("decrease_user_connections");
- DBUG_ASSERT(uc != 0);
-// DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
if (!--uc->connections && !mqh_used)
{
@@ -326,6 +324,10 @@ void free_max_user_conn(void)
/*
Check if maximum queries per hour limit has been reached
returns 0 if OK.
+
+ In theory we would need a mutex in the UC structure for this to be 100 %
+ safe, but as the worst scenario is that we would miss counting a couple of
+ queries, this isn't critical.
*/
static bool check_mqh(THD *thd)
@@ -335,15 +337,14 @@ static bool check_mqh(THD *thd)
UC *uc=thd->user_connect;
DBUG_ASSERT(uc != 0);
- /* TODO: Add username + host to THD for faster execution */
bool my_start = thd->start_time != 0;
time_t check_time = (my_start) ? thd->start_time : time(NULL);
if (check_time - uc->intime >= 3600)
{
-// (void) pthread_mutex_lock(&LOCK_user_conn);
- uc->questions=(uint) my_start;
+ (void) pthread_mutex_lock(&LOCK_user_conn);
+ uc->questions=1;
uc->intime=check_time;
-// (void) pthread_mutex_unlock(&LOCK_user_conn);
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
}
else if (uc->max_questions && ++(uc->questions) > uc->max_questions)
{
@@ -357,27 +358,22 @@ end:
DBUG_RETURN(error);
}
-static void reset_mqh(THD *thd,LEX_USER *lu, uint mq)
+
+static void reset_mqh(THD *thd, LEX_USER *lu, uint mq)
{
- char user[USERNAME_LENGTH+1];
- char host[USERNAME_LENGTH+1];
- char *where;
+ (void) pthread_mutex_lock(&LOCK_user_conn);
if (lu) // for GRANT
{
UC *uc;
- uint temp_len;
+ uint temp_len=lu->user.length+lu->host.length+2;
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
- memcpy(user,lu->user.str,lu->user.length);
- user[lu->user.length]='\0';
- memcpy(host,lu->host.str,lu->host.length);
- host[lu->host.length]='\0';
- temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host,
- NullS) - temp_user);
- uc = (struct user_conn *) hash_search(&hash_user_connections,
- (byte*) temp_user, temp_len);
- if (uc)
+ memcpy(temp_user,lu->user.str,lu->user.length);
+ memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
+ temp_user[lu->user.length]=temp_user[temp_len-1]=0;
+ if ((uc = (struct user_conn *) hash_search(&hash_user_connections,
+ (byte*) temp_user, temp_len)))
{
uc->questions=0;
uc->max_questions=mq;
@@ -385,21 +381,20 @@ static void reset_mqh(THD *thd,LEX_USER *lu, uint mq)
}
else // for FLUSH PRIVILEGES
{
- (void) pthread_mutex_lock(&LOCK_user_conn);
- for (uint idx=0;idx<hash_user_connections.records;idx++)
+ for (uint idx=0;idx < hash_user_connections.records; idx++)
{
- HASH_LINK *data=dynamic_element(&hash_user_connections.array,idx,HASH_LINK*);
- UC *uc=(struct user_conn *)data->data;
+ char user[USERNAME_LENGTH+1];
+ char *where;
+ UC *uc=(struct user_conn *) hash_element(&hash_user_connections, idx);
where=strchr(uc->user,'@');
- memcpy(user,uc->user,where - uc->user);
- user[where-uc->user]='\0'; where++;
- strcpy(host,where);
- uc->max_questions=get_mqh(user,host);
+ strmake(user,uc->user,where - uc->user);
+ uc->max_questions=get_mqh(user,where+1);
}
- (void) pthread_mutex_unlock(&LOCK_user_conn);
}
+ (void) pthread_mutex_unlock(&LOCK_user_conn);
}
+
/*
Check connnetion and get priviliges
Returns 0 on ok, -1 < if error is given > 0 on error.
@@ -624,7 +619,9 @@ pthread_handler_decl(handle_one_connection,arg)
thd->command=COM_SLEEP;
thd->version=refresh_version;
thd->set_time();
- init_sql_alloc(&thd->mem_root,8192,8192);
+ init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ init_sql_alloc(&thd->transaction.mem_root,
+ TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
while (!net->error && net->vio != 0 && !thd->killed)
{
if (do_command(thd))
@@ -697,7 +694,9 @@ pthread_handler_decl(handle_bootstrap,arg)
thd->priv_user=thd->user=(char*)"boot";
buff= (char*) thd->net.buff;
- init_sql_alloc(&thd->mem_root,8192,8192);
+ init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ init_sql_alloc(&thd->transaction.mem_root,
+ TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
@@ -721,6 +720,7 @@ pthread_handler_decl(handle_bootstrap,arg)
if (thd->fatal_error)
break;
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
}
thd->priv_user=thd->user=0;
@@ -834,8 +834,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
NET *net= &thd->net;
bool error=0;
- // commands which will always take a long time should be marked with
- // this so that they will not get logged to the slow query log
+ /*
+ Commands which will always take a long time should be marked with
+ this so that they will not get logged to the slow query log
+ */
bool slow_command=FALSE;
DBUG_ENTER("dispatch_command");
@@ -913,7 +915,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
if (max_connections && save_uc)
- decrease_user_connections (save_uc);
+ decrease_user_connections(save_uc);
x_free((gptr) save_db);
x_free((gptr) save_user);
thd->password=test(passwd[0]);
@@ -948,8 +950,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_PRINT("query",("%s",thd->query));
if (thd->user_connect && check_mqh(thd))
{
- error = TRUE;
- net->error = 0;
+ error = TRUE; // Abort client
+ net->error = 0; // Don't give abort message
break;
}
/* thd->query_length is set by mysql_parse() */
@@ -1072,11 +1074,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
else
send_eof(net);
if (mqh_used)
- {
- if (hash_user_connections.array.buffer == 0)
- init_max_user_conn();
- reset_mqh(thd,(LEX_USER *)NULL,0);
- }
+ reset_mqh(thd,(LEX_USER *) NULL, 0);
break;
}
case COM_SHUTDOWN:
@@ -1095,6 +1093,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
close_connection(net);
close_thread_tables(thd); // Free before kill
free_root(&thd->mem_root,MYF(0));
+ free_root(&thd->transaction.mem_root,MYF(0));
kill_mysql();
error=TRUE;
break;
@@ -1311,7 +1310,7 @@ mysql_execute_command(void)
if (!(res=open_and_lock_tables(thd,tables)))
{
- query_cache.store_query(thd, tables);
+ query_cache_store_query(thd, tables);
res=handle_select(thd, lex, result);
}
else
@@ -1322,6 +1321,10 @@ mysql_execute_command(void)
res=mysql_do(thd, *lex->insert_list);
break;
+ case SQLCOM_EMPTY_QUERY:
+ send_ok(&thd->net);
+ break;
+
case SQLCOM_PURGE:
{
if (check_process_priv(thd))
@@ -1627,7 +1630,7 @@ mysql_execute_command(void)
goto error;
}
}
- query_cache.invalidate(tables);
+ query_cache_invalidate3(thd, tables, 0);
if (end_active_trans(thd))
res= -1;
else if (mysql_rename_tables(thd,tables))
@@ -1666,7 +1669,7 @@ mysql_execute_command(void)
check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
goto error; /* purecov: inspected */
res = mysql_repair_table(thd, tables, &lex->check_opt);
- query_cache.invalidate(tables);
+ query_cache_invalidate3(thd, tables, 0);
break;
}
case SQLCOM_CHECK:
@@ -1675,7 +1678,7 @@ mysql_execute_command(void)
check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
goto error; /* purecov: inspected */
res = mysql_check_table(thd, tables, &lex->check_opt);
- query_cache.invalidate(tables);
+ query_cache_invalidate3(thd, tables, 0);
break;
}
case SQLCOM_ANALYZE:
@@ -2104,13 +2107,20 @@ mysql_execute_command(void)
{
uint privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
- if (!(lex->local_file && (thd->client_capabilities & CLIENT_LOCAL_FILES)))
+
+ if (!lex->local_file)
{
if (check_access(thd,privilege | FILE_ACL,tables->db))
goto error;
}
else
{
+ if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
+ ! opt_local_infile)
+ {
+ send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
+ goto error;
+ }
if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
grant_option && check_grant(thd,privilege,tables))
goto error;
@@ -2306,17 +2316,12 @@ mysql_execute_command(void)
Query_log_event qinfo(thd, thd->query);
mysql_bin_log.write(&qinfo);
}
- if (mqh_used)
+ if (mqh_used && lex->mqh)
{
- if (hash_user_connections.array.buffer == 0)
- init_max_user_conn();
- if (lex->mqh)
- {
- List_iterator <LEX_USER> str_list (lex->users_list);
- LEX_USER *Str;
- str_list.rewind();
- reset_mqh(thd,str_list++,lex->mqh);
- }
+ List_iterator <LEX_USER> str_list(lex->users_list);
+ LEX_USER *user;
+ while ((user=str_list++))
+ reset_mqh(thd,user,lex->mqh);
}
}
}
@@ -2397,6 +2402,7 @@ mysql_execute_command(void)
}
else
res= -1;
+ thd->transaction.cleanup();
break;
}
case SQLCOM_ROLLBACK:
@@ -2411,6 +2417,7 @@ mysql_execute_command(void)
else
res= -1;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->transaction.cleanup();
break;
default: /* Impossible */
send_ok(&thd->net);
@@ -2715,7 +2722,7 @@ mysql_parse(THD *thd,char *inBuf,uint length)
mysql_init_query(thd);
thd->query_length = length;
- if (query_cache.send_result_to_client(thd, inBuf, length) <= 0)
+ if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
LEX *lex=lex_start(thd, (uchar*) inBuf, length);
if (!yyparse() && ! thd->fatal_error)
@@ -2983,7 +2990,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if (new_field->length >= MAX_FIELD_WIDTH ||
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
- type != FIELD_TYPE_STRING))
+ type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
{
net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name,
MAX_FIELD_WIDTH-1); /* purecov: inspected */
@@ -3113,7 +3120,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
- ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) "");
+ if (table->db.str)
+ {
+ ptr->db= table->db.str;
+ ptr->db_length= table->db.length;
+ }
+ else if (thd->db)
+ {
+ ptr->db= thd->db;
+ ptr->db_length= thd->db_length;
+ }
+ else
+ {
+ ptr->db= (char*) "";
+ ptr->db_length= 0;
+ }
+
ptr->name=alias_str;
if (lower_case_table_names)
{
@@ -3121,6 +3143,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
casedn_str(table->table.str);
}
ptr->real_name=table->table.str;
+ ptr->real_name_length=table->table.length;
ptr->lock_type=flags;
ptr->updating=updating;
if (use_index)
@@ -3259,6 +3282,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
if (ha_flush_logs())
result=1;
}
+#ifdef HAVE_QUERY_CACHE
if (options & REFRESH_QUERY_CACHE_FREE)
{
query_cache.pack(); // FLUSH QUERY CACHE
@@ -3268,6 +3292,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
{
query_cache.flush(); // RESET QUERY CACHE
}
+#endif /*HAVE_QUERY_CACHE*/
if (options & (REFRESH_TABLES | REFRESH_READ_LOCK))
{
if ((options & REFRESH_READ_LOCK) && thd)
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index f2a0351361b..305491c7346 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -126,7 +126,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
new_table=ren_table->next;
sprintf(name,"%s/%s/%s%s",mysql_data_home,
- new_table->db,new_table->name,
+ new_table->db,new_table->real_name,
reg_ext);
if (!access(name,F_OK))
{
@@ -134,7 +134,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
DBUG_RETURN(ren_table); // This can't be skipped
}
sprintf(name,"%s/%s/%s%s",mysql_data_home,
- ren_table->db,ren_table->name,
+ ren_table->db,ren_table->real_name,
reg_ext);
if ((table_type=get_table_type(name)) == DB_TYPE_UNKNOWN)
{
@@ -143,11 +143,11 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
DBUG_RETURN(ren_table);
}
else if (mysql_rename_table(table_type,
- ren_table->db, ren_table->name,
- new_table->db, new_table->name))
+ ren_table->db, ren_table->real_name,
+ new_table->db, new_table->real_name))
{
if (!skip_error)
- return ren_table;
+ DBUG_RETURN(ren_table);
}
}
DBUG_RETURN(0);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 0b408920703..398ff443ad4 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -562,6 +562,8 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
return 1;
lock_slave_threads(mi); // this allows us to cleanly read slave_running
init_thread_mask(&thread_mask,mi,1 /* inverse */);
+ if (thd->lex.slave_thd_opt)
+ thread_mask &= thd->lex.slave_thd_opt;
if (thread_mask)
{
if (server_id_supplied && (!mi->inited || (mi->inited && *mi->host)))
@@ -602,6 +604,8 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
int thread_mask;
lock_slave_threads(mi);
init_thread_mask(&thread_mask,mi,0 /* not inverse*/);
+ if (thd->lex.slave_thd_opt)
+ thread_mask &= thd->lex.slave_thd_opt;
slave_errno = (thread_mask) ?
terminate_slave_threads(mi,thread_mask,
1 /*skip lock */) : ER_SLAVE_NOT_RUNNING;
@@ -686,6 +690,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
{
int error=0,restart_thread_mask;
const char* errmsg=0;
+ bool need_relay_log_purge=1;
// kill slave thread
lock_slave_threads(mi);
@@ -709,7 +714,10 @@ int change_master(THD* thd, MASTER_INFO* mi)
return 1;
}
- pthread_mutex_lock(&mi->data_lock);
+ /* data lock not needed since we have already stopped the running threads,
+ and we have the hold on the run locks which will keep all threads that
+ could possibly modify the data structures from running
+ */
if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos)
{
// if we change host or port, we must reset the postion
@@ -738,23 +746,56 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (lex_mi->connect_retry)
mi->connect_retry = lex_mi->connect_retry;
+ if (lex_mi->relay_log_name)
+ {
+ need_relay_log_purge = 0;
+ mi->rli.skip_log_purge=1;
+ strnmov(mi->rli.relay_log_name,lex_mi->relay_log_name,
+ sizeof(mi->rli.relay_log_name)-1);
+ }
+
+ if (lex_mi->relay_log_pos)
+ {
+ need_relay_log_purge=0;
+ mi->rli.relay_log_pos=lex_mi->relay_log_pos;
+ }
+
flush_master_info(mi);
- pthread_mutex_unlock(&mi->data_lock);
- thd->proc_info="purging old relay logs";
- if (purge_relay_logs(&mi->rli,0 /* not only reset, but also reinit*/,
- &errmsg))
+ if (need_relay_log_purge)
{
- send_error(&thd->net, 0, "Failed purging old relay logs");
- unlock_slave_threads(mi);
- return 1;
+ mi->rli.skip_log_purge=0;
+ thd->proc_info="purging old relay logs";
+ if (purge_relay_logs(&mi->rli,0 /* not only reset, but also reinit*/,
+ &errmsg))
+ {
+ net_printf(&thd->net, 0, "Failed purging old relay logs: %s",errmsg);
+ return 1;
+ }
+ }
+ else
+ {
+ const char* msg;
+ if (init_relay_log_pos(&mi->rli,0/*log already inited*/,
+ 0 /*pos already inited*/,
+ 0 /*no data lock*/,
+ &msg))
+ {
+ //Sasha: note that I had to change net_printf() to make this work
+ net_printf(&thd->net,0,"Failed initializing relay log position: %s",msg);
+ unlock_slave_threads(mi);
+ return 1;
+ }
+
}
- pthread_mutex_lock(&mi->rli.data_lock);
mi->rli.master_log_pos = mi->master_log_pos;
strnmov(mi->rli.master_log_name,mi->master_log_name,
sizeof(mi->rli.master_log_name));
if (!mi->rli.master_log_name[0]) // uninitialized case
mi->rli.master_log_pos=0;
- pthread_cond_broadcast(&mi->rli.data_cond);
+
+ pthread_mutex_lock(&mi->rli.data_lock);
+ mi->rli.abort_pos_wait = 1;
+ pthread_cond_broadcast(&mi->data_cond);
pthread_mutex_unlock(&mi->rli.data_lock);
thd->proc_info = "starting slave";
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0911ea57515..32f2e274132 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -144,7 +144,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static void init_sum_functions(Item_sum **func);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
- bool distinct);
+ bool distinct, const char *message=NullS);
static void describe_info(THD *thd, const char *info);
/*
@@ -187,7 +187,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
TABLE *tmp_table;
int error, tmp_error;
bool need_tmp,hidden_group_fields;
- bool simple_order,simple_group,no_order, skip_sort_order;
+ bool simple_order,simple_group,no_order, skip_sort_order, buffer_result;
Item::cond_result cond_value;
SQL_SELECT *select;
DYNAMIC_ARRAY keyuse;
@@ -195,11 +195,14 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
Procedure *procedure;
List<Item> all_fields(fields);
bool select_distinct;
+ SELECT_LEX *select_lex = &(thd->lex.select_lex);
+ SELECT_LEX *cur_sel = thd->lex.select;
DBUG_ENTER("mysql_select");
/* Check that all tables, fields, conds and order are ok */
select_distinct=test(select_options & SELECT_DISTINCT);
+ buffer_result=test(select_options & OPTION_BUFFER_RESULT) && !test(select_options & OPTION_FOUND_ROWS);
tmp_table=0;
select=0;
no_order=skip_sort_order=0;
@@ -350,10 +353,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
if (cond_value == Item::COND_FALSE || !thd->select_limit)
{ /* Impossible cond */
- error=return_zero_rows(result, tables, fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,"Impossible WHERE",having,
- procedure);
+ if (select_options & SELECT_DESCRIBE && select_lex->next)
+ select_describe(&join,false,false,false,"Impossible WHERE");
+ else
+ error=return_zero_rows(result, tables, fields,
+ join.tmp_table_param.sum_func_count != 0 && !group,
+ select_options,"Impossible WHERE",having,
+ procedure);
delete procedure;
DBUG_RETURN(error);
}
@@ -366,17 +372,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{
if (res < 0)
{
- error=return_zero_rows(result, tables, fields, !group,
- select_options,"No matching min/max row",
- having,procedure);
+ if (select_options & SELECT_DESCRIBE && select_lex->next)
+ select_describe(&join,false,false,false,"No matching min/max row");
+ else
+ error=return_zero_rows(result, tables, fields, !group,
+ select_options,"No matching min/max row",
+ having,procedure);
delete procedure;
DBUG_RETURN(error);
}
if (select_options & SELECT_DESCRIBE)
{
- describe_info(thd,"Select tables optimized away");
+ if (select_lex->next)
+ select_describe(&join,false,false,false,"Select tables optimized away");
+ else
+ describe_info(thd,"Select tables optimized away");
delete procedure;
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
tables=0; // All tables resolved
}
@@ -385,7 +397,12 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{ // Only test of functions
error=0;
if (select_options & SELECT_DESCRIBE)
- describe_info(thd,"No tables used");
+ {
+ if (select_lex->next)
+ select_describe(&join,false,false,false,"No tables used");
+ else
+ describe_info(thd,"No tables used");
+ }
else
{
result->send_fields(fields,1);
@@ -463,11 +480,14 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
if (make_join_select(&join,select,conds))
{
- error=return_zero_rows(result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,
- "Impossible WHERE noticed after reading const tables",
- having,procedure);
+ if (select_options & SELECT_DESCRIBE && select_lex->next)
+ select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables");
+ else
+ error=return_zero_rows(result,tables,fields,
+ join.tmp_table_param.sum_func_count != 0 && !group,
+ select_options,
+ "Impossible WHERE noticed after reading const tables",
+ having,procedure);
goto err;
}
@@ -528,14 +548,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
need_tmp= (join.const_tables != join.tables &&
((select_distinct || !simple_order || !simple_group) ||
- (group && order) ||
- test(select_options & OPTION_BUFFER_RESULT)));
+ (group && order) || buffer_result));
// No cache for MATCH
make_join_readinfo(&join,
(select_options & (SELECT_DESCRIBE |
SELECT_NO_JOIN_CACHE)) |
- (thd->lex.select_lex.ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
+ (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
/* Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL
@@ -594,8 +613,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
HA_POS_ERROR : thd->select_limit,0))))
order=0;
select_describe(&join,need_tmp,
- (order != 0 &&
- (!need_tmp || order != group || simple_group)),
+ order != 0 && !skip_sort_order,
select_distinct);
error=0;
goto err;
@@ -964,7 +982,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
s->dependent=(table_map) 0;
s->key_dependent=(table_map) 0;
if ((table->system || table->file->records <= 1) && ! s->dependent &&
- !(table->file->option_flag() & HA_NOT_EXACT_COUNT))
+ !(table->file->option_flag() & HA_NOT_EXACT_COUNT) &&
+ !table->fulltext_searched)
{
set_position(join,const_count++,s,(KEYUSE*) 0);
}
@@ -1095,7 +1114,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
} while (keyuse->table == table && keyuse->key == key);
if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
- (table->key_info[key].flags & HA_NOSAME))
+ (table->key_info[key].flags & HA_NOSAME) &&
+ !table->fulltext_searched)
{
if (const_ref == eq_part)
{ // Found everything for ref.
@@ -1228,14 +1248,14 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
{
if (new_fields->val->used_tables())
{
- if (old->val->eq(new_fields->val))
+ if (old->val->eq(new_fields->val, old->field->binary()))
{
old->level=old->const_level=and_level;
old->exists_optimize&=new_fields->exists_optimize;
}
}
- else if (old->val->eq(new_fields->val) && old->eq_func &&
- new_fields->eq_func)
+ else if (old->val->eq(new_fields->val, old->field->binary()) &&
+ old->eq_func && new_fields->eq_func)
{
old->level=old->const_level=and_level;
old->exists_optimize&=new_fields->exists_optimize;
@@ -1597,7 +1617,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
add_key_part(keyuse,field);
}
- if (thd->lex.select_lex.ftfunc_list.elements)
+ if (thd->lex.select->ftfunc_list.elements)
{
add_ft_keys(keyuse,join_tab,cond,normal_tables);
}
@@ -2516,6 +2536,7 @@ static void
make_join_readinfo(JOIN *join,uint options)
{
uint i;
+ SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
DBUG_ENTER("make_join_readinfo");
for (i=join->const_tables ; i < join->tables ; i++)
@@ -2598,7 +2619,7 @@ make_join_readinfo(JOIN *join,uint options)
/* These init changes read_record */
if (tab->use_quick == 2)
{
- join->thd->lex.select_lex.options|=QUERY_NO_GOOD_INDEX_USED;
+ select_lex->options|=QUERY_NO_GOOD_INDEX_USED;
tab->read_first_record= join_init_quick_read_record;
statistic_increment(select_range_check_count, &LOCK_status);
}
@@ -2613,7 +2634,7 @@ make_join_readinfo(JOIN *join,uint options)
}
else
{
- join->thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
+ select_lex->options|=QUERY_NO_INDEX_USED;
statistic_increment(select_scan_count, &LOCK_status);
}
}
@@ -2625,7 +2646,7 @@ make_join_readinfo(JOIN *join,uint options)
}
else
{
- join->thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
+ select_lex->options|=QUERY_NO_INDEX_USED;
statistic_increment(select_full_join_count, &LOCK_status);
}
}
@@ -2749,7 +2770,7 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
ORDER *order;
for (order=start_order ; order ; order=order->next)
{
- if ((*ref_item)->eq(order->item[0]))
+ if ((*ref_item)->eq(order->item[0],0))
break;
}
if (order)
@@ -2913,7 +2934,7 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
DBUG_ENTER("return_zero_rows");
if (select_options & SELECT_DESCRIBE)
- {
+ {
describe_info(current_thd, info);
DBUG_RETURN(0);
}
@@ -2929,17 +2950,17 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
if (having && having->val_int() == 0)
send_row=0;
}
- if (!tables || !(result->send_fields(fields,1)))
+ if (!(result->send_fields(fields,1)))
{
if (send_row)
result->send_data(fields);
- if (tables) // Not from do_select()
+ if (tables) // Not from do_select()
{
/* Close open cursors */
for (TABLE_LIST *table=tables; table ; table=table->next)
table->table->file->index_end();
- result->send_eof(); // Should be safe
}
+ result->send_eof(); // Should be safe
}
DBUG_RETURN(0);
}
@@ -3006,7 +3027,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
Item *right_item= func->arguments()[1];
Item_func::Functype functype= func->functype();
- if (right_item->eq(field) && left_item != value)
+ if (right_item->eq(field,0) && left_item != value)
{
Item *tmp=value->new_item();
if (tmp)
@@ -3025,7 +3046,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
func->arguments()[1]->result_type()));
}
}
- else if (left_item->eq(field) && right_item != value)
+ else if (left_item->eq(field,0) && right_item != value)
{
Item *tmp=value->new_item();
if (tmp)
@@ -3266,7 +3287,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
{ // boolan compare function
Item *left_item= ((Item_func*) cond)->arguments()[0];
Item *right_item= ((Item_func*) cond)->arguments()[1];
- if (left_item->eq(right_item))
+ if (left_item->eq(right_item,1))
{
if (!left_item->maybe_null ||
((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)
@@ -3311,22 +3332,22 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
return 0;
Item *left_item= ((Item_func*) cond)->arguments()[0];
Item *right_item= ((Item_func*) cond)->arguments()[1];
- if (left_item->eq(comp_item))
+ if (left_item->eq(comp_item,1))
{
if (right_item->const_item())
{
if (*const_item)
- return right_item->eq(*const_item);
+ return right_item->eq(*const_item, 1);
*const_item=right_item;
return 1;
}
}
- else if (right_item->eq(comp_item))
+ else if (right_item->eq(comp_item,1))
{
if (left_item->const_item())
{
if (*const_item)
- return left_item->eq(*const_item);
+ return left_item->eq(*const_item, 1);
*const_item=left_item;
return 1;
}
@@ -4665,7 +4686,7 @@ join_read_prev_same(READ_RECORD *info)
tab->ref.key_length))
{
table->status=STATUS_NOT_FOUND;
- error= 1;
+ error= -1;
}
return error;
}
@@ -4877,8 +4898,10 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
JOIN_TAB *jt=join->join_tab;
if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group
- && !join->send_group_parts && !join->having && !jt->select_cond)
+ && !join->send_group_parts && !join->having && !jt->select_cond &&
+ !(jt->table->file->option_flag() & HA_NOT_EXACT_COUNT))
{
+ /* Join over all rows in table; Return number of found rows */
join->select_options ^= OPTION_FOUND_ROWS;
join->send_records = jt->records;
}
@@ -5245,7 +5268,7 @@ static bool test_if_ref(Item_field *left_item,Item *right_item)
if (!field->table->const_table && !field->table->maybe_null)
{
Item *ref_item=part_of_refkey(field->table,field);
- if (ref_item && ref_item->eq(right_item))
+ if (ref_item && ref_item->eq(right_item,1))
{
if (right_item->type() == Item::FIELD_ITEM)
return (field->eq_def(((Item_field *) right_item)->field));
@@ -5429,7 +5452,16 @@ static uint find_shortest_key(TABLE *table, key_map usable_keys)
}
-/* Return 1 if we don't have to do file sorting */
+/*
+ Test if we can skip the ORDER BY by using an index.
+
+ If we can use an index, the JOIN_TAB / tab->select struct
+ is changed to use the index.
+
+ Return:
+ 0 We have to use filesort to do the sorting
+ 1 We can use an index.
+*/
static bool
test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
@@ -5475,15 +5507,22 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
{
if (select && select->quick)
{
- // ORDER BY range_key DESC
- QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
- used_key_parts);
- if (!tmp || tmp->error)
+ /*
+ Don't reverse the sort order, if it's already done.
+ (In some cases test_if_order_by_key() can be called multiple times
+ */
+ if (!select->quick->reverse_sorted())
{
- delete tmp;
- DBUG_RETURN(0); // Reverse sort not supported
+ // ORDER BY range_key DESC
+ QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
+ used_key_parts);
+ if (!tmp || tmp->error)
+ {
+ delete tmp;
+ DBUG_RETURN(0); // Reverse sort not supported
+ }
+ select->quick=tmp;
}
- select->quick=tmp;
DBUG_RETURN(1);
}
if (tab->ref.key_parts < used_key_parts)
@@ -5603,6 +5642,7 @@ create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows select_limit)
table->file->info(HA_STATUS_VARIABLE); // Get record count
table->found_records=filesort(table,sortorder,length,
select, 0L, select_limit, &examined_rows);
+ tab->records=table->found_records; // For SQL_CALC_ROWS
delete select; // filesort did select
tab->select=0;
tab->select_cond=0;
@@ -5959,10 +5999,10 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
/*****************************************************************************
-** Fill join cache with packed records
-** Records are stored in tab->cache.buffer and last record in
-** last record is stored with pointers to blobs to support very big
-** records
+ Fill join cache with packed records
+ Records are stored in tab->cache.buffer and last record in
+ last record is stored with pointers to blobs to support very big
+ records
******************************************************************************/
static int
@@ -6024,7 +6064,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
if (null_fields && tables[i].table->null_fields)
{ /* must copy null bits */
copy->str=(char*) tables[i].table->null_flags;
- copy->length=(tables[i].table->null_fields+7)/8;
+ copy->length=tables[i].table->null_bytes;
copy->strip=0;
copy->blob_field=0;
length+=copy->length;
@@ -6474,7 +6514,7 @@ test_if_subpart(ORDER *a,ORDER *b)
{
for (; a && b; a=a->next,b=b->next)
{
- if ((*a->item)->eq(*b->item))
+ if ((*a->item)->eq(*b->item,1))
a->asc=b->asc;
else
return 0;
@@ -6501,7 +6541,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
for (; a && b; a=a->next,b=b->next)
{
- if (!(*a->item)->eq(*b->item))
+ if (!(*a->item)->eq(*b->item,1))
DBUG_RETURN(0);
map|=a->item[0]->used_tables();
}
@@ -6937,16 +6977,20 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
****************************************************************************/
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
- bool distinct)
+ bool distinct,const char *message)
{
List<Item> field_list;
Item *item;
+ List<Item> item_list;
THD *thd=join->thd;
+ MYSQL_LOCK *save_lock;
+ SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
+ select_result *result=join->result;
DBUG_ENTER("select_describe");
/* Don't log this into the slow query log */
- join->thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
- if (join->thd->lex.select == &join->thd->lex.select_lex)
+ select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
+ if (thd->lex.select == select_lex)
{
field_list.push_back(new Item_empty_string("table",NAME_LEN));
field_list.push_back(new Item_empty_string("type",10));
@@ -6962,141 +7006,162 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item->maybe_null=1;
field_list.push_back(new Item_real("rows",0.0,0,10));
field_list.push_back(new Item_empty_string("Extra",255));
- if (send_fields(thd,field_list,1))
+ if (result->send_fields(field_list,1))
return;
}
- char buff[512],*buff_ptr;
- String tmp(buff,sizeof(buff)),*packet= &thd->packet;
- table_map used_tables=0;
- for (uint i=0 ; i < join->tables ; i++)
- {
- JOIN_TAB *tab=join->join_tab+i;
- TABLE *table=tab->table;
- if (tab->type == JT_ALL && tab->select && tab->select->quick)
- tab->type= JT_RANGE;
- packet->length(0);
- net_store_data(packet,table->table_name);
- net_store_data(packet,join_type_str[tab->type]);
- tmp.length(0);
- key_map bits;
- uint j;
- for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
- {
- if (bits & 1)
+ if (message)
+ {
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_empty_string("",0));
+ item_list.push_back(new Item_string(message,strlen(message)));
+ if (result->send_data(item_list))
+ result->send_error(0,NullS);
+ }
+ else
+ {
+ table_map used_tables=0;
+ for (uint i=0 ; i < join->tables ; i++)
+ {
+ JOIN_TAB *tab=join->join_tab+i;
+ TABLE *table=tab->table;
+ char buff[512],*buff_ptr=buff;
+ char buff1[512], buff2[512], bufff[512];
+ String tmp1(buff1,sizeof(buff1));
+ String tmp2(buff2,sizeof(buff2));
+ item_list.empty();
+ if (tab->type == JT_ALL && tab->select && tab->select->quick)
+ tab->type= JT_RANGE;
+ item_list.push_back(new Item_string(table->table_name,strlen(table->table_name)));
+ item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type])));
+ tmp1.length(0); tmp2.length(0);
+ key_map bits;
+ uint j;
+ for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
{
- if (tmp.length())
- tmp.append(',');
- tmp.append(table->key_info[j].name);
+ if (bits & 1)
+ {
+ if (tmp1.length())
+ tmp1.append(',');
+ tmp1.append(table->key_info[j].name);
+ }
}
- }
- if (tmp.length())
- net_store_data(packet,tmp.ptr(),tmp.length());
- else
- net_store_null(packet);
- if (tab->ref.key_parts)
- {
- net_store_data(packet,table->key_info[tab->ref.key].name);
- net_store_data(packet,(uint32) tab->ref.key_length);
- tmp.length(0);
- for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
+ if (tmp1.length())
+ item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length()));
+ else
+ item_list.push_back(new Item_null());
+ if (tab->ref.key_parts)
{
- if (tmp.length())
- tmp.append(',');
- tmp.append((*ref)->name());
+ item_list.push_back(new Item_string(table->key_info[tab->ref.key].name,
+ strlen(table->key_info[tab->ref.key].name)));
+ item_list.push_back(new Item_int((int32) tab->ref.key_length));
+ for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
+ {
+ if (tmp2.length())
+ tmp2.append(',');
+ tmp2.append((*ref)->name());
+ }
+ item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length()));
}
- net_store_data(packet,tmp.ptr(),tmp.length());
- }
- else if (tab->type == JT_NEXT)
- {
- net_store_data(packet,table->key_info[tab->index].name);
- net_store_data(packet,(uint32) table->key_info[tab->index].key_length);
- net_store_null(packet);
- }
- else if (tab->select && tab->select->quick)
- {
- net_store_data(packet,table->key_info[tab->select->quick->index].name);;
- net_store_data(packet,(uint32) tab->select->quick->max_used_key_length);
- net_store_null(packet);
- }
- else
- {
- net_store_null(packet);
- net_store_null(packet);
- net_store_null(packet);
- }
- sprintf(buff,"%.0f",join->best_positions[i].records_read);
- net_store_data(packet,buff);
- my_bool key_read=table->key_read;
- if (tab->type == JT_NEXT &&
- ((table->used_keys & ((key_map) 1 << tab->index))))
- key_read=1;
-
- buff_ptr=buff;
- if (tab->info)
- net_store_data(packet,tab->info);
- else if (tab->select)
- {
- if (tab->use_quick == 2)
+ else if (tab->type == JT_NEXT)
{
- sprintf(buff_ptr,"range checked for each record (index map: %u)",
- tab->keys);
- buff_ptr=strend(buff_ptr);
+ item_list.push_back(new Item_string(table->key_info[tab->index].name,strlen(table->key_info[tab->index].name)));
+ item_list.push_back(new Item_int((int32) table->key_info[tab->index].key_length));
+ item_list.push_back(new Item_null());
+ }
+ else if (tab->select && tab->select->quick)
+ {
+ item_list.push_back(new Item_string(table->key_info[tab->select->quick->index].name,strlen(table->key_info[tab->select->quick->index].name)));
+ item_list.push_back(new Item_int((int32) tab->select->quick->max_used_key_length));
+ item_list.push_back(new Item_null());
}
else
- buff_ptr=strmov(buff_ptr,"where used");
- }
- if (key_read)
- {
- if (buff != buff_ptr)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ item_list.push_back(new Item_null());
+ item_list.push_back(new Item_null());
+ item_list.push_back(new Item_null());
}
- buff_ptr=strmov(buff_ptr,"Using index");
- }
- if (table->reginfo.not_exists_optimize)
- {
- if (buff != buff_ptr)
+ sprintf(bufff,"%.0f",join->best_positions[i].records_read);
+ item_list.push_back(new Item_string(bufff,strlen(bufff)));
+ my_bool key_read=table->key_read;
+ if (tab->type == JT_NEXT &&
+ ((table->used_keys & ((key_map) 1 << tab->index))))
+ key_read=1;
+
+ if (tab->info)
+ item_list.push_back(new Item_string(tab->info,strlen(tab->info)));
+ else if (tab->select)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ if (tab->use_quick == 2)
+ {
+ sprintf(buff_ptr,"range checked for each record (index map: %u)",
+ tab->keys);
+ buff_ptr=strend(buff_ptr);
+ }
+ else
+ buff_ptr=strmov(buff_ptr,"where used");
}
- buff_ptr=strmov(buff_ptr,"Not exists");
- }
- if (need_tmp_table)
- {
- need_tmp_table=0;
- if (buff != buff_ptr)
+ if (key_read)
+ {
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using index");
+ }
+ if (table->reginfo.not_exists_optimize)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Not exists");
}
- buff_ptr=strmov(buff_ptr,"Using temporary");
- }
- if (need_order)
- {
- need_order=0;
- if (buff != buff_ptr)
+ if (need_tmp_table)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ need_tmp_table=0;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using temporary");
}
- buff_ptr=strmov(buff_ptr,"Using filesort");
- }
- if (distinct & test_all_bits(used_tables,thd->used_tables))
- {
- if (buff != buff_ptr)
+ if (need_order)
{
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ need_order=0;
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Using filesort");
+ }
+ if (distinct & test_all_bits(used_tables,thd->used_tables))
+ {
+ if (buff != buff_ptr)
+ {
+ buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
+ }
+ buff_ptr=strmov(buff_ptr,"Distinct");
}
- buff_ptr=strmov(buff_ptr,"Distinct");
+ item_list.push_back(new Item_string(buff,(uint) (buff_ptr - buff)));
+ // For next iteration
+ used_tables|=table->map;
+ if (result->send_data(item_list))
+ result->send_error(0,NullS);
}
- net_store_data(packet,buff,(uint) (buff_ptr - buff));
- if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
- DBUG_VOID_RETURN; /* purecov: inspected */
-
- // For next iteration
- used_tables|=table->map;
}
if (!join->thd->lex.select->next)
- send_eof(&thd->net);
+ {
+ save_lock=thd->lock;
+ thd->lock=(MYSQL_LOCK *)0;
+ result->send_eof();
+ thd->lock=save_lock;
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 131266a11d6..08c17c2e25d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -908,9 +908,21 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
packet->append(')');
}
- packet->append("\n)", 2);
handler *file = table->file;
+
+ /* Get possible foreign key definitions stored in InnoDB and append them
+ to the CREATE TABLE statement */
+
+ char* for_str = file->get_foreign_key_create_info();
+
+ if (for_str) {
+ packet->append(for_str, strlen(for_str));
+
+ file->free_foreign_key_create_info(for_str);
+ }
+
+ packet->append("\n)", 2);
packet->append(" TYPE=", 6);
packet->append(file->table_type());
char buff[128];
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 14daf8c1924..cda5d8c9b6b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -161,7 +161,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
if (some_tables_deleted)
{
- query_cache.invalidate(tables);
+ query_cache_invalidate3(thd, tables, 0);
if (!dont_log_query)
{
mysql_update_log.write(thd, thd->query,thd->query_length);
@@ -825,7 +825,7 @@ bool close_cached_table(THD *thd,TABLE *table)
/* Mark all tables that are in use as 'old' */
mysql_lock_abort(thd,table); // end threads waiting on lock
-#ifdef REMOVE_LOCKS
+#if defined(USING_TRANSACTIONS) || defined( __WIN__) || defined( __EMX__) || !defined(OS2)
/* Wait until all there are no other threads that has this table open */
while (remove_table_from_cache(thd,table->table_cache_key,
table->table_name))
@@ -870,7 +870,8 @@ static int send_check_errmsg(THD* thd, TABLE_LIST* table,
return 1;
}
-static int prepare_for_restore(THD* thd, TABLE_LIST* table)
+static int prepare_for_restore(THD* thd, TABLE_LIST* table,
+ HA_CHECK_OPT *check_opt)
{
DBUG_ENTER("prepare_for_restore");
@@ -911,16 +912,73 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table)
"Failed generating table from .frm file"));
}
}
+
+ // now we should be able to open the partially restored table
+ // to finish the restore in the handler later on
+ if (!(table->table = reopen_name_locked_table(thd, table)))
+ unlock_table_name(thd, table);
DBUG_RETURN(0);
}
+static int prepare_for_repair(THD* thd, TABLE_LIST* table,
+ HA_CHECK_OPT *check_opt)
+{
+ DBUG_ENTER("prepare_for_repair");
+
+ if (!(check_opt->sql_flags & TT_USEFRM))
+ {
+ DBUG_RETURN(0);
+ }
+ else
+ {
+
+ char from[FN_REFLEN],to[FN_REFLEN];
+ char* db = thd->db ? thd->db : table->db;
+
+ sprintf(from, "%s/%s/%s", mysql_real_data_home, db, table->name);
+ fn_format(from, from, "", MI_NAME_DEXT, 4);
+ sprintf(to,"%s-%lx_%lx", from, current_pid, thd->thread_id);
+
+
+ my_rename(to, from, MYF(MY_WME));
+
+ if (lock_and_wait_for_table_name(thd,table))
+ DBUG_RETURN(-1);
+
+ if (my_rename(from, to, MYF(MY_WME)))
+ {
+ unlock_table_name(thd, table);
+ DBUG_RETURN(send_check_errmsg(thd, table, "repair",
+ "Failed renaming .MYD file"));
+ }
+ if (mysql_truncate(thd, table, 1))
+ {
+ unlock_table_name(thd, table);
+ DBUG_RETURN(send_check_errmsg(thd, table, "repair",
+ "Failed generating table from .frm file"));
+ }
+ if (my_rename(to, from, MYF(MY_WME)))
+ {
+ unlock_table_name(thd, table);
+ DBUG_RETURN(send_check_errmsg(thd, table, "repair",
+ "Failed restoring .MYD file"));
+ }
+ }
+
+ // now we should be able to open the partially repaired table
+ // to finish the repair in the handler later on
+ if (!(table->table = reopen_name_locked_table(thd, table)))
+ unlock_table_name(thd, table);
+ DBUG_RETURN(0);
+}
static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT* check_opt,
const char *operator_name,
thr_lock_type lock_type,
- bool open_for_modify, bool restore,
+ bool open_for_modify,
uint extra_open_options,
+ int (*prepare_func)(THD *, TABLE_LIST *, HA_CHECK_OPT *),
int (handler::*operator_func)
(THD *, HA_CHECK_OPT *))
{
@@ -952,18 +1010,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
table->table = open_ltable(thd, table, lock_type);
thd->open_options&= ~extra_open_options;
packet->length(0);
- if (restore)
+ if (prepare_func)
{
- switch (prepare_for_restore(thd, table)) {
- case 1: continue; // error, message written to net
- case -1: goto err; // error, message could be written to net
- default: ;// should be 0 otherwise
+ switch ((*prepare_func)(thd, table, check_opt)) {
+ case 1: continue; // error, message written to net
+ case -1: goto err; // error, message could be written to net
+ default: ; // should be 0 otherwise
}
-
- // now we should be able to open the partially restored table
- // to finish the restore in the handler later on
- if (!(table->table = reopen_name_locked_table(thd, table)))
- unlock_table_name(thd, table);
}
if (!table->table)
@@ -1096,7 +1149,8 @@ int mysql_restore_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_restore_table");
DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
- "restore", TL_WRITE, 1, 1,0,
+ "restore", TL_WRITE, 1, 0,
+ &prepare_for_restore,
&handler::restore));
}
@@ -1104,7 +1158,8 @@ int mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
{
DBUG_ENTER("mysql_repair_table");
DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
- "repair", TL_WRITE, 1, 0, HA_OPEN_FOR_REPAIR,
+ "repair", TL_WRITE, 1, HA_OPEN_FOR_REPAIR,
+ &prepare_for_repair,
&handler::repair));
}
@@ -1143,7 +1198,7 @@ int mysql_check_table(THD* thd, TABLE_LIST* tables,HA_CHECK_OPT* check_opt)
DBUG_ENTER("mysql_check_table");
DBUG_RETURN(mysql_admin_table(thd, tables, check_opt,
"check", lock_type,
- 0, 0, HA_OPEN_FOR_REPAIR,
+ 0, HA_OPEN_FOR_REPAIR, 0,
&handler::check));
}
@@ -1157,7 +1212,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
ORDER *order,
bool drop_primary,
enum enum_duplicates handle_duplicates,
- enum enum_enable_or_disable keys_onoff,
+ enum enum_enable_or_disable keys_onoff,
bool simple_alter)
{
TABLE *table,*new_table;
@@ -1672,20 +1727,29 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
}
-#if defined( __WIN__) || defined( __EMX__) || defined( OS2)
- // Win32 can't rename an open table, so we must close the org table!
- table_name=thd->strdup(table_name); // must be saved
- if (close_cached_table(thd,table))
- { // Aborted
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
+#if (!defined( __WIN__) && !defined( __EMX__) && !defined( OS2))
+ if (table->file->has_transactions())
+#endif
+ {
+ /*
+ Win32 and InnoDB can't drop a table that is in use, so we must
+ close all the original table at before doing the rename
+ */
+ table_name=thd->strdup(table_name); // must be saved
+ if (close_cached_table(thd,table))
+ { // Aborted
+ VOID(quick_rm_table(new_db_type,new_db,tmp_name));
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ goto err;
+ }
+ table=0; // Marker that table is closed
}
- table=0; // Marker for win32 version
-#else
- table->file->extra(HA_EXTRA_FORCE_REOPEN); // Don't use this file anymore
+#if (!defined( __WIN__) && !defined( __EMX__) && !defined( OS2))
+ else
+ table->file->extra(HA_EXTRA_FORCE_REOPEN); // Don't use this file anymore
#endif
+
error=0;
if (mysql_rename_table(old_db_type,db,table_name,db,old_name))
{
@@ -1763,7 +1827,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
VOID(pthread_cond_broadcast(&COND_refresh));
VOID(pthread_mutex_unlock(&LOCK_open));
table_list->table=0; // For query cache
- query_cache.invalidate(table_list);
+ query_cache_invalidate3(thd, table_list, 0);
end_temporary:
sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted),
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 0d8a41e9966..541b2383e8d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -31,10 +31,12 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
ORDER *order;
List<Item> item_list;
TABLE *table;
+ int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0;
+ int res;
TABLE_LIST result_table_list;
+ TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first;
TMP_TABLE_PARAM tmp_table_param;
select_union *union_result;
- int res;
DBUG_ENTER("mysql_union");
/* Fix tables 'to-be-unioned-from' list to point at opened tables */
@@ -57,8 +59,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
the ORDER BY and LIMIT parameter for the whole UNION
*/
lex_sl= sl;
- last_sl->next=0; // Remove this extra element
order= (ORDER *) lex_sl->order_list.first;
+ if (!order || !describe)
+ last_sl->next=0; // Remove this extra element
}
else if (!last_sl->braces)
{
@@ -70,27 +73,26 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
lex_sl=0;
order=0;
}
-
- if (lex->select_lex.options & SELECT_DESCRIBE)
+
+ if (describe)
{
- for (sl= &lex->select_lex; sl; sl=sl->next)
- {
- lex->select=sl;
- res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first,
- sl->item_list,
- sl->where,
- ((sl->braces) ?
- (ORDER *) sl->order_list.first : (ORDER *) 0),
- (ORDER*) sl->group_list.first,
- sl->having,
- (ORDER*) NULL,
- (sl->options | thd->options | SELECT_NO_UNLOCK |
- SELECT_DESCRIBE),
- result);
- }
- DBUG_RETURN(0);
+ Item *item;
+ item_list.push_back(new Item_empty_string("table",NAME_LEN));
+ item_list.push_back(new Item_empty_string("type",10));
+ item_list.push_back(item=new Item_empty_string("possible_keys",
+ NAME_LEN*MAX_KEY));
+ item->maybe_null=1;
+ item_list.push_back(item=new Item_empty_string("key",NAME_LEN));
+ item->maybe_null=1;
+ item_list.push_back(item=new Item_int("key_len",0,3));
+ item->maybe_null=1;
+ item_list.push_back(item=new Item_empty_string("ref",
+ NAME_LEN*MAX_REF_PARTS));
+ item->maybe_null=1;
+ item_list.push_back(new Item_real("rows",0.0,0,10));
+ item_list.push_back(new Item_empty_string("Extra",255));
}
-
+ else
{
Item *item;
List_iterator<Item> it(lex->select_lex.item_list);
@@ -107,7 +109,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
- (ORDER*) 0, !lex->union_option,
+ (ORDER*) 0, !describe & !lex->union_option,
1, 0,
(lex->select_lex.options | thd->options |
TMP_TABLE_ALL_COLUMNS))))
@@ -124,8 +126,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
res= -1;
goto exit;
}
+ union_result->save_time_stamp=!describe;
+
for (sl= &lex->select_lex; sl; sl=sl->next)
{
+ lex->select=sl;
thd->offset_limit=sl->offset_limit;
thd->select_limit=sl->select_limit+sl->offset_limit;
if (thd->select_limit < sl->select_limit)
@@ -133,14 +138,14 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
if (thd->select_limit == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
- res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first,
+ res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first,
sl->item_list,
sl->where,
(sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0,
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
- sl->options | thd->options | SELECT_NO_UNLOCK,
+ sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
union_result);
if (res)
goto exit;
@@ -153,6 +158,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
delete union_result;
/* Send result to 'result' */
+ lex->select = &lex->select_lex;
res =-1;
{
/* Create a list of fields in the temporary table */
@@ -181,8 +187,15 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
if (thd->select_limit == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS;
}
+ else
+ {
+ thd->offset_limit= 0;
+ thd->select_limit= thd->default_select_limit;
+ }
+ if (describe)
+ thd->select_limit= HA_POS_ERROR; // no limit
res=mysql_select(thd,&result_table_list,
- item_list, NULL, /*ftfunc_list,*/ order,
+ item_list, NULL, (describe) ? 0 : order,
(ORDER*) NULL, NULL, (ORDER*) NULL,
thd->options, result);
}
@@ -216,7 +229,7 @@ select_union::~select_union()
int select_union::prepare(List<Item> &list)
{
- if (list.elements != table->fields)
+ if (save_time_stamp && list.elements != table->fields)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 6c868b542d1..db520af61c1 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -324,7 +324,8 @@ int mysql_update(THD *thd,
thd->lock=0;
}
if (updated)
- query_cache.invalidate(table_list);
+ query_cache_invalidate3(thd, table_list, 1);
+
delete select;
if (error >= 0)
send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
@@ -787,7 +788,8 @@ bool multi_update::send_eof()
sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
(long) thd->cuted_fields);
if (updated)
- query_cache.invalidate(update_tables);
+ query_cache_invalidate3(thd, update_tables, 1);
+
::send_ok(&thd->net,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 91cf0ae5fc9..8012768e508 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -32,7 +32,7 @@
extern void yyerror(const char*);
int yylex(void *yylval);
-#define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(F))) { yyerror((char*) (A)); return 2; }
+#define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(int*) (F))) { yyerror((char*) (A)); return 2; }
inline Item *or_or_concat(Item* A, Item* B)
{
@@ -123,6 +123,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token RESET_SYM
%token PURGE
%token SLAVE
+%token IO_THREAD
+%token SQL_THREAD
%token START_SYM
%token STOP_SYM
%token TRUNCATE_SYM
@@ -239,6 +241,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MASTER_PORT_SYM
%token MASTER_CONNECT_RETRY_SYM
%token MASTER_SERVER_ID_SYM
+%token RELAY_LOG_FILE_SYM
+%token RELAY_LOG_POS_SYM
%token MATCH
%token MAX_ROWS
%token MAX_QUERIES_PER_HOUR
@@ -322,6 +326,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token UNION_SYM
%token UNIQUE_SYM
%token USAGE
+%token USE_FRM
%token USE_SYM
%token USING
%token VALUES
@@ -596,9 +601,17 @@ END_OF_INPUT
query:
END_OF_INPUT
{
- if (!current_thd->bootstrap)
+ THD *thd=current_thd;
+ if (!thd->bootstrap &&
+ (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
+ {
send_error(&current_thd->net,ER_EMPTY_QUERY);
- YYABORT;
+ YYABORT;
+ }
+ else
+ {
+ thd->lex.sql_command = SQLCOM_EMPTY_QUERY;
+ }
}
| verb_clause END_OF_INPUT {}
@@ -690,6 +703,16 @@ master_def:
{
Lex->mi.connect_retry = $3;
}
+ |
+ RELAY_LOG_FILE_SYM EQ TEXT_STRING
+ {
+ Lex->mi.relay_log_name = $3.str;
+ }
+ |
+ RELAY_LOG_POS_SYM EQ ULONG_NUM
+ {
+ Lex->mi.relay_log_pos = $3;
+ }
/* create a table */
@@ -776,7 +799,7 @@ opt_table_options:
table_options:
table_option { $$=$1; }
- | table_option table_options { $$= $1 | $2 }
+ | table_option table_options { $$= $1 | $2; }
table_option:
TEMPORARY { $$=HA_LEX_CREATE_TMP_TABLE; }
@@ -1248,20 +1271,34 @@ opt_to:
| AS {}
slave:
- SLAVE START_SYM
+ SLAVE START_SYM slave_thread_opts
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_START;
lex->type = 0;
}
|
- SLAVE STOP_SYM
+ SLAVE STOP_SYM slave_thread_opts
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_STOP;
lex->type = 0;
};
+slave_thread_opts: slave_thread_opt
+ | slave_thread_opts ',' slave_thread_opt
+
+slave_thread_opt:
+ /*empty*/ {}
+ | SQL_THREAD
+ {
+ Lex->slave_thd_opt|=SLAVE_SQL;
+ }
+ | IO_THREAD
+ {
+ Lex->slave_thd_opt|=SLAVE_IO;
+ }
+
restore:
RESTORE_SYM table_or_tables
{
@@ -1281,7 +1318,6 @@ backup:
Lex->backup_dir = $6.str;
}
-
repair:
REPAIR table_or_tables
{
@@ -1289,24 +1325,20 @@ repair:
lex->sql_command = SQLCOM_REPAIR;
lex->check_opt.init();
}
- table_list opt_mi_check_type
+ table_list opt_mi_repair_type
-
-opt_mi_check_type:
+opt_mi_repair_type:
/* empty */ { Lex->check_opt.flags = T_MEDIUM; }
- | TYPE_SYM EQ mi_check_types {}
- | mi_check_types {}
+ | mi_repair_types {}
-mi_check_types:
- mi_check_type {}
- | mi_check_type mi_check_types {}
+mi_repair_types:
+ mi_repair_type {}
+ | mi_repair_type mi_repair_types {}
-mi_check_type:
- QUICK { Lex->check_opt.quick = 1; }
- | FAST_SYM { Lex->check_opt.flags|= T_FAST; }
- | MEDIUM_SYM { Lex->check_opt.flags|= T_MEDIUM; }
+mi_repair_type:
+ QUICK { Lex->check_opt.flags|= T_QUICK; }
| EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
- | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; }
+ | USE_FRM { Lex->check_opt.sql_flags|= TT_USEFRM; }
analyze:
ANALYZE_SYM table_or_tables
@@ -1326,6 +1358,21 @@ check:
}
table_list opt_mi_check_type
+opt_mi_check_type:
+ /* empty */ { Lex->check_opt.flags = T_MEDIUM; }
+ | mi_check_types {}
+
+mi_check_types:
+ mi_check_type {}
+ | mi_check_type mi_check_types {}
+
+mi_check_type:
+ QUICK { Lex->check_opt.flags|= T_QUICK; }
+ | FAST_SYM { Lex->check_opt.flags|= T_FAST; }
+ | MEDIUM_SYM { Lex->check_opt.flags|= T_MEDIUM; }
+ | EXTENDED_SYM { Lex->check_opt.flags|= T_EXTEND; }
+ | CHANGED { Lex->check_opt.flags|= T_CHECK_ONLY_CHANGED; }
+
optimize:
OPTIMIZE table_or_tables
{
@@ -1395,22 +1442,22 @@ select_option_list:
select_option:
STRAIGHT_JOIN { Select->options|= SELECT_STRAIGHT_JOIN; }
- | HIGH_PRIORITY { Lex->lock_option= TL_READ_HIGH_PRIORITY; }
+ | HIGH_PRIORITY { if (Select != &Lex->select_lex) YYABORT; Lex->lock_option= TL_READ_HIGH_PRIORITY; }
| DISTINCT { Select->options|= SELECT_DISTINCT; }
| SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; }
| SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; }
- | SQL_BUFFER_RESULT { Select->options|= OPTION_BUFFER_RESULT; }
- | SQL_CALC_FOUND_ROWS { Select->options|= OPTION_FOUND_ROWS; }
- | SQL_NO_CACHE_SYM { current_thd->safe_to_cache_query=0; }
- | SQL_CACHE_SYM { Select->options |= OPTION_TO_QUERY_CACHE; }
+ | SQL_BUFFER_RESULT { if (Select != &Lex->select_lex) YYABORT; Select->options|= OPTION_BUFFER_RESULT; }
+ | SQL_CALC_FOUND_ROWS { if (Select != &Lex->select_lex) YYABORT; Select->options|= OPTION_FOUND_ROWS; }
+ | SQL_NO_CACHE_SYM { if (Select != &Lex->select_lex) YYABORT; current_thd->safe_to_cache_query=0; }
+ | SQL_CACHE_SYM { if (Select != &Lex->select_lex) YYABORT; Select->options |= OPTION_TO_QUERY_CACHE; }
| ALL {}
select_lock_type:
/* empty */
| FOR_SYM UPDATE_SYM
- { Lex->lock_option= TL_WRITE; current_thd->safe_to_cache_query=0; }
+ { if (Select != &Lex->select_lex) YYABORT; Lex->lock_option= TL_WRITE; current_thd->safe_to_cache_query=0; }
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
- { Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; current_thd->safe_to_cache_query=0; }
+ { if (Select != &Lex->select_lex) YYABORT; Lex->lock_option= TL_READ_WITH_SHARED_LOCKS; current_thd->safe_to_cache_query=0; }
select_item_list:
select_item_list ',' select_item
@@ -1606,7 +1653,7 @@ simple_expr:
| BINARY expr %prec NEG { $$= new Item_func_binary($2); }
| CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); }
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
- { $$= new Item_func_case(* $4, $2, $5 ) }
+ { $$= new Item_func_case(* $4, $2, $5 ); }
| CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast($3, $5); }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
@@ -1872,7 +1919,7 @@ sum_expr:
{ $$=new Item_sum_sum($3); }
in_sum_expr:
- { Select->in_sum_expr++ }
+ { Select->in_sum_expr++; }
expr
{
Select->in_sum_expr--;
@@ -1920,7 +1967,7 @@ opt_else:
| ELSE expr { $$= $2; }
when_list:
- { Select->when_list.push_front(new List<Item>) }
+ { Select->when_list.push_front(new List<Item>); }
when_list2
{ $$= Select->when_list.pop(); }
@@ -1945,7 +1992,7 @@ opt_pad:
join_table_list:
'(' join_table_list ')' { $$=$2; }
| join_table { $$=$1; }
- | join_table_list normal_join join_table { $$=$3 }
+ | join_table_list normal_join join_table { $$=$3; }
| join_table_list STRAIGHT_JOIN join_table { $$=$3 ; $$->straight=1; }
| join_table_list INNER_SYM JOIN_SYM join_table ON expr
{ add_join_on($4,$6); $$=$4; }
@@ -2023,7 +2070,7 @@ opt_key_definition:
}
key_usage_list:
- key_or_index { Select->interval_list.empty() } '(' key_usage_list2 ')'
+ key_or_index { Select->interval_list.empty(); } '(' key_usage_list2 ')'
{ $$= &Select->interval_list; }
key_usage_list2:
@@ -2629,7 +2676,7 @@ describe:
YYABORT;
}
opt_describe_column
- | describe_command select { Lex->select_lex.options|= SELECT_DESCRIBE };
+ | describe_command select { Lex->select_lex.options|= SELECT_DESCRIBE; }
describe_command:
@@ -2828,7 +2875,7 @@ literal:
| FLOAT_NUM { $$ = new Item_float($1.str, $1.length); }
| NULL_SYM { $$ = new Item_null();
Lex->next_state=STATE_OPERATOR_OR_IDENT;}
- | HEX_NUM { $$ = new Item_varbinary($1.str,$1.length)};
+ | HEX_NUM { $$ = new Item_varbinary($1.str,$1.length);}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
| TIMESTAMP text_literal { $$ = $2; }
@@ -2978,6 +3025,7 @@ keyword:
| ISSUER_SYM {}
| INNOBASE_SYM {}
| INSERT_METHOD {}
+ | IO_THREAD {}
| LAST_SYM {}
| LEVEL_SYM {}
| LOCAL_SYM {}
@@ -3020,6 +3068,8 @@ keyword:
| RAID_CHUNKSIZE {}
| RAID_STRIPED_SYM {}
| RAID_TYPE {}
+ | RELAY_LOG_FILE_SYM {}
+ | RELAY_LOG_POS_SYM {}
| RELOAD {}
| REPAIR {}
| REPEATABLE_SYM {}
@@ -3039,6 +3089,7 @@ keyword:
| SQL_CACHE_SYM {}
| SQL_NO_CACHE_SYM {}
| SQL_QUERY_CACHE_TYPE_SYM {}
+ | SQL_THREAD {}
| START_SYM {}
| STATUS_SYM {}
| STOP_SYM {}
@@ -3053,10 +3104,10 @@ keyword:
| TYPE_SYM {}
| UDF_SYM {}
| UNCOMMITTED_SYM {}
+ | USE_FRM {}
| VARIABLES {}
| WORK_SYM {}
| YEAR_SYM {}
- | SLAVE {}
/* Option functions */
@@ -3069,7 +3120,7 @@ set:
lex->select->select_limit=lex->thd->default_select_limit;
lex->tx_isolation=lex->thd->tx_isolation;
lex->option_type=0;
- lex->option_list.empty()
+ lex->option_list.empty();
}
option_value_list
diff --git a/sql/table.cc b/sql/table.cc
index 9aae9e17e5a..023d4d85df9 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -130,8 +130,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0)));
if (read_string(file,(gptr*) &disk_buff,(uint) uint2korr(head+28)))
goto err_not_open; /* purecov: inspected */
- outparam->keys=keys=disk_buff[0];
- outparam->keys_in_use= (((key_map) 1) << keys)- (key_map) 1;
+ outparam->keys=keys= disk_buff[0];
+ outparam->keys_in_use= set_bits(key_map, keys);
outparam->key_parts=key_parts=disk_buff[1];
n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
@@ -576,6 +576,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
delete outparam->file;
outparam->file=0; // For easyer errorchecking
outparam->db_stat=0;
+ hash_free(&outparam->name_hash);
free_root(&outparam->mem_root,MYF(0));
my_free(outparam->table_name,MYF(MY_ALLOW_ZERO_PTR));
DBUG_RETURN (error);
diff --git a/sql/table.h b/sql/table.h
index 259c34030b2..209333c24b7 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -95,6 +95,7 @@ struct st_table {
my_bool db_low_byte_first; /* Portable row format */
my_bool locked_by_flush;
my_bool locked_by_name;
+ my_bool fulltext_searched;
my_bool crashed;
my_bool is_view;
my_bool no_keyread;
@@ -111,7 +112,7 @@ struct st_table {
char *table_name,*real_name,*path;
uint key_length; /* Length of key */
uint tablenr,used_fields,null_bytes;
- table_map map;
+ table_map map; /* ID bit of table (1,2,4,8,16...) */
ulong version,flush_version;
uchar *null_flags;
IO_CACHE *io_cache; /* If sorted trough file*/
@@ -137,18 +138,26 @@ struct st_table {
typedef struct st_table_list {
struct st_table_list *next;
char *db,*name,*real_name;
+ uint32 db_length, real_name_length;
Item *on_expr; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
- List<String> *use_index,*ignore_index;
+ /* ... join ... USE INDEX ... IGNORE INDEX */
+ List<String> *use_index,*ignore_index;
TABLE *table;
GRANT_INFO grant;
thr_lock_type lock_type;
uint outer_join; /* Which join type */
bool straight; /* optimize with prev table */
- bool updating; /* for replicate-do/ignore table */
+ bool updating; /* for replicate-do/ignore table */
bool shared; /* Used twice in union */
} TABLE_LIST;
+typedef struct st_changed_table_list {
+ struct st_changed_table_list *next;
+ char *key, *table_name;
+ uint32 key_length;
+} CHANGED_TABLE_LIST;
+
typedef struct st_open_table_list
{
struct st_open_table_list *next;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 8c72dfc2855..16ba8c7d58b 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -486,11 +486,11 @@ static bool pack_fields(File file,List<create_field> &create_fields)
if (field->interval_id > int_count)
{
int_count=field->interval_id;
- tmp.append('\377');
+ tmp.append(NAMES_SEP_CHAR);
for (const char **pos=field->interval->type_names ; *pos ; pos++)
{
tmp.append(*pos);
- tmp.append('\377');
+ tmp.append(NAMES_SEP_CHAR);
}
tmp.append('\0'); // End of intervall
}
diff --git a/sql/unireg.h b/sql/unireg.h
index 9b220f87918..c4d2052d1da 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -70,11 +70,6 @@
#define FERR -1 /* Error from my_functions */
#define CREATE_MODE 0 /* Default mode on new files */
#define NAMES_SEP_CHAR '\377' /* Char to sep. names */
-#ifdef MSDOS
-#define EXTRA_FIELD_CHAR (char) '\234' /* Interchangebly with '#' */
-#else
-#define EXTRA_FIELD_CHAR '#' /* Interchangebly with '#' */
-#endif
#define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */
#define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */