summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sergefp@mysql.com>2003-12-20 00:54:38 +0300
committerunknown <sergefp@mysql.com>2003-12-20 00:54:38 +0300
commitc0d9d43739df0bf92b83a6b328485c1f357ea253 (patch)
tree6f1ee123b4c43806a2d62ab70bfdc1402e51dff9 /sql
parent28ad1273ddf3d42a4ec9f9fdfdd150f39fa4772e (diff)
parentb41e6294ca97aaeb403972feb19ecc6d177096ca (diff)
downloadmariadb-git-c0d9d43739df0bf92b83a6b328485c1f357ea253.tar.gz
Merge mysql.com:/home/psergey/mysql-5.0-latest-pull
into mysql.com:/dbdata/psergey/mysql-5.0-imerge-unique BitKeeper/etc/logging_ok: auto-union include/my_global.h: Auto merged sql/filesort.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/handler.h: Auto merged sql/item_create.cc: Auto merged sql/item_func.cc: Auto merged sql/mysql_priv.h: Auto merged sql/opt_range.cc: Auto merged sql/records.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_select.cc: Auto merged sql/sql_union.cc: Auto merged sql/sql_update.cc: Auto merged sql/uniques.cc: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/client_settings.h2
-rw-r--r--sql/field.cc135
-rw-r--r--sql/field.h15
-rw-r--r--sql/filesort.cc56
-rw-r--r--sql/ha_innodb.cc6
-rw-r--r--sql/ha_myisam.cc4
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/handler.h2
-rw-r--r--sql/item.cc21
-rw-r--r--sql/item.h8
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/item_create.cc4
-rw-r--r--sql/item_func.cc46
-rw-r--r--sql/item_func.h46
-rw-r--r--sql/item_strfunc.cc29
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_subselect.cc16
-rw-r--r--sql/item_sum.cc189
-rw-r--r--sql/item_sum.h62
-rw-r--r--sql/item_timefunc.cc78
-rw-r--r--sql/lex.h2
-rw-r--r--sql/log.cc6
-rw-r--r--sql/log_event.cc13
-rw-r--r--sql/log_event.h4
-rw-r--r--sql/mysql_priv.h17
-rw-r--r--sql/mysqld.cc124
-rw-r--r--sql/net_serv.cc6
-rw-r--r--sql/nt_servc.cc4
-rw-r--r--sql/opt_range.cc52
-rw-r--r--sql/records.cc11
-rw-r--r--sql/repl_failsafe.cc10
-rw-r--r--sql/set_var.cc43
-rw-r--r--sql/set_var.h14
-rw-r--r--sql/share/czech/errmsg.txt6
-rw-r--r--sql/share/danish/errmsg.txt4
-rw-r--r--sql/share/dutch/errmsg.txt4
-rw-r--r--sql/share/english/errmsg.txt6
-rw-r--r--sql/share/estonian/errmsg.txt6
-rw-r--r--sql/share/french/errmsg.txt6
-rw-r--r--sql/share/greek/errmsg.txt6
-rw-r--r--sql/share/hungarian/errmsg.txt6
-rw-r--r--sql/share/italian/errmsg.txt4
-rw-r--r--sql/share/japanese/errmsg.txt6
-rw-r--r--sql/share/korean/errmsg.txt6
-rw-r--r--sql/share/norwegian-ny/errmsg.txt6
-rw-r--r--sql/share/norwegian/errmsg.txt6
-rw-r--r--sql/share/polish/errmsg.txt6
-rw-r--r--sql/share/romanian/errmsg.txt6
-rw-r--r--sql/share/russian/errmsg.txt4
-rw-r--r--sql/share/serbian/errmsg.txt4
-rw-r--r--sql/share/slovak/errmsg.txt6
-rw-r--r--sql/share/spanish/errmsg.txt4
-rw-r--r--sql/share/swedish/errmsg.txt4
-rw-r--r--sql/share/ukrainian/errmsg.txt4
-rw-r--r--sql/slave.cc36
-rw-r--r--sql/sql_acl.cc14
-rw-r--r--sql/sql_acl.h12
-rw-r--r--sql/sql_analyse.cc8
-rw-r--r--sql/sql_base.cc20
-rw-r--r--sql/sql_cache.cc36
-rw-r--r--sql/sql_class.h29
-rw-r--r--sql/sql_client.cc6
-rw-r--r--sql/sql_db.cc10
-rw-r--r--sql/sql_delete.cc22
-rw-r--r--sql/sql_insert.cc7
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_load.cc63
-rw-r--r--sql/sql_parse.cc282
-rw-r--r--sql/sql_prepare.cc16
-rw-r--r--sql/sql_rename.cc1
-rw-r--r--sql/sql_repl.cc12
-rw-r--r--sql/sql_select.cc62
-rw-r--r--sql/sql_show.cc20
-rw-r--r--sql/sql_sort.h1
-rw-r--r--sql/sql_table.cc16
-rw-r--r--sql/sql_update.cc34
-rw-r--r--sql/sql_yacc.yy47
-rw-r--r--sql/table.cc30
-rw-r--r--sql/table.h2
-rw-r--r--sql/time.cc72
-rw-r--r--sql/udf_example.cc8
-rw-r--r--sql/uniques.cc236
83 files changed, 1512 insertions, 737 deletions
diff --git a/sql/client_settings.h b/sql/client_settings.h
index b357e52ec9d..a8cd36af102 100644
--- a/sql/client_settings.h
+++ b/sql/client_settings.h
@@ -32,3 +32,5 @@
#undef HAVE_SMEM
#undef _CUSTOMCONFIG_
+#define mysql_server_init(a,b,c) 0
+
diff --git a/sql/field.cc b/sql/field.cc
index 237427a9d80..a9029b893e3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -791,7 +791,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
if (zerofill)
{
left_wall=to-1;
- while (pos != left_wall) // Fill with zeros
+ while (pos > left_wall) // Fill with zeros
*pos--='0';
}
else
@@ -799,7 +799,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
left_wall=to+(sign_char != 0)-1;
if (!expo_sign_char) // If exponent was specified, ignore prezeros
{
- for (;pos != left_wall && pre_zeros_from !=pre_zeros_end;
+ for (;pos > left_wall && pre_zeros_from !=pre_zeros_end;
pre_zeros_from++)
*pos--= '0';
}
@@ -1016,7 +1016,7 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
return 0;
if (*a_ptr == '-')
return -1;
- else if (*b_ptr == '-')
+ if (*b_ptr == '-')
return 1;
while (a_ptr != end)
@@ -2853,34 +2853,72 @@ int Field_timestamp::store(double nr)
function.
*/
-static longlong fix_datetime(longlong nr)
+static longlong fix_datetime(longlong nr, TIME *time_res,
+ const char *field_name, bool *error)
{
- current_thd->last_cuted_field= 0;
+ long part1,part2;
+
+ *error= 0;
if (nr == LL(0) || nr >= LL(10000101000000))
- return nr; // Normal datetime >= Year 1000
+ goto ok;
if (nr < 101)
goto err;
if (nr <= (YY_PART_YEAR-1)*10000L+1231L)
- return (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069
+ {
+ nr= (nr+20000000L)*1000000L; // YYMMDD, year: 2000-2069
+ goto ok;
+ }
if (nr < (YY_PART_YEAR)*10000L+101L)
goto err;
if (nr <= 991231L)
- return (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999
+ {
+ nr= (nr+19000000L)*1000000L; // YYMMDD, year: 1970-1999
+ goto ok;
+ }
if (nr < 10000101L)
goto err;
if (nr <= 99991231L)
- return nr*1000000L;
+ {
+ nr= nr*1000000L;
+ goto ok;
+ }
if (nr < 101000000L)
goto err;
if (nr <= (YY_PART_YEAR-1)*LL(10000000000)+LL(1231235959))
- return nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069
+ {
+ nr= nr+LL(20000000000000); // YYMMDDHHMMSS, 2000-2069
+ goto ok;
+ }
if (nr < YY_PART_YEAR*LL(10000000000)+ LL(101000000))
goto err;
if (nr <= LL(991231235959))
- return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999
-
+ nr= nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999
+
+ ok:
+ part1=(long) (nr/LL(1000000));
+ part2=(long) (nr - (longlong) part1*LL(1000000));
+ time_res->year= (int) (part1/10000L); part1%=10000L;
+ time_res->month= (int) part1 / 100;
+ time_res->day= (int) part1 % 100;
+ time_res->hour= (int) (part2/10000L); part2%=10000L;
+ time_res->minute=(int) part2 / 100;
+ time_res->second=(int) part2 % 100;
+
+ if (time_res->year <= 9999 && time_res->month <= 12 &&
+ time_res->day <= 31 && time_res->hour <= 23 &&
+ time_res->minute <= 59 && time_res->second <= 59)
+ return nr;
+
err:
- current_thd->last_cuted_field= 1;
+ THD *thd= current_thd;
+ if (thd->count_cuted_fields)
+ {
+ thd->cuted_fields++;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
+ field_name, thd->row_count);
+ }
+ *error= 1;
return LL(0);
}
@@ -2888,24 +2926,17 @@ static longlong fix_datetime(longlong nr)
int Field_timestamp::store(longlong nr)
{
TIME l_time;
- time_t timestamp;
- long part1,part2;
+ time_t timestamp= 0;
+ bool error;
- if ((nr=fix_datetime(nr)))
+ if ((nr= fix_datetime(nr, &l_time, field_name, &error)))
{
long not_used;
- part1=(long) (nr/LL(1000000));
- part2=(long) (nr - (longlong) part1*LL(1000000));
- l_time.year= (int) (part1/10000L); part1%=10000L;
- l_time.month= (int) part1 / 100;
- l_time.day= (int) part1 % 100;
- l_time.hour= (int) (part2/10000L); part2%=10000L;
- l_time.minute=(int) part2 / 100;
- l_time.second=(int) part2 % 100;
- timestamp=my_gmt_sec(&l_time, &not_used);
- }
- else
- timestamp=0;
+
+ if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1)
+ goto err;
+ timestamp= my_gmt_sec(&l_time, &not_used);
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -2914,9 +2945,12 @@ int Field_timestamp::store(longlong nr)
else
#endif
longstore(ptr,(uint32) timestamp);
- if (current_thd->last_cuted_field)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
- return 0;
+ return error;
+
+err:
+ longstore(ptr,(uint32) 0);
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
+ return 1;
}
@@ -3350,7 +3384,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
return 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
if (nr != 0 || len != 4)
{
@@ -3363,6 +3397,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
return 0;
}
+
int Field_year::store(double nr)
{
if (nr < 0.0 || nr >= 2155.0)
@@ -3825,15 +3860,10 @@ int Field_datetime::store(double nr)
int Field_datetime::store(longlong nr)
{
- int error= 0;
- if (nr < 0 || nr > LL(99991231235959))
- {
- nr=0;
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE);
- error= 1;
- }
- else
- nr=fix_datetime(nr);
+ TIME not_used;
+ bool error;
+
+ nr= fix_datetime(nr, &not_used, field_name, &error);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -3842,11 +3872,10 @@ int Field_datetime::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
- if (current_thd->last_cuted_field)
- set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
return error;
}
+
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
{
longlong tmp;
@@ -5064,7 +5093,7 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
uint tmp=find_type(typelib, from, length, 0);
if (!tmp)
{
- if (length < 6) // Can't be more than 99999 enums
+ if (length < 6) // Can't be more than 99999 enums
{
/* This is for reading numbers with LOAD DATA INFILE */
char *end;
@@ -5159,7 +5188,7 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
{
uint tmp=(uint) Field_enum::val_int();
if (!tmp || tmp > typelib->count)
- val_ptr->length(0);
+ val_ptr->set("", 0, field_charset);
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
(uint) strlen(typelib->type_names[tmp-1]),
@@ -5224,12 +5253,13 @@ void Field_enum::sql_type(String &res) const
int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
{
- bool set_warning= 0;
+ bool got_warning= 0;
int err= 0;
char *not_used;
uint not_used2;
char buff[80];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
+
/* Convert character set if nesessary */
if (use_conversion(cs, field_charset))
{
@@ -5238,7 +5268,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
length= tmpstr.length();
}
ulonglong tmp= find_set(typelib, from, length, &not_used, &not_used2,
- &set_warning);
+ &got_warning);
if (!tmp && length && length < 22)
{
/* This is for reading numbers with LOAD DATA INFILE */
@@ -5248,16 +5278,11 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
{
tmp=0;
- THD *thd= current_thd;
- if (thd->count_cuted_fields)
- {
- thd->cuted_fields++;
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
- field_name, 0);
- }
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
}
}
+ else if (got_warning)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
store_type(tmp);
return err;
}
diff --git a/sql/field.h b/sql/field.h
index 508fbad41a1..e3b4bf29fb8 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -872,11 +872,14 @@ public:
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg, cs) {};
- Field_varstring(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ unireg_check_arg, field_name_arg, table_arg, cs)
+ {}
+ Field_varstring(uint32 len_arg,bool maybe_null_arg,
+ const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs) {};
+ NONE, field_name_arg, table_arg, cs)
+ {}
enum_field_types type() const { return FIELD_TYPE_VAR_STRING; }
enum ha_base_keytype key_type() const
@@ -924,9 +927,9 @@ public:
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, table_arg, cs),
geom_flag(true), packlength(4)
- {
- flags|= BLOB_FLAG;
- }
+ {
+ flags|= BLOB_FLAG;
+ }
enum_field_types type() const { return FIELD_TYPE_BLOB;}
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 27c59a05941..f97126017cc 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -792,6 +792,39 @@ uint read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek,
} /* read_to_buffer */
+/*
+ Put all room used by freed buffer to use in adjacent buffer. Note, that
+ we can't simply distribute memory evenly between all buffers, because
+ new areas must not overlap with old ones.
+ SYNOPSYS
+ reuse_freed_buff()
+ queue IN list of non-empty buffers, without freed buffer
+ reuse IN empty buffer
+ key_length IN key length
+*/
+
+void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length)
+{
+ uchar *reuse_end= reuse->base + reuse->max_keys * key_length;
+ for (uint i= 0; i < queue->elements; ++i)
+ {
+ BUFFPEK *bp= (BUFFPEK *) queue_element(queue, i);
+ if (bp->base + bp->max_keys * key_length == reuse->base)
+ {
+ bp->max_keys+= reuse->max_keys;
+ return;
+ }
+ else if (bp->base == reuse_end)
+ {
+ bp->base= reuse->base;
+ bp->max_keys+= reuse->max_keys;
+ return;
+ }
+ }
+ DBUG_ASSERT(0);
+}
+
+
/*
Merge buffers to one buffer
*/
@@ -917,29 +950,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
if (!(error= (int) read_to_buffer(from_file,buffpek,
rec_length)))
{
- uchar *base= buffpek->base;
- ulong max_keys= buffpek->max_keys;
-
VOID(queue_remove(&queue,0));
-
- /* Put room used by buffer to use in other buffer */
- for (refpek= (BUFFPEK**) &queue_top(&queue);
- refpek <= (BUFFPEK**) &queue_end(&queue);
- refpek++)
- {
- buffpek= *refpek;
- if (buffpek->base+buffpek->max_keys*rec_length == base)
- {
- buffpek->max_keys+= max_keys;
- break;
- }
- else if (base+max_keys*rec_length == buffpek->base)
- {
- buffpek->base= base;
- buffpek->max_keys+= max_keys;
- break;
- }
- }
+ reuse_freed_buff(&queue, buffpek, rec_length);
break; /* One buffer have been removed */
}
else if (error == -1)
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index d949f8bcf9c..56bb5d4f1ae 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -33,11 +33,9 @@ InnoDB */
#include "mysql_priv.h"
#include "slave.h"
-#include "sql_cache.h"
#ifdef HAVE_INNOBASE_DB
#include <m_ctype.h>
-#include <assert.h>
#include <hash.h>
#include <myisampack.h>
@@ -1860,7 +1858,7 @@ ha_innobase::store_key_val_for_row(
|| mysql_type == FIELD_TYPE_BLOB
|| mysql_type == FIELD_TYPE_LONG_BLOB) {
- ut_a(key_part->key_part_flag & HA_PART_KEY);
+ ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
if (is_null) {
buff += key_part->length + 2;
@@ -3348,7 +3346,7 @@ create_index(
for (i = 0; i < n_fields; i++) {
key_part = key->key_part + i;
- /* (The flag HA_PART_KEY denotes in MySQL a column prefix
+ /* (The flag HA_PART_KEY_SEG denotes in MySQL a column prefix
field in an index: we only store a specified number of first
bytes of the column to the index field.) The flag does not
seem to be properly set by MySQL. Let us fall back on testing
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 6356f209ba2..1a597415ff3 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -390,7 +390,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
{
HA_CHECK_OPT tmp_check_opt;
- char* backup_dir = thd->lex->backup_dir;
+ char* backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
int error;
@@ -430,7 +430,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
- char* backup_dir = thd->lex->backup_dir;
+ char* backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
int error;
diff --git a/sql/handler.cc b/sql/handler.cc
index fe168d12fce..e9eecabaa84 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -104,7 +104,7 @@ enum db_type ha_resolve_by_name(const char *name, uint namelen)
return DB_TYPE_UNKNOWN;
}
-const char *ha_get_table_type(enum db_type db_type)
+const char *ha_get_storage_engine(enum db_type db_type)
{
show_table_type_st *types;
for (types= sys_table_types; types->type; types++)
diff --git a/sql/handler.h b/sql/handler.h
index 2ad37233c9e..4a8abf5f131 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -399,7 +399,7 @@ extern TYPELIB tx_isolation_typelib;
#define ha_supports_generate(T) (T != DB_TYPE_INNODB)
enum db_type ha_resolve_by_name(const char *name, uint namelen);
-const char *ha_get_table_type(enum db_type db_type);
+const char *ha_get_storage_engine(enum db_type db_type);
handler *get_new_handler(TABLE *table, enum db_type db_type);
my_off_t ha_get_ptr(byte *ptr, uint pack_length);
void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos);
diff --git a/sql/item.cc b/sql/item.cc
index e4023afe8a7..acb2fdbb40a 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -54,7 +54,7 @@ Item::Item():
thd->free_list= this;
/*
Item constructor can be called during execution other then SQL_COM
- command => we should check thd->lex.current_select on zero (thd->lex
+ command => we should check thd->lex->current_select on zero (thd->lex
can be uninitialised)
*/
if (thd->lex->current_select)
@@ -102,6 +102,14 @@ void Item::print_item_w_name(String *str)
}
+Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
+ const char *field_name_par)
+ :db_name(db_name_par),table_name(table_name_par),field_name(field_name_par),
+ depended_from(0)
+{
+ name = (char*) field_name_par;
+}
+
// Constructor used by Item_field & Item_ref (see Item comment)
Item_ident::Item_ident(THD *thd, Item_ident &item):
Item(thd, item),
@@ -676,10 +684,10 @@ String *Item_param::val_str(String* str)
{
switch (item_result_type) {
case INT_RESULT:
- str->set(int_value, default_charset());
+ str->set(int_value, &my_charset_bin);
return str;
case REAL_RESULT:
- str->set(real_value, 2, default_charset());
+ str->set(real_value, 2, &my_charset_bin);
return str;
default:
return (String*) &str_value;
@@ -865,7 +873,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Item **refer= (Item **)not_found_item;
uint counter;
// Prevent using outer fields in subselects, that is not supported now
- SELECT_LEX *cursel=(SELECT_LEX *) thd->lex->current_select;
+ SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select;
if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
{
SELECT_LEX_UNIT *prev_unit= cursel->master_unit();
@@ -1764,12 +1772,11 @@ Item_result item_cmp_type(Item_result a,Item_result b)
{
if (a == STRING_RESULT && b == STRING_RESULT)
return STRING_RESULT;
- else if (a == INT_RESULT && b == INT_RESULT)
+ if (a == INT_RESULT && b == INT_RESULT)
return INT_RESULT;
else if (a == ROW_RESULT || b == ROW_RESULT)
return ROW_RESULT;
- else
- return REAL_RESULT;
+ return REAL_RESULT;
}
diff --git a/sql/item.h b/sql/item.h
index d8aea6552c3..4c6be932376 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -330,12 +330,8 @@ public:
const char *field_name;
st_select_lex *depended_from;
Item_ident(const char *db_name_par,const char *table_name_par,
- const char *field_name_par)
- :db_name(db_name_par), table_name(table_name_par),
- field_name(field_name_par), depended_from(0)
- { name = (char*) field_name_par; }
- // Constructor used by Item_field & Item_ref (see Item comment)
- Item_ident(THD *thd, Item_ident &item);
+ const char *field_name_par);
+ Item_ident::Item_ident(THD *thd, Item_ident &item);
const char *full_name() const;
bool remove_dependence_processor(byte * arg);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index bd88c79c8fb..a79ef21e97a 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1723,7 +1723,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (item->maybe_null)
maybe_null=1;
}
- thd->lex->current_select->cond_count+=list.elements;
+ thd->lex->current_select->cond_count+= list.elements;
fix_length_and_dec();
fixed= 1;
return 0;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index aa64cf52017..cccbf6e4226 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -72,7 +72,7 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
THD *thd=current_thd;
- thd->lex->safe_to_cache_query=0;
+ thd->lex->safe_to_cache_query= 0;
return new Item_int(NullS,(longlong)
((thd->slave_thread) ?
thd->variables.pseudo_thread_id :
@@ -144,7 +144,7 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
THD *thd=current_thd;
- thd->lex->safe_to_cache_query=0;
+ thd->lex->safe_to_cache_query= 0;
return new Item_int(NullS,(longlong) thd->found_rows(),21);
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 1552e3ec274..117ffcfca05 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -320,6 +320,7 @@ void Item_func::print_op(String *str)
str->append(')');
}
+
bool Item_func::eq(const Item *item, bool binary_cmp) const
{
/* Assume we don't have rtti */
@@ -375,8 +376,7 @@ String *Item_real_func::val_str(String *str)
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
- else
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals, &my_charset_bin);
return str;
}
@@ -388,18 +388,17 @@ String *Item_num_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
- else if (!unsigned_flag)
- str->set(nr,default_charset());
+ if (!unsigned_flag)
+ str->set(nr,&my_charset_bin);
else
- str->set((ulonglong) nr,default_charset());
+ str->set((ulonglong) nr,&my_charset_bin);
}
else
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
- else
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals,&my_charset_bin);
}
return str;
}
@@ -425,10 +424,10 @@ String *Item_int_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else if (!unsigned_flag)
- str->set(nr,default_charset());
+ if (!unsigned_flag)
+ str->set(nr,&my_charset_bin);
else
- str->set((ulonglong) nr,default_charset());
+ str->set((ulonglong) nr,&my_charset_bin);
return str;
}
@@ -454,18 +453,17 @@ String *Item_num_op::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
- else if (!unsigned_flag)
- str->set(nr,default_charset());
+ if (!unsigned_flag)
+ str->set(nr,&my_charset_bin);
else
- str->set((ulonglong) nr,default_charset());
+ str->set((ulonglong) nr,&my_charset_bin);
}
else
{
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
- else
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals,&my_charset_bin);
}
return str;
}
@@ -1035,10 +1033,10 @@ String *Item_func_min_max::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else if (!unsigned_flag)
- str->set(nr,default_charset());
+ if (!unsigned_flag)
+ str->set(nr,&my_charset_bin);
else
- str->set((ulonglong) nr,default_charset());
+ str->set((ulonglong) nr,&my_charset_bin);
return str;
}
case REAL_RESULT:
@@ -1046,8 +1044,7 @@ String *Item_func_min_max::val_str(String *str)
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
- else
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals,&my_charset_bin);
return str;
}
case STRING_RESULT:
@@ -1682,8 +1679,7 @@ String *Item_func_udf_float::val_str(String *str)
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
- else
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals,&my_charset_bin);
return str;
}
@@ -1703,10 +1699,10 @@ String *Item_func_udf_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else if (!unsigned_flag)
- str->set(nr,default_charset());
+ if (!unsigned_flag)
+ str->set(nr,&my_charset_bin);
else
- str->set((ulonglong) nr,default_charset());
+ str->set((ulonglong) nr,&my_charset_bin);
return str;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index d3cfaf63b5a..c2aa62ec2d7 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -660,25 +660,31 @@ public:
void fix_length_and_dec();
};
+/* Base class for all bit functions: '~', '|', '^', '&', '>>', '<<' */
-class Item_func_bit_or :public Item_int_func
+class Item_func_bit: public Item_int_func
{
public:
- Item_func_bit_or(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_func_bit(Item *a, Item *b) :Item_int_func(a, b) {}
+ Item_func_bit(Item *a) :Item_int_func(a) {}
+ void fix_length_and_dec() { unsigned_flag= 1; }
+ void print(String *str) { print_op(str); }
+};
+
+class Item_func_bit_or :public Item_func_bit
+{
+public:
+ Item_func_bit_or(Item *a, Item *b) :Item_func_bit(a, b) {}
longlong val_int();
const char *func_name() const { return "|"; }
- void fix_length_and_dec() { unsigned_flag=1; }
- void print(String *str) { print_op(str); }
};
-class Item_func_bit_and :public Item_int_func
+class Item_func_bit_and :public Item_func_bit
{
public:
- Item_func_bit_and(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_func_bit_and(Item *a, Item *b) :Item_func_bit(a, b) {}
longlong val_int();
const char *func_name() const { return "&"; }
- void fix_length_and_dec() { unsigned_flag=1; }
- void print(String *str) { print_op(str); }
};
class Item_func_bit_count :public Item_int_func
@@ -690,34 +696,32 @@ public:
void fix_length_and_dec() { max_length=2; }
};
-class Item_func_shift_left :public Item_int_func
+class Item_func_shift_left :public Item_func_bit
{
public:
- Item_func_shift_left(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_func_shift_left(Item *a, Item *b) :Item_func_bit(a, b) {}
longlong val_int();
const char *func_name() const { return "<<"; }
- void fix_length_and_dec() { unsigned_flag=1; }
- void print(String *str) { print_op(str); }
};
-class Item_func_shift_right :public Item_int_func
+class Item_func_shift_right :public Item_func_bit
{
public:
- Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_func_shift_right(Item *a, Item *b) :Item_func_bit(a, b) {}
longlong val_int();
const char *func_name() const { return ">>"; }
- void print(String *str) { print_op(str); }
};
-class Item_func_bit_neg :public Item_int_func
+class Item_func_bit_neg :public Item_func_bit
{
public:
- Item_func_bit_neg(Item *a) :Item_int_func(a) {}
+ Item_func_bit_neg(Item *a) :Item_func_bit(a) {}
longlong val_int();
const char *func_name() const { return "~"; }
- void fix_length_and_dec() { unsigned_flag=1; }
+ void print(String *str) { Item_func::print(str); }
};
+
class Item_func_set_last_insert_id :public Item_int_func
{
public:
@@ -1024,14 +1028,12 @@ public:
};
-class Item_func_bit_xor : public Item_int_func
+class Item_func_bit_xor : public Item_func_bit
{
public:
- Item_func_bit_xor(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_func_bit_xor(Item *a, Item *b) :Item_func_bit(a, b) {}
longlong val_int();
const char *func_name() const { return "^"; }
- void fix_length_xor_dec() { unsigned_flag=1; }
- void print(String *str) { print_op(str); }
};
class Item_func_is_free_lock :public Item_int_func
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index f40d38dd4a8..3cb03d7ea49 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1582,6 +1582,11 @@ Item_func_format::Item_func_format(Item *org,int dec) :Item_str_func(org)
}
+/*
+ TODO: This needs to be fixed for multi-byte character set where numbers
+ are stored in more than one byte
+*/
+
String *Item_func_format::val_str(String *str)
{
double nr =args[0]->val();
@@ -1590,7 +1595,8 @@ String *Item_func_format::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
dec= decimals ? decimals+1 : 0;
- str->set(nr,decimals,default_charset());
+ /* Here default_charset() is right as this is not an automatic conversion */
+ str->set(nr,decimals, default_charset());
#ifdef HAVE_ISNAN
if (isnan(nr))
return str;
@@ -1839,14 +1845,11 @@ inline String* alloc_buffer(String *res,String *str,String *tmp_value,
str->length(length);
return str;
}
- else
- {
- if (tmp_value->alloc(length))
- return 0;
- (void) tmp_value->copy(*res);
- tmp_value->length(length);
- return tmp_value;
- }
+ if (tmp_value->alloc(length))
+ return 0;
+ (void) tmp_value->copy(*res);
+ tmp_value->length(length);
+ return tmp_value;
}
res->length(length);
return res;
@@ -1947,7 +1950,7 @@ String *Item_func_rpad::val_str(String *str)
int32 count= (int32) args[1]->val_int();
int32 byte_count= count * collation.collation->mbmaxlen;
String *res =args[0]->val_str(str);
- String *rpad = args[2]->val_str(str);
+ String *rpad = args[2]->val_str(&rpad_str);
if (!res || args[1]->null_value || !rpad || count < 0)
goto err;
@@ -2384,6 +2387,10 @@ String* Item_func_export_set::val_str(String* str)
null_value=1;
return 0;
}
+ /*
+ Arg count can only be 3, 4 or 5 here. This is guaranteed from the
+ grammar for EXPORT_SET()
+ */
switch(arg_count) {
case 5:
num_set_values = (uint) args[4]->val_int();
@@ -2513,7 +2520,7 @@ String *Item_func_quote::val_str(String *str)
new_length= arg_length+2; /* for beginning and ending ' signs */
for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++)
- new_length+= get_esc_bit(escmask, *from);
+ new_length+= get_esc_bit(escmask, (uchar) *from);
/*
We have to use realloc() instead of alloc() as we want to keep the
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index a7949511f02..40b00cdd488 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -474,7 +474,7 @@ public:
class Item_func_rpad :public Item_str_func
{
- String tmp_value;
+ String tmp_value, rpad_str;
public:
Item_func_rpad(Item *arg1,Item *arg2,Item *arg3)
:Item_str_func(arg1,arg2,arg3) {}
@@ -486,7 +486,7 @@ public:
class Item_func_lpad :public Item_str_func
{
- String tmp_value;
+ String tmp_value, lpad_str;
public:
Item_func_lpad(Item *arg1,Item *arg2,Item *arg3)
:Item_str_func(arg1,arg2,arg3) {}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 6f5e2e492e7..43775e1c96c 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -344,7 +344,7 @@ void Item_singlerow_subselect::bring_value()
exec();
}
-double Item_singlerow_subselect::val ()
+double Item_singlerow_subselect::val()
{
if (!exec() && !value->null_value)
{
@@ -358,7 +358,7 @@ double Item_singlerow_subselect::val ()
}
}
-longlong Item_singlerow_subselect::val_int ()
+longlong Item_singlerow_subselect::val_int()
{
if (!exec() && !value->null_value)
{
@@ -466,7 +466,7 @@ void Item_exists_subselect::fix_length_and_dec()
max_columns= engine->cols();
}
-double Item_exists_subselect::val ()
+double Item_exists_subselect::val()
{
if (exec())
{
@@ -476,7 +476,7 @@ double Item_exists_subselect::val ()
return (double) value;
}
-longlong Item_exists_subselect::val_int ()
+longlong Item_exists_subselect::val_int()
{
if (exec())
{
@@ -493,11 +493,11 @@ String *Item_exists_subselect::val_str(String *str)
reset();
return 0;
}
- str->set(value,default_charset());
+ str->set(value,&my_charset_bin);
return str;
}
-double Item_in_subselect::val ()
+double Item_in_subselect::val()
{
if (exec())
{
@@ -510,7 +510,7 @@ double Item_in_subselect::val ()
return (double) value;
}
-longlong Item_in_subselect::val_int ()
+longlong Item_in_subselect::val_int()
{
if (exec())
{
@@ -536,7 +536,7 @@ String *Item_in_subselect::val_str(String *str)
null_value= 1;
return 0;
}
- str->set(value,default_charset());
+ str->set(value, &my_charset_bin);
return str;
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index a3d652d2fe1..3bc52159a96 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -140,7 +140,7 @@ Item_sum_num::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals, &my_charset_bin);
return str;
}
@@ -148,10 +148,13 @@ Item_sum_num::val_str(String *str)
String *
Item_sum_int::val_str(String *str)
{
- longlong nr=val_int();
+ longlong nr= val_int();
if (null_value)
return 0;
- str->set(nr,default_charset());
+ if (unsigned_flag)
+ str->set((ulonglong) nr, &my_charset_bin);
+ else
+ str->set(nr, &my_charset_bin);
return str;
}
@@ -262,6 +265,122 @@ double Item_sum_sum::val()
}
+/* Item_sum_sum_distinct */
+
+Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
+ :Item_sum_num(item), sum(0.0), tree(0)
+{
+ /*
+ quick_group is an optimizer hint, which means that GROUP BY can be
+ handled with help of index on grouped columns.
+ By setting quick_group to zero we force creation of temporary table
+ to perform GROUP BY.
+ */
+ quick_group= 0;
+}
+
+
+Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd,
+ Item_sum_sum_distinct &original)
+ :Item_sum_num(thd, original), sum(0.0), tree(0)
+{
+ quick_group= 0;
+}
+
+
+Item_sum_sum_distinct::~Item_sum_sum_distinct()
+{
+ delete tree;
+}
+
+
+Item *
+Item_sum_sum_distinct::copy_or_same(THD *thd)
+{
+ return new (&thd->mem_root) Item_sum_sum_distinct(thd, *this);
+}
+
+C_MODE_START
+
+static int simple_raw_key_cmp(void* arg, const void* key1, const void* key2)
+{
+ return memcmp(key1, key2, *(uint *) arg);
+}
+
+C_MODE_END
+
+bool Item_sum_sum_distinct::setup(THD *thd)
+{
+ SELECT_LEX *select_lex= thd->lex->current_select;
+ /* what does it mean??? */
+ if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
+ return 1;
+
+ DBUG_ASSERT(tree == 0); /* setup can not be called twice */
+
+ /*
+ Uniques handles all unique elements in a tree until they can't fit in.
+ Then thee tree is dumped to the temporary file.
+ See class Unique for details.
+ */
+ null_value= maybe_null= 1;
+ /*
+ TODO: if underlying item result fits in 4 bytes we can take advantage
+ of it and have tree of long/ulong. It gives 10% performance boost
+ */
+ static uint key_length= sizeof(double);
+ tree= new Unique(simple_raw_key_cmp, &key_length, key_length,
+ thd->variables.max_heap_table_size);
+ return tree == 0;
+}
+
+void Item_sum_sum_distinct::clear()
+{
+ DBUG_ASSERT(tree); /* we always have a tree */
+ null_value= 1;
+ tree->reset();
+}
+
+bool Item_sum_sum_distinct::add()
+{
+ /* args[0]->val() may reset args[0]->null_value */
+ double val= args[0]->val();
+ if (!args[0]->null_value)
+ {
+ DBUG_ASSERT(tree);
+ null_value= 0;
+ if (val)
+ return tree->unique_add(&val);
+ }
+ return 0;
+}
+
+C_MODE_START
+
+static int sum_sum_distinct(void *element, element_count num_of_dups,
+ void *item_sum_sum_distinct)
+{
+ ((Item_sum_sum_distinct *)
+ (item_sum_sum_distinct))->add(* (double *) element);
+ return 0;
+}
+
+C_MODE_END
+
+double Item_sum_sum_distinct::val()
+{
+ /*
+ We don't have a tree only if 'setup()' hasn't been called;
+ this is the case of sql_select.cc:return_zero_rows.
+ */
+ sum= 0.0;
+ if (tree)
+ tree->walk(sum_sum_distinct, (void *) this);
+ return sum;
+}
+
+/* end of Item_sum_sum_distinct */
+
Item *Item_sum_count::copy_or_same(THD* thd)
{
return new (&thd->mem_root) Item_sum_count(thd, *this);
@@ -474,13 +593,13 @@ Item_sum_hybrid::val_str(String *str)
case STRING_RESULT:
return &value;
case REAL_RESULT:
- str->set(sum,decimals,default_charset());
+ str->set(sum,decimals, &my_charset_bin);
break;
case INT_RESULT:
if (unsigned_flag)
- str->set((ulonglong) sum_int,default_charset());
+ str->set((ulonglong) sum_int, &my_charset_bin);
else
- str->set((longlong) sum_int,default_charset());
+ str->set((longlong) sum_int, &my_charset_bin);
break;
case ROW_RESULT:
default:
@@ -776,9 +895,16 @@ void Item_sum_avg::reset_field()
void Item_sum_bit::reset_field()
{
+ reset();
+ int8store(result_field->ptr, bits);
+}
+
+void Item_sum_bit::update_field()
+{
char *res=result_field->ptr;
- ulonglong nr=(ulonglong) args[0]->val_int();
- int8store(res,nr);
+ bits= uint8korr(res);
+ add();
+ int8store(res, bits);
}
/*
@@ -916,37 +1042,6 @@ Item_sum_hybrid::min_max_update_int_field()
}
-void Item_sum_or::update_field()
-{
- ulonglong nr;
- char *res=result_field->ptr;
-
- nr=uint8korr(res);
- nr|= (ulonglong) args[0]->val_int();
- int8store(res,nr);
-}
-
-void Item_sum_xor::update_field()
-{
- ulonglong nr;
- char *res=result_field->ptr;
-
- nr=uint8korr(res);
- nr^= (ulonglong) args[0]->val_int();
- int8store(res,nr);
-}
-
-void Item_sum_and::update_field()
-{
- ulonglong nr;
- char *res=result_field->ptr;
-
- nr=uint8korr(res);
- nr&= (ulonglong) args[0]->val_int();
- int8store(res,nr);
-}
-
-
Item_avg_field::Item_avg_field(Item_sum_avg *item)
{
name=item->name;
@@ -956,6 +1051,7 @@ Item_avg_field::Item_avg_field(Item_sum_avg *item)
maybe_null=1;
}
+
double Item_avg_field::val()
{
double nr;
@@ -978,7 +1074,7 @@ String *Item_avg_field::val_str(String *str)
double nr=Item_avg_field::val();
if (null_value)
return 0;
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals, &my_charset_bin);
return str;
}
@@ -1026,7 +1122,7 @@ String *Item_variance_field::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals, &my_charset_bin);
return str;
}
@@ -1036,11 +1132,6 @@ String *Item_variance_field::val_str(String *str)
#include "sql_select.h"
-int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
-{
- return memcmp(key1, key2, *(uint*) arg);
-}
-
int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
@@ -1415,8 +1506,7 @@ String *Item_sum_udf_float::val_str(String *str)
double nr=val();
if (null_value)
return 0; /* purecov: inspected */
- else
- str->set(nr,decimals,default_charset());
+ str->set(nr,decimals, &my_charset_bin);
return str;
}
@@ -1441,8 +1531,7 @@ String *Item_sum_udf_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else
- str->set(nr,default_charset());
+ str->set(nr, &my_charset_bin);
return str;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index d454f06ccde..afed152bb0e 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -27,9 +27,9 @@ class Item_sum :public Item_result_field
{
public:
enum Sumfunctype
- { COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
- MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
- UDF_SUM_FUNC, GROUP_CONCAT_FUNC
+ { COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
+ MIN_FUNC, MAX_FUNC, UNIQUE_USERS_FUNC, STD_FUNC, VARIANCE_FUNC,
+ SUM_BIT_FUNC, UDF_SUM_FUNC, GROUP_CONCAT_FUNC
};
Item **args,*tmp_args[2];
@@ -65,7 +65,18 @@ public:
inline bool reset() { clear(); return add(); };
virtual void clear()= 0;
virtual bool add()=0;
+ /*
+ Called when new group is started and results are being saved in
+ a temporary table. Similar to reset(), but must also store value in
+ result_field. Like reset() it is supposed to reset start value to
+ default.
+ */
virtual void reset_field()=0;
+ /*
+ Called for each new value in the group, when temporary table is in use.
+ Similar to add(), but uses temporary table field to obtain current value,
+ Updated value is then saved in the field.
+ */
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; }
@@ -138,6 +149,39 @@ class Item_sum_sum :public Item_sum_num
};
+/*
+ Item_sum_sum_distinct - SELECT SUM(DISTINCT expr) FROM ...
+ support. See also: MySQL manual, chapter 'Adding New Functions To MySQL'
+ and comments in item_sum.cc.
+*/
+
+class Unique;
+
+class Item_sum_sum_distinct :public Item_sum_num
+{
+ double sum;
+ Unique *tree;
+private:
+ Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct &item);
+public:
+ Item_sum_sum_distinct(Item *item_par);
+ ~Item_sum_sum_distinct();
+
+ bool setup(THD *thd);
+ void clear();
+ bool add();
+ double val();
+
+ inline void add(double val) { sum+= val; }
+ enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
+ void reset_field() {} // not used
+ void update_field() {} // not used
+ const char *func_name() const { return "sum_distinct"; }
+ Item *copy_or_same(THD* thd);
+ virtual void no_rows_in_result() {}
+};
+
+
class Item_sum_count :public Item_sum_int
{
longlong count;
@@ -445,10 +489,10 @@ public:
class Item_sum_bit :public Item_sum_int
{
- protected:
+protected:
ulonglong reset_bits,bits;
- public:
+public:
Item_sum_bit(Item *item_par,ulonglong reset_arg)
:Item_sum_int(item_par),reset_bits(reset_arg),bits(reset_arg) {}
Item_sum_bit(THD *thd, Item_sum_bit &item):
@@ -457,6 +501,7 @@ class Item_sum_bit :public Item_sum_int
void clear();
longlong val_int();
void reset_field();
+ void update_field();
void fix_length_and_dec()
{ decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
};
@@ -464,11 +509,10 @@ class Item_sum_bit :public Item_sum_int
class Item_sum_or :public Item_sum_bit
{
- public:
+public:
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();
const char *func_name() const { return "bit_or"; }
Item *copy_or_same(THD* thd);
};
@@ -477,10 +521,9 @@ class Item_sum_or :public Item_sum_bit
class Item_sum_and :public Item_sum_bit
{
public:
- Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {}
+ Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ULONGLONG_MAX) {}
Item_sum_and(THD *thd, Item_sum_and &item) :Item_sum_bit(thd, item) {}
bool add();
- void update_field();
const char *func_name() const { return "bit_and"; }
Item *copy_or_same(THD* thd);
};
@@ -491,7 +534,6 @@ class Item_sum_xor :public Item_sum_bit
Item_sum_xor(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_xor(THD *thd, Item_sum_xor &item) :Item_sum_bit(thd, item) {}
bool add();
- void update_field();
const char *func_name() const { return "bit_xor"; }
Item *copy_or_same(THD* thd);
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 7936006acc4..7d28cd10b81 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -526,8 +526,11 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
uint year;
if (type == TIMESTAMP_TIME)
return 1;
- length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year),
- intbuff, 10) - intbuff;
+ length= int10_to_str(calc_week(l_time,
+ (*ptr) == 'U' ?
+ WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST,
+ &year),
+ intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 2, '0');
}
break;
@@ -537,8 +540,12 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
uint year;
if (type == TIMESTAMP_TIME)
return 1;
- length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year),
- intbuff, 10) - intbuff;
+ length= int10_to_str(calc_week(l_time,
+ ((*ptr) == 'V' ?
+ (WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
+ (WEEK_YEAR | WEEK_MONDAY_FIRST)),
+ &year),
+ intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 2, '0');
}
break;
@@ -548,7 +555,11 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
uint year;
if (type == TIMESTAMP_TIME)
return 1;
- (void) calc_week(l_time, 1, (*ptr) == 'X', &year);
+ (void) calc_week(l_time,
+ ((*ptr) == 'X' ?
+ WEEK_YEAR | WEEK_FIRST_WEEKDAY :
+ WEEK_YEAR | WEEK_MONDAY_FIRST),
+ &year);
length= int10_to_str(year, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 4, '0');
}
@@ -718,27 +729,51 @@ longlong Item_func_second::val_int()
}
-/*
- Returns the week of year.
+uint week_mode(uint mode)
+{
+ uint week_format= (mode & 7);
+ if (!(week_format & WEEK_MONDAY_FIRST))
+ week_format^= WEEK_FIRST_WEEKDAY;
+ return week_format;
+}
- The bits in week_format has the following meaning:
- 0 If not set: USA format: Sunday is first day of week
- If set: ISO format: Monday is first day of week
- 1 If not set: Week is in range 0-53
- If set Week is in range 1-53.
+/*
+ The bits in week_format(for calc_week() function) has the following meaning:
+ WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
+ If set Monday is first day of week
+ WEEK_YEAR (1) If not set Week is in range 0-53
+
+ Week 0 is returned for the the last week of the previous year (for
+ a date at start of january) In this case one can get 53 for the
+ first week of next year. This flag ensures that the week is
+ relevant for the given year. Note that this flag is only
+ releveant if WEEK_JANUARY is not set.
+
+ If set Week is in range 1-53.
+
+ In this case one may get week 53 for a date in January (when
+ the week is that last week of previous year) and week 1 for a
+ date in December.
+
+ WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
+ to ISO 8601:1988
+ If set The week that contains the first
+ 'first-day-of-week' is week 1.
+
+ ISO 8601:1988 means that if the week containing January 1 has
+ four or more days in the new year, then it is week 1;
+ Otherwise it is the last week of the previous year, and the
+ next week is week 1.
*/
longlong Item_func_week::val_int()
{
uint year;
- uint week_format;
TIME ltime;
if (get_arg0_date(&ltime,0))
return 0;
- week_format= (uint) args[1]->val_int();
- return (longlong) calc_week(&ltime,
- (week_format & 2) != 0,
- (week_format & 1) == 0,
+ return (longlong) calc_week(&ltime,
+ week_mode((uint) args[1]->val_int()),
&year);
}
@@ -749,7 +784,9 @@ longlong Item_func_yearweek::val_int()
TIME ltime;
if (get_arg0_date(&ltime,0))
return 0;
- week=calc_week(&ltime, 1, (args[1]->val_int() & 1) == 0, &year);
+ week= calc_week(&ltime,
+ (week_mode((uint) args[1]->val_int()) | WEEK_YEAR),
+ &year);
return week+year*100;
}
@@ -1721,10 +1758,7 @@ longlong Item_extract::val_int()
case INTERVAL_WEEK:
{
week_format= current_thd->variables.default_week_format;
- return calc_week(&ltime,
- (week_format & 2) != 0,
- (week_format & 1) == 0,
- &year);
+ return calc_week(&ltime, week_mode(week_format), &year);
}
case INTERVAL_DAY: return ltime.day;
case INTERVAL_DAY_HOUR: return (long) (ltime.day*100L+ltime.hour)*neg;
diff --git a/sql/lex.h b/sql/lex.h
index 7f7a27289b1..114e1a6b960 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -156,6 +156,7 @@ static SYMBOL symbols[] = {
{ "ENCLOSED", SYM(ENCLOSED),0,0},
{ "END", SYM(END),0,0},
{ "ENGINE", SYM(ENGINE_SYM),0,0},
+ { "ENGINES", SYM(ENGINES_SYM),0,0},
{ "ENUM", SYM(ENUM),0,0},
{ "ERRORS", SYM(ERRORS),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
@@ -421,6 +422,7 @@ static SYMBOL symbols[] = {
{ "STARTING", SYM(STARTING),0,0},
{ "STATUS", SYM(STATUS_SYM),0,0},
{ "STOP", SYM(STOP_SYM),0,0},
+ { "STORAGE", SYM(STORAGE_SYM),0,0},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0},
{ "STRING", SYM(STRING_SYM),0,0},
{ "STRIPED", SYM(RAID_STRIPED_SYM),0,0},
diff --git a/sql/log.cc b/sql/log.cc
index 95ee4928971..59bc7c7fae2 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -964,7 +964,7 @@ void MYSQL_LOG::new_file(bool need_lock)
We log the whole file name for log file as the user may decide
to change base names at some point.
*/
- THD* thd = current_thd;
+ THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
Rotate_log_event r(thd,new_name+dirname_length(new_name));
r.set_log_pos(this);
r.write(&log_file);
@@ -1231,8 +1231,6 @@ bool MYSQL_LOG::write(Log_event* event_info)
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
thd->current_insert_id);
e.set_log_pos(this);
- if (thd->server_id)
- e.server_id = thd->server_id;
if (e.write(file))
goto err;
}
@@ -1240,8 +1238,6 @@ bool MYSQL_LOG::write(Log_event* event_info)
{
Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id);
e.set_log_pos(this);
- if (thd->server_id)
- e.server_id = thd->server_id;
if (e.write(file))
goto err;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8c93a22cf6e..ca1b296009d 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -239,6 +239,13 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
}
+/*
+ This minimal constructor is for when you are not even sure that there is a
+ valid THD. For example in the server when we are shutting down or flushing
+ logs after receiving a SIGHUP (then we must write a Rotate to the binlog but
+ we have no THD, so we need this minimal constructor).
+*/
+
Log_event::Log_event()
:temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0),
thd(0)
@@ -1032,7 +1039,7 @@ Default database: '%s'",
thd->variables.convert_set = 0;
#endif
close_thread_tables(thd);
- free_root(&thd->mem_root,0);
+ free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
return (thd->query_error ? thd->query_error : Log_event::exec_event(rli));
}
#endif
@@ -1794,10 +1801,10 @@ Slave: load data infile on table '%s' at log position %s in log \
slave_print_error(rli,sql_errno,"\
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);
+ free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
return 1;
}
- free_root(&thd->mem_root,0);
+ free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
if (thd->is_fatal_error)
{
diff --git a/sql/log_event.h b/sql/log_event.h
index 6cc8a7ca06d..d615c0e361b 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -698,7 +698,7 @@ public:
#ifndef MYSQL_CLIENT
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
- :Log_event(),val(val_arg),type(type_arg)
+ :Log_event(thd_arg,0,0),val(val_arg),type(type_arg)
{}
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
@@ -841,7 +841,7 @@ public:
Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg,
uint ident_len_arg = 0,
ulonglong pos_arg = LOG_EVENT_OFFSET)
- :Log_event(thd_arg,0,0), new_log_ident(new_log_ident_arg),
+ :Log_event(), new_log_ident(new_log_ident_arg),
pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
(uint) strlen(new_log_ident_arg)), alloced(0)
{}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index e827e79af48..839a1f5f4a8 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -303,6 +303,11 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
#define tmp_file_prefix "#sql" /* Prefix for tmp tables */
#define tmp_file_prefix_length 4
+/* Flags for calc_week() function. */
+#define WEEK_MONDAY_FIRST 1
+#define WEEK_YEAR 2
+#define WEEK_FIRST_WEEKDAY 4
+
struct st_table;
class THD;
@@ -438,6 +443,7 @@ int mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
+bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
#ifndef EMBEDDED_LIBRARY
bool check_stack_overrun(THD *thd,char *dummy);
#else
@@ -451,17 +457,11 @@ void kill_mysql(void);
void close_connection(THD *thd, uint errcode, bool lock);
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
bool *write_to_binlog);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv,
bool no_grant, bool no_errors);
bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
bool no_errors);
bool check_global_access(THD *thd, ulong want_access);
-#else
-#define check_access(thd, access, db, save_priv, no_grant, no_errors) false
-#define check_table_access(thd, want_access, tables, no_errors) false
-#define check_global_access(thd, want_access) false
-#endif
int mysql_backup_table(THD* thd, TABLE_LIST* table_list);
int mysql_restore_table(THD* thd, TABLE_LIST* table_list);
@@ -626,7 +626,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
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);
+int mysqld_show_storage_engines(THD *thd);
int mysqld_show_privileges(THD *thd);
int mysqld_show_column_types(THD *thd);
int mysqld_help (THD *thd, const char *text);
@@ -997,8 +997,7 @@ void filesort_free_buffers(TABLE *table);
void change_double_for_sort(double nr,byte *to);
int get_quick_record(SQL_SELECT *select);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
-uint calc_week(TIME *ltime, bool with_year, bool sunday_first_day_of_week,
- uint *year);
+uint calc_week(TIME *l_time, uint week_behaviour, uint *year);
void find_date(char *pos,uint *vek,uint flag);
TYPELIB *convert_strings_to_array_type(my_string *typelibs, my_string *end);
TYPELIB *typelib(List<String> &strings);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 7b3d8411e32..6e286dcd01e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -500,6 +500,8 @@ static uint set_maximum_open_files(uint max_file_limit);
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
static void clean_up(bool print_message);
static void clean_up_mutexes(void);
+static int test_if_case_insensitive(const char *dir_name);
+static void create_pid_file();
#ifndef EMBEDDED_LIBRARY
/****************************************************************************
@@ -1061,7 +1063,7 @@ static void set_user(const char *user)
}
return;
}
- else if (!user)
+ if (!user)
{
if (!opt_bootstrap)
{
@@ -1276,7 +1278,7 @@ static void server_init(void)
void yyerror(const char *s)
{
THD *thd=current_thd;
- char *yytext=(char*) thd->lex->tok_start;
+ char *yytext= (char*) thd->lex->tok_start;
/* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
s=ER(ER_SYNTAX_ERROR);
@@ -1483,16 +1485,7 @@ static void start_signal_handler(void)
{
// Save vm id of this process
if (!opt_bootstrap)
- {
- File pidFile;
- if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0)
- {
- char buff[21];
- sprintf(buff,"%lu",(ulong) getpid());
- (void) my_write(pidFile, buff,strlen(buff),MYF(MY_WME));
- (void) my_close(pidFile,MYF(0));
- }
- }
+ create_pid_file();
// no signal handler
}
@@ -1778,16 +1771,8 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
/* Save pid to this process (or thread on Linux) */
if (!opt_bootstrap)
- {
- File pidFile;
- if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0)
- {
- char buff[21];
- ulong length= my_sprintf(buff, (buff,"%lu",(ulong) getpid()));
- (void) my_write(pidFile, buff, length, MYF(MY_WME));
- (void) my_close(pidFile,MYF(0));
- }
- }
+ create_pid_file();
+
#ifdef HAVE_STACK_TRACE_ON_SEGV
if (opt_do_pstack)
{
@@ -1900,7 +1885,7 @@ extern "C" int my_message_sql(uint error, const char *str,
DBUG_RETURN(0);
}
/*
- thd->lex.current_select == 0 if lex structure is not inited
+ thd->lex->current_select == 0 if lex structure is not inited
(not query command (COM_QUERY))
*/
if (thd->lex->current_select &&
@@ -2809,7 +2794,7 @@ default_service_handling(char **argv,
}
/* We must have servicename last */
*pos++= ' ';
- strmake(pos, servicename, (uint) (end+2 - pos));
+ (void) add_quoted_string(pos, servicename, end);
if (Service.got_service_option(argv, "install"))
{
@@ -3600,7 +3585,7 @@ enum options_mysqld
OPT_SKIP_HOST_CACHE, OPT_SHORT_LOG_FORMAT,
OPT_FLUSH, OPT_SAFE,
OPT_BOOTSTRAP, OPT_SKIP_SHOW_DB,
- OPT_TABLE_TYPE, OPT_INIT_FILE,
+ OPT_STORAGE_ENGINE, OPT_INIT_FILE,
OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
OPT_BDB_HOME, OPT_BDB_LOG,
@@ -3809,8 +3794,11 @@ Disable with --skip-bdb (will save memory).",
{"default-collation", OPT_DEFAULT_COLLATION, "Set the default collation.",
(gptr*) &default_collation_name, (gptr*) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"default-table-type", OPT_TABLE_TYPE,
- "Set the default table type for tables.", 0, 0,
+ {"default-storage-engine", OPT_STORAGE_ENGINE,
+ "Set the default storage engine (table tyoe) for tables.", 0, 0,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"default-table-type", OPT_STORAGE_ENGINE,
+ "(deprecated) Use default-storage-engine.", 0, 0,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"delay-key-write", OPT_DELAY_KEY_WRITE, "Type of DELAY_KEY_WRITE.",
0,0,0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
@@ -4646,7 +4634,7 @@ The minimum value for this variable is 4096.",
1, 0},
{"table_cache", OPT_TABLE_CACHE,
"The number of open tables for all threads.", (gptr*) &table_cache_size,
- (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 16384, 0, 1,
+ (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, ~0L, 0, 1,
0},
{"thread_concurrency", OPT_THREAD_CONCURRENCY,
"Permits the application to give the threads system a hint for the desired number of threads that should be run at the same time.",
@@ -4664,7 +4652,7 @@ The minimum value for this variable is 4096.",
{"thread_stack", OPT_THREAD_STACK,
"The stack size for each thread.", (gptr*) &thread_stack,
(gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
- 1024*32, ~0L, 0, 1024, 0},
+ 1024L*128L, ~0L, 0, 1024, 0},
{"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE,
"Allocation block size for transactions to be stored in binary log",
(gptr*) &global_system_variables.trans_alloc_block_size,
@@ -4689,7 +4677,7 @@ The minimum value for this variable is 4096.",
"The default week format used by WEEK() functions.",
(gptr*) &global_system_variables.default_week_format,
(gptr*) &max_system_variables.default_week_format,
- 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0},
+ 0, GET_ULONG, REQUIRED_ARG, 0, 0, 7L, 0, 1, 0},
{ "date-format", OPT_DATE_FORMAT,
"The DATE format (For future).",
(gptr*) &opt_date_time_formats[TIMESTAMP_DATE],
@@ -4788,8 +4776,8 @@ struct show_var_st status_vars[]= {
{"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
{"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
{"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
+ {"Com_show_storage_engines", (char*) (com_stat+(uint) SQLCOM_SHOW_STORAGE_ENGINES),SHOW_LONG},
{"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
- {"Com_show_table_types", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLE_TYPES),SHOW_LONG},
{"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
{"Com_show_warnings", (char*) (com_stat+(uint) SQLCOM_SHOW_WARNS),SHOW_LONG},
{"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
@@ -5427,11 +5415,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
my_use_symdir=0;
break;
case (int) OPT_BIND_ADDRESS:
- if (!argument ||
- (my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE)
+ if ((my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE)
{
struct hostent *ent;
- if (argument || argument[0])
+ if (argument[0])
ent=gethostbyname(argument);
else
{
@@ -5476,7 +5463,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case OPT_BOOTSTRAP:
opt_noacl=opt_bootstrap=1;
break;
- case OPT_TABLE_TYPE:
+ case OPT_STORAGE_ENGINE:
{
if ((enum db_type)((global_system_variables.table_type=
ha_resolve_by_name(argument, strlen(argument)))) == DB_TYPE_UNKNOWN)
@@ -5841,6 +5828,18 @@ static void fix_paths(void)
exit(1);
}
#endif /* HAVE_REPLICATION */
+
+ /*
+ Ensure that lower_case_table_names is set on system where we have case
+ insensitive names. If this is not done the users MyISAM tables will
+ get corrupted if accesses with names of different case.
+ */
+ if (!lower_case_table_names &&
+ test_if_case_insensitive(mysql_real_data_home) == 1)
+ {
+ sql_print_error("Warning: Setting lower_case_table_names=1 becasue file system %s is case insensitive", mysql_real_data_home);
+ lower_case_table_names= 1;
+ }
}
@@ -5994,6 +5993,61 @@ skipp: ;
} /* find_bit_type */
+/*
+ Check if file system used for databases is case insensitive
+
+ SYNOPSIS
+ test_if_case_sensitive()
+ dir_name Directory to test
+
+ RETURN
+ -1 Don't know (Test failed)
+ 0 File system is case sensitive
+ 1 File system is case insensitive
+*/
+
+static int test_if_case_insensitive(const char *dir_name)
+{
+ int result= 0;
+ File file;
+ char buff[FN_REFLEN], buff2[FN_REFLEN];
+ MY_STAT stat_info;
+
+ fn_format(buff, glob_hostname, dir_name, ".lower-test",
+ MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR);
+ fn_format(buff2, glob_hostname, dir_name, ".LOWER-TEST",
+ MY_UNPACK_FILENAME | MY_REPLACE_EXT | MY_REPLACE_DIR);
+ (void) my_delete(buff2, MYF(0));
+ if ((file= my_create(buff, 0666, O_RDWR, MYF(0))) < 0)
+ {
+ sql_print_error("Warning: Can't create test file %s", buff);
+ return -1;
+ }
+ my_close(file, MYF(0));
+ if (my_stat(buff2, &stat_info, MYF(0)))
+ result= 1; // Can access file
+ (void) my_delete(buff, MYF(MY_WME));
+ return result;
+}
+
+
+/* Create file to store pid number */
+
+static void create_pid_file()
+{
+ File file;
+ if ((file = my_create(pidfile_name,0664,
+ O_WRONLY | O_TRUNC, MYF(MY_WME))) >= 0)
+ {
+ char buff[21], *end;
+ end= int2str((long) getpid(), buff, 10);
+ *end++= '\n';
+ (void) my_write(file, (byte*) buff, (uint) (end-buff),MYF(MY_WME));
+ (void) my_close(file, MYF(0));
+ }
+}
+
+
/*****************************************************************************
Instantiate templates
*****************************************************************************/
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 0120ad80c0a..5e5d4b14c89 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -54,6 +54,12 @@
#ifdef EMBEDDED_LIBRARY
+#undef MYSQL_SERVER
+
+#ifndef MYSQL_CLIENT
+#define MYSQL_CLIENT
+#endif
+
#undef net_flush
extern "C" {
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index 25fc010d9a5..3e9d68d5fdb 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -496,9 +496,9 @@ BOOL NTService::IsService(LPCSTR ServiceName)
BOOL ret_value=FALSE;
SC_HANDLE service, scm;
- if (scm = OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE))
+ if ((scm= OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE)))
{
- if ((service = OpenService(scm,ServiceName, SERVICE_ALL_ACCESS )))
+ if ((service = OpenService(scm,ServiceName, SERVICE_QUERY_STATUS )))
{
ret_value=TRUE;
CloseServiceHandle(service);
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3a5278bdfac..8bba9382f85 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1699,9 +1699,10 @@ static SEL_ARG *
get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
Item_func::Functype type,Item *value)
{
- uint maybe_null=(uint) field->real_maybe_null();
+ uint maybe_null=(uint) field->real_maybe_null(), copies;
uint field_length=field->pack_length()+maybe_null;
SEL_ARG *tree;
+ char *str, *str2;
DBUG_ENTER("get_mm_leaf");
if (type == Item_func::LIKE_FUNC)
@@ -1802,16 +1803,38 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
/* This happens when we try to insert a NULL field in a not null column */
DBUG_RETURN(&null_element); // cmp with NULL is never true
}
- // Get local copy of key
- char *str= (char*) alloc_root(param->mem_root,
- key_part->part_length+maybe_null);
+ /* Get local copy of key */
+ copies= 1;
+ if (field->key_type() == HA_KEYTYPE_VARTEXT)
+ copies= 2;
+ str= str2= (char*) alloc_root(param->mem_root,
+ (key_part->part_length+maybe_null)*copies+1);
if (!str)
DBUG_RETURN(0);
if (maybe_null)
*str= (char) field->is_real_null(); // Set to 1 if null
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)))
+ if (copies == 2)
+ {
+ /*
+ The key is stored as 2 byte length + key
+ key doesn't match end space. In other words, a key 'X ' should match
+ all rows between 'X' and 'X ...'
+ */
+ uint length= uint2korr(str+maybe_null);
+ str2= str+ key_part->part_length + maybe_null;
+ /* remove end space */
+ while (length > 0 && str[length+HA_KEY_BLOB_LENGTH+maybe_null-1] == ' ')
+ length--;
+ int2store(str+maybe_null, length);
+ /* Create key that is space filled */
+ memcpy(str2, str, length + HA_KEY_BLOB_LENGTH + maybe_null);
+ bfill(str2+ length+ HA_KEY_BLOB_LENGTH +maybe_null,
+ key_part->part_length-length - HA_KEY_BLOB_LENGTH, ' ');
+ int2store(str2+maybe_null, key_part->part_length - HA_KEY_BLOB_LENGTH);
+ }
+ if (!(tree=new SEL_ARG(field,str,str2)))
DBUG_RETURN(0); // out of memory
switch (type) {
@@ -2279,7 +2302,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
}
return 0;
}
- else if (!key2)
+ if (!key2)
{
key1->use_count--;
key1->free_tree();
@@ -3038,7 +3061,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
param->range_count++;
if (!tmp_min_flag && ! tmp_max_flag &&
(uint) key_tree->part+1 == param->table->key_info[keynr].key_parts &&
- (param->table->key_info[keynr].flags & HA_NOSAME) &&
+ (param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
+ HA_NOSAME &&
min_key_length == max_key_length &&
!memcmp(param->min_key,param->max_key,min_key_length))
tmp=1; // Max one record
@@ -3194,7 +3218,8 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
KEY *table_key=quick->head->key_info+quick->index;
flag=EQ_RANGE;
- if (table_key->flags & HA_NOSAME && key->part == table_key->key_parts-1)
+ if ((table_key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME &&
+ key->part == table_key->key_parts-1)
{
if (!(table_key->flags & HA_NULL_PART_KEY) ||
!null_part_in_key(key,
@@ -3242,7 +3267,7 @@ bool QUICK_RANGE_SELECT::unique_key_range()
if ((tmp->flag & (EQ_RANGE | NULL_RANGE)) == EQ_RANGE)
{
KEY *key=head->key_info+index;
- return ((key->flags & HA_NOSAME) &&
+ return ((key->flags & (HA_NOSAME | HA_END_SPACE_KEY)) == HA_NOSAME &&
key->key_length == tmp->min_length);
}
}
@@ -3278,6 +3303,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
QUICK_RANGE_SELECT *quick=new QUICK_RANGE_SELECT(thd, table, ref->key, 1);
KEY *key_info = &table->key_info[ref->key];
KEY_PART *key_part;
+ QUICK_RANGE *range;
uint part;
if (!quick)
@@ -3291,17 +3317,17 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
if (cp_buffer_from_ref(ref))
{
if (thd->is_fatal_error)
- return 0; // out of memory
+ goto err; // out of memory
}
- QUICK_RANGE *range= new QUICK_RANGE();
- if (!range)
+ if (!(range= new QUICK_RANGE()))
goto err; // out of memory
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
range->flag= ((ref->key_length == key_info->key_length &&
- (key_info->flags & HA_NOSAME)) ? EQ_RANGE : 0);
+ (key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
+ HA_NOSAME) ? EQ_RANGE : 0);
if (!(quick->key_parts=key_part=(KEY_PART *)
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
diff --git a/sql/records.cc b/sql/records.cc
index b29b113a1bc..cd1de5af6aa 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -118,11 +118,12 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
info->read_record=rr_sequential;
table->file->rnd_init();
/* We can use record cache if we don't update dynamic length tables */
- if (use_record_cache > 0 ||
- (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
- !(table->db_options_in_use & HA_OPTION_PACK_RECORD) ||
- (use_record_cache < 0 &&
- !(table->file->table_flags() & HA_NOT_DELETE_WITH_CACHE)))
+ if (!table->no_cache &&
+ (use_record_cache > 0 ||
+ (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY ||
+ !(table->db_options_in_use & HA_OPTION_PACK_RECORD) ||
+ (use_record_cache < 0 &&
+ !(table->file->table_flags() & HA_NOT_DELETE_WITH_CACHE))))
VOID(table->file->extra_opt(HA_EXTRA_CACHE,
thd->variables.read_buff_size));
}
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 0efe57af0b0..81ea9d9e2ac 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -52,6 +52,13 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
const char* log_file_name,
char* errmsg);
+/*
+ All of the functions defined in this file which are not used (the ones to
+ handle failsafe) are not used; their code has not been updated for more than
+ one year now so should be considered as BADLY BROKEN. Do not enable it.
+ The used functions (to handle LOAD DATA FROM MASTER, plus some small
+ functions like register_slave()) are working.
+*/
static int init_failsafe_rpl_thread(THD* thd)
{
@@ -418,7 +425,6 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Could not find slave event in log '%s'",
(char*)log_file_name);
- delete ev;
return 0;
}
@@ -435,7 +441,7 @@ int show_new_master(THD* thd)
DBUG_ENTER("show_new_master");
List<Item> field_list;
char errmsg[SLAVE_ERRMSG_SIZE];
- LEX_MASTER_INFO* lex_mi = &thd->lex->mi;
+ LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
errmsg[0]=0; // Safety
if (translate_master(thd, lex_mi, errmsg))
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 092533a49e2..4cf9f07b4ba 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -295,6 +295,8 @@ sys_var_thd_sql_mode sys_sql_mode("sql_mode",
&SV::sql_mode);
sys_var_thd_table_type sys_table_type("table_type",
&SV::table_type);
+sys_var_thd_storage_engine sys_storage_engine("storage_engine",
+ &SV::table_type);
sys_var_long_ptr sys_table_cache_size("table_cache",
&table_cache_size);
sys_var_long_ptr sys_thread_cache_size("thread_cache_size",
@@ -527,6 +529,7 @@ sys_var *sys_variables[]=
&sys_sql_max_join_size,
&sys_sql_mode,
&sys_sql_warnings,
+ &sys_storage_engine,
&sys_table_cache_size,
&sys_table_type,
&sys_thread_cache_size,
@@ -732,6 +735,7 @@ struct show_var_st init_vars[]= {
#endif
{sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS},
{sys_sql_mode.name, (char*) &sys_sql_mode, SHOW_SYS},
+ {sys_storage_engine.name, (char*) &sys_storage_engine, SHOW_SYS},
{"table_cache", (char*) &table_cache_size, SHOW_LONG},
{sys_table_type.name, (char*) &sys_table_type, SHOW_SYS},
{sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS},
@@ -788,9 +792,8 @@ bool update_sys_var_str(sys_var_str *var_str, rw_lock_t *var_mutex,
/* If the string is "", delete old init command */
if (var && (new_length= var->value->str_value.length()))
{
- if (!(res= my_strdup_with_length(var->value->str_value.ptr(),
- new_length,
- MYF(0))))
+ if (!(res= my_strdup_with_length((byte*) var->value->str_value.ptr(),
+ new_length, MYF(0))))
return 1;
}
/*
@@ -2510,7 +2513,7 @@ int set_var_password::update(THD *thd)
/* Based upon sys_var::check_enum() */
-bool sys_var_thd_table_type::check(THD *thd, set_var *var)
+bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
{
char buff[80];
const char *value;
@@ -2527,25 +2530,26 @@ bool sys_var_thd_table_type::check(THD *thd, set_var *var)
}
return 0;
}
+ value= "unknown";
err:
- my_error(ER_UNKNOWN_TABLE_ENGINE, MYF(0), value);
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), value);
return 1;
}
-byte *sys_var_thd_table_type::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
+byte *sys_var_thd_storage_engine::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
{
ulong val;
val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
thd->variables.*offset);
- const char *table_type= ha_get_table_type((enum db_type)val);
+ const char *table_type= ha_get_storage_engine((enum db_type)val);
return (byte *) table_type;
}
-void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type)
+void sys_var_thd_storage_engine::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
global_system_variables.*offset= (ulong) DB_TYPE_MYISAM;
@@ -2554,7 +2558,7 @@ void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type)
}
-bool sys_var_thd_table_type::update(THD *thd, set_var *var)
+bool sys_var_thd_storage_engine::update(THD *thd, set_var *var)
{
if (var->type == OPT_GLOBAL)
global_system_variables.*offset= var->save_result.ulong_value;
@@ -2563,6 +2567,25 @@ bool sys_var_thd_table_type::update(THD *thd, set_var *var)
return 0;
}
+void sys_var_thd_table_type::warn_deprecated(THD *thd)
+{
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER(ER_WARN_DEPRECATED_SYNTAX), "table_type", "storage_engine");
+}
+
+void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type)
+{
+ warn_deprecated(thd);
+ sys_var_thd_storage_engine::set_default(thd, type);
+}
+
+bool sys_var_thd_table_type::update(THD *thd, set_var *var)
+{
+ warn_deprecated(thd);
+ return sys_var_thd_storage_engine::update(thd, var);
+}
+
/****************************************************************************
Functions to handle sql_mode
diff --git a/sql/set_var.h b/sql/set_var.h
index fc7610ee500..85871c90ebb 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -344,12 +344,12 @@ public:
};
-class sys_var_thd_table_type :public sys_var_thd
+class sys_var_thd_storage_engine :public sys_var_thd
{
protected:
ulong SV::*offset;
public:
- sys_var_thd_table_type(const char *name_arg, ulong SV::*offset_arg)
+ sys_var_thd_storage_engine(const char *name_arg, ulong SV::*offset_arg)
:sys_var_thd(name_arg), offset(offset_arg)
{}
bool check(THD *thd, set_var *var);
@@ -363,6 +363,16 @@ SHOW_TYPE type() { return SHOW_CHAR; }
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
+class sys_var_thd_table_type :public sys_var_thd_storage_engine
+{
+public:
+ sys_var_thd_table_type(const char *name_arg, ulong SV::*offset_arg)
+ :sys_var_thd_storage_engine(name_arg, offset_arg)
+ {}
+ void warn_deprecated(THD *thd);
+ void set_default(THD *thd, enum_var_type type);
+ bool update(THD *thd, set_var *var);
+};
class sys_var_thd_bit :public sys_var_thd
{
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 94ed6410f30..ae040fd92ac 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -213,7 +213,7 @@ character-set=latin2
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -272,8 +272,8 @@ character-set=latin2
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 8e2e4fac919..b7f947d346e 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -266,8 +266,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 8f8d5dcabfb..9e2bb859a45 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -274,8 +274,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 9750b47ab7f..cffbdeeeca2 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -204,7 +204,7 @@ character-set=latin1
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -263,8 +263,8 @@ character-set=latin1
"ZLIB: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"ZLIB: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index ed45006ad0d..34158b491b2 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -209,7 +209,7 @@ character-set=latin7
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"Kasutajal %-.64s on juba rohkem ühendusi kui lubatud 'max_user_connections' muutujaga",
"Ainult konstantsed suurused on lubatud SET klauslis",
@@ -268,8 +268,8 @@ character-set=latin7
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 84ae6d995cf..9a2b3a5ec6a 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -204,7 +204,7 @@ character-set=latin1
"Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord",
"Cette opération nécessite un esclave actif, configurez les esclaves et faites START SLAVE",
"Le server n'est pas configuré comme un esclave, changez le fichier de configuration ou utilisez CHANGE MASTER TO",
-"Impossible d'initialiser les structures d'information de maître, vérifiez les permissions sur master.info",
+"Impossible d'initialiser les structures d'information de maître, vous trouverez des messages d'erreur supplémentaires dans le journal des erreurs de MySQL",
"Impossible de créer une tâche esclave, vérifiez les ressources système",
"L'utilisateur %-.64s possède déjà plus de 'max_user_connections' connections actives",
"Seules les expressions constantes sont autorisées avec SET",
@@ -263,8 +263,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 94b9476b0ff..95c00ec2dd9 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -204,7 +204,7 @@ character-set=greek
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -263,8 +263,8 @@ character-set=greek
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 67a20b1c63b..4a10797e1d1 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -206,7 +206,7 @@ character-set=latin2
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -265,8 +265,8 @@ character-set=latin2
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index b2186baf558..2b8a7ea5632 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -263,8 +263,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index aea9c84b6e6..752ed402190 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -206,7 +206,7 @@ character-set=ujis
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -265,8 +265,8 @@ character-set=ujis
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 69bf4043b44..8d98d5cb610 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -204,7 +204,7 @@ character-set=euckr
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -263,8 +263,8 @@ character-set=euckr
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 8abc62814ca..f1dd2cb8371 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -206,7 +206,7 @@ character-set=latin1
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -265,8 +265,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index ed4540c377d..44705db0af5 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -206,7 +206,7 @@ character-set=latin1
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -265,8 +265,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index d0891a8080d..622e127dc5e 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -208,7 +208,7 @@ character-set=latin2
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -267,8 +267,8 @@ character-set=latin2
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 341747620d9..a37f29b8a33 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -208,7 +208,7 @@ character-set=latin2
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -267,8 +267,8 @@ character-set=latin2
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 61c03f2f960..2dbe6b9184c 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -265,8 +265,8 @@ character-set=koi8r
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index ef9ffab981b..97bef4e1714 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -258,8 +258,8 @@ character-set=cp1250
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index daf9e0bd200..e841214ba1c 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -212,7 +212,7 @@ character-set=latin2
"This operation cannot be performed with a running slave, run STOP SLAVE first",
"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
-"Could not initialize master info structure, check permisions on master.info",
+"Could not initialize master info structure, more error messages can be found in the MySQL error log",
"Could not create slave thread, check system resources",
"User %-.64s has already more than 'max_user_connections' active connections",
"You may only use constant expressions with SET",
@@ -271,8 +271,8 @@ character-set=latin2
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 9acc80a2211..cdabd339e1e 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -265,8 +265,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index d8e3291a9f6..aab70294ec8 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -263,8 +263,8 @@ character-set=latin1
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d rad(er) kapades av group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index a336eb3e159..828c0a46cad 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -268,8 +268,8 @@ character-set=koi8u
"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
-"Record count is fewer than the column count at row %ld",
-"Record count is more than the column count at row %ld",
+"Row %ld doesn't contain data for all columns",
+"Row %ld was truncated; It contained more data than there where input columns",
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld",
"Data truncated, out of range for column '%s' at row %ld",
"Data truncated for column '%s' at row %ld",
diff --git a/sql/slave.cc b/sql/slave.cc
index 3f8a3c37618..42a1e4e9061 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1388,6 +1388,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
1 /* no auto events */,
max_relay_log_size ? max_relay_log_size : max_binlog_size))
{
+ pthread_mutex_unlock(&rli->data_lock);
sql_print_error("Failed in open_log() called from init_relay_log_info()");
DBUG_RETURN(1);
}
@@ -2351,7 +2352,9 @@ improper_arguments: %d timed_out: %d",
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{
DBUG_ENTER("init_slave_thread");
- thd->system_thread = thd->bootstrap = 1;
+ thd->system_thread = (thd_type == SLAVE_THD_SQL) ?
+ SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
+ thd->bootstrap= 1;
thd->host_or_ip= "";
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
@@ -4034,8 +4037,20 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
sizeof(rli->event_relay_log_name)-1);
flush_relay_log_info(rli);
}
-
- // next log is hot
+
+ /*
+ Now we want to open this next log. To know if it's a hot log (the one
+ being written by the I/O thread now) or a cold log, we can use
+ is_active(); if it is hot, we use the I/O cache; if it's cold we open
+ the file normally. But if is_active() reports that the log is hot, this
+ may change between the test and the consequence of the test. So we may
+ open the I/O cache whereas the log is now cold, which is nonsense.
+ To guard against this, we need to have LOCK_log.
+ */
+
+ DBUG_PRINT("info",("hot_log: %d",hot_log));
+ if (!hot_log) /* if hot_log, we already have this mutex */
+ pthread_mutex_lock(log_lock);
if (rli->relay_log.is_active(rli->linfo.log_file_name))
{
#ifdef EXTRA_DEBUG
@@ -4048,15 +4063,24 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
/*
Read pointer has to be at the start since we are the only
- reader
+ reader.
+ We must keep the LOCK_log to read the 4 first bytes, as this is a hot
+ log (same as when we call read_log_event() above: for a hot log we
+ take the mutex).
*/
if (check_binlog_magic(cur_log,&errmsg))
+ {
+ if (!hot_log) pthread_mutex_unlock(log_lock);
goto err;
+ }
+ if (!hot_log) pthread_mutex_unlock(log_lock);
continue;
}
+ if (!hot_log) pthread_mutex_unlock(log_lock);
/*
- if we get here, the log was not hot, so we will have to
- open it ourselves
+ if we get here, the log was not hot, so we will have to open it
+ ourselves. We are sure that the log is still not hot now (a log can get
+ from hot to cold, but not from cold to hot). No need for LOCK_log.
*/
#ifdef EXTRA_DEBUG
sql_print_error("next log '%s' is not active",
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 2527edc1643..2feb9594715 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -697,6 +697,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
If cipher name is specified, we compare it to actual cipher in
use.
*/
+ X509 *cert;
if (vio_type(vio) != VIO_TYPE_SSL ||
SSL_get_verify_result(ssl) != X509_V_OK)
break;
@@ -717,7 +718,11 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
}
/* Prepare certificate (if exists) */
DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(ssl);
+ if (!(cert= SSL_get_peer_certificate(ssl)))
+ {
+ user_access=NO_ACCESS;
+ break;
+ }
DBUG_PRINT("info",("checkpoint 2"));
/* If X509 issuer is speified, we check it... */
if (acl_user->x509_issuer)
@@ -1246,6 +1251,7 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->user ? acl_user->user : "",
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
+ thd->clear_error();
Query_log_event qinfo(thd, buff, query_length, 0);
mysql_bin_log.write(&qinfo);
DBUG_RETURN(0);
@@ -1317,11 +1323,11 @@ static const char *calc_ip(const char *ip, long *val, char end)
static void update_hostname(acl_host_and_ip *host, const char *hostname)
{
host->hostname=(char*) hostname; // This will not be modified!
- if (hostname &&
+ if (!hostname ||
(!(hostname=calc_ip(hostname,&host->ip,'/')) ||
!(hostname=calc_ip(hostname+1,&host->ip_mask,'\0'))))
{
- host->ip=host->ip_mask=0; // Not a masked ip
+ host->ip= host->ip_mask=0; // Not a masked ip
}
}
@@ -1567,7 +1573,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
break;
}
- USER_RESOURCES mqh = thd->lex->mqh;
+ USER_RESOURCES mqh= thd->lex->mqh;
if (mqh.bits & 1)
table->field[28]->store((longlong) mqh.questions);
if (mqh.bits & 2)
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 9858b403d27..f17c9781e8c 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -58,8 +58,6 @@
#define EXTRA_ACL (1L << 29)
#define NO_ACCESS (1L << 30)
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-
/*
Defines to change the above bits to how things are stored in tables
This is needed as the 'host' and 'db' table is missing a few privileges
@@ -127,8 +125,6 @@ public:
char *user,*db;
};
-
-
/* prototypes */
bool hostname_requires_resolving(const char *hostname);
@@ -153,7 +149,7 @@ my_bool grant_init(THD *thd);
void grant_free(void);
void grant_reload(THD *thd);
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
- uint show_command=0, bool dont_print_error=0);
+ uint show_command, bool dont_print_error);
bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length,
uint show_command=0);
bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table);
@@ -166,5 +162,7 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc);
int mysql_drop_user(THD *thd, List <LEX_USER> &list);
int mysql_revoke_all(THD *thd, List <LEX_USER> &list);
-#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
-
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+#define check_grant(A,B,C,D,E) 0
+#define check_grant_db(A,B) 0
+#endif
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index a6c24a25d6e..9e73e06d9c6 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -213,8 +213,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
info->is_float = 1; // we can't use variable decimals here
return 1;
}
- else
- return 0;
+ return 0;
}
for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end
if (str == end) // number was something like '123.000'
@@ -229,11 +228,8 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
info->dval = atod(begin);
return 1;
}
- else
- return 0;
}
- else
- return 0;
+ return 0;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 5b347267adb..02ecb158ebe 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -513,8 +513,8 @@ void close_temporary_tables(THD *thd)
if (query && found_user_tables && mysql_bin_log.is_open())
{
/* The -1 is to remove last ',' */
+ thd->clear_error();
Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0);
- qinfo.error_code=0;
mysql_bin_log.write(&qinfo);
}
thd->temporary_tables=0;
@@ -1752,6 +1752,19 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
const char *table_name=item->table_name;
const char *name=item->field_name;
uint length=(uint) strlen(name);
+ char name_buff[NAME_LEN+1];
+
+ if (db && lower_case_table_names)
+ {
+ /*
+ convert database to lower case for comparision.
+ We can't do this in Item_field as this would change the
+ 'name' of the item which may be used in the select list
+ */
+ strmake(name_buff, db, sizeof(name_buff)-1);
+ my_casedn_str(files_charset_info, name_buff);
+ db= name_buff;
+ }
if (table_name && table_name[0])
{ /* Qualified field */
@@ -1969,7 +1982,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
while ( wild_num && (item= it++))
{
if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name &&
- ((Item_field*) item)->field_name[0] == '*')
+ ((Item_field*) item)->field_name[0] == '*' &&
+ !((Item_field*) item)->field)
{
uint elem= fields.elements;
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
@@ -2255,7 +2269,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
}
cond_and->used_tables_cache= t1->map | t2->map;
- thd->lex->current_select->cond_count+=cond_and->list.elements;
+ thd->lex->current_select->cond_count+= cond_and->list.elements;
if (!table->outer_join) // Not left join
{
if (!(*conds=and_conds(*conds, cond_and)))
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index edc61acb117..02df644f3b4 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -289,7 +289,7 @@ TODO list:
if (thd->temp_tables || global_merge_table_count)
- - Another option would be to set thd->lex.safe_to_cache_query to 0
+ - Another option would be to set thd->lex->safe_to_cache_query to 0
in 'get_lock_data' if any of the tables was a tmp table or a
MRG_ISAM table.
(This could be done with almost no speed penalty)
@@ -1211,9 +1211,29 @@ void Query_cache::invalidate(char *db)
if (query_cache_size > 0)
{
DUMP(this);
- /* invalidate_table reduce list while only root of list remain */
- while (tables_blocks !=0 )
- invalidate_table(tables_blocks);
+ restart_search:
+ if (tables_blocks)
+ {
+ Query_cache_block *curr= tables_blocks;
+ Query_cache_block *next;
+ do
+ {
+ next= curr->next;
+ if (strcmp(db, (char*)(curr->table()->db())) == 0)
+ invalidate_table(curr);
+ /*
+ invalidate_table can freed block on which point 'next' (if
+ table of this block used only in queries which was deleted
+ by invalidate_table). As far as we do not allocate new blocks
+ and mark all headers of freed blocks as 'FREE' (even if they are
+ merged with other blocks) we can just test type of block
+ to be sure that block is not deleted
+ */
+ if (next->type == Query_cache_block::FREE)
+ goto restart_search;
+ curr= next;
+ } while (curr != tables_blocks);
+ }
}
STRUCT_UNLOCK(&structure_guard_mutex);
}
@@ -2223,9 +2243,11 @@ void Query_cache::free_memory_block(Query_cache_block *block)
{
DBUG_ENTER("Query_cache::free_memory_block");
block->used=0;
- DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
- (ulong) first_block, (ulong) block,block->pnext,
- (ulong) block->pprev));
+ block->type= Query_cache_block::FREE; // mark block as free in any case
+ DBUG_PRINT("qcache",
+ ("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
+ (ulong) first_block, (ulong) block, (ulong) block->pnext,
+ (ulong) block->pprev));
if (block->pnext != first_block && block->pnext->is_free())
block = join_free_blocks(block, block->pnext);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e6b2af317e2..325271822ab 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -711,7 +711,7 @@ public:
long dbug_thread_id;
pthread_t real_id;
uint current_tablenr,tmp_table;
- uint server_status,open_options;
+ uint server_status,open_options,system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
@@ -728,7 +728,7 @@ public:
bool last_cuted_field;
bool no_errors, password, is_fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
- bool system_thread,in_lock_tables,global_read_lock;
+ bool in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
enum killed_state { NOT_KILLED=0, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
@@ -885,6 +885,11 @@ public:
void update_charset();
};
+/* Flags for the THD::system_thread (bitmap) variable */
+#define SYSTEM_THREAD_DELAYED_INSERT 1
+#define SYSTEM_THREAD_SLAVE_IO 2
+#define SYSTEM_THREAD_SLAVE_SQL 4
+
/*
Used to hold information about file and file structure in exchainge
via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
@@ -896,7 +901,7 @@ public:
String *field_term,*enclosed,*line_term,*line_start,*escaped;
bool opt_enclosed;
bool dumpfile;
- uint skip_lines;
+ ulong skip_lines;
sql_exchange(char *name,bool dumpfile_flag);
~sql_exchange() {}
};
@@ -1207,8 +1212,13 @@ class user_var_entry
DTCollation collation;
};
-
-/* Class for unique (removing of duplicates) */
+/*
+ Unique -- class for unique (removing of duplicates).
+ Puts all values to the TREE. If the tree becomes too big,
+ it's dumped to the file. User can request sorted values, or
+ just iterate through them. In the last case tree merging is performed in
+ memory simultaneously with iteration, so it should be ~2-3x faster.
+ */
class Unique :public Sql_alloc
{
@@ -1222,10 +1232,10 @@ class Unique :public Sql_alloc
public:
ulong elements;
- Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
+ Unique(qsort_cmp2 comp_func, void *comp_func_fixed_arg,
uint size_arg, ulong max_in_memory_size_arg);
~Unique();
- inline bool unique_add(gptr ptr)
+ inline bool unique_add(void *ptr)
{
if (tree.elements_in_tree > max_elements && flush())
return 1;
@@ -1243,6 +1253,9 @@ public:
return sizeof(uint)*(1 + nkeys/max_elems_in_tree);
}
+ void reset();
+ bool walk(tree_walk_action action, void *walk_action_arg);
+
friend int unique_write_to_file(gptr key, element_count count, Unique *unique);
friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique);
};
@@ -1253,7 +1266,7 @@ class multi_delete :public select_result
TABLE_LIST *delete_tables, *table_being_deleted;
Unique **tempfiles;
THD *thd;
- ha_rows deleted;
+ ha_rows deleted, found;
uint num_of_tables;
int error;
bool do_delete, transactional_tables, log_delayed, normal_tables;
diff --git a/sql/sql_client.cc b/sql/sql_client.cc
index 1ae9a23a924..49d0d3087ad 100644
--- a/sql/sql_client.cc
+++ b/sql/sql_client.cc
@@ -37,9 +37,3 @@ void my_net_local_init(NET *net)
#endif
}
}
-
-extern "C" {
-void mysql_once_init(void)
-{
-}
-}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index a057e0be967..2d636c51dd4 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -62,7 +62,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
ulong length;
CHARSET_INFO *cs= (create && create->default_table_charset) ?
create->default_table_charset :
- thd->variables.collation_database;
+ thd->variables.collation_server;
length= my_sprintf(buf,(buf,
"default-character-set=%s\ndefault-collation=%s\n",
cs->csname,cs->name));
@@ -101,7 +101,7 @@ static bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
uint nbytes;
bzero((char*) create,sizeof(*create));
- create->default_table_charset= global_system_variables.collation_database;
+ create->default_table_charset= thd->variables.collation_server;
if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0)
{
IO_CACHE cache;
@@ -289,13 +289,14 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
{
thd->db_charset= (create_info && create_info->default_table_charset) ?
create_info->default_table_charset :
- global_system_variables.collation_database;
+ thd->variables.collation_server;
thd->variables.collation_database= thd->db_charset;
}
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ thd->clear_error();
mysql_bin_log.write(&qinfo);
}
send_ok(thd, result);
@@ -381,6 +382,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0);
+ thd->clear_error();
mysql_bin_log.write(&qinfo);
}
send_ok(thd,(ulong) deleted);
@@ -660,7 +662,7 @@ bool mysql_change_db(THD *thd, const char *name)
load_db_opt(thd, path, &create);
thd->db_charset= create.default_table_charset ?
create.default_table_charset :
- global_system_variables.collation_database;
+ thd->variables.collation_server;
thd->variables.collation_database= thd->db_charset;
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 3abb09a5d60..03f952f3ff5 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -135,14 +135,20 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
- (SQL_SELECT *) 0, HA_POS_ERROR,
+ select, HA_POS_ERROR,
&examined_rows))
== HA_POS_ERROR)
{
delete select;
free_underlaid_joins(thd, &thd->lex->select_lex);
- DBUG_RETURN(-1); // This will force out message
+ DBUG_RETURN(-1); // This will force out message
}
+ /*
+ Filesort has already found and selected the rows we want to delete,
+ so we don't need the where clause
+ */
+ delete select;
+ select= 0;
}
init_read_record(&info,thd,table,select,1,1);
@@ -204,6 +210,8 @@ cleanup:
{
if (mysql_bin_log.is_open())
{
+ if (error <= 0)
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed);
if (mysql_bin_log.write(&qinfo) && transactional_table)
@@ -250,7 +258,7 @@ extern "C" int refposcmp2(void* arg, const void *a,const void *b)
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
uint num_of_tables_arg)
- : delete_tables(dt), thd(thd_arg), deleted(0),
+ : delete_tables(dt), thd(thd_arg), deleted(0), found(0),
num_of_tables(num_of_tables_arg), error(0),
do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
{
@@ -354,6 +362,7 @@ bool multi_delete::send_data(List<Item> &values)
continue;
table->file->position(table->record[0]);
+ found++;
if (secure_counter < 0)
{
@@ -429,7 +438,7 @@ int multi_delete::do_deletes(bool from_send_error)
if (from_send_error)
{
- /* Found out table number for 'table_being_deleted' */
+ /* Found out table number for 'table_being_deleted*/
for (TABLE_LIST *aux=delete_tables;
aux != table_being_deleted;
aux=aux->next)
@@ -439,6 +448,8 @@ int multi_delete::do_deletes(bool from_send_error)
table_being_deleted = delete_tables;
do_delete= 0;
+ if (!found)
+ DBUG_RETURN(0);
for (table_being_deleted=table_being_deleted->next;
table_being_deleted ;
table_being_deleted=table_being_deleted->next, counter++)
@@ -508,6 +519,8 @@ bool multi_delete::send_eof()
{
if (mysql_bin_log.is_open())
{
+ if (error <= 0)
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed);
if (mysql_bin_log.write(&qinfo) && !normal_tables)
@@ -618,6 +631,7 @@ end:
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
thd->tmp_table);
mysql_bin_log.write(&qinfo);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 1de86f486b4..88585db34ce 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -366,6 +366,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
{
if (mysql_bin_log.is_open())
{
+ if (error <= 0)
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed);
if (mysql_bin_log.write(&qinfo) && transactional_table)
@@ -630,7 +632,7 @@ public:
thd.lex->current_select= 0; /* for my_message_sql */
bzero((char*) &thd.net,sizeof(thd.net)); // Safety
- thd.system_thread=1;
+ thd.system_thread= SYSTEM_THREAD_DELAYED_INSERT;
thd.host_or_ip= "";
bzero((char*) &info,sizeof(info));
pthread_mutex_init(&mutex,MY_MUTEX_INIT_FAST);
@@ -1495,6 +1497,8 @@ bool select_insert::send_eof()
/* Write to binlog before commiting transaction */
if (mysql_bin_log.is_open())
{
+ if (!error)
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
table->file->has_transactions());
mysql_bin_log.write(&qinfo);
@@ -1508,7 +1512,6 @@ bool select_insert::send_eof()
::send_error(thd);
DBUG_RETURN(1);
}
-
char buff[160];
if (info.handle_duplicates == DUP_IGNORE)
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index a67ee2385b9..b0381ae1d30 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -455,7 +455,7 @@ int yylex(void *arg, void *yythd)
int tokval, result_state;
uint length;
enum my_lex_states state;
- LEX *lex= (((THD *)yythd)->lex);
+ LEX *lex= ((THD *)yythd)->lex;
YYSTYPE *yylval=(YYSTYPE*) arg;
CHARSET_INFO *cs= ((THD *) yythd)->charset();
uchar *state_map= cs->state_map;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 181db61013f..fb7d8415e91 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -76,7 +76,7 @@ enum enum_sql_command {
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
- SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
+ SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL,
SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION,
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 41d9f0b6c4d..2f8a979b5ee 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -72,10 +72,11 @@ public:
};
static int read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,
- List<Item> &fields, READ_INFO &read_info);
+ List<Item> &fields, READ_INFO &read_info,
+ ulong skip_lines);
static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
List<Item> &fields, READ_INFO &read_info,
- String &enclosed);
+ String &enclosed, ulong skip_lines);
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
List<Item> &fields, enum enum_duplicates handle_duplicates,
@@ -85,8 +86,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
File file;
TABLE *table;
int error;
- String *field_term=ex->field_term,*escaped=ex->escaped,
- *enclosed=ex->enclosed;
+ String *field_term=ex->field_term,*escaped=ex->escaped;
+ String *enclosed=ex->enclosed;
bool is_fifo=0;
#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
@@ -95,6 +96,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If no current database, use database where table is located */
char *tdb= thd->db ? thd->db : db;
bool transactional_table, log_delayed;
+ ulong skip_lines= ex->skip_lines;
DBUG_ENTER("mysql_load");
#ifdef EMBEDDED_LIBRARY
@@ -254,16 +256,18 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */
thd->cuted_fields=0L;
- if (ex->line_term->length() && field_term->length())
+ /* Skip lines if there is a line terminator */
+ if (ex->line_term->length())
{
- // ex->skip_lines needs to be preserved for logging
- uint skip_lines = ex->skip_lines;
- while (skip_lines--)
+ /* ex->skip_lines needs to be preserved for logging */
+ while (skip_lines > 0)
{
+ skip_lines--;
if (read_info.next_line())
break;
}
}
+
if (!(error=test(read_info.error)))
{
uint save_time_stamp=table->time_stamp;
@@ -279,9 +283,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table->file->deactivate_non_unique_index((ha_rows) 0);
table->copy_blobs=1;
if (!field_term->length() && !enclosed->length())
- error=read_fixed_length(thd,info,table,fields,read_info);
+ error=read_fixed_length(thd,info,table,fields,read_info,
+ skip_lines);
else
- error=read_sep_field(thd,info,table,fields,read_info,*enclosed);
+ error=read_sep_field(thd,info,table,fields,read_info,*enclosed,
+ skip_lines);
if (table->file->extra(HA_EXTRA_NO_CACHE))
error=1; /* purecov: inspected */
if (table->file->activate_all_index(thd))
@@ -290,7 +296,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table->time_stamp=save_time_stamp;
table->next_number_field=0;
}
- if (file >= 0) my_close(file,MYF(0));
+ if (file >= 0)
+ my_close(file,MYF(0));
free_blobs(table); /* if pack_blob was used */
table->copy_blobs=0;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -392,7 +399,7 @@ err:
static int
read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
- READ_INFO &read_info)
+ READ_INFO &read_info, ulong skip_lines)
{
List_iterator_fast<Item> it(fields);
Item_field *sql_field;
@@ -412,6 +419,17 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
thd->send_kill_message();
DBUG_RETURN(1);
}
+ if (skip_lines)
+ {
+ /*
+ We could implement this with a simple seek if:
+ - We are not using DATA INFILE LOCAL
+ - escape character is ""
+ - line starting prefix is ""
+ */
+ skip_lines--;
+ continue;
+ }
it.rewind();
byte *pos=read_info.row_start;
#ifdef HAVE_purify
@@ -482,7 +500,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
static int
read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
List<Item> &fields, READ_INFO &read_info,
- String &enclosed)
+ String &enclosed, ulong skip_lines)
{
List_iterator_fast<Item> it(fields);
Item_field *sql_field;
@@ -533,6 +551,12 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
}
if (read_info.error)
break;
+ if (skip_lines)
+ {
+ if (!--skip_lines)
+ thd->cuted_fields= 0L; // Reset warnings
+ continue;
+ }
if (sql_field)
{ // Last record
if (sql_field == (Item_field*) fields.head())
@@ -872,7 +896,18 @@ found_eof:
}
/*
-** One can't use fixed length with multi-byte charset **
+ Read a row with fixed length.
+
+ NOTES
+ The row may not be fixed size on disk if there are escape
+ characters in the file.
+
+ IMPLEMENTATION NOTE
+ One can't use fixed length with multi-byte charset **
+
+ RETURN
+ 0 ok
+ 1 error
*/
int READ_INFO::read_fixed_length()
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1ff4d721924..4b1e2397ffd 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -63,14 +63,9 @@ extern "C" int gethostname(char *name, int namelen);
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
static bool single_table_command_access(THD *thd, ulong privilege,
TABLE_LIST *tables, int *res);
-#else
-#define check_merge_table_access(thd, db, tables) false
-#define single_table_command_access(thd, privilege, tables, res) false
-#endif
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, char **filename_ptr,
@@ -189,7 +184,6 @@ end:
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check if user exist and password supplied is correct.
@@ -222,6 +216,11 @@ int check_user(THD *thd, enum enum_server_command command,
{
DBUG_ENTER("check_user");
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ thd->master_access= GLOBAL_ACLS; // Full rights
+ return 0;
+#else
+
my_bool opt_secure_auth_local;
pthread_mutex_lock(&LOCK_global_system_variables);
opt_secure_auth_local= opt_secure_auth;
@@ -346,7 +345,7 @@ int check_user(THD *thd, enum enum_server_command command,
}
}
else
- send_ok(thd);
+ send_ok(thd);
thd->password= test(passwd_len); // remember for error messages
/* Ready to handle queries */
DBUG_RETURN(0);
@@ -367,11 +366,9 @@ int check_user(THD *thd, enum enum_server_command command,
thd->host_or_ip,
passwd_len ? ER(ER_YES) : ER(ER_NO));
DBUG_RETURN(-1);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
-#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
-
-
/*
Check for maximum allowable user connections, if the mysqld server is
started with corresponding variable that is greater then 0.
@@ -522,7 +519,6 @@ bool is_update_query(enum enum_sql_command command)
return uc_update_queries[command];
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check if maximum queries per hour limit has been reached
returns 0 if OK.
@@ -541,6 +537,9 @@ static bool check_mqh(THD *thd, uint check_command)
DBUG_ENTER("check_mqh");
DBUG_ASSERT(uc != 0);
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_RETURN(0);
+#else
/* If more than a hour since last check, reset resource checking */
if (check_time - uc->intime >= 3600)
{
@@ -574,12 +573,13 @@ static bool check_mqh(THD *thd, uint check_command)
}
end:
DBUG_RETURN(error);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
{
-
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
(void) pthread_mutex_lock(&LOCK_user_conn);
if (lu) // for GRANT
{
@@ -603,7 +603,8 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
{
for (uint idx=0;idx < hash_user_connections.records; idx++)
{
- USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections, idx);
+ USER_CONN *uc=(struct user_conn *) hash_element(&hash_user_connections,
+ idx);
if (get_them)
get_mqh(uc->user,uc->host,uc);
uc->questions=0;
@@ -612,8 +613,8 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
}
}
(void) pthread_mutex_unlock(&LOCK_user_conn);
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
-#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
/*
Perform handshake, authorize client and update thd ACL variables.
@@ -1075,7 +1076,6 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0';
thd->query_id=query_id++;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
{
thd->net.error = 0;
@@ -1083,7 +1083,6 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
break;
}
-#endif
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
@@ -1147,12 +1146,10 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege,0,0))
goto err;
- if (grant_option && check_grant(thd, SELECT_ACL, table_list))
+ if (grant_option && check_grant(thd, SELECT_ACL, table_list, 0, 0))
goto err;
-#endif
thd->free_list = 0;
thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
@@ -1459,13 +1456,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_casedn_str(files_charset_info, table_list.real_name);
remove_escape(table_list.real_name); // This can't have wildcards
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access,0,0))
break;
table_list.grant.privilege=thd->col_access;
- if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
+ if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2,0))
break;
-#endif /*DONT_ALLOW_SHOW_COMMANDS*/
mysqld_list_fields(thd,&table_list,fields);
free_items(thd->free_list);
break;
@@ -1609,19 +1604,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_INFO:
statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
-#endif
mysql_log.write(thd,command,NullS);
mysqld_list_processes(thd,
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->master_access & PROCESS_ACL ?
- NullS : thd->priv_user
-#else
- NullS
-#endif
- ,0);
+ NullS : thd->priv_user, 0);
break;
case COM_PROCESS_KILL:
{
@@ -1834,6 +1822,7 @@ mysql_execute_command(THD *thd)
}
}
if (&lex->select_lex != lex->all_selects_list &&
+ lex->sql_command != SQLCOM_CREATE_TABLE &&
lex->unit.create_total_list(thd, lex, &tables, 0))
DBUG_RETURN(0);
@@ -1842,11 +1831,7 @@ mysql_execute_command(THD *thd)
Except for the replication thread and the 'super' users.
*/
if (opt_readonly &&
- !(thd->slave_thread
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- || (thd->master_access & SUPER_ACL)
-#endif
- ) &&
+ !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
(uc_update_queries[lex->sql_command] > 0))
{
send_error(thd, ER_CANT_UPDATE_WITH_READLOCK);
@@ -1858,7 +1843,6 @@ mysql_execute_command(THD *thd)
case SQLCOM_SELECT:
{
select_result *result=lex->result;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (tables)
{
res=check_table_access(thd,
@@ -1874,7 +1858,6 @@ mysql_execute_command(THD *thd)
res=0;
break; // Error message is given
}
-#endif
/*
In case of single SELECT unit->global_parameters points on first SELECT
TODO: move counters to SELECT_LEX
@@ -2111,7 +2094,6 @@ mysql_execute_command(THD *thd)
{
if (!tables->db)
tables->db=thd->db;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
if (grant_option)
@@ -2119,12 +2101,11 @@ mysql_execute_command(THD *thd)
/* Check that the first table has CREATE privilege */
TABLE_LIST *tmp_table_list=tables->next;
tables->next=0;
- bool error=check_grant(thd,CREATE_ACL,tables);
+ bool error=check_grant(thd,CREATE_ACL,tables,0,0);
tables->next=tmp_table_list;
if (error)
goto error;
}
-#endif
if (strlen(tables->real_name) > NAME_LEN)
{
net_printf(thd,ER_WRONG_TABLE_NAME, tables->real_name);
@@ -2147,43 +2128,34 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /* Skip first table, which is the table we are creating */
+ TABLE_LIST *create_table= tables;
+ tables= tables->next;
+ lex->select_lex.table_list.first= (byte*) (tables);
+ create_table->next= 0;
+ if (&lex->select_lex != lex->all_selects_list &&
+ lex->unit.create_total_list(thd, lex, &tables, 0))
+ DBUG_RETURN(-1);
+
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
CREATE_TMP_ACL : CREATE_ACL);
-#endif
- if (!tables->db)
- tables->db=thd->db;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_access(thd,want_priv,tables->db,&tables->grant.privilege,0,0) ||
- check_merge_table_access(thd, tables->db,
+ if (check_access(thd, want_priv, create_table->db,
+ &create_table->grant.privilege, 0, 0) ||
+ check_merge_table_access(thd, create_table->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
- if (grant_option && want_priv != CREATE_TMP_ACL)
- {
- /* Check that the first table has CREATE privilege */
- TABLE_LIST *tmp_table_list=tables->next;
- tables->next=0;
- bool error=check_grant(thd, want_priv, tables);
- tables->next=tmp_table_list;
- if (error)
+ if (grant_option && want_priv != CREATE_TMP_ACL &&
+ check_grant(thd, want_priv, create_table,0,0))
goto error;
- }
-#endif
- if (strlen(tables->real_name) > NAME_LEN)
- {
- net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
- res=0;
- break;
- }
#ifndef HAVE_READLINK
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
/* Fix names if symlinked tables */
if (append_file_to_dir(thd, &lex->create_info.data_file_name,
- tables->real_name) ||
+ create_table->real_name) ||
append_file_to_dir(thd,&lex->create_info.index_file_name,
- tables->real_name))
+ create_table->real_name))
{
res=-1;
break;
@@ -2207,49 +2179,42 @@ mysql_execute_command(THD *thd)
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- find_real_table_in_list(tables->next, tables->db, tables->real_name))
+ find_real_table_in_list(tables, create_table->db,
+ create_table->real_name))
{
- net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
DBUG_RETURN(-1);
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (tables->next)
- {
- if (check_table_access(thd, SELECT_ACL, tables->next,0))
- goto error; // Error message is given
- }
-#endif
+ if (tables && check_table_access(thd, SELECT_ACL, tables,0))
+ goto error; // Error message is given
select_lex->options|= SELECT_NO_UNLOCK;
unit->offset_limit_cnt= select_lex->offset_limit;
unit->select_limit_cnt= select_lex->select_limit+
select_lex->offset_limit;
if (unit->select_limit_cnt < select_lex->select_limit)
- unit->select_limit_cnt= HA_POS_ERROR; // No limit
+ unit->select_limit_cnt= HA_POS_ERROR; // No limit
- /* Skip first table, which is the table we are creating */
- lex->select_lex.table_list.first=
- (byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
- if (!(res=open_and_lock_tables(thd,tables->next)))
+ if (!(res=open_and_lock_tables(thd,tables)))
{
- if ((result=new select_create(tables->db ? tables->db : thd->db,
- tables->real_name, &lex->create_info,
+ res= -1; // If error
+ if ((result=new select_create(create_table->db,
+ create_table->real_name,
+ &lex->create_info,
lex->create_list,
lex->key_list,
select_lex->item_list,lex->duplicates)))
res=handle_select(thd, lex, result);
- else
- res= -1;
}
}
else // regular create
{
if (lex->name)
- res= mysql_create_like_table(thd, tables, &lex->create_info,
+ res= mysql_create_like_table(thd, create_table, &lex->create_info,
(Table_ident *)lex->name);
else
{
- res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
- tables->real_name, &lex->create_info,
+ res= mysql_create_table(thd,create_table->db,
+ create_table->real_name, &lex->create_info,
lex->create_list,
lex->key_list,0,0,0); // do logging
}
@@ -2261,12 +2226,10 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_INDEX:
if (!tables->db)
tables->db=thd->db;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INDEX_ACL,tables))
+ if (grant_option && check_grant(thd,INDEX_ACL,tables,0,0))
goto error;
-#endif
thd->slow_command=TRUE;
if (end_active_trans(thd))
res= -1;
@@ -2334,10 +2297,9 @@ mysql_execute_command(THD *thd)
goto error; /* purecov: inspected */
if (!tables->db)
tables->db=thd->db;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{
- if (check_grant(thd,ALTER_ACL,tables))
+ if (check_grant(thd,ALTER_ACL,tables,0,0))
goto error;
if (lex->name && !test_all_bits(priv,INSERT_ACL | CREATE_ACL))
{ // Rename of table
@@ -2346,11 +2308,10 @@ mysql_execute_command(THD *thd)
tmp_table.real_name=lex->name;
tmp_table.db=select_lex->db;
tmp_table.grant.privilege=priv;
- if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables))
+ if (check_grant(thd,INSERT_ACL | CREATE_ACL,tables,0,0))
goto error;
}
}
-#endif
/* Don't yet allow changing of symlinks with ALTER TABLE */
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
/* ALTER TABLE ends previous transaction */
@@ -2378,7 +2339,6 @@ mysql_execute_command(THD *thd)
TABLE_LIST *table;
if (check_db_used(thd,tables))
goto error;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
for (table=tables ; table ; table=table->next->next)
{
if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
@@ -2392,14 +2352,13 @@ mysql_execute_command(THD *thd)
old_list=table[0];
new_list=table->next[0];
old_list.next=new_list.next=0;
- if (check_grant(thd,ALTER_ACL,&old_list) ||
+ if (check_grant(thd,ALTER_ACL,&old_list,0,0) ||
(!test_all_bits(table->next->grant.privilege,
INSERT_ACL | CREATE_ACL) &&
- check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list)))
+ check_grant(thd,INSERT_ACL | CREATE_ACL, &new_list,0,0)))
goto error;
}
}
-#endif
query_cache_invalidate3(thd, tables, 0);
if (end_active_trans(thd))
res= -1;
@@ -2550,12 +2509,10 @@ mysql_execute_command(THD *thd)
res= -1;
break;
case SQLCOM_UPDATE_MULTI:
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege,0,0))
goto error;
- if (grant_option && check_grant(thd,UPDATE_ACL,tables))
+ if (grant_option && check_grant(thd,UPDATE_ACL,tables,0,0))
goto error;
-#endif
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
@@ -2585,16 +2542,12 @@ mysql_execute_command(THD *thd)
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
ulong privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
if (single_table_command_access(thd, privilege, tables, &res))
goto error;
-#else
- my_bool update=(lex->value_list.elements ? 1 : 0);
-#endif
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
@@ -2610,12 +2563,10 @@ mysql_execute_command(THD *thd)
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
-
/*
Check that we have modify privileges for the first table and
select privileges for the rest
*/
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
{
ulong privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL);
@@ -2623,14 +2574,18 @@ mysql_execute_command(THD *thd)
tables->next=0;
if (check_access(thd, privilege,
tables->db,&tables->grant.privilege,0,0) ||
- (grant_option && check_grant(thd, privilege, tables)))
+ (grant_option && check_grant(thd, privilege, tables,0,0)))
goto error;
tables->next=save_next;
if ((res=check_table_access(thd, SELECT_ACL, save_next,0)))
goto error;
}
-#endif
+
+ /* Fix lock for first table */
+ if (tables->lock_type == TL_WRITE_DELAYED)
+ tables->lock_type= TL_WRITE;
+
/* Don't unlock tables until command is written to binary log */
select_lex->options|= SELECT_NO_UNLOCK;
@@ -2664,12 +2619,10 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_TRUNCATE:
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,DELETE_ACL,tables))
+ if (grant_option && check_grant(thd,DELETE_ACL,tables,0,0))
goto error;
-#endif
/*
Don't allow this within a transaction because we want to use
re-generate table
@@ -2683,12 +2636,10 @@ mysql_execute_command(THD *thd)
break;
case SQLCOM_DELETE:
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (single_table_command_access(thd, DELETE_ACL, tables, &res))
goto error;
// Set privilege for the WHERE clause
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
-#endif
res = mysql_delete(thd,tables, select_lex->where,
(ORDER*) select_lex->order_list.first,
select_lex->select_limit, select_lex->options);
@@ -2698,7 +2649,7 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_DELETE_MULTI:
{
- TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
+ TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
TABLE_LIST *auxi;
uint table_count=0;
multi_delete *result;
@@ -2810,12 +2761,10 @@ mysql_execute_command(THD *thd)
case SQLCOM_DROP_INDEX:
if (!tables->db)
tables->db=thd->db;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INDEX_ACL,tables))
+ if (grant_option && check_grant(thd,INDEX_ACL,tables,0,0))
goto error;
-#endif
if (end_active_trans(thd))
res= -1;
else
@@ -2833,21 +2782,14 @@ mysql_execute_command(THD *thd)
break;
#endif
case SQLCOM_SHOW_PROCESSLIST:
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
-#endif
mysqld_list_processes(thd,
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->master_access & PROCESS_ACL ? NullS :
- thd->priv_user
-#else
- NullS
-#endif
- ,lex->verbose);
+ thd->priv_user,lex->verbose);
break;
- case SQLCOM_SHOW_TABLE_TYPES:
- res= mysqld_show_table_types(thd);
+ case SQLCOM_SHOW_STORAGE_ENGINES:
+ res= mysqld_show_storage_engines(thd);
break;
case SQLCOM_SHOW_PRIVILEGES:
res= mysqld_show_privileges(thd);
@@ -2870,10 +2812,8 @@ mysql_execute_command(THD *thd)
goto error;
#else
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
goto error;
-#endif
res= mysqld_show_logs(thd);
break;
}
@@ -2897,7 +2837,6 @@ mysql_execute_command(THD *thd)
net_printf(thd,ER_WRONG_DB_NAME, db);
goto error;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
goto error; /* purecov: inspected */
if (!thd->col_access && check_grant_db(thd,db))
@@ -2908,7 +2847,6 @@ mysql_execute_command(THD *thd)
db);
goto error;
}
-#endif
/* grant is checked in mysqld_show_tables */
if (select_lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
@@ -2942,13 +2880,11 @@ mysql_execute_command(THD *thd)
}
remove_escape(db); // Fix escaped '_'
remove_escape(tables->real_name);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access,0,0))
goto error; /* purecov: inspected */
tables->grant.privilege=thd->col_access;
- if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
+ if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0))
goto error;
-#endif
res= mysqld_show_fields(thd,tables,
(lex->wild ? lex->wild->ptr() : NullS),
lex->verbose);
@@ -2971,13 +2907,11 @@ mysql_execute_command(THD *thd)
remove_escape(tables->real_name);
if (!tables->db)
tables->db=thd->db;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
goto error; /* purecov: inspected */
tables->grant.privilege=thd->col_access;
- if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
+ if (grant_option && check_grant(thd,SELECT_ACL,tables,2,0))
goto error;
-#endif
res= mysqld_show_keys(thd,tables);
break;
}
@@ -2988,7 +2922,6 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOAD:
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL);
@@ -3005,11 +2938,11 @@ mysql_execute_command(THD *thd)
send_error(thd,ER_NOT_ALLOWED_COMMAND);
goto error;
}
- if (check_access(thd,privilege,tables->db,&tables->grant.privilege,0,0) ||
- grant_option && check_grant(thd,privilege,tables))
+ if (check_access(thd,privilege,tables->db,&tables->grant.privilege,0,
+ 0) ||
+ grant_option && check_grant(thd,privilege,tables,0,0))
goto error;
}
-#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
res=mysql_load(thd, lex->exchange, tables, lex->field_list,
lex->duplicates, (bool) lex->local_file, lex->lock_option);
break;
@@ -3249,13 +3182,14 @@ mysql_execute_command(THD *thd)
if (grant_option && check_grant(thd,
(lex->grant | lex->grant_tot_col |
GRANT_ACL),
- tables))
+ tables,0,0))
goto error;
if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
lex->grant,
lex->sql_command == SQLCOM_REVOKE)) &&
mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -3274,6 +3208,7 @@ mysql_execute_command(THD *thd)
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -3708,7 +3643,6 @@ error:
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check grants for commands which work only with one table and all other
tables belong to subselects.
@@ -3729,23 +3663,23 @@ static bool single_table_command_access(THD *thd, ulong privilege,
TABLE_LIST *tables, int *res)
{
- if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
- return 1;
+ if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
+ return 1;
- // Show only 1 table for check_grant
- TABLE_LIST *subselects_tables= tables->next;
- tables->next= 0;
- if (grant_option && check_grant(thd, privilege, tables))
- return 1;
+ // Show only 1 table for check_grant
+ TABLE_LIST *subselects_tables= tables->next;
+ tables->next= 0;
+ if (grant_option && check_grant(thd, privilege, tables, 0, 0))
+ return 1;
- // check rights on tables of subselect (if exists)
- if (subselects_tables)
- {
- tables->next= subselects_tables;
- if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables,0)))
- return 1;
- }
- return 0;
+ // check rights on tables of subselect (if exists)
+ if (subselects_tables)
+ {
+ tables->next= subselects_tables;
+ if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables,0)))
+ return 1;
+ }
+ return 0;
}
@@ -3788,6 +3722,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_RETURN(TRUE); /* purecov: tested */
}
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ DBUG_RETURN(0);
+#else
if ((thd->master_access & want_access) == want_access)
{
/*
@@ -3837,6 +3774,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
thd->priv_host,
db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -3861,6 +3799,9 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
bool check_global_access(THD *thd, ulong want_access)
{
+#ifdef NO_EMBEDDED_ACCESS_CHECKS
+ return 0;
+#else
char command[128];
if ((thd->master_access & want_access))
return 0;
@@ -3868,6 +3809,7 @@ bool check_global_access(THD *thd, ulong want_access)
net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
command);
return 1;
+#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}
@@ -3932,7 +3874,6 @@ static bool check_merge_table_access(THD *thd, char *db,
return error;
}
-#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
@@ -4016,7 +3957,7 @@ void
mysql_init_query(THD *thd, bool lexonly)
{
DBUG_ENTER("mysql_init_query");
- LEX *lex=thd->lex;
+ LEX *lex= thd->lex;
lex->unit.init_query();
lex->unit.init_select();
lex->unit.thd= thd;
@@ -4048,7 +3989,9 @@ mysql_init_query(THD *thd, bool lexonly)
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
thd->sent_row_count= thd->examined_row_count= 0;
thd->is_fatal_error= thd->rand_used= 0;
- thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
+ thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS |
+ SERVER_QUERY_NO_INDEX_USED |
+ SERVER_QUERY_NO_GOOD_INDEX_USED);
thd->tmp_table_used= 0;
if (opt_bin_log)
reset_dynamic(&thd->user_var_events);
@@ -4203,9 +4146,7 @@ mysql_parse(THD *thd, char *inBuf, uint length)
else
{
mysql_execute_command(thd);
-#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
query_cache_end_of_result(&thd->net);
-#endif
}
}
}
@@ -4213,7 +4154,6 @@ mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
-#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
query_cache_abort(&thd->net);
if (thd->lex->sphead)
{
@@ -4222,7 +4162,6 @@ mysql_parse(THD *thd, char *inBuf, uint length)
delete thd->lex->sphead;
thd->lex->sphead= NULL;
}
-#endif
}
thd->proc_info="freeing items";
free_items(thd->free_list); /* Free strings used by items */
@@ -4272,7 +4211,12 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
if (default_value)
{
- if (default_value->type() == Item::NULL_ITEM)
+ if (type == FIELD_TYPE_TIMESTAMP)
+ {
+ net_printf(thd, ER_INVALID_DEFAULT, field_name);
+ DBUG_RETURN(1);
+ }
+ else if (default_value->type() == Item::NULL_ITEM)
{
default_value=0;
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
@@ -4937,10 +4881,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
UNLOCK_ACTIVE_MI;
}
#endif
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_USER_RESOURCES)
reset_mqh(thd,(LEX_USER *) NULL);
-#endif
if (write_to_binlog)
*write_to_binlog= tmp_write_to_binlog;
return result;
@@ -4975,18 +4917,14 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
if ((thd->master_access & SUPER_ACL) ||
!strcmp(thd->user,tmp->user))
-#endif
{
tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
error=0;
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
else
error=ER_KILL_DENIED_ERROR;
-#endif
pthread_mutex_unlock(&tmp->LOCK_delete);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index bf7da934a2d..964cf55f942 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -545,7 +545,7 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
if (check_access(thd,privilege,table_list->db,
&table_list->grant.privilege,0,0) ||
- (grant_option && check_grant(thd,privilege,table_list)))
+ (grant_option && check_grant(thd,privilege,table_list,0,0)))
DBUG_RETURN(1);
#endif
if (open_and_lock_tables(thd, table_list))
@@ -600,7 +600,7 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,UPDATE_ACL,table_list->db,
&table_list->grant.privilege,0,0) ||
- (grant_option && check_grant(thd,UPDATE_ACL,table_list)))
+ (grant_option && check_grant(thd,UPDATE_ACL,table_list,0,0)))
DBUG_RETURN(1);
#endif
if (open_and_lock_tables(thd, table_list))
@@ -641,7 +641,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
SELECT_LEX *select_lex)
{
THD *thd= stmt->thd;
- LEX *lex= thd->lex;
+ LEX *lex= &thd->main_lex;
select_result *result= thd->lex->result;
DBUG_ENTER("mysql_test_select_fields");
@@ -703,7 +703,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
static bool send_prepare_results(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
- LEX *lex= thd->lex;
+ LEX *lex= &thd->main_lex;
enum enum_sql_command sql_command= thd->lex->sql_command;
DBUG_ENTER("send_prepare_results");
DBUG_PRINT("enter",("command: %d, param_count: %ld",
@@ -812,7 +812,7 @@ static bool init_param_items(PREP_STMT *stmt)
Item_param **to;
uint32 length= thd->query_length;
- stmt->lex= *thd->lex;
+ stmt->lex= thd->main_lex;
if (mysql_bin_log.is_open())
{
@@ -972,8 +972,8 @@ void mysql_stmt_execute(THD *thd, char *packet)
DBUG_VOID_RETURN;
}
- LEX *thd_lex= thd->lex;
- thd->lex= &stmt->lex;
+ LEX thd_lex= thd->main_lex;
+ thd->main_lex= stmt->lex;
for (sl= stmt->lex.all_selects_list;
sl;
@@ -1012,7 +1012,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- thd->lex= thd_lex;
+ thd->main_lex= thd_lex;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 5ef8d5d1c1d..29b4f2f4a01 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -81,6 +81,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index c0ee4277128..d3c033d985c 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -679,7 +679,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
bit to 0 for the other thread
*/
if (thd->lex->slave_thd_opt)
- thread_mask &= thd->lex->slave_thd_opt;
+ thread_mask&= thd->lex->slave_thd_opt;
if (thread_mask) //some threads are stopped, start them
{
if (init_master_info(mi,master_info_file,relay_log_info_file, 0))
@@ -700,7 +700,7 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
mi->rli.until_condition= RELAY_LOG_INFO::UNTIL_MASTER_POS;
mi->rli.until_log_pos= thd->lex->mi.pos;
/*
- We don't check thd->lex.mi.log_file_name for NULL here
+ We don't check thd->lex->mi.log_file_name for NULL here
since it is checked in sql_yacc.yy
*/
strmake(mi->rli.until_log_name, thd->lex->mi.log_file_name,
@@ -975,7 +975,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
}
thd->proc_info = "Changing master";
- LEX_MASTER_INFO* lex_mi = &thd->lex->mi;
+ 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))
{
@@ -1204,7 +1204,7 @@ int show_binlog_events(THD* thd)
if (mysql_bin_log.is_open())
{
- LEX_MASTER_INFO *lex_mi = &thd->lex->mi;
+ LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
ha_rows event_count, limit_start, limit_end;
my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
@@ -1213,8 +1213,8 @@ int show_binlog_events(THD* thd)
LOG_INFO linfo;
Log_event* ev;
- limit_start = thd->lex->current_select->offset_limit;
- limit_end = thd->lex->current_select->select_limit + limit_start;
+ limit_start= thd->lex->current_select->offset_limit;
+ limit_end= thd->lex->current_select->select_limit + limit_start;
name= search_file_name;
if (log_file_name)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 10c4603875d..9f26d7458d0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1121,8 +1121,21 @@ JOIN::exec()
if (select_options & SELECT_DESCRIBE)
{
- if (!order && !no_order)
- order=group_list;
+ /*
+ Check if we managed to optimize ORDER BY away and don't use temporary
+ table to resolve ORDER BY: in that case, we only may need to do
+ filesort for GROUP BY.
+ */
+ if (!order && !no_order && (!skip_sort_order || !need_tmp))
+ {
+ /*
+ Reset 'order' to 'group_list' and reinit variables describing
+ 'order'
+ */
+ order= group_list;
+ simple_order= simple_group;
+ skip_sort_order= 0;
+ }
if (order &&
(const_tables == tables ||
((simple_order || skip_sort_order) &&
@@ -1861,7 +1874,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
} while (keyuse->table == table && keyuse->key == key);
if (eq_part.is_prefix(table->key_info[key].key_parts) &&
- (table->key_info[key].flags & HA_NOSAME) &&
+ ((table->key_info[key].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
+ HA_NOSAME) &&
!table->fulltext_searched)
{
if (const_ref == eq_part)
@@ -2345,10 +2359,6 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
}
}
}
- /* Mark that we can optimize LEFT JOIN */
- if (key_field->val->type() == Item::NULL_ITEM &&
- !key_field->field->real_maybe_null())
- key_field->field->table->reginfo.not_exists_optimize=1;
}
@@ -2447,15 +2457,28 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
SELECT_LEX *select_lex)
{
uint and_level,i,found_eq_constant;
- KEY_FIELD *key_fields,*end;
+ KEY_FIELD *key_fields, *end, *field;
if (!(key_fields=(KEY_FIELD*)
thd->alloc(sizeof(key_fields[0])*
(thd->lex->current_select->cond_count+1)*2)))
return TRUE; /* purecov: inspected */
- and_level=0; end=key_fields;
+ and_level= 0;
+ field= end= key_fields;
+ if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
+ return TRUE;
if (cond)
+ {
add_key_fields(join_tab,&end,&and_level,cond,normal_tables);
+ for (; field != end ; field++)
+ {
+ add_key_part(keyuse,field);
+ /* Mark that we can optimize LEFT JOIN */
+ if (field->val->type() == Item::NULL_ITEM &&
+ !field->field->real_maybe_null())
+ field->field->table->reginfo.not_exists_optimize=1;
+ }
+ }
for (i=0 ; i < tables ; i++)
{
if (join_tab[i].on_expr)
@@ -2464,10 +2487,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
join_tab[i].table->map);
}
}
- if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64))
- return TRUE;
/* fill keyuse with found key parts */
- for (KEY_FIELD *field=key_fields ; field != end ; field++)
+ for ( ; field != end ; field++)
add_key_part(keyuse,field);
if (select_lex->ftfunc_list->elements)
@@ -2717,7 +2738,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
!found_ref_or_null)
{ /* use eq key */
max_key_part= (uint) ~0;
- if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY |
+ HA_END_SPACE_KEY)) == HA_NOSAME)
{
tmp=prev_record_reads(join,found_ref);
records=1.0;
@@ -3230,9 +3252,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
return 0;
if (j->type == JT_CONST)
j->table->const_table= 1;
- else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY))
- != HA_NOSAME) || keyparts != keyinfo->key_parts ||
- null_ref_key)
+ else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY |
+ HA_END_SPACE_KEY)) != HA_NOSAME) ||
+ keyparts != keyinfo->key_parts || null_ref_key)
{
/* Must read with repeat */
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
@@ -3529,7 +3551,7 @@ static void
make_join_readinfo(JOIN *join, uint options)
{
uint i;
- SELECT_LEX *select_lex = &(join->thd->lex->select_lex);
+ SELECT_LEX *select_lex= &join->thd->lex->select_lex;
DBUG_ENTER("make_join_readinfo");
for (i=join->const_tables ; i < join->tables ; i++)
@@ -4053,6 +4075,8 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
}
result->send_eof(); // Should be safe
}
+ /* Update results for FOUND_ROWS */
+ join->thd->limit_found_rows= join->thd->examined_row_count= 0;
DBUG_RETURN(0);
}
@@ -6766,7 +6790,7 @@ part_of_refkey(TABLE *table,Field *field)
for (uint part=0 ; part < ref_parts ; part++,key_part++)
if (field->eq(key_part->field) &&
- !(key_part->key_part_flag & HA_PART_KEY))
+ !(key_part->key_part_flag & HA_PART_KEY_SEG))
return table->reginfo.join_tab->ref.items[part];
}
return (Item*) 0;
@@ -8933,7 +8957,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
List<Item> field_list;
List<Item> item_list;
THD *thd=join->thd;
- SELECT_LEX *select_lex = &(join->thd->lex->select_lex);
+ SELECT_LEX *select_lex= &join->thd->lex->select_lex;
select_result *result=join->result;
Item *item_null= new Item_null();
CHARSET_INFO *cs= &my_charset_latin1;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1816e68b706..3dfef4b7189 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -173,11 +173,11 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
** List all table types supported
***************************************************************************/
-int mysqld_show_table_types(THD *thd)
+int mysqld_show_storage_engines(THD *thd)
{
List<Item> field_list;
Protocol *protocol= thd->protocol;
- DBUG_ENTER("mysqld_show_table_types");
+ DBUG_ENTER("mysqld_show_storage_engines");
field_list.push_back(new Item_empty_string("Type",10));
field_list.push_back(new Item_empty_string("Support",10));
@@ -187,7 +187,7 @@ int mysqld_show_table_types(THD *thd)
DBUG_RETURN(1);
const char *default_type_name=
- ha_get_table_type((enum db_type)thd->variables.table_type);
+ ha_get_storage_engine((enum db_type)thd->variables.table_type);
show_table_type_st *types;
for (types= sys_table_types; types->type; types++)
@@ -384,11 +384,23 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
#ifdef USE_SYMDIR
char *ext;
if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym"))
+ {
+ /* Only show the sym file if it points to a directory */
+ char buff[FN_REFLEN], *end;
+ MY_STAT status;
*ext=0; /* Remove extension */
+ unpack_dirname(buff, file->name);
+ end= strend(buff);
+ if (end != buff && end[-1] == FN_LIBCHAR)
+ end[-1]= 0; // Remove end FN_LIBCHAR
+ if (!my_stat(buff, &status, MYF(0)) ||
+ !MY_S_ISDIR(status.st_mode))
+ continue;
+ }
else
#endif
{
- if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
+ if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) ||
(wild && wild_compare(file->name,wild,0)))
continue;
}
diff --git a/sql/sql_sort.h b/sql/sql_sort.h
index 9f95ffa4884..1831c4a2f3d 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -78,3 +78,4 @@ int merge_buffers(SORTPARAM *param,IO_CACHE *from_file,
IO_CACHE *to_file, uchar *sort_buffer,
BUFFPEK *lastbuff,BUFFPEK *Fb,
BUFFPEK *Tb,int flag);
+void reuse_freed_buff(QUEUE *queue, BUFFPEK *reuse, uint key_length);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9405004abbd..fe2cfcf2b41 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -257,6 +257,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
query_cache_invalidate3(thd, tables, 0);
if (!dont_log_query && mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
tmp_table_deleted && !some_tables_deleted);
mysql_bin_log.write(&qinfo);
@@ -306,10 +307,10 @@ static int sort_keys(KEY *a, KEY *b)
{
if (!(b->flags & HA_NOSAME))
return -1;
- if ((a->flags ^ b->flags) & HA_NULL_PART_KEY)
+ if ((a->flags ^ b->flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY))
{
/* Sort NOT NULL keys before other keys */
- return (a->flags & HA_NULL_PART_KEY) ? 1 : -1;
+ return (a->flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1;
}
if (a->name == primary_key_name)
return -1;
@@ -400,7 +401,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
- ha_get_table_type(new_db_type),
+ ha_get_storage_engine(new_db_type),
table_name);
}
db_options=create_info->table_options;
@@ -984,8 +985,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
thd->tmp_table_used= 1;
}
if (!tmp_table && !no_log && mysql_bin_log.is_open())
- // Must be written before unlock
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
test(create_info->options &
HA_LEX_CREATE_TMP_TABLE));
@@ -1236,7 +1237,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
}
else
{
- char* backup_dir = thd->lex->backup_dir;
+ char* backup_dir= thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
char* db = thd->db ? thd->db : table->db;
@@ -2007,7 +2008,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_USING_OTHER_HANDLER,
ER(ER_WARN_USING_OTHER_HANDLER),
- ha_get_table_type(new_db_type),
+ ha_get_storage_engine(new_db_type),
new_name);
}
if (create_info->row_type == ROW_TYPE_NOT_USED)
@@ -2072,6 +2073,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -2454,6 +2456,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
@@ -2584,6 +2587,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
thd->proc_info="end";
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f256506593e..2f4c6b55963 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -359,6 +359,8 @@ int mysql_update(THD *thd,
{
if (mysql_bin_log.is_open())
{
+ if (error <= 0)
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed);
if (mysql_bin_log.write(&qinfo) && transactional_table)
@@ -480,7 +482,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
:all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0),
updated(0), found(0), fields(field_list), values(value_list),
table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg),
- do_update(1), trans_safe(0)
+ do_update(1), trans_safe(0), transactional_tables(1)
{}
@@ -584,6 +586,27 @@ int multi_update::prepare(List<Item> &not_used_values,
for (i=0 ; i < table_count ; i++)
set_if_bigger(max_fields, fields_for_table[i]->elements);
copy_field= new Copy_field[max_fields];
+
+ /*
+ Mark all copies of tables that are updates to ensure that
+ init_read_record() will not try to enable a cache on them
+
+ The problem is that for queries like
+
+ UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a;
+
+ the row buffer may contain things that doesn't match what is on disk
+ which will cause an error when reading a row.
+ (This issue is mostly relevent for MyISAM tables)
+ */
+ for (table_ref= all_tables; table_ref; table_ref=table_ref->next)
+ {
+ TABLE *table=table_ref->table;
+ if (!(tables_to_update & table->map) &&
+ find_real_table_in_list(update_tables, table_ref->db,
+ table_ref->real_name))
+ table->no_cache= 1; // Disable row cache
+ }
DBUG_RETURN(thd->is_fatal_error != 0);
}
@@ -743,7 +766,7 @@ multi_update::~multi_update()
{
TABLE_LIST *table;
for (table= update_tables ; table; table= table->next)
- table->table->no_keyread=0;
+ table->table->no_keyread= table->table->no_cache= 0;
if (tmp_tables)
{
@@ -878,8 +901,11 @@ int multi_update::do_updates(bool from_send_error)
ha_rows org_updated;
TABLE *table;
DBUG_ENTER("do_updates");
+
- do_update= 0; // Don't retry this function
+ do_update= 0; // Don't retry this function
+ if (!found)
+ DBUG_RETURN(0);
for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
{
table = cur_table->table;
@@ -1005,6 +1031,8 @@ bool multi_update::send_eof()
{
if (mysql_bin_log.is_open())
{
+ if (local_error <= 0)
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
log_delayed);
if (mysql_bin_log.write(&qinfo) && trans_safe)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a16fc60dfbd..a5ec1a20959 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -28,7 +28,7 @@
#define MYSQL_YACC
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
-#define Lex ((YYTHD->lex))
+#define Lex (YYTHD->lex)
#define Select Lex->current_select
#include "mysql_priv.h"
#include "slave.h"
@@ -390,6 +390,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SSL_SYM
%token STARTING
%token STATUS_SYM
+%token STORAGE_SYM
%token STRAIGHT_JOIN
%token SUBJECT_SYM
%token TABLES
@@ -506,6 +507,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ELT_FUNC
%token ENCODE_SYM
%token ENGINE_SYM
+%token ENGINES_SYM
%token ENCRYPT
%token EXPORT_SET
%token EXTRACT_SYM
@@ -627,9 +629,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%left SHIFT_LEFT SHIFT_RIGHT
%left '-' '+'
%left '*' '/' '%' DIV_SYM MOD_SYM
-%left NEG '~'
%left XOR
%left '^'
+%left NEG '~'
%right NOT
%right BINARY COLLATE_SYM
@@ -706,7 +708,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <interval_time_st> interval_time_st
-%type <db_type> table_types
+%type <db_type> storage_engines
%type <row_type> row_types
@@ -798,7 +800,7 @@ query:
}
else
{
- thd->lex->sql_command = SQLCOM_EMPTY_QUERY;
+ thd->lex->sql_command= SQLCOM_EMPTY_QUERY;
}
}
| verb_clause END_OF_INPUT {};
@@ -2103,8 +2105,8 @@ create_table_options:
| create_table_option ',' create_table_options;
create_table_option:
- ENGINE_SYM opt_equal table_types { Lex->create_info.db_type= $3; }
- | TYPE_SYM opt_equal table_types { Lex->create_info.db_type= $3; WARN_DEPRECATED("TYPE=database_engine","ENGINE=database_engine"); }
+ ENGINE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; }
+ | TYPE_SYM opt_equal storage_engines { Lex->create_info.db_type= $3; WARN_DEPRECATED("TYPE=database_engine","ENGINE=database_engine"); }
| MAX_ROWS opt_equal ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
| MIN_ROWS opt_equal ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
| AVG_ROW_LENGTH opt_equal ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
@@ -2157,12 +2159,12 @@ create_table_option:
{ Lex->create_info.data_file_name= $4.str; }
| INDEX DIRECTORY_SYM opt_equal TEXT_STRING_sys { Lex->create_info.index_file_name= $4.str; };
-table_types:
+storage_engines:
ident_or_text
{
$$ = ha_resolve_by_name($1.str,$1.length);
if ($$ == DB_TYPE_UNKNOWN) {
- net_printf(YYTHD, ER_UNKNOWN_TABLE_ENGINE, $1.str);
+ net_printf(YYTHD, ER_UNKNOWN_STORAGE_ENGINE, $1.str);
YYABORT;
}
};
@@ -4053,14 +4055,25 @@ sum_expr:
{ $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); }
| MIN_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_min($3); }
+/*
+ According to ANSI SQL, DISTINCT is allowed and has
+ no sence inside MIN and MAX grouping functions; so MIN|MAX(DISTINCT ...)
+ is processed like an ordinary MIN | MAX()
+ */
+ | MIN_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_min($4); }
| MAX_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_max($3); }
+ | MAX_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_max($4); }
| STD_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_std($3); }
| VARIANCE_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_variance($3); }
| SUM_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_sum($3); }
+ | SUM_SYM '(' DISTINCT in_sum_expr ')'
+ { $$=new Item_sum_sum_distinct($4); }
| GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause
opt_gconcat_separator ')'
{
@@ -5112,7 +5125,7 @@ show_param:
lex->select_lex.db= $3;
lex->select_lex.options= 0;
}
- | ENGINE_SYM table_types
+ | ENGINE_SYM storage_engines
{ Lex->create_info.db_type= $2; }
show_engine_param
| opt_full COLUMNS from_or_in table_ident opt_db wild
@@ -5162,7 +5175,13 @@ show_param:
| TABLE_SYM TYPES_SYM
{
LEX *lex=Lex;
- lex->sql_command= SQLCOM_SHOW_TABLE_TYPES;
+ lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
+ WARN_DEPRECATED("SHOW TABLE TYPES", "SHOW [STORAGE] ENGINES");
+ }
+ | opt_storage ENGINES_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_STORAGE_ENGINES;
}
| PRIVILEGES
{
@@ -5271,6 +5290,10 @@ master_or_binary:
MASTER_SYM
| BINARY;
+opt_storage:
+ /* empty */
+ | STORAGE_SYM;
+
opt_db:
/* empty */ { $$= 0; }
| from_or_in ident { $$= $2.str; };
@@ -5846,6 +5869,7 @@ keyword:
| END {}
| ENUM {}
| ENGINE_SYM {}
+ | ENGINES_SYM {}
| ERRORS {}
| ESCAPE_SYM {}
| EVENTS_SYM {}
@@ -5978,6 +6002,7 @@ keyword:
| START_SYM {}
| STATUS_SYM {}
| STOP_SYM {}
+ | STORAGE_SYM {}
| STRING_SYM {}
| SUBDATE_SYM {}
| SUBJECT_SYM {}
@@ -5992,6 +6017,7 @@ keyword:
| TIMESTAMP_DIFF {}
| TIME_SYM {}
| TYPE_SYM {}
+ | TYPES_SYM {}
| FUNCTION_SYM {}
| UNCOMMITTED_SYM {}
| UNICODE_SYM {}
@@ -6713,6 +6739,7 @@ order_or_limit:
union_option:
/* empty */ {}
+ | DISTINCT {}
| ALL {Select->master_unit()->union_option|= UNION_ALL;};
singlerow_subselect:
diff --git a/sql/table.cc b/sql/table.cc
index 7c12762d9c4..912c133e571 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -507,14 +507,17 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
{
/*
- If the UNIQUE key don't have NULL columns, declare this as
- a primary key.
+ If the UNIQUE key doesn't have NULL columns and is not a part key
+ declare this as a primary key.
*/
primary_key=key;
for (i=0 ; i < keyinfo->key_parts ;i++)
{
- if (!key_part[i].fieldnr ||
- outparam->field[key_part[i].fieldnr-1]->null_ptr)
+ uint fieldnr= key_part[i].fieldnr;
+ if (!fieldnr ||
+ outparam->field[fieldnr-1]->null_ptr ||
+ outparam->field[fieldnr-1]->key_length() !=
+ key_part[i].length)
{
primary_key=MAX_KEY; // Can't be used
break;
@@ -554,6 +557,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
key_part->store_length+=HA_KEY_BLOB_LENGTH;
keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
+ /*
+ Mark that there may be many matching values for one key
+ combination ('a', 'a ', 'a '...)
+ */
+ if (!(field->flags & BINARY_FLAG))
+ keyinfo->flags|= HA_END_SPACE_KEY;
}
if (i == 0 && key != primary_key)
field->flags |=
@@ -591,7 +600,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
if (field->key_length() != key_part->length)
{
- key_part->key_part_flag|= HA_PART_KEY;
+ key_part->key_part_flag|= HA_PART_KEY_SEG;
if (!(field->flags & BLOB_FLAG))
{ // Create a new field
field=key_part->field=field->new_field(&outparam->mem_root,
@@ -605,7 +614,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
as we need to test for NULL = NULL.
*/
if (field->real_maybe_null())
- key_part->key_part_flag|= HA_PART_KEY;
+ key_part->key_part_flag|= HA_PART_KEY_SEG;
}
else
{ // Error: shorten key
@@ -1237,14 +1246,17 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
char *get_field(MEM_ROOT *mem, Field *field)
{
- char buff[MAX_FIELD_WIDTH];
+ char buff[MAX_FIELD_WIDTH], *to;
String str(buff,sizeof(buff),&my_charset_bin);
uint length;
field->val_str(&str,&str);
- if (!(length= str.length()))
+ length= str.length();
+ if (!length || !(to= (char*) alloc_root(mem,length+1)))
return NullS;
- return strmake_root(mem, str.ptr(), length);
+ memcpy(to,str.ptr(),(uint) length);
+ to[length]=0;
+ return to;
}
diff --git a/sql/table.h b/sql/table.h
index e492398ed17..ba7349d33fc 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -117,7 +117,7 @@ struct st_table {
my_bool fulltext_searched;
my_bool crashed;
my_bool is_view;
- my_bool no_keyread;
+ my_bool no_keyread, no_cache;
my_bool clear_query_id; /* To reset query_id for tables and cols */
my_bool auto_increment_field_not_null;
Field *next_number_field, /* Set if next_number is activated */
diff --git a/sql/time.cc b/sql/time.cc
index fe22b80d59d..9a18a150c50 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -124,6 +124,8 @@ long my_gmt_sec(TIME *t, long *my_timezone)
tmp-=t->minute*60 + t->second; // Move to previous hour
}
*my_timezone= current_timezone;
+ if (tmp < 0 && t->year <= 1900+YY_PART_YEAR)
+ tmp= 0;
return (long) tmp;
} /* my_gmt_sec */
@@ -174,42 +176,72 @@ uint calc_days_in_year(uint year)
366 : 365;
}
-/* Calculate week. If 'with_year' is not set, then return a week 0-53, where
- 0 means that it's the last week of the previous year.
- If 'with_year' is set then the week will always be in the range 1-53 and
- the year out parameter will contain the year for the week */
-uint calc_week(TIME *l_time, bool with_year, bool sunday_first_day_of_week,
- uint *year)
+/*
+ The bits in week_format has the following meaning:
+ WEEK_MONDAY_FIRST (0) If not set Sunday is first day of week
+ If set Monday is first day of week
+ WEEK_YEAR (1) If not set Week is in range 0-53
+
+ Week 0 is returned for the the last week of the previous year (for
+ a date at start of january) In this case one can get 53 for the
+ first week of next year. This flag ensures that the week is
+ relevant for the given year. Note that this flag is only
+ releveant if WEEK_JANUARY is not set.
+
+ If set Week is in range 1-53.
+
+ In this case one may get week 53 for a date in January (when
+ the week is that last week of previous year) and week 1 for a
+ date in December.
+
+ WEEK_FIRST_WEEKDAY (2) If not set Weeks are numbered according
+ to ISO 8601:1988
+ If set The week that contains the first
+ 'first-day-of-week' is week 1.
+
+ ISO 8601:1988 means that if the week containing January 1 has
+ four or more days in the new year, then it is week 1;
+ Otherwise it is the last week of the previous year, and the
+ next week is week 1.
+*/
+
+uint calc_week(TIME *l_time, uint week_behaviour, uint *year)
{
uint days;
ulong daynr=calc_daynr(l_time->year,l_time->month,l_time->day);
ulong first_daynr=calc_daynr(l_time->year,1,1);
- uint weekday=calc_weekday(first_daynr,sunday_first_day_of_week);
+ bool monday_first= test(week_behaviour & WEEK_MONDAY_FIRST);
+ bool week_year= test(week_behaviour & WEEK_YEAR);
+ bool first_weekday= test(week_behaviour & WEEK_FIRST_WEEKDAY);
+
+ uint weekday=calc_weekday(first_daynr, !monday_first);
*year=l_time->year;
- if (l_time->month == 1 && l_time->day <= 7-weekday &&
- ((!sunday_first_day_of_week && weekday >= 4) ||
- (sunday_first_day_of_week && weekday != 0)))
+
+ if (l_time->month == 1 && l_time->day <= 7-weekday)
{
- /* Last week of the previous year */
- if (!with_year)
+ if (!week_year &&
+ (first_weekday && weekday != 0 ||
+ !first_weekday && weekday >= 4))
return 0;
- with_year=0; // Don't check the week again
+ week_year= 1;
(*year)--;
first_daynr-= (days=calc_days_in_year(*year));
weekday= (weekday + 53*7- days) % 7;
}
- if ((sunday_first_day_of_week && weekday != 0) ||
- (!sunday_first_day_of_week && weekday >= 4))
+
+ if ((first_weekday && weekday != 0) ||
+ (!first_weekday && weekday >= 4))
days= daynr - (first_daynr+ (7-weekday));
else
days= daynr - (first_daynr - weekday);
- if (with_year && days >= 52*7)
+
+ if (week_year && days >= 52*7)
{
- /* Check if we are on the first week of the next year (or week 53) */
weekday= (weekday + calc_days_in_year(*year)) % 7;
- if (weekday < 4)
- { // We are at first week on next year
+ if (!first_weekday && weekday < 4 ||
+ first_weekday && weekday == 0)
+ {
(*year)++;
return 1;
}
@@ -605,7 +637,7 @@ time_t str_to_timestamp(const char *str,uint length)
if (str_to_TIME(str,length,&l_time,0) <= TIMESTAMP_DATETIME_ERROR)
return(0);
- if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR)
+ if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1)
{
current_thd->cuted_fields++;
return(0);
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index 6748be5a06f..f0f33ed6fd7 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -685,7 +685,7 @@ my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
}
initid->max_length=11;
initid->maybe_null=1;
-#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
(void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
#endif
return 0;
@@ -693,7 +693,7 @@ my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
void lookup_deinit(UDF_INIT *initid)
{
-#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
(void) pthread_mutex_destroy(&LOCK_hostname);
#endif
}
@@ -760,7 +760,7 @@ my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
}
initid->max_length=32;
initid->maybe_null=1;
-#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
(void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
#endif
return 0;
@@ -768,7 +768,7 @@ my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
void reverse_lookup_deinit(UDF_INIT *initid)
{
-#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+#if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_SOLARIS_STYLE_GETHOST)
(void) pthread_mutex_destroy(&LOCK_hostname);
#endif
}
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 17c412873d4..037474fae5d 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -328,6 +328,7 @@ bool Unique::flush()
elements+= tree.elements_in_tree;
file_ptr.count=tree.elements_in_tree;
file_ptr.file_pos=my_b_tell(&file);
+
if (tree_walk(&tree, (tree_walk_action) unique_write_to_file,
(void*) this, left_root_right) ||
insert_dynamic(&file_ptrs, (gptr) &file_ptr))
@@ -338,6 +339,237 @@ bool Unique::flush()
/*
+ Clear the tree and the file.
+ You must call reset() if you want to reuse Unique after walk().
+*/
+
+void
+Unique::reset()
+{
+ reset_tree(&tree);
+ /*
+ If elements != 0, some trees were stored in the file (see how
+ flush() works). Note, that we can not count on my_b_tell(&file) == 0
+ here, because it can return 0 right after walk(), and walk() does not
+ reset any Unique member.
+ */
+ if (elements)
+ {
+ reset_dynamic(&file_ptrs);
+ reinit_io_cache(&file, WRITE_CACHE, 0L, 0, 1);
+ }
+ elements= 0;
+}
+
+/*
+ The comparison function, passed to queue_init() in merge_walk() must
+ use comparison function of Uniques::tree, but compare members of struct
+ BUFFPEK.
+*/
+
+struct BUFFPEK_COMPARE_CONTEXT
+{
+ qsort_cmp2 key_compare;
+ void *key_compare_arg;
+};
+
+C_MODE_START
+
+static int buffpek_compare(void *arg, byte *key_ptr1, byte *key_ptr2)
+{
+ BUFFPEK_COMPARE_CONTEXT *ctx= (BUFFPEK_COMPARE_CONTEXT *) arg;
+ return ctx->key_compare(ctx->key_compare_arg,
+ *((byte **) key_ptr1), *((byte **)key_ptr2));
+}
+
+C_MODE_END
+
+
+/*
+ DESCRIPTION
+ Function is very similar to merge_buffers, but instead of writing sorted
+ unique keys to the output file, it invokes walk_action for each key.
+ This saves I/O if you need to pass through all unique keys only once.
+ SYNOPSIS
+ merge_walk()
+ All params are 'IN' (but see comment for begin, end):
+ merge_buffer buffer to perform cached piece-by-piece loading
+ of trees; initially the buffer is empty
+ merge_buffer_size size of merge_buffer. Must be aligned with
+ key_length
+ key_length size of tree element; key_length * (end - begin)
+ must be less or equal than merge_buffer_size.
+ begin pointer to BUFFPEK struct for the first tree.
+ end pointer to BUFFPEK struct for the last tree;
+ end > begin and [begin, end) form a consecutive
+ range. BUFFPEKs structs in that range are used and
+ overwritten in merge_walk().
+ walk_action element visitor. Action is called for each unique
+ key.
+ walk_action_arg argument to walk action. Passed to it on each call.
+ compare elements comparison function
+ compare_arg comparison function argument
+ file file with all trees dumped. Trees in the file
+ must contain sorted unique values. Cache must be
+ initialized in read mode.
+ RETURN VALUE
+ 0 ok
+ <> 0 error
+*/
+
+static bool merge_walk(uchar *merge_buffer, uint merge_buffer_size,
+ uint key_length, BUFFPEK *begin, BUFFPEK *end,
+ tree_walk_action walk_action, void *walk_action_arg,
+ qsort_cmp2 compare, void *compare_arg,
+ IO_CACHE *file)
+{
+ BUFFPEK_COMPARE_CONTEXT compare_context = { compare, compare_arg };
+ QUEUE queue;
+ if (end <= begin ||
+ merge_buffer_size < key_length * (end - begin + 1) ||
+ init_queue(&queue, end - begin, offsetof(BUFFPEK, key), 0,
+ buffpek_compare, &compare_context))
+ return 1;
+ /* we need space for one key when a piece of merge buffer is re-read */
+ merge_buffer_size-= key_length;
+ uchar *save_key_buff= merge_buffer + merge_buffer_size;
+ uint max_key_count_per_piece= merge_buffer_size/(end-begin)/key_length;
+ /* if piece_size is aligned reuse_freed_buffer will always hit */
+ uint piece_size= max_key_count_per_piece * key_length;
+ uint bytes_read; /* to hold return value of read_to_buffer */
+ BUFFPEK *top;
+ int res= 1;
+ /*
+ Invariant: queue must contain top element from each tree, until a tree
+ is not completely walked through.
+ Here we're forcing the invariant, inserting one element from each tree
+ to the queue.
+ */
+ for (top= begin; top != end; ++top)
+ {
+ top->base= merge_buffer + (top - begin) * piece_size;
+ top->max_keys= max_key_count_per_piece;
+ bytes_read= read_to_buffer(file, top, key_length);
+ if (bytes_read == (uint) (-1))
+ goto end;
+ DBUG_ASSERT(bytes_read);
+ queue_insert(&queue, (byte *) top);
+ }
+ top= (BUFFPEK *) queue_top(&queue);
+ while (queue.elements > 1)
+ {
+ /*
+ Every iteration one element is removed from the queue, and one is
+ inserted by the rules of the invariant. If two adjacent elements on
+ the top of the queue are not equal, biggest one is unique, because all
+ elements in each tree are unique. Action is applied only to unique
+ elements.
+ */
+ void *old_key= top->key;
+ /*
+ read next key from the cache or from the file and push it to the
+ queue; this gives new top.
+ */
+ top->key+= key_length;
+ if (--top->mem_count)
+ queue_replaced(&queue);
+ else /* next piece should be read */
+ {
+ /* save old_key not to overwrite it in read_to_buffer */
+ memcpy(save_key_buff, old_key, key_length);
+ old_key= save_key_buff;
+ bytes_read= read_to_buffer(file, top, key_length);
+ if (bytes_read == (uint) (-1))
+ goto end;
+ else if (bytes_read > 0) /* top->key, top->mem_count are reset */
+ queue_replaced(&queue); /* in read_to_buffer */
+ else
+ {
+ /*
+ Tree for old 'top' element is empty: remove it from the queue and
+ give all its memory to the nearest tree.
+ */
+ queue_remove(&queue, 0);
+ reuse_freed_buff(&queue, top, key_length);
+ }
+ }
+ top= (BUFFPEK *) queue_top(&queue);
+ /* new top has been obtained; if old top is unique, apply the action */
+ if (compare(compare_arg, old_key, top->key))
+ {
+ if (walk_action(old_key, 1, walk_action_arg))
+ goto end;
+ }
+ }
+ /*
+ Applying walk_action to the tail of the last tree: this is safe because
+ either we had only one tree in the beginning, either we work with the
+ last tree in the queue.
+ */
+ do
+ {
+ do
+ {
+ if (walk_action(top->key, 1, walk_action_arg))
+ goto end;
+ top->key+= key_length;
+ }
+ while (--top->mem_count);
+ bytes_read= read_to_buffer(file, top, key_length);
+ if (bytes_read == (uint) (-1))
+ goto end;
+ }
+ while (bytes_read);
+ res= 0;
+end:
+ delete_queue(&queue);
+ return res;
+}
+
+
+/*
+ DESCRIPTION
+ Walks consecutively through all unique elements:
+ if all elements are in memory, then it simply invokes 'tree_walk', else
+ all flushed trees are loaded to memory piece-by-piece, pieces are
+ sorted, and action is called for each unique value.
+ Note: so as merging resets file_ptrs state, this method can change
+ internal Unique state to undefined: if you want to reuse Unique after
+ walk() you must call reset() first!
+ SYNOPSIS
+ Unique:walk()
+ All params are 'IN':
+ action function-visitor, typed in include/my_tree.h
+ function is called for each unique element
+ arg argument for visitor, which is passed to it on each call
+ RETURN VALUE
+ 0 OK
+ <> 0 error
+ */
+
+bool Unique::walk(tree_walk_action action, void *walk_action_arg)
+{
+ if (elements == 0) /* the whole tree is in memory */
+ return tree_walk(&tree, action, walk_action_arg, left_root_right);
+
+ /* flush current tree to the file to have some memory for merge buffer */
+ if (flush())
+ return 1;
+ if (flush_io_cache(&file) || reinit_io_cache(&file, READ_CACHE, 0L, 0, 0))
+ return 1;
+ uchar *merge_buffer= (uchar *) my_malloc(max_in_memory_size, MYF(0));
+ if (merge_buffer == 0)
+ return 1;
+ int res= merge_walk(merge_buffer, max_in_memory_size, size,
+ (BUFFPEK *) file_ptrs.buffer,
+ (BUFFPEK *) file_ptrs.buffer + file_ptrs.elements,
+ action, walk_action_arg,
+ tree.compare, tree.custom_arg, &file);
+ x_free(merge_buffer);
+ return res;
+}
+
+/*
Modify the TABLE element so that when one calls init_records()
the rows will be read in priority order.
*/
@@ -358,7 +590,7 @@ bool Unique::get(TABLE *table)
return 0;
}
}
- /* Not enough memory; Save the result to file */
+ /* Not enough memory; Save the result to file && free memory used by tree */
if (flush())
return 1;
@@ -382,7 +614,7 @@ bool Unique::get(TABLE *table)
bzero((char*) &sort_param,sizeof(sort_param));
sort_param.max_rows= elements;
sort_param.sort_form=table;
- sort_param.rec_length= sort_param.sort_length=sort_param.ref_length=
+ sort_param.rec_length= sort_param.sort_length= sort_param.ref_length=
size;
sort_param.keys= max_in_memory_size / sort_param.sort_length;
sort_param.not_killable=1;