summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@narttu.mysql.fi>2003-08-29 13:44:35 +0300
committerunknown <monty@narttu.mysql.fi>2003-08-29 13:44:35 +0300
commit0fa5279543d20c0d0c9ef6a1835c7f5056f0a997 (patch)
treeaeb2314adbd714c7e2b032209bfd7914e3cfda3d /sql
parentfb3ab3c855fa8f154d1f018bb6eea155614289c9 (diff)
parentf2adc9f3dd62a9f1f7493d8401542bc8a007fe47 (diff)
downloadmariadb-git-0fa5279543d20c0d0c9ef6a1835c7f5056f0a997.tar.gz
merge with 4.0.15
BitKeeper/etc/ignore: auto-union BitKeeper/etc/logging_ok: auto-union BitKeeper/deleted/.del-database.c~af098622e818ce0d: Auto merged BitKeeper/deleted/.del-have_openssl_2.inc~8c9f1a45676b698f: Auto merged BitKeeper/deleted/.del-have_openssl_2.require~53bbdfc136fb514: Auto merged BitKeeper/deleted/.del-mini_client.cc~8677895ec8169183: Auto merged BitKeeper/deleted/.del-openssl_2.test~f2dfa927f19d14f8: Auto merged Build-tools/Bootstrap: Auto merged Build-tools/Do-compile: Auto merged SSL/cacert.pem: Auto merged acconfig.h: Auto merged acinclude.m4: Auto merged configure.in: Auto merged SSL/client-cert.pem: Auto merged SSL/client-key.pem: Auto merged SSL/server-cert.pem: Auto merged SSL/server-key.pem: Auto merged VC++Files/client/mysql.dsp: Auto merged VC++Files/client/mysqladmin.dsp: Auto merged VC++Files/client/mysqlclient.dsp: Auto merged VC++Files/client/mysqldump.dsp: Auto merged VC++Files/client/mysqlimport.dsp: Auto merged VC++Files/client/mysqlshow.dsp: Auto merged VC++Files/comp_err/comp_err.dsp: Auto merged VC++Files/innobase/innobase.dsp: Auto merged VC++Files/isamchk/isamchk.dsp: Auto merged VC++Files/libmysql/libmysql.dsp: Auto merged VC++Files/libmysqltest/myTest.dsp: Auto merged VC++Files/my_print_defaults/my_print_defaults.dsp: Auto merged VC++Files/myisamlog/myisamlog.dsp: Auto merged VC++Files/mysql.dsw: Auto merged VC++Files/mysqlbinlog/mysqlbinlog.dsp: Auto merged VC++Files/mysqlcheck/mysqlcheck.dsp: Auto merged VC++Files/mysqlmanager/MySqlManager.dsp: Auto merged VC++Files/mysqlserver/mysqlserver.dsp: Auto merged VC++Files/mysqlshutdown/mysqlshutdown.dsp: Auto merged VC++Files/mysys/mysys.dsp: Auto merged VC++Files/pack_isam/pack_isam.dsp: Auto merged VC++Files/perror/perror.dsp: Auto merged VC++Files/replace/replace.dsp: Auto merged VC++Files/test1/test1.dsp: Auto merged VC++Files/thr_test/thr_test.dsp: Auto merged VC++Files/vio/vio.dsp: Auto merged VC++Files/zlib/zlib.dsp: Auto merged client/mysqlbinlog.cc: Auto merged client/mysqldump.c: Auto merged client/mysqlimport.c: Auto merged extra/my_print_defaults.c: Auto merged extra/resolveip.c: Auto merged include/m_string.h: Auto merged include/my_sys.h: Auto merged include/mysql_com.h: Auto merged innobase/dict/dict0dict.c: Auto merged innobase/os/os0file.c: Auto merged isam/_search.c: Auto merged libmysql/Makefile.am: Auto merged libmysql/errmsg.c: Auto merged libmysql/libmysql.c: Auto merged myisam/mi_check.c: Auto merged myisam/mi_create.c: Auto merged myisam/mi_open.c: Auto merged myisam/mi_search.c: Auto merged myisam/mi_write.c: Auto merged myisam/myisamchk.c: Auto merged myisam/myisamlog.c: Auto merged mysql-test/mysql-test-run.sh: Auto merged mysql-test/r/group_by.result: Auto merged mysql-test/r/isam.result: Auto merged mysql-test/r/loaddata.result: Auto merged mysql-test/r/lowercase_table.result: Auto merged mysql-test/r/multi_update.result: Auto merged mysql-test/r/openssl_1.result: Auto merged mysql-test/r/packet.result: Auto merged mysql-test/r/query_cache.result: Auto merged mysql-test/r/range.result: Auto merged mysql-test/r/select_safe.result: Auto merged mysql-test/r/show_check.result: Auto merged mysql-test/t/grant.test: Auto merged mysql-test/t/group_by.test: Auto merged mysql-test/t/lock_tables_lost_commit-master.opt: Auto merged mysql-test/t/lowercase_table.test: Auto merged mysql-test/t/multi_update.test: Auto merged mysql-test/t/openssl_1.test: Auto merged mysql-test/t/range.test: Auto merged mysql-test/t/rpl_loaddata.test: Auto merged mysql-test/t/rpl_log.test: Auto merged mysql-test/t/select_safe.test: Auto merged mysql-test/t/show_check.test: Auto merged mysql-test/t/symlink.test: Auto merged mysys/default.c: Auto merged mysys/my_getopt.c: Auto merged mysys/my_pthread.c: Auto merged scripts/make_binary_distribution.sh: Auto merged scripts/make_win_src_distribution.sh: Auto merged scripts/mysql_install_db.sh: Auto merged scripts/mysqld_safe.sh: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_myisam.cc: Auto merged sql/handler.cc: Auto merged sql/item_uniq.h: Auto merged sql/log_event.h: Auto merged sql/net_serv.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_update.cc: Auto merged vio/Makefile.am: Auto merged vio/vio.c: Auto merged mysql-test/t/myisam.test: merge with 4.0.15 Extra tests mysys/mf_keycache.c: Keep local file
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc18
-rw-r--r--sql/ha_innodb.cc1
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/handler.cc86
-rw-r--r--sql/item.cc7
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_cmpfunc.cc24
-rw-r--r--sql/item_func.cc8
-rw-r--r--sql/item_func.h1
-rw-r--r--sql/item_sum.cc75
-rw-r--r--sql/item_sum.h34
-rw-r--r--sql/item_uniq.h2
-rw-r--r--sql/log.cc57
-rw-r--r--sql/log_event.cc225
-rw-r--r--sql/log_event.h27
-rw-r--r--sql/mysql_priv.h32
-rw-r--r--sql/mysqld.cc32
-rw-r--r--sql/net_serv.cc30
-rw-r--r--sql/opt_range.cc89
-rw-r--r--sql/repl_failsafe.cc15
-rw-r--r--sql/set_var.cc36
-rw-r--r--sql/share/portuguese/errmsg.txt24
-rw-r--r--sql/share/spanish/errmsg.txt34
-rw-r--r--sql/slave.cc70
-rw-r--r--sql/slave.h28
-rw-r--r--sql/sql_acl.cc21
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_insert.cc6
-rw-r--r--sql/sql_load.cc13
-rw-r--r--sql/sql_parse.cc19
-rw-r--r--sql/sql_repl.cc16
-rw-r--r--sql/sql_select.cc79
-rw-r--r--sql/sql_show.cc175
-rw-r--r--sql/sql_table.cc3
-rw-r--r--sql/sql_union.cc37
-rw-r--r--sql/sql_update.cc6
37 files changed, 869 insertions, 472 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 051a4fa8057..efdf1762c0b 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -771,7 +771,7 @@ int Field_decimal::store(double nr)
char buff[320];
fyllchar = zerofill ? (char) '0' : (char) ' ';
-#ifdef HAVE_SNPRINTF_
+#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
length=(uint) strlen(buff);
@@ -2016,9 +2016,16 @@ double Field_longlong::val_real(void)
else
#endif
longlongget(j,ptr);
- return unsigned_flag ? ulonglong2double((ulonglong) j) : (double) j;
+ /* The following is open coded to avoid a bug in gcc 3.3 */
+ if (unsigned_flag)
+ {
+ ulonglong tmp= (ulonglong) j;
+ return ulonglong2double(tmp);
+ }
+ return (double) j;
}
+
longlong Field_longlong::val_int(void)
{
longlong j;
@@ -4413,8 +4420,11 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
Field_blob::store_length(length);
if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
{ // Must make a copy
- value.copy(from,length,charset());
- from=value.ptr();
+ if (from != value.ptr()) // For valgrind
+ {
+ value.copy(from,length,charset());
+ from=value.ptr();
+ }
}
bmove(ptr+packlength,(char*) &from,sizeof(char*));
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index d870d0debfd..bcdb01da9ca 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -28,7 +28,6 @@ InnoDB */
#include "mysql_priv.h"
#include "slave.h"
-#include "sql_cache.h"
#ifdef HAVE_INNOBASE_DB
#include <m_ctype.h>
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index e8e4798c2b2..043cdafa275 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -1109,7 +1109,7 @@ THR_LOCK_DATA **ha_myisam::store_lock(THD *thd,
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
{
- table->file->info(HA_STATUS_AUTO | HA_STATUS_CONST);
+ ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
{
create_info->auto_increment_value=auto_increment_value;
diff --git a/sql/handler.cc b/sql/handler.cc
index b4d370491bb..a8e9f9cf50a 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -359,7 +359,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
my_b_tell(&thd->transaction.trans_log))
{
- mysql_bin_log.write(thd, &thd->transaction.trans_log);
+ mysql_bin_log.write(thd, &thd->transaction.trans_log, 1);
reinit_io_cache(&thd->transaction.trans_log,
WRITE_CACHE, (my_off_t) 0, 0, 1);
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
@@ -442,9 +442,21 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
}
#endif
if (trans == &thd->transaction.all)
+ {
+ /*
+ Update the binary log with a BEGIN/ROLLBACK block if we have cached some
+ queries and we updated some non-transactional table. Such cases should
+ be rare (updating a non-transactional table inside a transaction...).
+ */
+ if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ mysql_bin_log.is_open() &&
+ my_b_tell(&thd->transaction.trans_log)))
+ mysql_bin_log.write(thd, &thd->transaction.trans_log, 0);
+ /* Flushed or not, empty the binlog cache */
reinit_io_cache(&thd->transaction.trans_log,
- WRITE_CACHE, (my_off_t) 0, 0, 1);
- thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
+ WRITE_CACHE, (my_off_t) 0, 0, 1);
+ thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
+ }
thd->variables.tx_isolation=thd->session_tx_isolation;
if (operation_done)
{
@@ -458,9 +470,27 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
/*
-Rolls the current transaction back to a savepoint.
-Return value: 0 if success, 1 if there was not a savepoint of the given
-name.
+ Rolls the current transaction back to a savepoint.
+ Return value: 0 if success, 1 if there was not a savepoint of the given
+ name.
+ NOTE: how do we handle this (unlikely but legal) case:
+ [transaction] + [update to non-trans table] + [rollback to savepoint] ?
+ The problem occurs when a savepoint is before the update to the
+ non-transactional table. Then when there's a rollback to the savepoint, if we
+ simply truncate the binlog cache, we lose the part of the binlog cache where
+ the update is. If we want to not lose it, we need to write the SAVEPOINT
+ command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
+ is easy: it's just write at the end of the binlog cache, but the former should
+ be *inserted* to the place where the user called SAVEPOINT. The solution is
+ that when the user calls SAVEPOINT, we write it to the binlog cache (so no
+ need to later insert it). As transactions are never intermixed in the binary log
+ (i.e. they are serialized), we won't have conflicts with savepoint names when
+ using mysqlbinlog or in the slave SQL thread.
+ Then when ROLLBACK TO SAVEPOINT is called, if we updated some
+ non-transactional table, we don't truncate the binlog cache but instead write
+ ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
+ will chop the SAVEPOINT command from the binlog cache, which is good as in
+ that case there is no need to have it in the binlog).
*/
int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
@@ -485,8 +515,24 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
error=1;
}
else
- reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
- binlog_cache_pos, 0, 0);
+ {
+ /*
+ Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
+ non-transactional table. Otherwise, truncate the binlog cache starting
+ from the SAVEPOINT command.
+ */
+ if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ mysql_bin_log.is_open() &&
+ my_b_tell(&thd->transaction.trans_log)))
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
+ if (mysql_bin_log.write(&qinfo))
+ error= 1;
+ }
+ else
+ reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
+ binlog_cache_pos, 0, 0);
+ }
operation_done=1;
#endif
if (operation_done)
@@ -515,6 +561,13 @@ int ha_savepoint(THD *thd, char *savepoint_name)
#ifdef HAVE_INNOBASE_DB
innobase_savepoint(thd,savepoint_name, binlog_cache_pos);
#endif
+ /* Write it to the binary log (see comments of ha_rollback_to_savepoint). */
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
+ if (mysql_bin_log.write(&qinfo))
+ error= 1;
+ }
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
@@ -1051,14 +1104,25 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
void ha_key_cache(void)
{
- if (keybuff_size)
- (void) init_key_cache((ulong) keybuff_size);
+ /*
+ The following mutex is not really needed as long as keybuff_size is
+ treated as a long value, but we use the mutex here to guard for future
+ changes.
+ */
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ long tmp= (long) keybuff_size;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ if (tmp)
+ (void) init_key_cache(tmp);
}
void ha_resize_key_cache(void)
{
- (void) resize_key_cache((ulong) keybuff_size);
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ long tmp= (long) keybuff_size;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ (void) resize_key_cache(tmp);
}
diff --git a/sql/item.cc b/sql/item.cc
index 0ea2231ca4b..371ce0a947d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -903,6 +903,13 @@ void Item::make_field(Send_field *tmp_field)
init_make_field(tmp_field, field_type());
}
+
+void Item_empty_string::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_VAR_STRING);
+}
+
+
enum_field_types Item::field_type() const
{
return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING :
diff --git a/sql/item.h b/sql/item.h
index 07be964092a..12f047bbebc 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -505,6 +505,7 @@ public:
Item_empty_string(const char *header,uint length) :Item_string("",0,
&my_charset_bin)
{ name=(char*) header; max_length=length;}
+ void make_field(Send_field *field);
};
class Item_return_int :public Item_int
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 3471ddd30e9..09b92d7df40 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -545,6 +545,7 @@ void Item_func_interval::fix_length_and_dec()
used_tables_cache|= row->used_tables();
not_null_tables_cache&= row->not_null_tables();
with_sum_func= with_sum_func || row->with_sum_func;
+ const_item_cache&= row->const_item();
}
@@ -1458,17 +1459,20 @@ void Item_func_in::fix_length_and_dec()
DBUG_ASSERT(0);
return;
}
- uint j=0;
- for (uint i=1 ; i < arg_count ; i++)
+ if (array && !(current_thd->fatal_error)) // If not EOM
{
- array->set(j,args[i]);
- if (!args[i]->null_value) // Skip NULL values
- j++;
- else
- have_null= 1;
+ uint j=0;
+ for (uint i=1 ; i < arg_count ; i++)
+ {
+ array->set(j,args[i]);
+ if (!args[i]->null_value) // Skip NULL values
+ j++;
+ else
+ have_null= 1;
+ }
+ if ((array->used_count=j))
+ array->sort();
}
- if ((array->used_count=j))
- array->sort();
}
else
{
@@ -1567,7 +1571,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
and_tables_cache= ~(table_map) 0;
if (thd && check_stack_overrun(thd,buff))
- return 0; // Fatal error flag is set!
+ return 1; // Fatal error flag is set!
while ((item=li++))
{
table_map tmp_table_map;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 4bda8ae78cd..bfb62febce4 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -173,13 +173,15 @@ bool
Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
Item **arg,**arg_end;
+#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
char buff[STACK_BUFF_ALLOC]; // Max argument in function
+#endif
used_tables_cache= not_null_tables_cache= 0;
const_item_cache=1;
if (thd && check_stack_overrun(thd,buff))
- return 0; // Fatal error if flag is set!
+ return 1; // Fatal error if flag is set!
if (arg_count)
{ // Print purify happy
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
@@ -1431,13 +1433,15 @@ bool
udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
uint arg_count, Item **arguments)
{
+#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
char buff[STACK_BUFF_ALLOC]; // Max argument in function
+#endif
DBUG_ENTER("Item_udf_func::fix_fields");
if (thd)
{
if (check_stack_overrun(thd,buff))
- return 0; // Fatal error flag is set!
+ DBUG_RETURN(1); // Fatal error flag is set!
}
else
thd=current_thd; // In WHERE / const clause
diff --git a/sql/item_func.h b/sql/item_func.h
index 7fedbcf48ee..2b114f5c87d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -538,6 +538,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
+ table_map not_null_tables() const { return 0; }
};
class Item_func_min :public Item_func_min_max
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index c429346a2e6..de6282b1324 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -70,6 +70,8 @@ void Item_sum::make_field(Send_field *tmp_field)
tmp_field->db_name=(char*)"";
tmp_field->org_table_name=tmp_field->table_name=(char*)"";
tmp_field->org_col_name=tmp_field->col_name=name;
+ if (maybe_null)
+ tmp_field->flags&= ~NOT_NULL_FLAG;
}
else
init_make_field(tmp_field, field_type());
@@ -197,7 +199,8 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
max_length=item->max_length;
}
decimals=item->decimals;
- maybe_null=item->maybe_null;
+ /* MIN/MAX can return NULL for empty set indepedent of the used column */
+ maybe_null= 1;
unsigned_flag=item->unsigned_flag;
collation.set(item->collation);
result_field=0;
@@ -388,15 +391,15 @@ void Item_sum_variance::reset_field()
}
}
-void Item_sum_variance::update_field(int offset)
+void Item_sum_variance::update_field()
{
double nr,old_nr,old_sqr;
longlong field_count;
char *res=result_field->ptr;
- float8get(old_nr,res+offset);
- float8get(old_sqr,res+offset+sizeof(double));
- field_count=sint8korr(res+offset+sizeof(double)*2);
+ float8get(old_nr, res);
+ float8get(old_sqr, res+sizeof(double));
+ field_count=sint8korr(res+sizeof(double)*2);
nr=args[0]->val();
if (!args[0]->null_value)
@@ -753,12 +756,12 @@ void Item_sum_bit::reset_field()
** calc next value and merge it with field_value
*/
-void Item_sum_sum::update_field(int offset)
+void Item_sum_sum::update_field()
{
double old_nr,nr;
char *res=result_field->ptr;
- float8get(old_nr,res+offset);
+ float8get(old_nr,res);
nr=args[0]->val();
if (!args[0]->null_value)
{
@@ -769,12 +772,12 @@ void Item_sum_sum::update_field(int offset)
}
-void Item_sum_count::update_field(int offset)
+void Item_sum_count::update_field()
{
longlong nr;
char *res=result_field->ptr;
- nr=sint8korr(res+offset);
+ nr=sint8korr(res);
if (!args[0]->maybe_null)
nr++;
else
@@ -787,14 +790,14 @@ void Item_sum_count::update_field(int offset)
}
-void Item_sum_avg::update_field(int offset)
+void Item_sum_avg::update_field()
{
double nr,old_nr;
longlong field_count;
char *res=result_field->ptr;
- float8get(old_nr,res+offset);
- field_count=sint8korr(res+offset+sizeof(double));
+ float8get(old_nr,res);
+ field_count=sint8korr(res+sizeof(double));
nr=args[0]->val();
if (!args[0]->null_value)
@@ -807,77 +810,65 @@ void Item_sum_avg::update_field(int offset)
int8store(res,field_count);
}
-void Item_sum_hybrid::update_field(int offset)
+void Item_sum_hybrid::update_field()
{
if (hybrid_type == STRING_RESULT)
- min_max_update_str_field(offset);
+ min_max_update_str_field();
else if (hybrid_type == INT_RESULT)
- min_max_update_int_field(offset);
+ min_max_update_int_field();
else
- min_max_update_real_field(offset);
+ min_max_update_real_field();
}
void
-Item_sum_hybrid::min_max_update_str_field(int offset)
+Item_sum_hybrid::min_max_update_str_field()
{
String *res_str=args[0]->val_str(&value);
- if (args[0]->null_value)
- result_field->copy_from_tmp(offset); // Use old value
- else
+ if (!args[0]->null_value)
{
res_str->strip_sp();
- result_field->ptr+=offset; // Get old max/min
result_field->val_str(&tmp_value,&tmp_value);
- result_field->ptr-=offset;
if (result_field->is_null() ||
(cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0)
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
- else
- { // Use old value
- char *res=result_field->ptr;
- memcpy(res,res+offset,result_field->pack_length());
- }
result_field->set_notnull();
}
}
void
-Item_sum_hybrid::min_max_update_real_field(int offset)
+Item_sum_hybrid::min_max_update_real_field()
{
double nr,old_nr;
- result_field->ptr+=offset;
old_nr=result_field->val_real();
nr=args[0]->val();
if (!args[0]->null_value)
{
- if (result_field->is_null(offset) ||
+ if (result_field->is_null(0) ||
(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
old_nr=nr;
result_field->set_notnull();
}
- else if (result_field->is_null(offset))
+ else if (result_field->is_null(0))
result_field->set_null();
- result_field->ptr-=offset;
result_field->store(old_nr);
}
void
-Item_sum_hybrid::min_max_update_int_field(int offset)
+Item_sum_hybrid::min_max_update_int_field()
{
longlong nr,old_nr;
- result_field->ptr+=offset;
old_nr=result_field->val_int();
nr=args[0]->val_int();
if (!args[0]->null_value)
{
- if (result_field->is_null(offset))
+ if (result_field->is_null(0))
old_nr=nr;
else
{
@@ -890,30 +881,29 @@ Item_sum_hybrid::min_max_update_int_field(int offset)
}
result_field->set_notnull();
}
- else if (result_field->is_null(offset))
+ else if (result_field->is_null(0))
result_field->set_null();
- result_field->ptr-=offset;
result_field->store(old_nr);
}
-void Item_sum_or::update_field(int offset)
+void Item_sum_or::update_field()
{
ulonglong nr;
char *res=result_field->ptr;
- nr=uint8korr(res+offset);
+ nr=uint8korr(res);
nr|= (ulonglong) args[0]->val_int();
int8store(res,nr);
}
-void Item_sum_and::update_field(int offset)
+void Item_sum_and::update_field()
{
ulonglong nr;
char *res=result_field->ptr;
- nr=uint8korr(res+offset);
+ nr=uint8korr(res);
nr&= (ulonglong) args[0]->val_int();
int8store(res,nr);
}
@@ -1931,6 +1921,3 @@ String* Item_func_group_concat::val_str(String* str)
}
return &result;
}
-
-
-
diff --git a/sql/item_sum.h b/sql/item_sum.h
index e9f9890f41d..6cc8d768be5 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -66,7 +66,7 @@ public:
virtual void clear()= 0;
virtual bool add()=0;
virtual void reset_field()=0;
- virtual void update_field(int offset)=0;
+ virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
virtual const char *func_name() const { return "?"; }
@@ -129,7 +129,7 @@ class Item_sum_sum :public Item_sum_num
bool add();
double val();
void reset_field();
- void update_field(int offset);
+ void update_field();
void no_rows_in_result() {}
const char *func_name() const { return "sum"; }
Item *copy_or_same(THD* thd);
@@ -158,7 +158,7 @@ class Item_sum_count :public Item_sum_int
void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
longlong val_int();
void reset_field();
- void update_field(int offset);
+ void update_field();
const char *func_name() const { return "count"; }
Item *copy_or_same(THD* thd);
};
@@ -230,7 +230,7 @@ class Item_sum_count_distinct :public Item_sum_int
bool add();
longlong val_int();
void reset_field() { return ;} // Never called
- void update_field(int offset) { return ; } // Never called
+ void update_field() { return ; } // Never called
const char *func_name() const { return "count_distinct"; }
bool setup(THD *thd);
void make_unique();
@@ -274,7 +274,7 @@ class Item_sum_avg :public Item_sum_num
bool add();
double val();
void reset_field();
- void update_field(int offset);
+ void update_field();
Item *result_item(Field *field)
{ return new Item_avg_field(this); }
const char *func_name() const { return "avg"; }
@@ -327,7 +327,7 @@ class Item_sum_variance : public Item_sum_num
bool add();
double val();
void reset_field();
- void update_field(int offset);
+ void update_field();
Item *result_item(Field *field)
{ return new Item_variance_field(this); }
const char *func_name() const { return "variance"; }
@@ -407,10 +407,10 @@ class Item_sum_hybrid :public Item_sum
bool keep_field_type(void) const { return 1; }
enum Item_result result_type () const { return hybrid_type; }
enum enum_field_types field_type() const { return hybrid_field_type; }
- void update_field(int offset);
- void min_max_update_str_field(int offset);
- void min_max_update_real_field(int offset);
- void min_max_update_int_field(int offset);
+ void update_field();
+ void min_max_update_str_field();
+ void min_max_update_real_field();
+ void min_max_update_int_field();
};
@@ -465,7 +465,7 @@ class Item_sum_or :public Item_sum_bit
Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_or(THD *thd, Item_sum_or &item) :Item_sum_bit(thd, item) {}
bool add();
- void update_field(int offset);
+ void update_field();
const char *func_name() const { return "bit_or"; }
Item *copy_or_same(THD* thd);
};
@@ -477,7 +477,7 @@ class Item_sum_and :public Item_sum_bit
Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {}
Item_sum_and(THD *thd, Item_sum_and &item) :Item_sum_bit(thd, item) {}
bool add();
- void update_field(int offset);
+ void update_field();
const char *func_name() const { return "bit_and"; }
Item *copy_or_same(THD* thd);
};
@@ -512,7 +512,7 @@ public:
void clear();
bool add();
void reset_field() {};
- void update_field(int offset_arg) {};
+ void update_field() {};
};
@@ -593,7 +593,7 @@ class Item_sum_udf_float :public Item_sum_num
double val() { return 0.0; }
void clear() {}
bool add() { return 0; }
- void update_field(int offset) {}
+ void update_field() {}
};
@@ -610,7 +610,7 @@ public:
double val() { return 0; }
void clear() {}
bool add() { return 0; }
- void update_field(int offset) {}
+ void update_field() {}
};
@@ -630,7 +630,7 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
void clear() {}
bool add() { return 0; }
- void update_field(int offset) {}
+ void update_field() {}
};
#endif /* HAVE_DLOPEN */
@@ -720,7 +720,7 @@ class Item_func_group_concat : public Item_sum
bool fix_fields(THD *, TABLE_LIST *, Item **);
bool setup(THD *thd);
void make_unique();
- virtual void update_field(int offset) {};
+ virtual void update_field() {}
double val()
{
String *res; res=val_str(&str_value);
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index e41397dac44..9b370b70181 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -44,7 +44,7 @@ public:
void clear() {}
bool add() { return 0; }
void reset_field() {}
- void update_field(int offset) {}
+ void update_field() {}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
fixed= 1;
diff --git a/sql/log.cc b/sql/log.cc
index d3ba5b63e19..f279d6d679c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -270,7 +270,8 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
an extension for the binary log files.
In this case we write a standard header to it.
*/
- if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, BIN_LOG_HEADER_SIZE))
+ if (my_b_safe_write(&log_file, (byte*) BINLOG_MAGIC,
+ BIN_LOG_HEADER_SIZE))
goto err;
bytes_written += BIN_LOG_HEADER_SIZE;
write_file_name_to_index_file=1;
@@ -1175,14 +1176,24 @@ bool MYSQL_LOG::write(Log_event* event_info)
*/
if (is_open())
{
- const char *local_db = event_info->get_db();
+ const char *local_db= event_info->get_db();
+ IO_CACHE *file= &log_file;
#ifdef USING_TRANSACTIONS
- IO_CACHE *file = ((event_info->get_cache_stmt()) ?
- &thd->transaction.trans_log :
- &log_file);
-#else
- IO_CACHE *file = &log_file;
-#endif
+ /*
+ Should we write to the binlog cache or to the binlog on disk?
+ Write to the binlog cache if:
+ - it is already not empty (meaning we're in a transaction; note that the
+ present event could be about a non-transactional table, but still we need
+ to write to the binlog cache in that case to handle updates to mixed
+ trans/non-trans table types the best possible in binlogging)
+ - or if the event asks for it (cache_stmt == true).
+ */
+ if (opt_using_transactions &&
+ (event_info->get_cache_stmt() ||
+ (thd && my_b_tell(&thd->transaction.trans_log))))
+ file= &thd->transaction.trans_log;
+#endif
+ DBUG_PRINT("info",("event type=%d",event_info->get_type_code()));
#ifdef HAVE_REPLICATION
/*
In the future we need to add to the following if tests like
@@ -1401,6 +1412,13 @@ uint MYSQL_LOG::next_file_id()
/*
Write a cached log entry to the binary log
+ SYNOPSIS
+ write()
+ thd
+ cache The cache to copy to the binlog
+ commit_or_rollback If true, will write "COMMIT" in the end, if false will
+ write "ROLLBACK".
+
NOTE
- We only come here if there is something in the cache.
- The thing in the cache is always a complete transaction
@@ -1408,10 +1426,13 @@ uint MYSQL_LOG::next_file_id()
IMPLEMENTATION
- To support transaction over replication, we wrap the transaction
- with BEGIN/COMMIT in the binary log.
+ with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
+ We want to write a BEGIN/ROLLBACK block when a non-transactional table was
+ updated in a transaction which was rolled back. This is to ensure that the
+ same updates are run on the slave.
*/
-bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
+bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
{
VOID(pthread_mutex_lock(&LOCK_log));
DBUG_ENTER("MYSQL_LOG::write(cache");
@@ -1465,7 +1486,10 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
*/
{
- Query_log_event qinfo(thd, "COMMIT", 6, TRUE);
+ Query_log_event qinfo(thd,
+ commit_or_rollback ? "COMMIT" : "ROLLBACK",
+ commit_or_rollback ? 6 : 8,
+ TRUE);
qinfo.set_log_pos(this);
if (qinfo.write(&log_file) || flush_io_cache(&log_file))
goto err;
@@ -1642,6 +1666,9 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
SYNOPSIS
wait_for_update()
thd Thread variable
+ master_or_slave If 0, the caller is the Binlog_dump thread from master;
+ if 1, the caller is the SQL thread from the slave. This
+ influences only thd->proc_info.
NOTES
One must have a lock on LOCK_log before calling this function.
@@ -1653,11 +1680,15 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
If you don't do it this way, you will get a deadlock in THD::awake()
*/
-void MYSQL_LOG:: wait_for_update(THD* thd)
+void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave)
{
safe_mutex_assert_owner(&LOCK_log);
const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log,
- "Slave: waiting for binlog update");
+ master_or_slave ?
+ "Has read all relay log; waiting for \
+the I/O slave thread to update it" :
+ "Has sent all binlog to slave; \
+waiting for binlog to be updated");
pthread_cond_wait(&update_cond, &LOCK_log);
pthread_mutex_unlock(&LOCK_log); // See NOTES
thd->exit_cond(old_msg);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8a52ad9ebca..48c2000d11b 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -27,25 +27,6 @@
#define log_cs &my_charset_latin1
/*
- my_b_safe_write()
-*/
-
-inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
- int len)
-{
- /*
- Sasha: We are not writing this with the ? operator to avoid hitting
- a possible compiler bug. At least gcc 2.95 cannot deal with
- several layers of ternary operators that evaluated comma(,) operator
- expressions inside - I do have a test case if somebody wants it
- */
- if (file->type == SEQ_READ_APPEND)
- return my_b_append(file, buf,len);
- return my_b_write(file, buf,len);
-}
-
-
-/*
pretty_print_str()
*/
@@ -239,12 +220,11 @@ const char* Log_event::get_type_str()
#ifndef MYSQL_CLIENT
Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
- :temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg),
- thd(thd_arg)
+ :log_pos(0), temp_buf(0), exec_time(0), cached_event_len(0),
+ flags(flags_arg), thd(thd_arg)
{
server_id= thd->server_id;
when= thd->start_time;
- log_pos= thd->log_pos;
cache_stmt= (using_trans &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
}
@@ -331,7 +311,6 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
handler and MyISAM and STOP SLAVE is issued in the middle of the
"transaction". START SLAVE will resume at BEGIN while the MyISAM table
has already been updated.
-
*/
if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
rli->inc_event_relay_log_pos(get_event_len());
@@ -605,6 +584,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;
@@ -932,6 +913,18 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
mysql_parse(thd, thd->query, q_len);
/*
+ Set a flag if we are inside an transaction so that we can restart
+ the transaction from the start if we are killed
+
+ This will only be done if we are supporting transactional tables
+ in the slave.
+ */
+ if (!strcmp(thd->query,"BEGIN"))
+ rli->inside_transaction= opt_using_transactions;
+ else if (!(strcmp(thd->query,"COMMIT") && strcmp(thd->query,"ROLLBACK")))
+ rli->inside_transaction=0;
+
+ /*
If we expected a non-zero error code, and we don't get the same error
code, and none of them should be ignored.
*/
@@ -988,14 +981,14 @@ Default database: '%s'",
*/
} /* End of if (db_ok(... */
-end:
-
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->db= 0; // prevent db from being freed
thd->query= 0; // just to be sure
VOID(pthread_mutex_unlock(&LOCK_thread_count));
// assume no convert for next query unless set explictly
- //thd->variables.convert_set = 0;
+#ifdef TO_BE_REMOVED
+ thd->variables.convert_set = 0;
+#endif
close_thread_tables(thd);
free_root(&thd->mem_root,0);
return (thd->query_error ? thd->query_error : Log_event::exec_event(rli));
@@ -1091,15 +1084,6 @@ int Start_log_event::write_data(IO_CACHE* file)
the use of a bit of memory for a user lock which will not be used
anymore. If the user lock is later used, the old one will be released. In
other words, no deadlock problem.
- - If we have an active transaction at this point, the master died
- in the middle while writing the transaction to the binary log.
- In this case we should stop the slave.
- Guilhem 2003-06: I don't think we should. As the binlog is written before
- the table changes are committed, rollback has occured on the master; we
- should rather rollback on the slave and go on. If we don't rollback, and
- the next query is not BEGIN, then it will be considered as part of the
- unfinished transaction, and so will be rolled back at next BEGIN, which
- is a bug.
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
@@ -1471,6 +1455,13 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
#ifdef MYSQL_CLIENT
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
{
+ print(file, short_form, last_db, 0);
+}
+
+
+void Load_log_event::print(FILE* file, bool short_form, char* last_db,
+ bool commented)
+{
if (!short_form)
{
print_header(file);
@@ -1486,9 +1477,12 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
}
if (db && db[0] && !same_db)
- fprintf(file, "use %s;\n", db);
+ fprintf(file, "%suse %s;\n",
+ commented ? "# " : "",
+ db);
- fprintf(file, "LOAD DATA ");
+ fprintf(file, "%sLOAD DATA ",
+ commented ? "# " : "");
if (check_fname_outside_temp_buf())
fprintf(file, "LOCAL ");
fprintf(file, "INFILE '%-*s' ", fname_len, fname);
@@ -1535,8 +1529,8 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len);
}
- if ((int)skip_lines > 0)
- fprintf(file, " IGNORE %ld LINES ", (long) skip_lines);
+ if ((long) skip_lines > 0)
+ fprintf(file, " IGNORE %ld LINES", (long) skip_lines);
if (num_fields)
{
@@ -1613,6 +1607,18 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
thd->query = 0; // Should not be needed
thd->query_error = 0;
+ /*
+ We test replicate_*_db rules. Note that we have already prepared the file
+ to load, even if we are going to ignore and delete it now. So it is
+ possible that we did a lot of disk writes for nothing. In other words, a
+ big LOAD DATA INFILE on the master will still consume a lot of space on
+ the slave (space in the relay log + space of temp files: twice the space
+ of the file to load...) even if it will finally be ignored.
+ TODO: fix this; this can be done by testing rules in
+ Create_file_log_event::exec_event() and then discarding Append_block and
+ al. Another way is do the filtering in the I/O thread (more efficient: no
+ disk writes at all).
+ */
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->set_time((time_t)when);
@@ -1642,20 +1648,22 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
else if (sql_ex.opt_flags & IGNORE_FLAG)
handle_dup= DUP_IGNORE;
else
+ {
/*
- Note that when replication is running fine, if it was DUP_ERROR on the
+ When replication is running fine, if it was DUP_ERROR on the
master then we could choose DUP_IGNORE here, because if DUP_ERROR
suceeded on master, and data is identical on the master and slave,
then there should be no uniqueness errors on slave, so DUP_IGNORE is
the same as DUP_ERROR. But in the unlikely case of uniqueness errors
- (because the data on the master and slave happen to be different (user
- error or bug), we want LOAD DATA to print an error message on the
- slave to discover the problem.
+ (because the data on the master and slave happen to be different
+ (user error or bug), we want LOAD DATA to print an error message on
+ the slave to discover the problem.
If reading from net (a 3.23 master), mysql_load() will change this
to DUP_IGNORE.
*/
handle_dup= DUP_ERROR;
+ }
sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
@@ -1731,7 +1739,7 @@ Slave: load data infile on table '%s' at log position %s in log \
err=ER(sql_errno);
}
slave_print_error(rli,sql_errno,"\
-Error '%s' running lOAD DATA INFILE on table '%s'. Default database: '%s'",
+Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
err, (char*)table_name, print_slave_db_safe(db));
free_root(&thd->mem_root,0);
return 1;
@@ -1762,14 +1770,13 @@ Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'",
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void Rotate_log_event::pack_info(Protocol *protocol)
{
- char *buf, *b_pos;
- if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME))))
- return;
- memcpy(buf, new_log_ident, ident_len);
- b_pos= strmov(buf + ident_len, ";pos=");
- b_pos= longlong10_to_str(pos, b_pos, 10);
- protocol->store(buf, (uint) (b_pos-buf), &my_charset_bin);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ char buf1[256], buf[22];
+ String tmp(buf1, sizeof(buf1));
+ tmp.length(0);
+ tmp.append(new_log_ident, ident_len);
+ tmp.append(";pos=");
+ tmp.append(llstr(pos,buf));
+ protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
}
#endif
@@ -1858,6 +1865,25 @@ int Rotate_log_event::write_data(IO_CACHE* file)
We can't rotate the slave as this will cause infinitive rotations
in a A -> B -> A setup.
+ NOTES
+ As a transaction NEVER spans on 2 or more binlogs:
+ if we have an active transaction at this point, the master died while
+ writing the transaction to the binary log, i.e. while flushing the binlog
+ cache to the binlog. As the write was started, the transaction had been
+ committed on the master, so we lack of information to replay this
+ transaction on the slave; all we can do is stop with error.
+ If we didn't detect it, then positions would start to become garbage (as we
+ are incrementing rli->relay_log_pos whereas we are in a transaction: the
+ new rli->relay_log_pos will be
+ relay_log_pos of the BEGIN + size of the Rotate event = garbage.
+
+ Since MySQL 4.0.14, the master ALWAYS sends a Rotate event when it starts
+ sending the next binlog, so we are sure to receive a Rotate event just
+ after the end of the "dead master"'s binlog; so this exec_event() is the
+ right place to catch the problem. If we would wait until
+ Start_log_event::exec_event() it would be too late, rli->relay_log_pos
+ would already be garbage.
+
RETURN VALUES
0 ok
*/
@@ -1869,6 +1895,18 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
DBUG_ENTER("Rotate_log_event::exec_event");
pthread_mutex_lock(&rli->data_lock);
+
+ if (rli->inside_transaction)
+ {
+ slave_print_error(rli, 0,
+ "there is an unfinished transaction in the relay log \
+(could find neither COMMIT nor ROLLBACK in the relay log); it could be that \
+the master died while writing the transaction to its binary log. Now the slave \
+is rolling back the transaction.");
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_RETURN(1);
+ }
+
memcpy(log_name, new_log_ident, ident_len+1);
rli->group_master_log_pos = pos;
rli->event_relay_log_pos += get_event_len();
@@ -1894,8 +1932,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void Intvar_log_event::pack_info(Protocol *protocol)
{
- char buf[64], *pos;
- pos= strmov(buf, get_var_type_name());
+ char buf[256], *pos;
+ pos= strmake(buf, get_var_type_name(), sizeof(buf)-23);
*pos++= '=';
pos= longlong10_to_str(val, pos, -10);
protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
@@ -2462,8 +2500,8 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
Stop_log_event::exec_event()
The master stopped.
- We used to clean up all temporary tables but this is useless as, as the master
- has shut down properly, it has written all DROP TEMPORARY TABLE and DO
+ We used to clean up all temporary tables but this is useless as, as the
+ master has shut down properly, it has written all DROP TEMPORARY TABLE and DO
RELEASE_LOCK (prepared statements' deletion is TODO).
We used to clean up slave_load_tmpdir, but this is useless as it has been
cleared at the end of LOAD DATA INFILE.
@@ -2605,10 +2643,12 @@ void Create_file_log_event::print(FILE* file, bool short_form,
if (enable_local)
{
- if (!check_fname_outside_temp_buf())
- fprintf(file, "#");
- Load_log_event::print(file, 1, last_db);
- fprintf(file, "#");
+ Load_log_event::print(file, 1, last_db, !check_fname_outside_temp_buf());
+ /*
+ That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
+ SHOW BINLOG EVENTS we don't.
+ */
+ fprintf(file, "#");
}
fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len);
@@ -2641,7 +2681,7 @@ void Create_file_log_event::pack_info(Protocol *protocol)
pos= int10_to_str((long) block_len, pos, 10);
protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/*
@@ -2665,7 +2705,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
goto err;
}
@@ -2676,7 +2716,9 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
if (write_base(&file))
{
strmov(p, ".info"); // to have it right in the error message
- slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
+ slave_print_error(rli,my_errno,
+ "Error in Create_file event: could not write to file '%s'",
+ fname_buf);
goto err;
}
end_io_cache(&file);
@@ -2686,16 +2728,14 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
MYF(MY_WME))) < 0)
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
goto err;
}
if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
{
- slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
+ slave_print_error(rli,my_errno, "Error in Create_file event: write to '%s' failed", fname_buf);
goto err;
}
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
error=0; // Everything is ok
err:
@@ -2705,7 +2745,7 @@ err:
my_close(fd, MYF(0));
return error ? 1 : Log_event::exec_event(rli);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/**************************************************************************
@@ -2717,11 +2757,12 @@ err:
*/
#ifndef MYSQL_CLIENT
-Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
+Append_block_log_event::Append_block_log_event(THD* thd_arg, const char* db_arg,
+ char* block_arg,
uint block_len_arg,
bool using_trans)
:Log_event(thd_arg,0, using_trans), block(block_arg),
- block_len(block_len_arg), file_id(thd_arg->file_id)
+ block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg)
{
}
#endif
@@ -2787,7 +2828,7 @@ void Append_block_log_event::pack_info(Protocol *protocol)
block_len));
protocol->store(buf, length, &my_charset_bin);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/*
@@ -2805,16 +2846,14 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
memcpy(p, ".data", 6);
if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ slave_print_error(rli,my_errno, "Error in Append_block event: could not open file '%s'", fname);
goto err;
}
if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
{
- slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
+ slave_print_error(rli,my_errno, "Error in Append_block event: write to '%s' failed", fname);
goto err;
}
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
error=0;
err:
@@ -2834,8 +2873,9 @@ err:
*/
#ifndef MYSQL_CLIENT
-Delete_file_log_event::Delete_file_log_event(THD *thd_arg, bool using_trans)
- :Log_event(thd_arg, 0, using_trans),file_id(thd_arg->file_id)
+Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
{
}
#endif
@@ -2908,11 +2948,9 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
(void) my_delete(fname, MYF(MY_WME));
memcpy(p, ".info", 6);
(void) my_delete(fname, MYF(MY_WME));
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
return Log_event::exec_event(rli);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/**************************************************************************
@@ -2924,8 +2962,9 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
*/
#ifndef MYSQL_CLIENT
-Execute_load_log_event::Execute_load_log_event(THD *thd_arg, bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
+Execute_load_log_event::Execute_load_log_event(THD *thd_arg, const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
{
}
#endif
@@ -2997,7 +3036,6 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
char *p= slave_load_file_stem(fname, file_id, server_id);
int fd;
int error = 1;
- ulong save_options;
IO_CACHE file;
Load_log_event* lev = 0;
@@ -3006,7 +3044,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ slave_print_error(rli,my_errno, "Error in Exec_load event: could not open file '%s'", fname);
goto err;
}
if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
@@ -3014,21 +3052,16 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
(bool)0)) ||
lev->get_type_code() != NEW_LOAD_EVENT)
{
- slave_print_error(rli,0, "File '%s' appears corrupted", fname);
+ slave_print_error(rli,0, "Error in Exec_load event: file '%s' appears corrupted", fname);
goto err;
}
- /*
- We are going to create a Load_log_event to finally load into the table.
- This event should not go into the binlog: in the binlog we only want the
- Create_file, Append_blocks and Execute_load. We disable binary logging and
- restore the thread's options just after finishing the load.
- */
- save_options = thd->options;
- thd->options &= ~ (ulong) (OPTION_BIN_LOG);
+
lev->thd = thd;
/*
lev->exec_event should use rli only for errors
- i.e. should not advance rli's position
+ i.e. should not advance rli's position.
+ lev->exec_event is the place where the table is loaded (it calls
+ mysql_load()).
*/
if (lev->exec_event(0,rli,1))
{
@@ -3049,15 +3082,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
tmp, fname);
my_free(tmp,MYF(0));
}
- thd->options= save_options;
goto err;
}
- thd->options = save_options;
(void) my_delete(fname, MYF(MY_WME));
memcpy(p, ".data", 6);
(void) my_delete(fname, MYF(MY_WME));
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
error = 0;
err:
diff --git a/sql/log_event.h b/sql/log_event.h
index a58479e2589..8ba5d0379a0 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -590,6 +590,7 @@ public:
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form, char* last_db, bool commented);
#endif
Load_log_event(const char* buf, int event_len, bool old_format);
@@ -934,9 +935,20 @@ public:
char* block;
uint block_len;
uint file_id;
-
+ /*
+ 'db' is filled when the event is created in mysql_load() (the event needs to
+ have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not
+ written to the binlog (it's not used by Append_block_log_event::write()), so
+ it can't be read in the Append_block_log_event(const char* buf, int
+ event_len) constructor.
+ In other words, 'db' is used only for filtering by binlog-*-db rules.
+ Create_file_log_event is different: its 'db' (which is inherited from
+ Load_log_event) is written to the binlog and can be re-read.
+ */
+ const char* db;
+
#ifndef MYSQL_CLIENT
- Append_block_log_event(THD* thd, char* block_arg,
+ Append_block_log_event(THD* thd, const char* db_arg, char* block_arg,
uint block_len_arg, bool using_trans);
#ifdef HAVE_REPLICATION
int exec_event(struct st_relay_log_info* rli);
@@ -952,6 +964,7 @@ public:
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
bool is_valid() { return block != 0; }
int write_data(IO_CACHE* file);
+ const char* get_db() { return db; }
};
/*****************************************************************************
@@ -963,9 +976,10 @@ class Delete_file_log_event: public Log_event
{
public:
uint file_id;
+ const char* db; /* see comment in Append_block_log_event */
#ifndef MYSQL_CLIENT
- Delete_file_log_event(THD* thd, bool using_trans);
+ Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
@@ -981,6 +995,7 @@ public:
int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
bool is_valid() { return file_id != 0; }
int write_data(IO_CACHE* file);
+ const char* get_db() { return db; }
};
/*****************************************************************************
@@ -992,9 +1007,10 @@ class Execute_load_log_event: public Log_event
{
public:
uint file_id;
-
+ const char* db; /* see comment in Append_block_log_event */
+
#ifndef MYSQL_CLIENT
- Execute_load_log_event(THD* thd, bool using_trans);
+ Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
@@ -1009,6 +1025,7 @@ public:
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
bool is_valid() { return file_id != 0; }
int write_data(IO_CACHE* file);
+ const char* get_db() { return db; }
};
#ifdef MYSQL_CLIENT
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a5d9ce5bce3..269846db446 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -212,16 +212,17 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_NOT_USED 16
#define MODE_ONLY_FULL_GROUP_BY 32
#define MODE_NO_UNSIGNED_SUBTRACTION 64
-#define MODE_POSTGRESQL 128
-#define MODE_ORACLE 256
-#define MODE_MSSQL 512
-#define MODE_DB2 1024
-#define MODE_SAPDB 2048
-#define MODE_NO_KEY_OPTIONS 4096
-#define MODE_NO_TABLE_OPTIONS 8192
-#define MODE_NO_FIELD_OPTIONS 16384
-#define MODE_MYSQL323 32768
-#define MODE_MYSQL40 65536
+#define MODE_NO_DIR_IN_CREATE 128
+#define MODE_POSTGRESQL 256
+#define MODE_ORACLE 512
+#define MODE_MSSQL 1024
+#define MODE_DB2 2048
+#define MODE_SAPDB 4096
+#define MODE_NO_KEY_OPTIONS 8192
+#define MODE_NO_TABLE_OPTIONS 16384
+#define MODE_NO_FIELD_OPTIONS 32768
+#define MODE_MYSQL323 65536
+#define MODE_MYSQL40 (MODE_MYSQL323*2)
#define MODE_ANSI (MODE_MYSQL40*2)
#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
@@ -558,7 +559,8 @@ void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
int mysqld_show_variables(THD *thd,const char *wild);
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
- enum enum_var_type value_type);
+ enum enum_var_type value_type,
+ pthread_mutex_t *mutex);
int mysqld_show_charsets(THD *thd,const char *wild);
int mysqld_show_collations(THD *thd,const char *wild);
int mysqld_show_table_types(THD *thd);
@@ -746,6 +748,7 @@ extern ulong ha_read_first_count, ha_read_last_count;
extern ulong ha_read_rnd_count, ha_read_rnd_next_count;
extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
+extern ulong slave_net_timeout;
extern ulong max_insert_delayed_threads, max_user_connections;
extern ulong long_query_count, what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
@@ -963,6 +966,12 @@ inline void mark_as_null_row(TABLE *table)
bfill(table->null_flags,table->null_bytes,255);
}
+inline void table_case_convert(char * name, uint length)
+{
+ if (lower_case_table_names)
+ my_casedn(files_charset_info, name, length);
+}
+
compare_func_creator comp_eq_creator(bool invert);
compare_func_creator comp_ge_creator(bool invert);
compare_func_creator comp_gt_creator(bool invert);
@@ -979,6 +988,7 @@ compare_func_creator comp_ne_creator(bool invert);
table_list TABLE_LIST structure pointer (owner of TABLE)
tablenr - table number
*/
+
inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
{
table->used_fields= 0;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 41bd9706fc3..d6b1426ed35 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -210,6 +210,7 @@ const char *sql_mode_names[] =
{
"REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
"?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
+ "NO_DIR_IN_CREATE",
"POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS",
"NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
"NO_AUTO_VALUE_ON_ZERO", NullS
@@ -1119,7 +1120,14 @@ static void server_init(void)
IPaddr.sin_family = AF_INET;
IPaddr.sin_addr.s_addr = my_bind_addr;
IPaddr.sin_port = (unsigned short) htons((unsigned short) mysqld_port);
+
+#ifndef __WIN__
+ /*
+ We should not use SO_REUSEADDR on windows as this would enable a
+ user to open two mysqld servers with the same TCP/IP port.
+ */
(void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
+#endif /* __WIN__ */
if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
sizeof(IPaddr)) < 0)
{
@@ -2050,7 +2058,10 @@ static int init_common_variables(const char *conf_file_name, int argc,
max_connections,table_cache_size));
sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size);
}
+ open_files_limit= files;
}
+#else
+ open_files_limit= 0; /* Can't set or detect limit */
#endif
unireg_init(opt_specialflag); /* Set up extern variabels */
init_errmessage(); /* Read error messages from file */
@@ -3104,6 +3115,12 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
}
if (sock == unix_sock)
thd->host=(char*) localhost;
+#ifdef __WIN__
+ /* Set default wait_timeout */
+ ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;
+ (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout,
+ sizeof(wait_timeout));
+#endif
create_new_thread(thd);
}
@@ -4196,7 +4213,7 @@ replicating a LOAD DATA INFILE command.",
"Max packetlength to send/receive from to server.",
(gptr*) &global_system_variables.max_allowed_packet,
(gptr*) &max_system_variables.max_allowed_packet, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L, 80, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
+ REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
{"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
"Can be used to restrict the total size used to cache a multi-transaction query.",
(gptr*) &max_binlog_cache_size, (gptr*) &max_binlog_cache_size, 0,
@@ -5563,6 +5580,19 @@ static void fix_paths(void)
}
+/*
+ set how many open files we want to be able to handle
+
+ SYNOPSIS
+ set_maximum_open_files()
+ max_file_limit Files to open
+
+ NOTES
+ The request may not fulfilled becasue of system limitations
+
+ RETURN
+ Files available to open
+*/
#ifdef SET_RLIMIT_NOFILE
static uint set_maximum_open_files(uint max_file_limit)
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index f12705572d6..d39fca595ac 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -240,10 +240,12 @@ my_bool net_flush(NET *net)
*****************************************************************************/
/*
-** Write a logical packet with packet header
-** Format: Packet length (3 bytes), packet number(1 byte)
-** When compression is used a 3 byte compression length is added
-** NOTE: If compression is used the original package is modified!
+ Write a logical packet with packet header
+ Format: Packet length (3 bytes), packet number(1 byte)
+ When compression is used a 3 byte compression length is added
+
+ NOTE
+ If compression is used the original package is modified!
*/
my_bool
@@ -364,8 +366,8 @@ net_write_command(NET *net,uchar command,
The cached buffer can be sent as it is with 'net_flush()'.
In this code we have to be careful to not send a packet longer than
- MAX_PACKET_LENGTH to net_real_write() if we are using the compressed protocol
- as we store the length of the compressed packet in 3 bytes.
+ MAX_PACKET_LENGTH to net_real_write() if we are using the compressed
+ protocol as we store the length of the compressed packet in 3 bytes.
RETURN
0 ok
@@ -483,6 +485,7 @@ net_real_write(NET *net,const char *packet,ulong len)
thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff);
#else
alarmed=0;
+ vio_timeout(net->vio, net->write_timeout);
#endif /* NO_ALARM */
pos=(char*) packet; end=pos+len;
@@ -674,6 +677,8 @@ my_real_read(NET *net, ulong *complen)
#ifndef NO_ALARM
if (net_blocking)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
+#else
+ vio_timeout(net->vio, net->read_timeout);
#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
@@ -877,20 +882,23 @@ my_net_read(NET *net)
{
/* We are using the compressed protocol */
- ulong buf_length= net->buf_length;
- ulong start_of_packet= net->buf_length - net->remain_in_buf;
- ulong first_packet_offset=start_of_packet;
+ ulong buf_length;
+ ulong start_of_packet;
+ ulong first_packet_offset;
uint read_length, multi_byte_packet=0;
if (net->remain_in_buf)
{
+ buf_length= net->buf_length; // Data left in old packet
+ first_packet_offset= start_of_packet= (net->buf_length -
+ net->remain_in_buf);
/* Restore the character that was overwritten by the end 0 */
- net->buff[start_of_packet]=net->save_char;
+ net->buff[start_of_packet]= net->save_char;
}
else
{
/* reuse buffer, as there is nothing in it that we need */
- buf_length=start_of_packet=first_packet_offset=0;
+ buf_length= start_of_packet= first_packet_offset= 0;
}
for (;;)
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 23fb36c0c91..947c930b2f4 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -341,8 +341,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
DBUG_RETURN(0);
if (!(select= new SQL_SELECT))
{
- *error= 1;
- DBUG_RETURN(0); /* purecov: inspected */
+ *error= 1; // out of memory
+ DBUG_RETURN(0); /* purecov: inspected */
}
select->read_tables=read_tables;
select->const_tables=const_tables;
@@ -456,15 +456,17 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
SEL_ARG *tmp;
if (type != KEY_RANGE)
{
- tmp=new SEL_ARG(type);
+ if(!(tmp=new SEL_ARG(type)))
+ return 0; // out of memory
tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp;
(*next_arg)= tmp;
}
else
{
- tmp=new SEL_ARG(field,part, min_value,max_value,
- min_flag, max_flag, maybe_flag);
+ if(!(tmp=new SEL_ARG(field,part, min_value,max_value,
+ min_flag, max_flag, maybe_flag)))
+ return 0; // out of memory
tmp->parent=new_parent;
tmp->next_key_part=next_key_part;
if (left != &null_element)
@@ -762,6 +764,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
while ((item=li++))
{
SEL_TREE *new_tree=get_mm_tree(param,item);
+ if(current_thd->fatal_error)
+ DBUG_RETURN(0); // out of memory
tree=tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
break;
@@ -777,7 +781,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
SEL_TREE *new_tree=get_mm_tree(param,item);
if (!new_tree)
- DBUG_RETURN(0);
+ DBUG_RETURN(0); // out of memory
tree=tree_or(param,tree,new_tree);
if (!tree || tree->type == SEL_TREE::ALWAYS)
break;
@@ -793,18 +797,16 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
DBUG_RETURN(new SEL_TREE(SEL_TREE::ALWAYS));
DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE));
}
+
table_map ref_tables=cond->used_tables();
- if (ref_tables & ~(param->prev_tables | param->read_tables |
- param->current_table))
- DBUG_RETURN(0); // Can't be calculated yet
if (cond->type() != Item::FUNC_ITEM)
{ // Should be a field
- if (ref_tables & param->current_table)
+ if ((ref_tables & param->current_table) ||
+ (ref_tables & ~(param->prev_tables | param->read_tables)))
DBUG_RETURN(0);
DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
}
- if (!(ref_tables & param->current_table))
- DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
+
Item_func *cond_func= (Item_func*) cond;
if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0); // Can't be calculated
@@ -815,12 +817,13 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
Item_result cmp_type=field->cmp_type();
- tree= get_mm_parts(param,field,Item_func::GE_FUNC,
- cond_func->arguments()[1],cmp_type);
- DBUG_RETURN(tree_and(param,tree,
+ DBUG_RETURN(tree_and(param,
+ get_mm_parts(param, field,
+ Item_func::GE_FUNC,
+ cond_func->arguments()[1], cmp_type),
get_mm_parts(param, field,
Item_func::LE_FUNC,
- cond_func->arguments()[2],cmp_type)));
+ cond_func->arguments()[2], cmp_type)));
}
DBUG_RETURN(0);
}
@@ -846,6 +849,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
DBUG_RETURN(0); // Can't optimize this IN
}
+ if (ref_tables & ~(param->prev_tables | param->read_tables |
+ param->current_table))
+ DBUG_RETURN(0); // Can't be calculated yet
+ if (!(ref_tables & param->current_table))
+ DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
+
/* check field op const */
/* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
@@ -877,14 +886,15 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
static SEL_TREE *
-get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
- Item_result cmp_type)
+get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
+ Item *value, Item_result cmp_type)
{
DBUG_ENTER("get_mm_parts");
if (field->table != param->table)
DBUG_RETURN(0);
- KEY_PART *key_part = param->key_parts,*end=param->key_parts_end;
+ KEY_PART *key_part = param->key_parts;
+ KEY_PART *end = param->key_parts_end;
SEL_TREE *tree=0;
if (value &&
value->used_tables() & ~(param->prev_tables | param->read_tables))
@@ -894,8 +904,8 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
if (field->eq(key_part->field))
{
SEL_ARG *sel_arg=0;
- if (!tree)
- tree=new SEL_TREE();
+ if (!tree && !(tree=new SEL_TREE()))
+ DBUG_RETURN(0); // out of memory
if (!value || !(value->used_tables() & ~param->read_tables))
{
sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value);
@@ -907,8 +917,11 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
DBUG_RETURN(tree);
}
}
- else
- sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY);// This key may be used later
+ else {
+ // This key may be used later
+ if(!(sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY)))
+ DBUG_RETURN(0); // out of memory
+ }
sel_arg->part=(uchar) key_part->part;
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
}
@@ -995,9 +1008,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(0);
if (!maybe_null) // Not null field
DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
- tree=new SEL_ARG(field,is_null_string,is_null_string);
- if (!tree)
- DBUG_RETURN(0);
+ if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
+ DBUG_RETURN(0); // out of memory
if (type == Item_func::ISNOTNULL_FUNC)
{
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
@@ -1035,7 +1047,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
field->get_key_image(str+maybe_null,key_part->part_length,
field->charset(),key_part->image_type);
if (!(tree=new SEL_ARG(field,str,str)))
- DBUG_RETURN(0);
+ DBUG_RETURN(0); // out of memory
switch (type) {
case Item_func::LT_FUNC:
@@ -1475,7 +1487,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
SEL_ARG *key2_next=key2->next;
if (key2_shared)
{
- key2=new SEL_ARG(*key2);
+ if(!(key2=new SEL_ARG(*key2)))
+ return 0; // out of memory
key2->increment_use_count(key1->use_count+1);
key2->next=key2_next; // New copy of key2
}
@@ -2319,16 +2332,16 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
}
/* Get range for retrieving rows in QUICK_SELECT::get_next */
- range= new QUICK_RANGE(param->min_key,
- (uint) (tmp_min_key - param->min_key),
- param->max_key,
- (uint) (tmp_max_key - param->max_key),
- flag);
+ if(!(range= new QUICK_RANGE(param->min_key,
+ (uint) (tmp_min_key - param->min_key),
+ param->max_key,
+ (uint) (tmp_max_key - param->max_key),
+ flag)))
+ return 1; // out of memory
+
set_if_bigger(quick->max_used_key_length,range->min_length);
set_if_bigger(quick->max_used_key_length,range->max_length);
set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1);
- if (!range) // Not enough memory
- return 1;
quick->ranges.push_back(range);
end:
@@ -2389,17 +2402,17 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
uint part;
if (!quick)
- return 0;
+ return 0; /* no ranges found */
if (cp_buffer_from_ref(ref))
{
if (current_thd->is_fatal_error)
- return 0; // End of memory
+ return 0; // out of memory
return quick; // empty range
}
QUICK_RANGE *range= new QUICK_RANGE();
if (!range)
- goto err;
+ goto err; // out of memory
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index e9c3b1ed0b0..402a37efc37 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -250,6 +250,18 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
/* Impossible */
}
+/*
+ Before 4.0.15 we had a member of THD called log_pos, it was meant for
+ failsafe replication code in repl_failsafe.cc which is disabled until
+ it is reworked. Event's log_pos used to be preserved through
+ log-slave-updates to make code in repl_failsafe.cc work (this
+ function, SHOW NEW MASTER); but on the other side it caused unexpected
+ values in Exec_master_log_pos in A->B->C replication setup,
+ synchronization problems in master_pos_wait(), ... So we
+ (Dmitri & Guilhem) removed it.
+
+ So for now this function is broken.
+*/
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
{
@@ -415,6 +427,9 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
return (Slave_log_event*)ev;
}
+/*
+ This function is broken now. See comment for translate_master().
+ */
int show_new_master(THD* thd)
{
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 91583759c70..cce9298c4ac 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -615,13 +615,6 @@ struct show_var_st init_vars[]= {
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
{sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
- {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
- {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
- {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
-#ifdef HAVE_REPLICATION
- {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
-#endif
- {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
#ifdef HAVE_QUERY_CACHE
{sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS},
{sys_query_cache_min_res_unit.name, (char*) &sys_query_cache_min_res_unit,
@@ -629,6 +622,13 @@ struct show_var_st init_vars[]= {
{sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS},
{sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS},
#endif /* HAVE_QUERY_CACHE */
+ {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
+ {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
+ {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
+#ifdef HAVE_REPLICATION
+ {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
+#endif
+ {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
#ifdef HAVE_SMEM
{"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL},
{"shared_memory_base_name", (char*) &shared_memory_base_name, SHOW_CHAR_PTR},
@@ -845,10 +845,12 @@ void fix_max_relay_log_size(THD *thd, enum_var_type type)
bool sys_var_long_ptr::update(THD *thd, set_var *var)
{
ulonglong tmp= var->value->val_int();
+ pthread_mutex_lock(&LOCK_global_system_variables);
if (option_limits)
*value= (ulong) getopt_ull_limit_value(tmp, option_limits);
else
*value= (ulong) tmp;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
return 0;
}
@@ -862,17 +864,21 @@ void sys_var_long_ptr::set_default(THD *thd, enum_var_type type)
bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var)
{
ulonglong tmp= var->value->val_int();
+ pthread_mutex_lock(&LOCK_global_system_variables);
if (option_limits)
*value= (ulonglong) getopt_ull_limit_value(tmp, option_limits);
else
*value= (ulonglong) tmp;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
return 0;
}
void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type)
{
+ pthread_mutex_lock(&LOCK_global_system_variables);
*value= (ulonglong) option_limits->def_value;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
}
@@ -1164,9 +1170,21 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
case SHOW_LONG:
return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type, base));
case SHOW_LONGLONG:
- return new Item_int(*(longlong*) value_ptr(thd, var_type, base));
+ {
+ longlong value;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ value= *(longlong*) value_ptr(thd, var_type, base);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return new Item_int(value);
+ }
case SHOW_HA_ROWS:
- return new Item_int((longlong) *(ha_rows*) value_ptr(thd, var_type, base));
+ {
+ ha_rows value;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ value= *(ha_rows*) value_ptr(thd, var_type, base);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return new Item_int((longlong) value);
+ }
case SHOW_MY_BOOL:
return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1);
case SHOW_CHAR:
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 99a940e62ab..b1b607ca6e3 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -219,26 +219,26 @@
"Não pode acrescentar uma restrição de chave estrangeira",
"Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou",
"Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou",
-"Erro connectando para o master: %-.128s",
+"Erro conectando com o master: %-.128s",
"Erro rodando consulta no master: %-.128s",
"Erro quando executando comando %s: %-.128s",
"Uso errado de %s e %s",
-"Os comandos SELECT usados têm diferentes números de colunas",
-"Não pode executar a consulta porque você tem um conflitante travamento de leitura",
-"Combinação de tabelas transacionais e não transacionais está desativada",
+"Os comandos SELECT usados têm diferente número de colunas",
+"Não posso executar a consulta porque você tem um conflito de travamento de leitura",
+"Mistura de tabelas transacional e não-transacional está desabilitada",
"Opção '%s' usada duas vezes no comando",
-"Usuário '%-.64s' há excedido o '%s' de recursos (atual valor: %ld)",
-"Acesso negado. Você necessita o privilégio %-.128s para essa operação",
+"Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)",
+"Acesso negado. Você precisa o privilégio %-.128s para essa operação",
"Variável '%-.64s' é uma LOCAL variável e não pode ser usada com SET GLOBAL",
-"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL",
-"Variável '%-.64s' não tem um valor default (padrão)",
+"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL",
+"Variável '%-.64s' não tem um valor padrão",
"Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'",
-"Tipo de argumento errado para a variável '%-.64s'",
+"Tipo errado de argumento para variável '%-.64s'",
"Variável '%-.64s' somente pode ser configurada, não lida",
-"Uso/localização errada de '%s'",
+"Errado uso/colocação de '%s'",
"Esta versão de MySQL não suporta ainda '%s'",
-"Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
+"Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log",
+"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela"
"Definição errada da chave estrangeira para '%-.64s': %s",
"Referência da chave e referência da tabela não coincidem",
"Error de cardinalidade (mais/menos que %d colunas)",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index df18b8bf7f0..2b3a6a042fc 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -223,23 +223,23 @@
"Error de coneccion a master: %-128s",
"Error executando el query en master: %-128%",
"Error de %s: %-128%",
-"Wrong usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied. You need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Wrong argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Wrong usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
+"Equivocado uso de %s y %s",
+"El comando SELECT usado tiene diferente número de columnas",
+"No puedo ejecutar el query porque usted tiene conflicto de traba de lectura",
+"Mezla de transancional y no-transancional tablas está deshabilitada",
+"Opción '%s' usada dos veces en el comando",
+"Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)",
+"Acceso negado. Usted necesita el privilegio %-.128s para esta operación",
+"Variable '%-.64s' es una LOCAL variable y no puede ser usada con SET GLOBAL",
+"Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL",
+"Variable '%-.64s' no tiene un valor patrón",
+"Variable '%-.64s' no puede ser configurada para el valor de '%-.64s'",
+"Tipo de argumento equivocado para variable '%-.64s'",
+"Variable '%-.64s' solamente puede ser configurada, no leída",
+"Equivocado uso/colocación de '%s'",
+"Esta versión de MySQL no soporta todavia '%s'",
+"Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log",
+"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla"
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
diff --git a/sql/slave.cc b/sql/slave.cc
index d5da8325c93..9e03856e284 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1505,11 +1505,10 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
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";
save_proc_info= thd->enter_cond(&rli->log_space_cond,
&rli->log_space_lock,
- "Waiting for relay log space to free");
+ "\
+Waiting for the SQL slave thread to free enough relay log space");
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
@@ -2058,7 +2057,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
DBUG_PRINT("info",("Waiting for master update"));
const char* msg = thd->enter_cond(&data_cond, &data_lock,
- "Waiting for master update");
+ "Waiting for the SQL slave thread to \
+advance position");
/*
We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
will wake us up.
@@ -2125,7 +2125,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->master_access= ~0;
thd->priv_user = 0;
thd->slave_thread = 1;
- thd->options = (((opt_log_slave_updates) ? OPTION_BIN_LOG:0) | OPTION_AUTO_IS_NULL) ;
+ thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
+ OPTION_AUTO_IS_NULL;
+ /*
+ It's nonsense to constraint the slave threads with max_join_size; if a
+ query succeeded on master, we HAVE to execute it.
+ */
+ thd->variables.max_join_size= HA_POS_ERROR;
thd->client_capabilities = CLIENT_LOCAL_FILES;
thd->real_id=pthread_self();
pthread_mutex_lock(&LOCK_thread_count);
@@ -2145,11 +2151,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
-
if (thd_type == SLAVE_THD_SQL)
- thd->proc_info= "Waiting for the next event in slave queue";
+ thd->proc_info= "Waiting for the next event in relay log";
else
thd->proc_info= "Waiting for master update";
thd->version=refresh_version;
@@ -2390,7 +2393,6 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
if (!ev->when)
ev->when = time(NULL);
ev->thd = thd;
- thd->log_pos = ev->log_pos;
exec_res = ev->exec_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
delete ev;
@@ -2398,7 +2400,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
}
else
{
- sql_print_error("\
+ slave_print_error(rli, 0, "\
Could not parse relay log event entry. The possible reasons are: the master's \
binary log is corrupted (you can check this by running 'mysqlbinlog' on the \
binary log), the slave's relay log is corrupted (you can check this by running \
@@ -2473,7 +2475,7 @@ slave_begin:
}
- thd->proc_info = "connecting to master";
+ thd->proc_info = "Connecting to master";
// we can get killed during safe_connect
if (!safe_connect(thd, mysql, mi))
sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\
@@ -2520,7 +2522,7 @@ dump");
goto err;
}
- thd->proc_info = "Waiting to reconnect after a failed dump request";
+ thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
end_server(mysql);
/*
First time retry immediately, assuming that we can recover
@@ -2541,7 +2543,7 @@ dump");
goto err;
}
- thd->proc_info = "Reconnecting after a failed dump request";
+ thd->proc_info = "Reconnecting after a failed binlog dump request";
if (!suppress_warnings)
sql_print_error("Slave I/O thread: failed dump request, \
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
@@ -2560,7 +2562,13 @@ after reconnect");
while (!io_slave_killed(thd,mi))
{
bool suppress_warnings= 0;
- thd->proc_info = "Reading master update";
+ /*
+ We say "waiting" because read_event() will wait if there's nothing to
+ read. But if there's something to read, it will not wait. The important
+ thing is to not confuse users by saying "reading" whereas we're in fact
+ receiving nothing.
+ */
+ thd->proc_info = "Waiting for master to send event";
ulong event_len = read_event(mysql, mi, &suppress_warnings);
if (io_slave_killed(thd,mi))
{
@@ -2587,7 +2595,7 @@ max_allowed_packet",
mysql_error(mysql));
goto err;
}
- thd->proc_info = "Waiting to reconnect after a failed read";
+ thd->proc_info = "Waiting to reconnect after a failed master event read";
end_server(mysql);
if (retry_count++)
{
@@ -2603,7 +2611,7 @@ max_allowed_packet",
reconnect after a failed read");
goto err;
}
- thd->proc_info = "Reconnecting after a failed read";
+ thd->proc_info = "Reconnecting after a failed master event read";
if (!suppress_warnings)
sql_print_error("Slave I/O thread: Failed reading log event, \
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
@@ -2620,7 +2628,7 @@ reconnect done to recover from failed read");
} // if (event_len == packet_error)
retry_count=0; // ok event, reset retry counter
- thd->proc_info = "Queueing event from master";
+ thd->proc_info = "Queueing master event to the relay log";
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
event_len))
{
@@ -2802,7 +2810,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
while (!sql_slave_killed(thd,rli))
{
- thd->proc_info = "Processing master log event";
+ thd->proc_info = "Reading event from the relay log";
DBUG_ASSERT(rli->sql_thd == thd);
THD_CHECK_SENTRY(thd);
if (exec_relay_log_event(thd,rli))
@@ -2834,6 +2842,12 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
/* When master_pos_wait() wakes up it will check this and terminate */
rli->slave_running= 0;
+ /*
+ Going out of the transaction. Necessary to mark it, in case the user
+ restarts replication from a non-transactional statement (with CHANGE
+ MASTER).
+ */
+ rli->inside_transaction= 0;
/* Wake up master_pos_wait() */
pthread_mutex_unlock(&rli->data_lock);
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
@@ -2909,7 +2923,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
in the loop
*/
{
- Append_block_log_event aev(thd,0,0,0);
+ Append_block_log_event aev(thd,0,0,0,0);
for (;;)
{
@@ -2922,7 +2936,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
if (unlikely(!num_bytes)) /* eof */
{
net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
- Execute_load_log_event xev(thd,0);
+ Execute_load_log_event xev(thd,0,0);
xev.log_pos = mi->master_log_pos;
if (unlikely(mi->rli.relay_log.append(&xev)))
{
@@ -3049,6 +3063,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer
buf = (const char*)tmp_buf;
}
+ /*
+ This will transform LOAD_EVENT into CREATE_FILE_EVENT, ask the master to
+ send the loaded file, and write it to the relay log in the form of
+ Append_block/Exec_load (the SQL thread needs the data, as that thread is not
+ connected to the master).
+ */
Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
1 /*old format*/ );
if (unlikely(!ev))
@@ -3076,6 +3096,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
inc_pos= 0;
break;
case CREATE_FILE_EVENT:
+ /*
+ Yes it's possible to have CREATE_FILE_EVENT here, even if we're in
+ queue_old_event() which is for 3.23 events which don't comprise
+ CREATE_FILE_EVENT. This is because read_log_event() above has just
+ transformed LOAD_EVENT into CREATE_FILE_EVENT.
+ */
{
/* We come here when and only when tmp_buf != 0 */
DBUG_ASSERT(tmp_buf);
@@ -3575,7 +3601,7 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
// Note that wait_for_update unlocks lock_log !
- rli->relay_log.wait_for_update(rli->sql_thd);
+ rli->relay_log.wait_for_update(rli->sql_thd, 1);
// re-acquire data lock since we released it earlier
pthread_mutex_lock(&rli->data_lock);
continue;
diff --git a/sql/slave.h b/sql/slave.h
index 0cd291a50f8..3afa1723cf1 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -32,6 +32,30 @@
*****************************************************************************/
+/*
+ MUTEXES in replication:
+
+ LOCK_active_mi: this is meant for multimaster, when we can switch from a
+ master to another. It protects active_mi. We don't care of it for the moment,
+ as active_mi never moves (it's created at startup and deleted at shutdown,
+ and not changed: it always points to the same MASTER_INFO struct), because we
+ don't have multimaster. So for the moment, mi does not move, and mi->rli does
+ not either.
+
+ In MASTER_INFO: run_lock, data_lock
+ run_lock protects all information about the run state: slave_running, and the
+ existence of the I/O thread (to stop/start it, you need this mutex).
+ data_lock protects some moving members of the struct: counters (log name,
+ position) and relay log (MYSQL_LOG object).
+
+ In RELAY_LOG_INFO: run_lock, data_lock
+ see MASTER_INFO
+
+ In MYSQL_LOG: LOCK_log, LOCK_index of the binlog and the relay log
+ LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog
+ (so that you have to update the .index file).
+*/
+
extern ulong master_retry_count;
extern MY_BITMAP slave_error_mask;
extern bool use_slave_mask;
@@ -43,10 +67,6 @@ extern my_bool opt_log_slave_updates;
extern ulonglong relay_log_space_limit;
struct st_master_info;
-extern "C" {
- extern ulong slave_net_timeout;
-};
-
enum enum_binlog_formats {
BINLOG_FORMAT_CURRENT=0, /* 0 is important for easy 'if (mi->old_format)' */
BINLOG_FORMAT_323_LESS_57,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 9738c0c5d9e..904080f3745 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -599,6 +599,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
{
Vio *vio=thd->net.vio;
+#ifdef HAVE_OPENSSL
+ SSL *ssl= (SSL*) vio->ssl_arg;
+#endif
/*
At this point we know that user is allowed to connect
from given host by given username/password pair. Now
@@ -624,8 +627,8 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
we should reject connection.
*/
if (vio_type(vio) == VIO_TYPE_SSL &&
- SSL_get_verify_result(vio->ssl_) == X509_V_OK &&
- SSL_get_peer_certificate(vio->ssl_))
+ SSL_get_verify_result(ssl) == X509_V_OK &&
+ SSL_get_peer_certificate(ssl))
user_access=acl_user->access;
break;
case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
@@ -636,27 +639,27 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
use.
*/
if (vio_type(vio) != VIO_TYPE_SSL ||
- SSL_get_verify_result(vio->ssl_) != X509_V_OK)
+ SSL_get_verify_result(ssl) != X509_V_OK)
break;
if (acl_user->ssl_cipher)
{
DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
- if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
+ acl_user->ssl_cipher,SSL_get_cipher(ssl)));
+ if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
user_access=acl_user->access;
else
{
if (global_system_variables.log_warnings)
sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'",
acl_user->ssl_cipher,
- SSL_get_cipher(vio->ssl_));
+ SSL_get_cipher(ssl));
user_access=NO_ACCESS;
break;
}
}
/* Prepare certificate (if exists) */
DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ X509* cert=SSL_get_peer_certificate(ssl);
DBUG_PRINT("info",("checkpoint 2"));
/* If X509 issuer is speified, we check it... */
if (acl_user->x509_issuer)
@@ -2445,7 +2448,7 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
{
my_printf_error(ER_WRONG_USAGE, ER(ER_WRONG_USAGE), MYF(0),
"DB GRANT","GLOBAL PRIVILEGES");
- result= -1;
+ result= 1;
}
}
}
@@ -3172,6 +3175,8 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14);
+ else if (!(table_access & ~GRANT_ACL))
+ global.append("USAGE",5);
else
{
int found= 0;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 763408dc5c2..e743c3ecdb8 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -133,7 +133,6 @@ THD::THD():user_time(0), is_fatal_error(0),
where="field list";
server_id = ::server_id;
slave_net = 0;
- log_pos = 0;
command=COM_CONNECT;
set_query_id=1;
db_access=NO_ACCESS;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e10795c4d9d..9149be9f1ae 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -129,7 +129,7 @@ public:
}
void set_max_size(ulong max_size_arg);
void signal_update() { pthread_cond_broadcast(&update_cond);}
- void wait_for_update(THD* thd);
+ void wait_for_update(THD* thd, bool master_or_slave);
void set_need_start_event() { need_start_event = 1; }
void init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg,
@@ -146,7 +146,7 @@ public:
bool write(THD *thd, const char *query, uint query_length,
time_t query_start=0);
bool write(Log_event* event_info); // binary log write
- bool write(THD *thd, IO_CACHE *cache);
+ bool write(THD *thd, IO_CACHE *cache, bool commit_or_rollback);
/*
v stands for vector
@@ -560,7 +560,6 @@ public:
char scramble[SCRAMBLE41_LENGTH+1];
// old scramble is needed to handle old clients
char old_scramble[SCRAMBLE_LENGTH+1];
- uint8 query_cache_type; // type of query cache processing
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
bool last_cuted_field;
@@ -580,7 +579,6 @@ public:
*/
LOG_INFO* current_linfo;
NET* slave_net; // network connection from slave -> m.
- my_off_t log_pos;
/* Used by the sys_var class to store temporary values */
union
{
@@ -965,7 +963,6 @@ typedef struct st_sort_buffer {
SORT_FIELD *sortorder;
} SORT_BUFFER;
-
/* Structure for db & table in sql_yacc */
class Table_ident :public Sql_alloc
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 947205949f1..66af0298f3e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1448,6 +1448,8 @@ void select_insert::send_error(uint errcode,const char *err)
table->file->has_transactions());
mysql_bin_log.write(&qinfo);
}
+ if (!table->tmp_table)
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (info.copied || info.deleted)
query_cache_invalidate3(thd, table, 1);
@@ -1468,7 +1470,11 @@ bool select_insert::send_eof()
*/
if (info.copied || info.deleted)
+ {
query_cache_invalidate3(thd, table, 1);
+ if (!(table->file->has_transactions() || table->tmp_table))
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ }
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index d030eaf617c..8820629c73f 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -171,7 +171,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else
#endif
{
- read_file_from_client=0;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
ex->file_name+=dirname_length(ex->file_name);
#endif
@@ -311,7 +310,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
which is nonsense.
*/
read_info.end_io_cache();
- Delete_file_log_event d(thd, log_delayed);
+ Delete_file_log_event d(thd, db, log_delayed);
mysql_bin_log.write(&d);
}
}
@@ -343,7 +342,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache(); // make sure last block gets logged
if (lf_info.wrote_create_file)
{
- Execute_load_log_event e(thd, log_delayed);
+ Execute_load_log_event e(thd, db, log_delayed);
mysql_bin_log.write(&e);
}
}
@@ -806,9 +805,13 @@ int READ_INFO::read_field()
row_end= to;
return 0;
}
- /* Copy the found '"' character */
+ /*
+ The string didn't terminate yet.
+ Store back next character for the loop
+ */
PUSH(chr);
- chr='"';
+ /* copy the found term character to 'to' */
+ chr= found_enclosed_char;
}
else if (chr == field_term_char && found_enclosed_char == INT_MAX)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 33e96cc2776..890334e8c94 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1878,6 +1878,7 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
+ /* This query don't work now. See comment in repl_failsafe.cc */
#ifndef WORKING_NEW_MASTER
net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
res= 1;
@@ -2678,11 +2679,12 @@ mysql_execute_command(THD *thd)
break;
case SQLCOM_SHOW_STATUS:
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
- OPT_GLOBAL);
+ OPT_GLOBAL, &LOCK_status);
break;
case SQLCOM_SHOW_VARIABLES:
res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
- init_vars, lex->option_type);
+ init_vars, lex->option_type,
+ &LOCK_global_system_variables);
break;
case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
@@ -3204,7 +3206,16 @@ mysql_execute_command(THD *thd)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
{
- if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
+ /*
+ If a non-transactional table was updated, warn; don't warn if this is a
+ slave thread (because when a slave thread executes a ROLLBACK, it has
+ been read from the binary log, so it's 100% sure and normal to produce
+ error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
+ slave SQL thread, it would not stop the thread but just be printed in
+ the error log; but we don't want users to wonder why they have this
+ message in the error log, so we don't send it.
+ */
+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
else
send_ok(thd);
@@ -3216,7 +3227,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
{
- if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
else
send_ok(thd);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 3cdf033c477..2bfc73ae1a1 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -545,7 +545,7 @@ Increase max_allowed_packet on master";
if (!thd->killed)
{
/* Note that the following call unlocks lock_log */
- mysql_bin_log.wait_for_update(thd);
+ mysql_bin_log.wait_for_update(thd, 0);
}
else
pthread_mutex_unlock(log_lock);
@@ -560,7 +560,7 @@ Increase max_allowed_packet on master";
if (read_packet)
{
- thd->proc_info = "sending update to slave";
+ thd->proc_info = "Sending binlog event to slave";
if (my_net_write(net, (char*)packet->ptr(), packet->length()) )
{
errmsg = "Failed on my_net_write()";
@@ -597,7 +597,7 @@ Increase max_allowed_packet on master";
{
bool loop_breaker = 0;
// need this to break out of the for loop from switch
- thd->proc_info = "switching to next log";
+ thd->proc_info = "Finished reading one binlog; switching to next binlog";
switch (mysql_bin_log.find_next_log(&linfo, 1)) {
case LOG_INFO_EOF:
loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
@@ -636,14 +636,14 @@ end:
(void)my_close(file, MYF(MY_WME));
send_eof(thd);
- thd->proc_info = "waiting to finalize termination";
+ thd->proc_info = "Waiting to finalize termination";
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
err:
- thd->proc_info = "waiting to finalize termination";
+ thd->proc_info = "Waiting to finalize termination";
end_io_cache(&log);
/*
Exclude iteration through thread list
@@ -903,7 +903,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(1);
}
- thd->proc_info = "changing master";
+ thd->proc_info = "Changing master";
LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
// TODO: see if needs re-write
if (init_master_info(mi, master_info_file, relay_log_info_file, 0))
@@ -969,7 +969,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (need_relay_log_purge)
{
relay_log_purge= 1;
- thd->proc_info="purging old relay logs";
+ thd->proc_info="Purging old relay logs";
if (purge_relay_logs(&mi->rli, thd,
0 /* not only reset, but also reinit */,
&errmsg))
@@ -1258,7 +1258,7 @@ int log_loaded_block(IO_CACHE* file)
lf_info->last_pos_in_file = file->pos_in_file;
if (lf_info->wrote_create_file)
{
- Append_block_log_event a(lf_info->thd, buffer, block_len,
+ Append_block_log_event a(lf_info->thd, lf_info->db, buffer, block_len,
lf_info->log_delayed);
mysql_bin_log.write(&a);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index de6b2ce443f..771a3d701bb 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1414,7 +1414,6 @@ JOIN::exec()
curr_join->group_list : curr_join->order,
curr_join->select_limit, unit->select_limit_cnt))
DBUG_VOID_RETURN;
- }
}
curr_join->having= curr_join->tmp_having;
thd->proc_info="Sending data";
@@ -2046,28 +2045,34 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
static void
add_key_field(KEY_FIELD **key_fields,uint and_level,
- Field *field,bool eq_func,Item *value,
+ Field *field,bool eq_func,Item **value, uint num_values,
table_map usable_tables)
{
uint exists_optimize= 0;
if (!(field->flags & PART_KEY_FLAG))
{
// Don't remove column IS NULL on a LEFT JOIN table
- if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
- !field->table->maybe_null || field->null_ptr)
+ if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
+ !field->table->maybe_null || field->null_ptr)
return; // Not a key. Skip it
exists_optimize= KEY_OPTIMIZE_EXISTS;
}
else
{
table_map used_tables=0;
- if (value && ((used_tables=value->used_tables()) &
- (field->table->map | RAND_TABLE_BIT)))
+ bool optimizable=0;
+ for (uint i=0; i<num_values; i++)
+ {
+ used_tables|=(*value)->used_tables();
+ if (!((*value)->used_tables() & (field->table->map | RAND_TABLE_BIT)))
+ optimizable=1;
+ }
+ if (!optimizable)
return;
if (!(usable_tables & field->table->map))
{
- if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
- !field->table->maybe_null || field->null_ptr)
+ if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
+ !field->table->maybe_null || field->null_ptr)
return; // Can't use left join optimize
exists_optimize= KEY_OPTIMIZE_EXISTS;
}
@@ -2078,12 +2083,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
field->table->keys_in_use_for_query);
stat[0].keys|= possible_keys; // Add possible keys
- if (!value)
- { // Probably BETWEEN or IN
- stat[0].const_keys |= possible_keys;
- return; // Can't be used as eq key
- }
-
/*
Save the following cases:
Field op constant
@@ -2092,26 +2091,38 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
Field op formula
Field IS NULL
Field IS NOT NULL
+ Field BETWEEN ...
+ Field IN ...
*/
stat[0].key_dependent|=used_tables;
- if (value->const_item())
- stat[0].const_keys |= possible_keys;
+ bool is_const=1;
+ for (uint i=0; i<num_values; i++)
+ is_const&= (*value)->const_item();
+ if (is_const)
+ stat[0].const_keys |= possible_keys;
/*
We can't always use indexes when comparing a string index to a
- number. cmp_type() is checked to allow compare of dates to numbers
- */
+ number. cmp_type() is checked to allow compare of dates to numbers.
+ eq_func is NEVER true when num_values > 1
+ */
if (!eq_func ||
field->result_type() == STRING_RESULT &&
- value->result_type() != STRING_RESULT &&
- field->cmp_type() != value->result_type())
+ (*value)->result_type() != STRING_RESULT &&
+ field->cmp_type() != (*value)->result_type())
return;
}
}
+ DBUG_ASSERT(num_values == 1);
+ /*
+ For the moment eq_func is always true. This slot is reserved for future
+ extensions where we want to remembers other things than just eq comparisons
+ */
+ DBUG_ASSERT(eq_func);
/* Store possible eq field */
(*key_fields)->field= field;
(*key_fields)->eq_func= eq_func;
- (*key_fields)->val= value;
+ (*key_fields)->val= *value;
(*key_fields)->level= and_level;
(*key_fields)->optimize= exists_optimize;
(*key_fields)++;
@@ -2160,12 +2171,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
case Item_func::OPTIMIZE_NONE:
break;
case Item_func::OPTIMIZE_KEY:
+ // BETWEEN or IN
if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
add_key_field(key_fields,*and_level,
- ((Item_field*) (cond_func->key_item()->real_item()))
- ->field,
- 0,(Item*) 0,usable_tables);
+ ((Item_field*) (cond_func->key_item()->real_item()))->field, 0,
+ cond_func->arguments()+1, cond_func->argument_count()-1,
+ usable_tables);
break;
case Item_func::OPTIMIZE_OP:
{
@@ -2179,7 +2191,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
((Item_field*) (cond_func->arguments()[0])->real_item())
->field,
equal_func,
- (cond_func->arguments()[1]),usable_tables);
+ cond_func->arguments()+1, 1, usable_tables);
}
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
cond_func->functype() != Item_func::LIKE_FUNC &&
@@ -2189,7 +2201,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
((Item_field*) (cond_func->arguments()[1])->real_item())
->field,
equal_func,
- (cond_func->arguments()[0]),usable_tables);
+ cond_func->arguments(),1,usable_tables);
}
break;
}
@@ -2198,11 +2210,14 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
{
+ Item *tmp=new Item_null;
+ if (!tmp) // Should never be true
+ return;
add_key_field(key_fields,*and_level,
((Item_field*) (cond_func->arguments()[0])->real_item())
->field,
cond_func->functype() == Item_func::ISNULL_FUNC,
- new Item_null, usable_tables);
+ &tmp, 1, usable_tables);
}
break;
}
@@ -3992,7 +4007,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
static void
-propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
+propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
COND *cond)
{
if (cond->type() == Item::COND_ITEM)
@@ -4018,7 +4033,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
cond_cmp->cmp_func->arguments()[1]);
}
}
- else if (and_level != cond && !cond->marker) // In a AND group
+ else if (and_father != cond && !cond->marker) // In a AND group
{
if (cond->type() == Item::FUNC_ITEM &&
(((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
@@ -4036,7 +4051,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
func->arguments()[1]=resolve_const_item(func->arguments()[1],
func->arguments()[0]);
func->update_used_tables();
- change_cond_ref_to_const(save_list,and_level,and_level,
+ change_cond_ref_to_const(save_list,and_father,and_father,
func->arguments()[0],
func->arguments()[1]);
}
@@ -4045,7 +4060,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
func->arguments()[0]=resolve_const_item(func->arguments()[0],
func->arguments()[1]);
func->update_used_tables();
- change_cond_ref_to_const(save_list,and_level,and_level,
+ change_cond_ref_to_const(save_list,and_father,and_father,
func->arguments()[1],
func->arguments()[0]);
}
@@ -8206,7 +8221,7 @@ update_tmptable_sum_func(Item_sum **func_ptr,
{
Item_sum *func;
while ((func= *(func_ptr++)))
- func->update_field(0);
+ func->update_field();
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9084269f486..997dcce55b4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -791,9 +791,14 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(1);
}
+ if (store_create_info(thd, table, &buffer))
+ DBUG_RETURN(-1);
+
List<Item> field_list;
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH));
+ // 1024 is for not to confuse old clients
+ field_list.push_back(new Item_empty_string("Create Table",
+ max(buffer.length(),1024)));
if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(1);
@@ -1017,11 +1022,38 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
}
}
+
+/* Append directory name (if exists) to CREATE INFO */
+
+static void append_directory(THD *thd, String *packet, const char *dir_type,
+ const char *filename)
+{
+ uint length;
+ if (filename && !(thd->sql_mode & MODE_NO_DIR_IN_CREATE))
+ {
+ length= dirname_length(filename);
+ packet->append(' ');
+ packet->append(dir_type);
+ packet->append(" DIRECTORY='", 12);
+ packet->append(filename, length);
+ packet->append('\'');
+ }
+}
+
+
#define LIST_PROCESS_HOST_LEN 64
static int
store_create_info(THD *thd, TABLE *table, String *packet)
{
+ List<Item> field_list;
+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
+ String type(tmp, sizeof(tmp),&my_charset_bin);
+ Field **ptr,*field;
+ uint primary_key;
+ KEY *key_info;
+ handler *file= table->file;
+ HA_CREATE_INFO create_info;
my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
MODE_ORACLE |
MODE_MSSQL |
@@ -1037,9 +1069,6 @@ store_create_info(THD *thd, TABLE *table, String *packet)
restore_record(table,default_values); // Get empty record
- List<Item> field_list;
- char tmp[MAX_FIELD_WIDTH];
- String type(tmp, sizeof(tmp),&my_charset_bin);
if (table->tmp_table)
packet->append("CREATE TEMPORARY TABLE ", 23);
else
@@ -1047,13 +1076,14 @@ store_create_info(THD *thd, TABLE *table, String *packet)
append_identifier(thd,packet, table->real_name, strlen(table->real_name));
packet->append(" (\n", 3);
- Field **ptr,*field;
for (ptr=table->field ; (field= *ptr); ptr++)
{
+ bool has_default;
+ uint flags = field->flags;
+
if (ptr != table->field)
packet->append(",\n", 2);
- uint flags = field->flags;
packet->append(" ", 2);
append_identifier(thd,packet,field->field_name, strlen(field->field_name));
packet->append(' ');
@@ -1090,9 +1120,9 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (flags & NOT_NULL_FLAG)
packet->append(" NOT NULL", 9);
- bool has_default = (field->type() != FIELD_TYPE_BLOB &&
- field->type() != FIELD_TYPE_TIMESTAMP &&
- field->unireg_check != Field::NEXT_NUMBER);
+ has_default= (field->type() != FIELD_TYPE_BLOB &&
+ field->type() != FIELD_TYPE_TIMESTAMP &&
+ field->unireg_check != Field::NEXT_NUMBER);
if (has_default)
{
@@ -1122,9 +1152,11 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
}
- KEY *key_info=table->key_info;
- table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
- uint primary_key = table->primary_key;
+ key_info= table->key_info;
+ file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
+ bzero((char*) &create_info, sizeof(create_info));
+ file->update_create_info(&create_info);
+ primary_key= table->primary_key;
for (uint i=0 ; i < table->keys ; i++,key_info++)
{
@@ -1175,7 +1207,6 @@ store_create_info(THD *thd, TABLE *table, String *packet)
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & HA_FULLTEXT)))
{
- char buff[64];
buff[0] = '(';
char* end=int10_to_str((long) key_part->length, buff + 1,10);
*end++ = ')';
@@ -1189,10 +1220,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
Get possible foreign key definitions stored in InnoDB and append them
to the CREATE TABLE statement
*/
- handler *file = table->file;
- char* for_str= file->get_foreign_key_create_info();
- if (for_str)
+ if ((for_str= file->get_foreign_key_create_info()))
{
packet->append(for_str, strlen(for_str));
file->free_foreign_key_create_info(for_str);
@@ -1203,8 +1232,6 @@ store_create_info(THD *thd, TABLE *table, String *packet)
{
packet->append(" TYPE=", 6);
packet->append(file->table_type());
- char buff[128];
- char* p;
if (table->table_charset &&
!(thd->variables.sql_mode & MODE_MYSQL323) &&
@@ -1222,21 +1249,22 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (table->min_rows)
{
packet->append(" MIN_ROWS=");
- p = longlong10_to_str(table->min_rows, buff, 10);
- packet->append(buff, (uint) (p - buff));
+ end= longlong10_to_str(table->min_rows, buff, 10);
+ packet->append(buff, (uint) (end- buff));
}
if (table->max_rows)
{
packet->append(" MAX_ROWS=");
- p = longlong10_to_str(table->max_rows, buff, 10);
- packet->append(buff, (uint) (p - buff));
+ end= longlong10_to_str(table->max_rows, buff, 10);
+ packet->append(buff, (uint) (end - buff));
}
+
if (table->avg_row_length)
{
packet->append(" AVG_ROW_LENGTH=");
- p=longlong10_to_str(table->avg_row_length, buff,10);
- packet->append(buff, (uint) (p - buff));
+ end= longlong10_to_str(table->avg_row_length, buff,10);
+ packet->append(buff, (uint) (end - buff));
}
if (table->db_create_options & HA_OPTION_PACK_KEYS)
@@ -1260,12 +1288,15 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
if (file->raid_type)
{
- char buff[100];
- sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
- my_raid_type(file->raid_type), file->raid_chunks,
- file->raid_chunksize/RAID_BLOCK_SIZE);
- packet->append(buff);
+ uint length;
+ length= my_snprintf(buff,sizeof(buff),
+ " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
+ my_raid_type(file->raid_type), file->raid_chunks,
+ file->raid_chunksize/RAID_BLOCK_SIZE);
+ packet->append(buff, length);
}
+ append_directory(thd, packet, "DATA", create_info.data_file_name);
+ append_directory(thd, packet, "INDEX", create_info.index_file_name);
}
DBUG_RETURN(0);
}
@@ -1522,7 +1553,8 @@ err:
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
- enum enum_var_type value_type)
+ enum enum_var_type value_type,
+ pthread_mutex_t *mutex)
{
char buff[1024];
List<Item> field_list;
@@ -1536,8 +1568,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
DBUG_RETURN(1); /* purecov: inspected */
null_lex_str.str= 0; // For sys_var->value_ptr()
- /* pthread_mutex_lock(&THR_LOCK_keycache); */
- pthread_mutex_lock(&LOCK_status);
+ pthread_mutex_lock(mutex);
for (; variables->name; variables++)
{
if (!(wild && wild[0] && wild_case_compare(system_charset_info,
@@ -1625,83 +1656,83 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
case SHOW_SSL_CTX_SESS_ACCEPT:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_accept(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_accept_good(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_connect_good(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)),
+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CB_HITS:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_HITS:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_hits(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CACHE_FULL:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_cache_full(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_MISSES:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_misses(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_TIMEOUTS:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_SESS_NUMBER:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_SESS_CONNECT:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_GET_VERIFY_MODE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
@@ -1711,7 +1742,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
end= pos+4;
break;
}
- switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
+ switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
{
case SSL_SESS_CACHE_OFF:
pos= "OFF";
@@ -1739,40 +1770,50 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
break;
/* First group - functions relying on SSL */
case SHOW_SSL_GET_VERSION:
- pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : "";
+ pos= (thd->net.vio->ssl_arg ?
+ SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
end= strend(pos);
break;
case SHOW_SSL_SESSION_REUSED:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_session_reused(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_session_reused((SSL*) thd->net.vio->
+ ssl_arg) :
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_DEFAULT_TIMEOUT:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_get_default_timeout(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_default_timeout((SSL*) thd->net.vio->
+ ssl_arg) :
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_VERIFY_MODE:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_get_verify_mode(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_verify_mode((SSL*) thd->net.vio->
+ ssl_arg):
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_VERIFY_DEPTH:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_get_verify_depth(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_verify_depth((SSL*) thd->net.vio->
+ ssl_arg):
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_CIPHER:
- pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : "";
+ pos= (thd->net.vio->ssl_arg ?
+ SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
end= strend(pos);
break;
case SHOW_SSL_GET_CIPHER_LIST:
- if (thd->net.vio->ssl_)
+ if (thd->net.vio->ssl_arg)
{
char *to= buff;
for (int i=0 ; i++ ;)
{
- const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i);
+ const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
if (p == NULL)
break;
to= strmov(to, p);
@@ -1796,14 +1837,12 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
goto err; /* purecov: inspected */
}
}
- pthread_mutex_unlock(&LOCK_status);
- /* pthread_mutex_unlock(&THR_LOCK_keycache); */
+ pthread_mutex_unlock(mutex);
send_eof(thd);
DBUG_RETURN(0);
err:
- pthread_mutex_unlock(&LOCK_status);
- /* pthread_mutex_unlock(&THR_LOCK_keycache); */
+ pthread_mutex_unlock(mutex);
DBUG_RETURN(1);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 37f8d0d7f4f..b1141d15309 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -914,7 +914,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
thd->proc_info="creating table";
+ if (thd->sql_mode & MODE_NO_DIR_IN_CREATE)
+ create_info->data_file_name= create_info->index_file_name= 0;
create_info->table_options=db_options;
+
if (rea_create_table(thd, path, create_info, fields, key_count,
key_info_buffer))
{
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 24497589c73..2b10fe2cd2a 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -123,8 +123,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
DBUG_RETURN(0);
prepared= 1;
res= 0;
- found_rows_for_union= test(first_select_in_union()->options
- & OPTION_FOUND_ROWS);
+ found_rows_for_union= first_select_in_union()->options & OPTION_FOUND_ROWS;
TMP_TABLE_PARAM tmp_table_param;
result= sel_result;
t_and_f= tables_and_fields_initied;
@@ -239,7 +238,7 @@ int st_select_lex_unit::exec()
{
SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor=first_select_in_union();
- ha_rows add_rows=0;
+ ulonglong add_rows=0;
DBUG_ENTER("st_select_lex_unit::exec");
if (executed && !(dependent || uncacheable))
@@ -263,10 +262,30 @@ int st_select_lex_unit::exec()
res= sl->join->reinit();
else
{
- offset_limit_cnt= sl->offset_limit;
- select_limit_cnt= sl->select_limit+sl->offset_limit;
+ /* Don't use offset for the last union if there is no braces */
+ if (sl != lex_sl)
+ {
+ offset_limit_cnt= sl->offset_limit;
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ }
+ else
+ {
+ offset_limit_cnt= 0;
+ /*
+ We can't use LIMIT at this stage if we are using ORDER BY for the
+ whole query
+ */
+ select_limit_cnt= HA_POS_ERROR;
+ if (! sl->order_list.first)
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ }
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
+
+ /*
+ When using braces, SQL_CALC_FOUND_ROWS affects the whole query.
+ We don't calculate found_rows() per union part
+ */
if (select_limit_cnt == HA_POS_ERROR || sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
else
@@ -318,11 +337,13 @@ int st_select_lex_unit::exec()
thd->lex.current_select= lex_select_save;
DBUG_RETURN(res);
}
+ /* Needed for the following test and for records_at_start in next loop */
+ table->file->info(HA_STATUS_VARIABLE);
if (found_rows_for_union & sl->options)
{
/*
- This is a union without braces. Remember the number of rows that could
- also have been part of the result set.
+ This is a union without braces. Remember the number of rows that
+ could also have been part of the result set.
We get this from the difference of between total number of possible
rows and actual rows added to the temporary table.
*/
@@ -341,7 +362,7 @@ int st_select_lex_unit::exec()
List<Item_func_match> empty_list;
empty_list.empty();
- if (!thd->is_fatal_error) // Check if EOM
+ if (!thd->is_fatal_error) // Check if EOM
{
ulong options= thd->options;
thd->lex.current_select= fake_select_lex;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 29138f10989..7430029a5e5 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -600,6 +600,7 @@ multi_update::initialize_tables(JOIN *join)
{
TABLE *table=table_ref->table;
uint cnt= table_ref->shared;
+ Item_field *If;
List<Item> temp_fields= *fields_for_table[cnt];
ORDER group;
@@ -623,7 +624,10 @@ multi_update::initialize_tables(JOIN *join)
/* ok to be on stack as this is not referenced outside of this func */
Field_string offset(table->file->ref_length, 0, "offset",
table, &my_charset_bin);
- if (temp_fields.push_front(new Item_field(((Field *) &offset))))
+ if (!(If=new Item_field(((Field *) &offset))))
+ DBUG_RETURN(1);
+ If->maybe_null=0;
+ if (temp_fields.push_front(If))
DBUG_RETURN(1);
/* Make an unique key over the first field to avoid duplicated updates */