diff options
author | unknown <monty@mysql.com> | 2003-12-17 17:35:34 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2003-12-17 17:35:34 +0200 |
commit | 0fb88806e44f48aba363bfda5ebedaaa3b05b975 (patch) | |
tree | 93924b5aab311e02a0f0931cf91e67cdfad04bdf /sql | |
parent | 029e30b4aa357708bdbf924cfd78069fb19382bb (diff) | |
parent | 4bdfe0fb0107f2fb3e9cfb1c8a417e1028c67dcc (diff) | |
download | mariadb-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')
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, ¬_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, ¬_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, ¬_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, ¬_used, ¬_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(<ime,0)) return 0; - week_format= (uint) args[1]->val_int(); - return (longlong) calc_week(<ime, - (week_format & 2) != 0, - (week_format & 1) == 0, + return (longlong) calc_week(<ime, + week_mode((uint) args[1]->val_int()), &year); } @@ -749,7 +784,9 @@ longlong Item_func_yearweek::val_int() TIME ltime; if (get_arg0_date(<ime,0)) return 0; - week=calc_week(<ime, 1, (args[1]->val_int() & 1) == 0, &year); + week= calc_week(<ime, + (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> ¬_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; |