summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2003-12-17 17:35:34 +0200
committerunknown <monty@mysql.com>2003-12-17 17:35:34 +0200
commit0fb88806e44f48aba363bfda5ebedaaa3b05b975 (patch)
tree93924b5aab311e02a0f0931cf91e67cdfad04bdf /sql
parent029e30b4aa357708bdbf924cfd78069fb19382bb (diff)
parent4bdfe0fb0107f2fb3e9cfb1c8a417e1028c67dcc (diff)
downloadmariadb-git-0fb88806e44f48aba363bfda5ebedaaa3b05b975.tar.gz
Merge with 4.0.17
BitKeeper/etc/logging_ok: auto-union Build-tools/Do-compile: Auto merged acinclude.m4: Auto merged configure.in: Auto merged dbug/dbug.c: Auto merged include/config-win.h: Auto merged include/my_base.h: Auto merged include/my_global.h: Auto merged include/my_pthread.h: Auto merged include/my_sys.h: Auto merged include/mysql.h: Auto merged include/mysql_com.h: Auto merged innobase/lock/lock0lock.c: Auto merged innobase/row/row0ins.c: Auto merged innobase/row/row0sel.c: Auto merged innobase/row/row0umod.c: Auto merged innobase/row/row0upd.c: Auto merged myisam/ft_boolean_search.c: Auto merged myisam/mi_check.c: Auto merged myisam/mi_dbug.c: Auto merged myisam/mi_open.c: Auto merged mysql-test/r/auto_increment.result: Auto merged mysql-test/r/bdb.result: Auto merged mysql-test/r/func_op.result: Auto merged Build-tools/Bootstrap: Merge with 4.0 client/mysql.cc: Merge with 4.0 client/mysqldump.c: Merge with 4.0 client/mysqltest.c: Use local version innobase/btr/btr0cur.c: Merge with 4.0 (Heikki should check if we should remove btr_cur_update_sec_rec_in_place() libmysql/libmysql.c: Merge with 4.0 libmysqld/lib_sql.cc: Merge with 4.0 myisam/mi_key.c: Merge with 4.0 myisam/mi_search.c: Merge with 4.0 mysql-test/r/binary.result: Merge with 4.0 mysql-test/r/func_group.result: Merge with 4.0 mysql-test/r/func_str.result: Merge with 4.0 mysql-test/r/func_time.result: Merge with 4.0 mysql-test/r/group_by.result: Merge with 4.0 mysql-test/r/handler.result: Merge with 4.0 mysql-test/r/innodb.result: Merge with 4.0 mysql-test/r/insert.result: Merge with 4.0 mysql-test/r/join_outer.result: Merge with 4.0 mysql-test/r/loaddata.result: Merge with 4.0 mysql-test/r/lowercase_table.result: Merge with 4.0 mysql-test/r/multi_update.result: Merge with 4.0 mysql-test/r/mysqldump.result: Merge with 4.0 mysql-test/r/query_cache.result: Merge with 4.0 mysql-test/r/rpl_max_relay_size.result: Merge with 4.0 mysql-test/r/rpl_rotate_logs.result: Merge with 4.0 mysql-test/r/rpl_trunc_binlog.result: Merge with 4.0 mysql-test/r/select_found.result: Merge with 4.0 mysql-test/r/symlink.result: Merge with 4.0 mysql-test/r/truncate.result: Merge with 4.0 mysql-test/r/type_blob.result: Merge with 4.0 mysql-test/r/type_datetime.result: Merge with 4.0 mysql-test/r/type_decimal.result: Merge with 4.0 mysql-test/r/type_enum.result: Merge with 4.0 mysql-test/r/type_timestamp.result: Merge with 4.0 mysql-test/r/union.result: Merge with 4.0 mysql-test/t/auto_increment.test: Merge with 4.0 mysql-test/t/bdb.test: Merge with 4.0 mysql-test/t/func_group.test: Merge with 4.0 mysql-test/t/func_op.test: Merge with 4.0 mysql-test/t/func_str.test: Merge with 4.0 mysql-test/t/func_time.test: Merge with 4.0 mysql-test/t/group_by.test: Merge with 4.0 mysql-test/t/handler.test: Merge with 4.0 mysql-test/t/innodb.test: Merge with 4.0 mysql-test/t/insert.test: Merge with 4.0 mysql-test/t/join_outer.test: Merge with 4.0 mysql-test/t/limit.test: Merge with 4.0 mysql-test/t/loaddata.test: Merge with 4.0 mysql-test/t/lowercase_table.test: Merge with 4.0 mysql-test/t/multi_update.test: Merge with 4.0 mysql-test/t/mysqldump.test: Merge with 4.0 mysql-test/t/query_cache.test: Merge with 4.0 mysql-test/t/rpl_log_pos.test: Merge with 4.0 mysql-test/t/rpl_max_relay_size.test: Merge with 4.0 mysql-test/t/rpl_rotate_logs.test: Merge with 4.0 mysql-test/t/rpl_trunc_binlog.test: Merge with 4.0 mysql-test/t/select_found.test: Merge with 4.0 mysql-test/t/symlink.test: Merge with 4.0 mysql-test/t/truncate.test: Merge with 4.0 mysql-test/t/type_blob.test: Merge with 4.0 mysql-test/t/type_datetime.test: Merge with 4.0 mysql-test/t/type_decimal.test: Merge with 4.0 mysql-test/t/type_enum.test: Merge with 4.0 mysql-test/t/type_timestamp.test: Merge with 4.0 mysql-test/t/union.test: Merge with 4.0 mysys/charset.c: Merge with 4.0 mysys/my_init.c: Merge with 4.0 mysys/my_symlink.c: Merge with 4.0 mysys/my_thr_init.c: Merge with 4.0 regex/reginit.c: Merge with 4.0 sql/field.cc: Change fix_datetime() to print errors sql/field.h: Merge with 4.0 sql/ha_innodb.cc: Merge with 4.0 sql/item.cc: Merge with 4.0 sql/item.h: Merge with 4.0 sql/item_cmpfunc.cc: Merge with 4.0 sql/item_func.cc: Merge with 4.0 sql/item_func.h: Merge with 4.0 sql/item_strfunc.cc: Merge with 4.0 sql/item_strfunc.h: Merge with 4.0 sql/item_sum.cc: Merge with 4.0 sql/item_sum.h: Merge with 4.0 sql/item_timefunc.cc: Merge with 4.0 sql/lex.h: Merge with 4.0 sql/log.cc: Merge with 4.0 sql/log_event.cc: Merge with 4.0 sql/log_event.h: Merge with 4.0 sql/mysql_priv.h: Merge with 4.0 sql/mysqld.cc: Merge with 4.0 sql/nt_servc.cc: Merge with 4.0 sql/opt_range.cc: Merge with 4.0 sql/records.cc: Merge with 4.0 sql/repl_failsafe.cc: Merge with 4.0 sql/slave.cc: Merge with 4.0 sql/sql_acl.cc: Merge with 4.0 sql/sql_analyse.cc: Merge with 4.0 sql/sql_base.cc: Merge with 4.0 sql/sql_cache.cc: Merge with 4.0 sql/sql_class.h: Merge with 4.0 sql/sql_db.cc: Merge with 4.0 sql/sql_delete.cc: Merge with 4.0 sql/sql_insert.cc: Merge with 4.0 sql/sql_load.cc: Merge with 4.0 sql/sql_parse.cc: Merge with 4.0 sql/sql_rename.cc: Merge with 4.0 sql/sql_select.cc: Merge with 4.0 sql/sql_show.cc: Merge with 4.0 sql/sql_table.cc: Merge with 4.0 sql/sql_update.cc: Merge with 4.0 sql/sql_yacc.yy: Merge with 4.0 sql/table.cc: Merge with 4.0 sql/table.h: Merge with 4.0 sql/time.cc: Merge with 4.0 sql/uniques.cc: Merge with 4.0 strings/ctype-tis620.c: Merge with 4.0 strings/strto.c: Merge with 4.0 support-files/mysql.server.sh: Merge with 4.0 support-files/mysql.spec.sh: Merge with 4.0
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc136
-rw-r--r--sql/field.h8
-rw-r--r--sql/ha_innodb.cc4
-rw-r--r--sql/item.cc13
-rw-r--r--sql/item.h7
-rw-r--r--sql/item_func.cc25
-rw-r--r--sql/item_func.h45
-rw-r--r--sql/item_strfunc.cc21
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_sum.cc56
-rw-r--r--sql/item_sum.h21
-rw-r--r--sql/item_timefunc.cc73
-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.h9
-rw-r--r--sql/mysqld.cc103
-rw-r--r--sql/nt_servc.cc4
-rw-r--r--sql/opt_range.cc53
-rw-r--r--sql/records.cc11
-rw-r--r--sql/repl_failsafe.cc8
-rw-r--r--sql/slave.cc35
-rw-r--r--sql/sql_acl.cc12
-rw-r--r--sql/sql_analyse.cc8
-rw-r--r--sql/sql_base.cc18
-rw-r--r--sql/sql_cache.cc34
-rw-r--r--sql/sql_class.h13
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_delete.cc22
-rw-r--r--sql/sql_insert.cc7
-rw-r--r--sql/sql_load.cc63
-rw-r--r--sql/sql_parse.cc37
-rw-r--r--sql/sql_rename.cc1
-rw-r--r--sql/sql_select.cc54
-rw-r--r--sql/sql_show.cc14
-rw-r--r--sql/sql_table.cc9
-rw-r--r--sql/sql_update.cc33
-rw-r--r--sql/sql_yacc.yy1
-rw-r--r--sql/table.cc29
-rw-r--r--sql/table.h2
-rw-r--r--sql/time.cc72
-rw-r--r--sql/uniques.cc16
42 files changed, 756 insertions, 350 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 23f6e1232b6..c54e27360b5 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,71 @@ 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;
+ 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 +2925,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 +2944,14 @@ 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);
+ if (current_thd->count_cuted_fields)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED,
+ field_name, 0);
+ return 1;
}
@@ -3350,7 +3385,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 +3398,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 +3861,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 +3873,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 +5094,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 +5189,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((char*)"",0);
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
(uint) strlen(typelib->type_names[tmp-1]),
@@ -5219,12 +5249,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))
{
@@ -5233,7 +5264,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 */
@@ -5243,16 +5274,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..223ff4135d4 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -872,11 +872,12 @@ 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) {};
+ 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
@@ -927,6 +928,7 @@ public:
{
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/ha_innodb.cc b/sql/ha_innodb.cc
index 7fc0664445d..4e42d629a0f 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1860,7 +1860,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;
@@ -3345,7 +3345,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/item.cc b/sql/item.cc
index 072a7e5878f..9a9b8fe26a8 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -101,6 +101,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),
@@ -1734,12 +1742,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 a94a7a77597..90a0a706073 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -239,12 +239,7 @@ 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);
const char *full_name() const;
bool remove_dependence_processor(byte * arg);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0ccc7febd0a..7495987856a 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -372,8 +372,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,default_charset());
return str;
}
@@ -385,7 +384,7 @@ String *Item_num_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
- else if (!unsigned_flag)
+ if (!unsigned_flag)
str->set(nr,default_charset());
else
str->set((ulonglong) nr,default_charset());
@@ -395,8 +394,7 @@ String *Item_num_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,default_charset());
}
return str;
}
@@ -422,7 +420,7 @@ String *Item_int_func::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else if (!unsigned_flag)
+ if (!unsigned_flag)
str->set(nr,default_charset());
else
str->set((ulonglong) nr,default_charset());
@@ -451,7 +449,7 @@ String *Item_num_op::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0; /* purecov: inspected */
- else if (!unsigned_flag)
+ if (!unsigned_flag)
str->set(nr,default_charset());
else
str->set((ulonglong) nr,default_charset());
@@ -461,8 +459,7 @@ String *Item_num_op::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,default_charset());
}
return str;
}
@@ -1032,7 +1029,7 @@ String *Item_func_min_max::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else if (!unsigned_flag)
+ if (!unsigned_flag)
str->set(nr,default_charset());
else
str->set((ulonglong) nr,default_charset());
@@ -1043,8 +1040,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,default_charset());
return str;
}
case STRING_RESULT:
@@ -1672,8 +1668,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,default_charset());
return str;
}
@@ -1693,7 +1688,7 @@ String *Item_func_udf_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- else if (!unsigned_flag)
+ if (!unsigned_flag)
str->set(nr,default_charset());
else
str->set((ulonglong) nr,default_charset());
diff --git a/sql/item_func.h b/sql/item_func.h
index 6b43ebaccbe..739110fd81f 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -659,25 +659,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
@@ -689,32 +695,29 @@ 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_int::print(str); }
};
class Item_func_set_last_insert_id :public Item_int_func
@@ -1021,14 +1024,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..16c886b558e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1839,14 +1839,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 +1944,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 +2381,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 +2514,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_sum.cc b/sql/item_sum.cc
index 62782e1f710..8d9973e78f8 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -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;
}
@@ -776,9 +779,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 +926,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 +935,7 @@ Item_avg_field::Item_avg_field(Item_sum_avg *item)
maybe_null=1;
}
+
double Item_avg_field::val()
{
double nr;
@@ -1415,8 +1395,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 +1420,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..3fe40ca4c68 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -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; }
@@ -445,10 +456,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):
@@ -464,11 +475,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 +487,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);
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index a5372a4ae60..9799c5814c4 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;
}
diff --git a/sql/log.cc b/sql/log.cc
index 936373daf03..b490845c256 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 d0dc0a83b11..b609e6c6b11 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 7164a4e496d..bff9ed94a23 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -283,6 +283,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;
@@ -418,6 +423,7 @@ void 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
@@ -977,8 +983,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 49f0b753549..36fa744e328 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -497,6 +497,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
/****************************************************************************
@@ -1058,7 +1060,7 @@ static void set_user(const char *user)
}
return;
}
- else if (!user)
+ if (!user)
{
if (!opt_bootstrap)
{
@@ -1480,16 +1482,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
}
@@ -1775,16 +1768,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)
{
@@ -2756,7 +2741,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"))
{
@@ -4592,7 +4577,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.",
@@ -4635,7 +4620,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],
@@ -5373,11 +5358,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
{
@@ -5787,6 +5771,17 @@ 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 because file system for '%s' is case insensitive", mysql_real_data_home);
+ }
}
@@ -5940,6 +5935,60 @@ 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];
+ sprintf(buff,"%lu\n",(ulong) getpid());
+ (void) my_write(file, buff,strlen(buff),MYF(MY_WME));
+ (void) my_close(file, MYF(0));
+ }
+}
+
+
/*****************************************************************************
Instantiate templates
*****************************************************************************/
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 bbdc1913a8c..54c3f3c0ae3 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -966,9 +966,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)
@@ -1069,16 +1070,39 @@ 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);
+ char *end;
+ 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) {
@@ -1460,7 +1484,7 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
}
return 0;
}
- else if (!key2)
+ if (!key2)
{
key1->use_count--;
key1->free_tree();
@@ -2219,7 +2243,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
@@ -2373,7 +2398,8 @@ get_quick_keys(PARAM *param,QUICK_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,
@@ -2419,7 +2445,7 @@ bool QUICK_SELECT::unique_key_range()
if (((tmp=ranges.head())->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);
}
}
@@ -2454,6 +2480,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
QUICK_SELECT *quick=new QUICK_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)
@@ -2461,18 +2488,18 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
if (cp_buffer_from_ref(ref))
{
if (thd->is_fatal_error)
- return 0; // out of memory
+ goto err; // out of memory
return quick; // empty range
}
- 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 7ba9ff0f42f..0feb873a6af 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 084f7386b7b..18456af8048 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;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index b13ac799c9b..7f9967618ca 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2352,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);
@@ -4036,8 +4038,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
@@ -4050,15 +4064,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 5364357a24b..c0f36f202f3 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)
@@ -1186,6 +1191,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();
mysql_update_log.write(thd, buff, query_length);
Query_log_event qinfo(thd, buff, query_length, 0);
mysql_bin_log.write(&qinfo);
@@ -1258,11 +1264,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
}
}
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 55ddfec6bfb..ebb94e11d9d 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);
+ casedn_str(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,
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 396764cd532..71dd7123d98 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1206,9 +1206,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);
}
@@ -2218,9 +2238,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 1fce0049269..5479a3cecb6 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -589,7 +589,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 query_length;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
@@ -607,7 +607,7 @@ public:
bool last_cuted_field;
bool no_errors, allow_sum_func, 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;
bool volatile killed;
bool tmp_table_used;
@@ -750,6 +750,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...)
@@ -761,7 +766,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() {}
};
@@ -1109,7 +1114,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_db.cc b/sql/sql_db.cc
index c61e6800cfa..1f652524ed3 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -298,6 +298,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
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);
@@ -384,6 +385,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);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 94ae1743fd9..4ab0cfa20c1 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);
@@ -205,6 +211,8 @@ cleanup:
mysql_update_log.write(thd,thd->query, thd->query_length);
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)
@@ -251,7 +259,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)
{
@@ -355,6 +363,7 @@ bool multi_delete::send_data(List<Item> &values)
continue;
table->file->position(table->record[0]);
+ found++;
if (secure_counter < 0)
{
@@ -430,7 +439,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)
@@ -440,6 +449,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++)
@@ -510,6 +521,8 @@ bool multi_delete::send_eof()
mysql_update_log.write(thd,thd->query,thd->query_length);
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)
@@ -621,6 +634,7 @@ end:
mysql_update_log.write(thd,thd->query,thd->query_length);
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 4484cdbe248..46ff9770893 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -380,6 +380,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
mysql_update_log.write(thd, thd->query, thd->query_length);
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)
@@ -645,7 +647,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);
@@ -1512,6 +1514,8 @@ bool select_insert::send_eof()
mysql_update_log.write(thd,thd->query,thd->query_length);
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);
@@ -1525,7 +1529,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_load.cc b/sql/sql_load.cc
index 0f39ab2663f..0c35e99ed08 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;
@@ -395,7 +402,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;
@@ -415,6 +422,17 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
my_error(ER_SERVER_SHUTDOWN,MYF(0));
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
@@ -485,7 +503,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;
@@ -536,6 +554,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())
@@ -875,7 +899,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 92a21b5982d..6e6ec025a1f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -333,8 +333,7 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1);
}
}
- else
- send_ok(thd);
+ send_ok(thd);
thd->password= test(passwd_len); // remember for error messages
/* Ready to handle queries */
DBUG_RETURN(0);
@@ -1815,9 +1814,18 @@ mysql_execute_command(THD *thd)
}
}
}
- if (&lex->select_lex != lex->all_selects_list &&
- lex->unit.create_total_list(thd, lex, &tables, 0))
- DBUG_VOID_RETURN;
+ if (&lex->select_lex != lex->all_selects_list)
+ {
+ byte *save= lex->select_lex.table_list.first;
+ if (lex->sql_command == SQLCOM_CREATE_TABLE)
+ {
+ /* Skip first table, which is the table we are creating */
+ lex->select_lex.table_list.first= (byte*) (((TABLE_LIST *) save)->next);
+ }
+ if (lex->unit.create_total_list(thd, lex, &tables, 0))
+ DBUG_VOID_RETURN;
+ lex->select_lex.table_list.first= save;
+ }
/*
When option readonly is set deny operations which change tables.
@@ -2595,7 +2603,6 @@ 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
@@ -2616,6 +2623,11 @@ mysql_execute_command(THD *thd)
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;
@@ -3247,6 +3259,7 @@ mysql_execute_command(THD *thd)
mysql_update_log.write(thd, thd->query, thd->query_length);
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);
}
@@ -3267,6 +3280,7 @@ mysql_execute_command(THD *thd)
mysql_update_log.write(thd, thd->query, thd->query_length);
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);
}
@@ -3780,7 +3794,9 @@ mysql_init_query(THD *thd)
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);
@@ -3987,7 +4003,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->net, 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)) ==
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 19b4d299e59..3ab6621f35b 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -82,6 +82,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
mysql_update_log.write(thd,thd->query,thd->query_length);
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_select.cc b/sql/sql_select.cc
index 0bf493ee953..b2224d3ca9d 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1119,6 +1119,21 @@ JOIN::exec()
if (select_options & SELECT_DESCRIBE)
{
+ /*
+ 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 && !no_order)
order=group_list;
if (order &&
@@ -1859,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)
@@ -2343,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;
}
@@ -2445,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)
@@ -2465,7 +2490,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
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)
@@ -2715,7 +2740,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;
@@ -3228,9 +3254,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;
@@ -4051,6 +4077,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);
}
@@ -6764,7 +6792,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;
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 855b5d1e97e..741c8e3a1f5 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -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_table.cc b/sql/sql_table.cc
index 3a579986b6e..4b94559b5eb 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -260,6 +260,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
mysql_update_log.write(thd, thd->query,thd->query_length);
if (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);
@@ -310,10 +311,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;
@@ -993,6 +994,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
+ thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
test(create_info->options &
HA_LEX_CREATE_TMP_TABLE));
@@ -2082,6 +2084,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_update_log.write(thd, thd->query, thd->query_length);
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);
}
@@ -2465,6 +2468,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_update_log.write(thd, thd->query,thd->query_length);
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);
}
@@ -2596,6 +2600,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_update_log.write(thd, thd->query,thd->query_length);
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 95dff107350..9f54b838e41 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -352,6 +352,8 @@ int mysql_update(THD *thd,
mysql_update_log.write(thd,thd->query,thd->query_length);
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)
@@ -473,7 +475,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)
{}
@@ -577,6 +579,26 @@ 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) &&
+ check_dup(table_ref->db, table_ref->real_name, update_tables))
+ table->no_cache= 1; // Disable row cache
+ }
DBUG_RETURN(thd->is_fatal_error != 0);
}
@@ -718,7 +740,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)
{
@@ -853,8 +875,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;
@@ -981,6 +1006,8 @@ bool multi_update::send_eof()
mysql_update_log.write(thd,thd->query,thd->query_length);
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 3e013d89992..ef71036206a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5491,6 +5491,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 e87cafd5275..fc1b8a13497 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
@@ -1225,14 +1234,16 @@ 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()))
+ 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 4dcd24b2aff..00fe803cde2 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -116,7 +116,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/uniques.cc b/sql/uniques.cc
index f289fd11f5b..d060965aa66 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -37,14 +37,20 @@
int unique_write_to_file(gptr key, element_count count, Unique *unique)
{
+ /*
+ Use unique->size (size of element stored in the tree) and not
+ unique->tree.size_of_element. The latter is different from unique->size
+ when tree implementation chooses to store pointer to key in TREE_ELEMENT
+ (instead of storing the element itself there)
+ */
return my_b_write(&unique->file, (byte*) key,
- unique->tree.size_of_element) ? 1 : 0;
+ unique->size) ? 1 : 0;
}
int unique_write_to_ptrs(gptr key, element_count count, Unique *unique)
{
- memcpy(unique->record_pointers, key, unique->tree.size_of_element);
- unique->record_pointers+=unique->tree.size_of_element;
+ memcpy(unique->record_pointers, key, unique->size);
+ unique->record_pointers+=unique->size;
return 0;
}
@@ -132,8 +138,8 @@ 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=
- tree.size_of_element;
+ 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;