diff options
author | unknown <bell@sanja.is.com.ua> | 2004-07-16 15:45:06 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2004-07-16 15:45:06 +0300 |
commit | da3e0586a075d163e6d10b45328e622a897542b2 (patch) | |
tree | a2a5f299312fcc90c5a9d8008f5365989bfb76bf /sql | |
parent | 1c8e92c67eb007fed97c074ad51fb4024e6349c3 (diff) | |
parent | 8fb915f8e497a0376e213a48038517b3838b26db (diff) | |
download | mariadb-git-da3e0586a075d163e6d10b45328e622a897542b2.tar.gz |
Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-4.1
into sanja.is.com.ua:/home/bell/mysql/bk/work-4.1
Diffstat (limited to 'sql')
59 files changed, 509 insertions, 135 deletions
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index e052a819ef8..a4fe2aaa8cc 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -188,9 +188,9 @@ static int free_share(ARCHIVE_SHARE *share) hash_delete(&archive_open_tables, (byte*) share); thr_lock_delete(&share->lock); pthread_mutex_destroy(&share->mutex); - my_free((gptr) share, MYF(0)); if (gzclose(share->archive_write) == Z_ERRNO) rc= -1; + my_free((gptr) share, MYF(0)); } pthread_mutex_unlock(&archive_mutex); diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 03e296d0eae..2fab80f0598 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -72,7 +72,7 @@ public: return (HA_REC_NOT_IN_SEQ | HA_NOT_EXACT_COUNT | HA_NO_AUTO_INCREMENT | HA_FILE_BASED); } - ulong index_flags(uint idx, uint part) const + ulong index_flags(uint idx, uint part, bool all_parts) const { return 0; } diff --git a/sql/examples/ha_example.h b/sql/examples/ha_example.h index dc8f265c16e..3c6ce4220ee 100644 --- a/sql/examples/ha_example.h +++ b/sql/examples/ha_example.h @@ -69,12 +69,16 @@ public: return 0; } /* - This is a list of flags that says how the storage engine + This is a bitmap of flags that says how the storage engine implements indexes. The current index flags are documented in handler.h. If you do not implement indexes, just return zero here. + + part is the key part to check. First key part is 0 + If all_parts it's set, MySQL want to know the flags for the combined + index up to and including 'part'. */ - ulong index_flags(uint inx, uint part) const + ulong index_flags(uint inx, uint part, bool all_parts) const { return 0; } diff --git a/sql/field.cc b/sql/field.cc index 2d3729817b7..26c84575b4d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -431,9 +431,9 @@ void Field::store_time(TIME *ltime,timestamp_type type) } -bool Field::optimize_range(uint idx) +bool Field::optimize_range(uint idx, uint part) { - return test(table->file->index_flags(idx) & HA_READ_RANGE); + return test(table->file->index_flags(idx, part, 1) & HA_READ_RANGE); } /**************************************************************************** diff --git a/sql/field.h b/sql/field.h index a2fe77e18a3..24faee9d314 100644 --- a/sql/field.h +++ b/sql/field.h @@ -178,7 +178,7 @@ public: inline bool real_maybe_null(void) { return null_ptr != 0; } virtual void make_field(Send_field *)=0; virtual void sort_string(char *buff,uint length)=0; - virtual bool optimize_range(uint idx); + virtual bool optimize_range(uint idx, uint part); virtual bool store_for_compare() { return 0; } virtual void free() {} Field *new_field(MEM_ROOT *root, struct st_table *new_table) @@ -1134,7 +1134,7 @@ public: uint size_of() const { return sizeof(*this); } enum_field_types real_type() const { return FIELD_TYPE_ENUM; } virtual bool zero_pack() const { return 0; } - bool optimize_range(uint idx) { return 0; } + bool optimize_range(uint idx, uint part) { return 0; } bool eq_def(Field *field); bool has_charset(void) const { return TRUE; } field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; } diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 4bed33af15b..39ef6ca855a 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -340,6 +340,35 @@ const char **ha_berkeley::bas_ext() const { static const char *ext[]= { ha_berkeley_ext, NullS }; return ext; } +ulong ha_berkeley::index_flags(uint idx, uint part, bool all_parts) const +{ + ulong flags= (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_KEYREAD_ONLY + | HA_READ_RANGE); + for (uint i= all_parts ? 0 : part ; i <= part ; i++) + { + if (table->key_info[idx].key_part[i].field->type() == FIELD_TYPE_BLOB) + { + /* We can't use BLOBS to shortcut sorts */ + flags&= ~(HA_READ_ORDER | HA_KEYREAD_ONLY | HA_READ_RANGE); + break; + } + switch (table->key_info[idx].key_part[i].field->key_type()) { + case HA_KEYTYPE_TEXT: + case HA_KEYTYPE_VARTEXT: + /* + As BDB stores only one copy of equal strings, we can't use key read + on these + */ + flags&= ~HA_KEYREAD_ONLY; + break; + default: // Keep compiler happy + break; + } + } + return flags; +} + + static int berkeley_cmp_hidden_key(DB* file, const DBT *new_key, const DBT *saved_key) { diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index 52116710726..5cba3bebf10 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -94,14 +94,7 @@ class ha_berkeley: public handler changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0) {} ~ha_berkeley() {} const char *table_type() const { return "BerkeleyDB"; } - ulong index_flags(uint idx, uint part) const - { - ulong flags=HA_READ_NEXT | HA_READ_PREV; - if (part == (uint)~0 || - table->key_info[idx].key_part[part].field->key_type() != HA_KEYTYPE_TEXT) - flags|= HA_READ_ORDER | HA_KEYREAD_ONLY | HA_READ_RANGE; - return flags; - } + ulong index_flags(uint idx, uint part, bool all_parts) const; const char *index_type(uint key_number) { return "BTREE"; } const char **bas_ext() const; ulong table_flags(void) const { return int_table_flags; } diff --git a/sql/ha_heap.h b/sql/ha_heap.h index f05146acdc4..9ca6b9b76b6 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -44,7 +44,7 @@ class ha_heap: public handler HA_REC_NOT_IN_SEQ | HA_READ_RND_SAME | HA_CAN_INSERT_DELAYED); } - ulong index_flags(uint inx, uint part) const + ulong index_flags(uint inx, uint part, bool all_parts) const { return ((table->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ? HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE : diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 7e05488289e..e09697f7ce6 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -94,7 +94,7 @@ class ha_innobase: public handler const char *index_type(uint key_number) { return "BTREE"; } const char** bas_ext() const; ulong table_flags() const { return int_table_flags; } - ulong index_flags(uint idx, uint part) const + ulong index_flags(uint idx, uint part, bool all_parts) const { return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER | HA_READ_RANGE | HA_KEYREAD_ONLY); diff --git a/sql/ha_isam.h b/sql/ha_isam.h index 521946a17b5..b3e932696cb 100644 --- a/sql/ha_isam.h +++ b/sql/ha_isam.h @@ -36,7 +36,7 @@ class ha_isam: public handler HA_DUPP_POS | HA_NOT_DELETE_WITH_CACHE | HA_FILE_BASED) {} ~ha_isam() {} - ulong index_flags(uint idx, uint part) const + ulong index_flags(uint idx, uint part, bool all_parts) const { return HA_READ_NEXT; } // but no HA_READ_PREV here!!! const char *table_type() const { return "ISAM"; } const char *index_type(uint key_number) { return "BTREE"; } diff --git a/sql/ha_isammrg.h b/sql/ha_isammrg.h index 166a96cf9e4..657e5060272 100644 --- a/sql/ha_isammrg.h +++ b/sql/ha_isammrg.h @@ -34,7 +34,8 @@ class ha_isammrg: public handler const char **bas_ext() const; ulong table_flags() const { return (HA_READ_RND_SAME | HA_REC_NOT_IN_SEQ | HA_FILE_BASED); } - ulong index_flags(uint idx, uint part) const { DBUG_ASSERT(0); return 0; } + ulong index_flags(uint idx, uint part, bool all_parts) const + { DBUG_ASSERT(0); return 0; } uint max_supported_keys() const { return 0; } bool low_byte_first() const { return 0; } diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 77615d68fe4..51c8521c376 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -336,7 +336,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) HA_STATUS_CONST); } } - else if (!mi_is_crashed(file)) + else if (!mi_is_crashed(file) && !thd->killed) { mi_mark_crashed(file); file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; @@ -378,7 +378,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt) error=update_state_info(¶m,file,UPDATE_STAT); pthread_mutex_unlock(&share->intern_lock); } - else if (!mi_is_crashed(file)) + else if (!mi_is_crashed(file) && !thd->killed) mi_mark_crashed(file); return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; } diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index ef3f00577dd..6fde84d6f6f 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -55,11 +55,11 @@ class ha_myisam: public handler const char *index_type(uint key_number); const char **bas_ext() const; ulong table_flags() const { return int_table_flags; } - ulong index_flags(uint inx, uint part) const + ulong index_flags(uint inx, uint part, bool all_parts) const { return ((table->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ? - 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | - HA_READ_ORDER | HA_KEYREAD_ONLY); + 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | + HA_READ_ORDER | HA_KEYREAD_ONLY); } uint max_supported_keys() const { return MI_MAX_KEY; } uint max_supported_key_length() const { return MI_MAX_KEY_LENGTH; } diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h index 995cfe9ad4a..264c580220c 100644 --- a/sql/ha_myisammrg.h +++ b/sql/ha_myisammrg.h @@ -38,11 +38,11 @@ class ha_myisammrg: public handler HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED | HA_CAN_INSERT_DELAYED); } - ulong index_flags(uint inx, uint part) const + ulong index_flags(uint inx, uint part, bool all_parts) const { return ((table->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ? - 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | - HA_READ_ORDER | HA_KEYREAD_ONLY); + 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE | + HA_READ_ORDER | HA_KEYREAD_ONLY); } uint max_supported_keys() const { return MI_MAX_KEY; } uint max_supported_key_length() const { return MI_MAX_KEY_LENGTH; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index d499218a8c3..5b36d6d2b55 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -524,7 +524,8 @@ inline NDB_INDEX_TYPE ha_ndbcluster::get_index_type(uint idx_no) const flags depending on the type of the index. */ -inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part) const +inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part, + bool all_parts) const { DBUG_ENTER("index_flags"); DBUG_PRINT("info", ("idx_no: %d", idx_no)); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 39c1779a27a..f094b79ef35 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -93,7 +93,7 @@ class ha_ndbcluster: public handler const char * table_type() const { return("ndbcluster");} const char ** bas_ext() const; ulong table_flags(void) const { return m_table_flags; } - ulong index_flags(uint idx, uint part) const; + ulong index_flags(uint idx, uint part, bool all_parts) const; uint max_supported_record_length() const { return NDB_MAX_TUPLE_SIZE; }; uint max_supported_keys() const { return MAX_KEY; } uint max_supported_key_parts() const diff --git a/sql/handler.h b/sql/handler.h index 506038fccfd..28b0b8df6e2 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -449,7 +449,7 @@ public: virtual const char *table_type() const =0; virtual const char **bas_ext() const =0; virtual ulong table_flags(void) const =0; - virtual ulong index_flags(uint idx, uint part=~0) const =0; + virtual ulong index_flags(uint idx, uint part, bool all_parts) const =0; virtual ulong index_ddl_flags(KEY *wanted_index) const { return (HA_DDL_SUPPORT); } virtual int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 91257c31fb9..60f80249e94 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -483,7 +483,14 @@ bool Item_in_optimizer::fix_left(THD *thd, return 1; cache->setup(args[0]); - cache->store(args[0]); + /* + If it is preparation PS only then we do not know values of parameters => + cant't get there values and do not need that values. + + TODO: during merge with 5.0 it should be changed on !thd->only_prepare() + */ + if (!thd->current_statement) + cache->store(args[0]); if (cache->cols() == 1) { if ((used_tables_cache= args[0]->used_tables())) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b0c685c1c46..a8805be7854 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2294,40 +2294,49 @@ inline int hexchar_to_int(char c) return -1; } + + /* Convert given hex string to a binary string */ + String *Item_func_unhex::val_str(String *str) { - DBUG_ASSERT(fixed == 1); - /* Convert given hex string to a binary string */ - String *res= args[0]->val_str(str); - const char *from=res->ptr(), *end; + const char *from, *end; char *to; - int r; - if (!res || tmp_value.alloc((1+res->length())/2)) + String *res; + uint length; + DBUG_ASSERT(fixed == 1); + + res= args[0]->val_str(str); + if (!res || tmp_value.alloc(length= (1+res->length())/2)) { null_value=1; return 0; } - null_value=0; - tmp_value.length((1+res->length())/2); + + from= res->ptr(); + null_value= 0; + tmp_value.length(length); to= (char*) tmp_value.ptr(); if (res->length() % 2) { - *to++= r= hexchar_to_int(*from++); - if ((null_value= (r == -1))) + int hex_char; + *to++= hex_char= hexchar_to_int(*from++); + if ((null_value= (hex_char == -1))) return 0; } for (end=res->ptr()+res->length(); from < end ; from+=2, to++) { - *to= (r= hexchar_to_int(from[0])) << 4; - if ((null_value= (r == -1))) + int hex_char; + *to= (hex_char= hexchar_to_int(from[0])) << 4; + if ((null_value= (hex_char == -1))) return 0; - *to|= r= hexchar_to_int(from[1]); - if ((null_value= (r == -1))) + *to|= hex_char= hexchar_to_int(from[1]); + if ((null_value= (hex_char == -1))) return 0; } return &tmp_value; } + void Item_func_binary::print(String *str) { str->append("cast(", 5); diff --git a/sql/log.cc b/sql/log.cc index 124439ae9eb..afba530ce49 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2046,10 +2046,8 @@ bool flush_error_log() bool MYSQL_LOG::cut_spurious_tail() { int error= 0; - char llbuf1[22], llbuf2[22]; - ulonglong actual_size; - DBUG_ENTER("cut_spurious_tail"); + #ifdef HAVE_INNOBASE_DB if (have_innodb != SHOW_OPTION_YES) DBUG_RETURN(0); @@ -2059,6 +2057,9 @@ bool MYSQL_LOG::cut_spurious_tail() */ char *name= ha_innobase::get_mysql_bin_log_name(); ulonglong pos= ha_innobase::get_mysql_bin_log_pos(); + ulonglong actual_size; + char llbuf1[22], llbuf2[22]; + if (name[0] == 0 || pos == ULONGLONG_MAX) { DBUG_PRINT("info", ("InnoDB has not set binlog info")); diff --git a/sql/log_event.cc b/sql/log_event.cc index 315b0f670dd..8075cd3f4d2 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1696,9 +1696,9 @@ void Load_log_event::set_fields(List<Item> &field_list) int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, bool use_rli_only_for_errors) { + char *load_data_query= 0; thd->db= (char*) rewrite_db(db); DBUG_ASSERT(thd->query == 0); - thd->query= 0; // Should not be needed thd->query_length= 0; // Should not be needed thd->query_error= 0; clear_all_errors(thd, rli); @@ -1749,6 +1749,19 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, { char llbuff[22]; enum enum_duplicates handle_dup; + /* + Make a simplified LOAD DATA INFILE query, for the information of the + user in SHOW PROCESSLIST. Note that db is known in the 'db' column. + */ + if ((load_data_query= (char *) my_alloca(18 + strlen(fname) + 14 + + strlen(tables.real_name) + 8))) + { + thd->query_length= (uint)(strxmov(load_data_query, + "LOAD DATA INFILE '", fname, + "' INTO TABLE `", tables.real_name, + "` <...>", NullS) - load_data_query); + thd->query= load_data_query; + } if (sql_ex.opt_flags & REPLACE_FLAG) handle_dup= DUP_REPLACE; else if (sql_ex.opt_flags & IGNORE_FLAG) @@ -1830,8 +1843,14 @@ Slave: load data infile on table '%s' at log position %s in log \ } thd->net.vio = 0; - thd->db= 0; // prevent db from being freed + VOID(pthread_mutex_lock(&LOCK_thread_count)); + thd->db= 0; + thd->query= 0; + thd->query_length= 0; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); close_thread_tables(thd); + if (load_data_query) + my_afree(load_data_query); if (thd->query_error) { /* this err/sql_errno code is copy-paste from send_error() */ @@ -2378,17 +2397,18 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db) > the string constant is still unescaped according to SJIS, not > according to UCS2. */ - char *p, *q; - if (!(p= (char *)my_alloca(2*val_len+1+2))) // 2 hex digits per byte + char *hex_str; + CHARSET_INFO *cs; + + if (!(hex_str= (char *)my_alloca(2*val_len+1+2))) // 2 hex digits / byte break; // no error, as we are 'void' - str_to_hex(p, val, val_len); + str_to_hex(hex_str, val, val_len); /* For proper behaviour when mysqlbinlog|mysql, we need to explicitely specify the variable's collation. It will however cause problems when people want to mysqlbinlog|mysql into another server not supporting the character set. But there's not much to do about this and it's unlikely. */ - CHARSET_INFO *cs; if (!(cs= get_charset(charset_number, MYF(0)))) /* Generate an unusable command (=> syntax error) is probably the best @@ -2396,8 +2416,8 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db) */ fprintf(file, ":=???;\n"); else - fprintf(file, ":=_%s %s COLLATE %s;\n", cs->csname, p, cs->name); - my_afree(p); + fprintf(file, ":=_%s %s COLLATE %s;\n", cs->csname, hex_str, cs->name); + my_afree(hex_str); } break; case ROW_RESULT: @@ -2845,7 +2865,7 @@ void Create_file_log_event::pack_info(Protocol *protocol) #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Create_file_log_event::exec_event(struct st_relay_log_info* rli) { - char fname_buf[FN_REFLEN+10]; + char proc_info[17+FN_REFLEN+10], *fname_buf= proc_info+17; char *p; int fd = -1; IO_CACHE file; @@ -2854,6 +2874,8 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli) bzero((char*)&file, sizeof(file)); p = slave_load_file_stem(fname_buf, file_id, server_id); strmov(p, ".info"); // strmov takes less code than memcpy + strnmov(proc_info, "Making temp file ", 17); // no end 0 + thd->proc_info= proc_info; if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, MYF(MY_WME))) < 0 || init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, @@ -2897,6 +2919,7 @@ err: end_io_cache(&file); if (fd >= 0) my_close(fd, MYF(0)); + thd->proc_info= 0; return error ? 1 : Log_event::exec_event(rli); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -2994,13 +3017,15 @@ void Append_block_log_event::pack_info(Protocol *protocol) #if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Append_block_log_event::exec_event(struct st_relay_log_info* rli) { - char fname[FN_REFLEN+10]; + char proc_info[17+FN_REFLEN+10], *fname= proc_info+17; char *p= slave_load_file_stem(fname, file_id, server_id); int fd; int error = 1; DBUG_ENTER("Append_block_log_event::exec_event"); memcpy(p, ".data", 6); + strnmov(proc_info, "Making temp file ", 17); // no end 0 + thd->proc_info= proc_info; if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0) { slave_print_error(rli,my_errno, "Error in Append_block event: could not open file '%s'", fname); @@ -3016,6 +3041,7 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli) err: if (fd >= 0) my_close(fd, MYF(0)); + thd->proc_info= 0; DBUG_RETURN(error ? error : Log_event::exec_event(rli)); } #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 72ac3af70ff..8707bc205df 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -635,6 +635,8 @@ int mysqld_show_variables(THD *thd,const char *wild); int mysqld_show(THD *thd, const char *wild, show_var_st *variables, enum enum_var_type value_type, pthread_mutex_t *mutex); +int mysql_find_files(THD *thd,List<char> *files, const char *db, + const char *path, const char *wild, bool dir); int mysqld_show_charsets(THD *thd,const char *wild); int mysqld_show_collations(THD *thd,const char *wild); int mysqld_show_storage_engines(THD *thd); @@ -801,6 +803,9 @@ bool is_keyword(const char *name, uint len); #define MY_DB_OPT_FILE "db.opt" bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create); +bool my_dbopt_init(void); +void my_dbopt_cleanup(void); +void my_dbopt_free(void); /* External variables diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 436f693d734..4fd13d33bab 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -885,6 +885,7 @@ extern "C" void unireg_abort(int exit_code) } #endif + void clean_up(bool print_message) { DBUG_PRINT("exit",("clean_up")); @@ -901,6 +902,7 @@ void clean_up(bool print_message) bitmap_free(&slave_error_mask); #endif my_tz_free(); + my_dbopt_free(); #ifndef NO_EMBEDDED_ACCESS_CHECKS acl_free(1); grant_free(); @@ -1299,6 +1301,19 @@ void yyerror(const char *s) #ifndef EMBEDDED_LIBRARY +/* + Close a connection + + SYNOPSIS + close_connection() + thd Thread handle + errcode Error code to print to console + lock 1 if we have have to lock LOCK_thread_count + + NOTES + For the connection that is doing shutdown, this is called twice +*/ + void close_connection(THD *thd, uint errcode, bool lock) { st_vio *vio; @@ -2274,7 +2289,6 @@ static int init_common_variables(const char *conf_file_name, int argc, */ global_system_variables.time_zone= my_tz_SYSTEM; - /* Init mutexes for the global MYSQL_LOG objects. As safe_mutex depends on what MY_INIT() does, we can't init the mutexes of @@ -2381,6 +2395,9 @@ static int init_common_variables(const char *conf_file_name, int argc, if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; + if (my_dbopt_init()) + return 1; + return 0; } @@ -4673,26 +4690,26 @@ replicating a LOAD DATA INFILE command.", "The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", (gptr*) &dflt_key_cache_var.param_buff_size, (gptr*) 0, - 0, (enum get_opt_var_type) (GET_ULL | GET_ASK_ADDR), + 0, (GET_ULL | GET_ASK_ADDR), REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "The default size of key cache blocks", (gptr*) &dflt_key_cache_var.param_block_size, (gptr*) 0, - 0, (enum get_opt_var_type) (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, + 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, KEY_CACHE_BLOCK_SIZE , 512, 1024*16, MALLOC_OVERHEAD, 512, 0}, {"key_cache_division_limit", OPT_KEY_CACHE_DIVISION_LIMIT, "The minimum percentage of warm blocks in key cache", (gptr*) &dflt_key_cache_var.param_division_limit, (gptr*) 0, - 0, (enum get_opt_var_type) (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, + 0, (GET_ULONG | GET_ASK_ADDR) , REQUIRED_ARG, 100, 1, 100, 0, 1, 0}, {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, "This characterizes the number of hits a hot block has to be untouched until it is considered aged enough to be downgraded to a warm block. This specifies the percentage ratio of that number of hits to the total number of blocks in key cache", (gptr*) &dflt_key_cache_var.param_age_threshold, (gptr*) 0, - 0, (enum get_opt_var_type) (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, + 0, (GET_ULONG | GET_ASK_ADDR), REQUIRED_ARG, 300, 100, ~0L, 0, 100, 0}, {"long_query_time", OPT_LONG_QUERY_TIME, "Log all queries that have taken more than long_query_time seconds to execute to file.", diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 32a0391a777..40e3ffebe56 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -727,7 +727,8 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, found_records=check_quick_select(¶m, idx, *key); if (found_records != HA_POS_ERROR && found_records > 2 && head->used_keys.is_set(keynr) && - (head->file->index_flags(keynr) & HA_KEYREAD_ONLY)) + (head->file->index_flags(keynr, param.max_key_part, 1) & + HA_KEYREAD_ONLY)) { /* We can resolve this by only reading through this key. @@ -1028,7 +1029,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, String tmp(buff1,sizeof(buff1),value->collation.collation),*res; uint length,offset,min_length,max_length; - if (!field->optimize_range(param->real_keynr[key_part->key])) + if (!field->optimize_range(param->real_keynr[key_part->key], + key_part->part)) DBUG_RETURN(0); // Can't optimize this if (!(res= value->val_str(&tmp))) DBUG_RETURN(&null_element); @@ -1093,7 +1095,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, DBUG_RETURN(new SEL_ARG(field,min_str,max_str)); } - if (!field->optimize_range(param->real_keynr[key_part->key]) && + if (!field->optimize_range(param->real_keynr[key_part->key], + key_part->part) && type != Item_func::EQ_FUNC && type != Item_func::EQUAL_FUNC) DBUG_RETURN(0); // Can't optimize this diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 75b00b97ce7..f4c39462d0c 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -629,7 +629,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, if (!(field->flags & PART_KEY_FLAG)) return 0; // Not key field *prefix_len= 0; - + TABLE *table= field->table; uint idx= 0; @@ -637,16 +637,17 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, for (keyinfo= table->key_info, keyinfo_end= keyinfo+table->keys ; keyinfo != keyinfo_end; keyinfo++,idx++) - { - if (!(table->file->index_flags(idx) & HA_READ_ORDER)) - break; - + { KEY_PART_INFO *part,*part_end; key_part_map key_part_to_use= 0; + uint jdx= 0; for (part= keyinfo->key_part, part_end= part+keyinfo->key_parts ; part != part_end ; - part++, key_part_to_use= (key_part_to_use << 1) | 1) + part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1) { + if (!(table->file->index_flags(idx, jdx, 0) & HA_READ_ORDER)) + return 0; + if (field->eq(part->field)) { ref->key= idx; diff --git a/sql/set_var.cc b/sql/set_var.cc index 840a7ae075a..e1cfb77d297 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -802,6 +802,9 @@ struct show_var_st init_vars[]= { {sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS}, #endif {sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS}, +#ifdef HAVE_TZNAME + {"system_time_zone", system_time_zone, SHOW_CHAR}, +#endif {"table_cache", (char*) &table_cache_size, SHOW_LONG}, {sys_table_type.name, (char*) &sys_table_type, SHOW_SYS}, {sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS}, @@ -810,9 +813,6 @@ struct show_var_st init_vars[]= { #endif {"thread_stack", (char*) &thread_stack, SHOW_LONG}, {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS}, -#ifdef HAVE_TZNAME - {"system_time_zone", system_time_zone, SHOW_CHAR}, -#endif {"time_zone", (char*) &sys_time_zone, SHOW_SYS}, {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS}, {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR}, @@ -1744,10 +1744,10 @@ bool sys_var_collation::check(THD *thd, set_var *var) } else // INT_RESULT { - if (!(tmp=get_charset(var->value->val_int(),MYF(0)))) + if (!(tmp=get_charset((int) var->value->val_int(),MYF(0)))) { char buf[20]; - int10_to_str(var->value->val_int(), buf, -10); + int10_to_str((int) var->value->val_int(), buf, -10); my_error(ER_UNKNOWN_COLLATION, MYF(0), buf); return 1; } @@ -1783,10 +1783,10 @@ bool sys_var_character_set::check(THD *thd, set_var *var) } else // INT_RESULT { - if (!(tmp=get_charset(var->value->val_int(),MYF(0)))) + if (!(tmp=get_charset((int) var->value->val_int(),MYF(0)))) { char buf[20]; - int10_to_str(var->value->val_int(), buf, -10); + int10_to_str((int) var->value->val_int(), buf, -10); my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), buf); return 1; } diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 2d377929229..3cc665f0597 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -312,3 +312,4 @@ character-set=latin2 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index af7b8263e6b..7b42d47f008 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -306,3 +306,4 @@ character-set=latin1 "Modtog temporary fejl %d '%-.100s' fra %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index aa20996680e..ce1d06d4356 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -314,3 +314,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index b5a7f7962cf..b8b4cd1127d 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -303,3 +303,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 0cc6e06ab26..a2f4c848217 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -308,3 +308,4 @@ character-set=latin7 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 2e23db62ddb..7b3497ead2b 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -303,3 +303,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index c63162c84f6..75732b3f732 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -315,3 +315,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index fa94b0f5107..3825240927a 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -303,3 +303,4 @@ character-set=greek "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 56fae82c438..eb968dd3a27 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -305,3 +305,4 @@ character-set=latin2 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 31768f172b4..7112bcce5f2 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -303,3 +303,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 4385f25c991..005f85c6ad7 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -305,3 +305,4 @@ character-set=ujis "Got temporary NDB error %d '%-.100s'", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index a6e84fad01e..a1b6a6c2654 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -303,3 +303,4 @@ character-set=euckr "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index eaf7b3482ee..52f1a4ec12c 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -305,3 +305,4 @@ character-set=latin1 "Mottok temporary feil %d '%-.100s' fra %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 692c10db58f..fadcc203c37 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -305,3 +305,4 @@ character-set=latin1 "Mottok temporary feil %d '%-.100s' fra %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 19f2c1c6983..bac2e0678a8 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -307,3 +307,4 @@ character-set=latin2 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index c77d10d83de..9e5988490b3 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -304,3 +304,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 5ee4efd0063..29dd9eb022a 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -307,3 +307,4 @@ character-set=latin2 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 20188723f6d..7cbbd6e36b8 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -305,3 +305,4 @@ character-set=koi8r "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index cc822431464..c45df8bfbe9 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -309,3 +309,4 @@ character-set=cp1250 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index ee6aac5081b..f94bb70d9e8 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -311,3 +311,4 @@ character-set=latin2 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 483ec7068a2..68488528309 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -305,3 +305,4 @@ character-set=latin1 "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index d9f3adf92d4..6bb2ede2cb1 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -303,3 +303,4 @@ character-set=latin1 "Fick tilfällig felkod %d '%-.100s' från %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index acf6f5121e8..e16b4ef64d6 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -308,3 +308,4 @@ character-set=koi8u "Got temporary error %d '%-.100s' from %s", "Unknown or incorrect time zone: '%-.64s'", "Invalid TIMESTAMP value in column '%s' at row %ld", +"Invalid %s character string: '%.64s'", diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a03e371dd63..fa8065a5fc3 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1790,11 +1790,13 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) col_privs->field[3]->pack_length()); key_copy(key,col_privs,0,key_len); col_privs->field[4]->store("",0, &my_charset_latin1); - if (col_privs->file->index_read_idx(col_privs->record[0],0, + col_privs->file->ha_index_init(0); + if (col_privs->file->index_read(col_privs->record[0], (byte*) col_privs->field[0]->ptr, key_len, HA_READ_KEY_EXACT)) { cols = 0; /* purecov: deadcode */ + col_privs->file->ha_index_end(); return; } do @@ -1814,6 +1816,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) my_hash_insert(&hash_columns, (byte *) mem_check); } while (!col_privs->file->index_next(col_privs->record[0]) && !key_cmp_if_same(col_privs,key,0,key_len)); + col_privs->file->ha_index_end(); } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 7aa3bbbdd7b..ad4eb9f6801 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -533,21 +533,23 @@ bool THD::convert_string(String *s, CHARSET_INFO *from_cs, CHARSET_INFO *to_cs) return FALSE; } + /* Update some cache variables when character set changes */ void THD::update_charset() { - charset_is_system_charset= my_charset_same(charset(),system_charset_info); - charset_is_collation_connection= my_charset_same(charset(), - variables. - collation_connection); + uint32 not_used; + charset_is_system_charset= !String::needs_conversion(0,charset(), + system_charset_info, + ¬_used); + charset_is_collation_connection= + !String::needs_conversion(0,charset(),variables.collation_connection, + ¬_used); } - - /* routings to adding tables to list of changed in transaction tables */ inline static void list_include(CHANGED_TABLE_LIST** prev, diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 9db2198268a..d3804b972c8 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -39,6 +39,197 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, const char *path, uint level); +/* Database options hash */ +static HASH dboptions; +static my_bool dboptions_init= 0; +static rw_lock_t LOCK_dboptions; + +/* Structure for database options */ +typedef struct my_dbopt_st +{ + char *name; /* Database name */ + uint name_length; /* Database length name */ + CHARSET_INFO *charset; /* Database default character set */ +} my_dbopt_t; + + +/* + Function we use in the creation of our hash to get key. +*/ +static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, + my_bool not_used __attribute__((unused))) +{ + *length= opt->name_length; + return (byte*) opt->name; +} + + +/* + Function to free dboptions hash element +*/ + +static void free_dbopt(void *dbopt) +{ + my_free((gptr) dbopt, MYF(0)); +} + + +/* + Initialize database option hash + + SYNOPSIS + my_dbopt_init() + + NOTES + Must be called before any other database function is called. + + RETURN + 0 ok + 1 Fatal error +*/ + +bool my_dbopt_init(void) +{ + bool error= 0; + (void) my_rwlock_init(&LOCK_dboptions, NULL); + if (!dboptions_init) + { + dboptions_init= 1; + error= hash_init(&dboptions, lower_case_table_names ? + &my_charset_bin : system_charset_info, + 32, 0, 0, (hash_get_key) dboptions_get_key, + free_dbopt,0); + } + return error; +} + + +/* + Free database option hash. +*/ + +void my_dbopt_free(void) +{ + if (dboptions_init) + { + dboptions_init= 0; + hash_free(&dboptions); + (void) rwlock_destroy(&LOCK_dboptions); + } +} + + +void my_dbopt_cleanup(void) +{ + rw_wrlock(&LOCK_dboptions); + hash_free(&dboptions); + hash_init(&dboptions, lower_case_table_names ? + &my_charset_bin : system_charset_info, + 32, 0, 0, (hash_get_key) dboptions_get_key, + free_dbopt,0); + rw_unlock(&LOCK_dboptions); +} + + +/* + Find database options in the hash. + + DESCRIPTION + Search a database options in the hash, usings its path. + Fills "create" on success. + + RETURN VALUES + 0 on success. + 1 on error. +*/ + +static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create) +{ + my_dbopt_t *opt; + uint length; + my_bool error= 1; + + length= (uint) strlen(dbname); + + rw_rdlock(&LOCK_dboptions); + if ((opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length))) + { + create->default_table_charset= opt->charset; + error= 0; + } + rw_unlock(&LOCK_dboptions); + return error; +} + + +/* + Writes database options into the hash. + + DESCRIPTION + Inserts database options into the hash, or updates + options if they are already in the hash. + + RETURN VALUES + 0 on success. + 1 on error. +*/ + +static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create) +{ + my_dbopt_t *opt; + uint length; + my_bool error= 0; + DBUG_ENTER("put_dbopt"); + + length= (uint) strlen(dbname); + + rw_wrlock(&LOCK_dboptions); + if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length))) + { + /* Options are not in the hash, insert them */ + char *tmp_name; + if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), + &opt, (uint) sizeof(*opt), &tmp_name, length+1, + NullS)) + { + error= 1; + goto end; + } + + opt->name= tmp_name; + strmov(opt->name, dbname); + opt->name_length= length; + + if ((error= my_hash_insert(&dboptions, (byte*) opt))) + { + my_free((gptr) opt, MYF(0)); + goto end; + } + } + + /* Update / write options in hash */ + opt->charset= create->default_table_charset; + +end: + rw_unlock(&LOCK_dboptions); + DBUG_RETURN(error); +} + + +/* + Deletes database options from the hash. +*/ + +void del_dbopt(const char *path) +{ + my_dbopt_t *opt; + rw_wrlock(&LOCK_dboptions); + if ((opt= (my_dbopt_t *)hash_search(&dboptions, path, strlen(path)))) + hash_delete(&dboptions, (byte*) opt); + rw_unlock(&LOCK_dboptions); +} + + /* Create database options file: @@ -56,15 +247,20 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) char buf[256]; // Should be enough for one option bool error=1; + if (!create->default_table_charset) + create->default_table_charset= thd->variables.collation_server; + + if (put_dbopt(path, create)) + return 1; + if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) { ulong length; - CHARSET_INFO *cs= ((create && create->default_table_charset) ? - create->default_table_charset : - thd->variables.collation_server); - length= my_sprintf(buf,(buf, - "default-character-set=%s\ndefault-collation=%s\n", - cs->csname,cs->name)); + length= (ulong) (strxnmov(buf, sizeof(buf), "default-character-set=", + create->default_table_charset->csname, + "\ndefault-collation=", + create->default_table_charset->name, + "\n", NullS) - buf); /* Error is written by my_write */ if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME))) @@ -101,6 +297,12 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) bzero((char*) create,sizeof(*create)); create->default_table_charset= thd->variables.collation_server; + + /* Check if options for this database are already in the hash */ + if (!get_dbopt(path, create)) + DBUG_RETURN(0); + + /* Otherwise, load options from the .opt file */ if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0) { IO_CACHE cache; @@ -137,9 +339,16 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) } } } - error=0; end_io_cache(&cache); my_close(file,MYF(0)); + /* + Put the loaded value into the hash. + Note that another thread could've added the same + entry to the hash after we called get_dbopt(), + but it's not an error, as put_dbopt() takes this + possibility into account. + */ + error= put_dbopt(path, create); } DBUG_RETURN(error); } @@ -167,10 +376,11 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) { char path[FN_REFLEN+16]; - long result=1; - int error = 0; + long result= 1; + int error= 0; MY_STAT stat_info; - uint create_options = create_info ? create_info->options : 0; + uint create_options= create_info ? create_info->options : 0; + uint path_len; DBUG_ENTER("mysql_create_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -184,17 +394,18 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, /* Check directory */ strxmov(path, mysql_data_home, "/", db, NullS); - unpack_dirname(path,path); // Convert if not unix + path_len= unpack_dirname(path,path); // Convert if not unix + path[path_len-1]= 0; // Remove last '/' from path if (my_stat(path,&stat_info,MYF(0))) { if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS)) { my_error(ER_DB_CREATE_EXISTS,MYF(0),db); - error = -1; + error= -1; goto exit; } - result = 0; + result= 0; } else { @@ -203,23 +414,23 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, my_error(EE_STAT, MYF(0),path,my_errno); goto exit; } - strend(path)[-1]=0; // Remove last '/' from path if (my_mkdir(path,0777,MYF(0)) < 0) { my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno); - error = -1; + error= -1; goto exit; } } - unpack_dirname(path, path); - strcat(path,MY_DB_OPT_FILE); + path[path_len-1]= FN_LIBCHAR; + strmake(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1); if (write_db_opt(thd, path, create_info)) { /* Could not create options file. Restore things to beginning. */ + path[path_len]= 0; if (rmdir(path) >= 0) { error= -1; @@ -271,7 +482,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) { char path[FN_REFLEN+16]; long result=1; - int error = 0; + int error= 0; DBUG_ENTER("mysql_alter_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -281,7 +492,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) goto exit2; /* Check directory */ - (void)sprintf(path,"%s/%s/%s", mysql_data_home, db, MY_DB_OPT_FILE); + strxmov(path, mysql_data_home, "/", db, "/", MY_DB_OPT_FILE, NullS); fn_format(path, path, "", "", MYF(MY_UNPACK_FILENAME)); if ((error=write_db_opt(thd, path, create_info))) goto exit; @@ -335,9 +546,11 @@ exit2: int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) { long deleted=0; - int error = 0; + int error= 0; char path[FN_REFLEN+16], tmp_db[NAME_LEN+1]; MY_DIR *dirp; + uint length; + my_dbopt_t *dbopt; DBUG_ENTER("mysql_rm_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -350,9 +563,13 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } (void) sprintf(path,"%s/%s",mysql_data_home,db); - unpack_dirname(path,path); // Convert if not unix + length= unpack_dirname(path,path); // Convert if not unix + strmov(path+length, MY_DB_OPT_FILE); // Append db option file name + del_dbopt(path); // Remove dboption hash entry + path[length]= '\0'; // Remove file name + /* See if the directory exists */ - if (!(dirp = my_dir(path,MYF(MY_DONT_SORT)))) + if (!(dirp= my_dir(path,MYF(MY_DONT_SORT)))) { if (!if_exists) { @@ -636,8 +853,10 @@ bool mysql_change_db(THD *thd, const char *name) int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); char path[FN_REFLEN]; - ulong db_access; HA_CREATE_INFO create; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + ulong db_access; +#endif DBUG_ENTER("mysql_change_db"); if (!dbname || !(db_length= strlen(dbname))) @@ -698,4 +917,3 @@ bool mysql_change_db(THD *thd, const char *name) thd->variables.collation_database= thd->db_charset; DBUG_RETURN(0); } - diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0cc25c4fe6e..e83868bac7c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4805,6 +4805,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (lock_global_read_lock(thd)) return 1; } + my_dbopt_cleanup(); result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables); } if (options & REFRESH_HOSTS) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2f8ede4b4cb..657853c98ba 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2825,7 +2825,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, Set tmp to (previous record count) * (records / combination) */ if ((found_part & 1) && - (!(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX) || + (!(table->file->index_flags(key,0,0) & HA_ONLY_WHOLE_INDEX) || found_part == PREV_BITS(uint,keyinfo->key_parts))) { max_key_part=max_part_bit(found_part); @@ -7171,7 +7171,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ if (!select->quick->reverse_sorted()) { - if (!(table->file->index_flags(ref_key) & HA_READ_PREV)) + // here used_key_parts >0 + if (!(table->file->index_flags(ref_key,used_key_parts-1, 1) + & HA_READ_PREV)) DBUG_RETURN(0); // Use filesort // ORDER BY range_key DESC QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick, @@ -7193,8 +7195,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, Use a traversal function that starts by reading the last row with key part (A) and then traverse the index backwards. */ - if (!(table->file->index_flags(ref_key) & HA_READ_PREV)) - DBUG_RETURN(0); // Use filesort + if (!(table->file->index_flags(ref_key,used_key_parts-1, 1) + & HA_READ_PREV)) + DBUG_RETURN(0); // Use filesort tab->read_first_record= join_read_last_key; tab->read_record.read_record= join_read_prev_same; /* fall through */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 823552be3a4..6d328243a59 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -37,9 +37,6 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), grant_names}; #endif -static int mysql_find_files(THD *thd,List<char> *files, const char *db, - const char *path, const char *wild, bool dir); - static int store_create_info(THD *thd, TABLE *table, String *packet); @@ -361,7 +358,7 @@ int mysqld_show_column_types(THD *thd) } -static int +int mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, const char *wild, bool dir) { @@ -701,8 +698,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, byte *pos; uint flags=field->flags; String type(tmp,sizeof(tmp), system_charset_info); +#ifndef NO_EMBEDDED_ACCESS_CHECKS uint col_access; - +#endif protocol->prepare_for_resend(); protocol->store(field->field_name, system_charset_info); field->sql_type(type); @@ -995,7 +993,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) str=(key_part->field ? key_part->field->field_name : "?unknown field?"); protocol->store(str, system_charset_info); - if (table->file->index_flags(i) & HA_READ_ORDER) + if (table->file->index_flags(i, j, 0) & HA_READ_ORDER) protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ? "D" : "A"), 1, system_charset_info); else diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a560bd40028..8d82ca44951 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1158,6 +1158,23 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } #endif + /* + If the table character set was not given explicitely, + let's fetch the database default character set and + apply it to the table. + */ + if (!create_info->default_table_charset) + { + HA_CREATE_INFO db_info; + uint length; + char path[FN_REFLEN]; + strxmov(path, mysql_data_home, "/", db, NullS); + length= unpack_dirname(path,path); // Convert if not unix + strmov(path+length, MY_DB_OPT_FILE); + load_db_opt(thd, path, &db_info); + create_info->default_table_charset= db_info.default_table_charset; + } + if (mysql_prepare_table(thd, create_info, fields, keys, tmp_table, db_options, file, key_info_buffer, &key_count, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 18394d007ed..db4edff4fa1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -61,7 +61,10 @@ int mysql_update(THD *thd, bool safe_update= thd->options & OPTION_SAFE_UPDATES; bool used_key_is_modified, transactional_table, log_delayed; int error=0; - uint used_index, want_privilege; + uint used_index; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + uint want_privilege; +#endif ulong query_id=thd->query_id, timestamp_query_id; ha_rows updated, found; key_map old_used_keys; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d284bff8c7c..ccbaf7c0112 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1023,7 +1023,7 @@ create: bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.options=$2 | $4; lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type; - lex->create_info.default_table_charset= thd->variables.collation_database; + lex->create_info.default_table_charset= NULL; lex->name=0; } create2 @@ -1815,7 +1815,7 @@ alter: lex->select_lex.db=lex->name=0; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.db_type= DB_TYPE_DEFAULT; - lex->create_info.default_table_charset= thd->variables.collation_database; + lex->create_info.default_table_charset= NULL; lex->create_info.row_type= ROW_TYPE_NOT_USED; lex->alter_info.reset(); lex->alter_info.is_simple= 1; @@ -4884,7 +4884,19 @@ IDENT_sys: { THD *thd= YYTHD; if (thd->charset_is_system_charset) + { + CHARSET_INFO *cs= system_charset_info; + uint wlen= cs->cset->well_formed_len(cs, $1.str, + $1.str+$1.length, + $1.length); + if (wlen < $1.length) + { + net_printf(YYTHD, ER_INVALID_CHARACTER_STRING, cs->csname, + $1.str + wlen); + YYABORT; + } $$= $1; + } else thd->convert_string(&$$, system_charset_info, $1.str, $1.length, thd->charset()); diff --git a/sql/table.cc b/sql/table.cc index 5024015c382..7d1c733b116 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -167,9 +167,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->keys= keys= disk_buff[0]; outparam->key_parts= key_parts= disk_buff[1]; } - outparam->keys_for_keyread.init(keys); + outparam->keys_for_keyread.init(0); outparam->keys_in_use.init(keys); - outparam->read_only_keys.init(0); + outparam->read_only_keys.init(keys); outparam->quick_keys.init(); outparam->used_keys.init(); outparam->keys_in_use_for_query.init(); @@ -500,13 +500,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (outparam->key_info[key].flags & HA_FULLTEXT) outparam->key_info[key].algorithm= HA_KEY_ALG_FULLTEXT; - /* This has to be done after the above fulltext correction */ - if (!(outparam->file->index_flags(key) & HA_KEYREAD_ONLY)) - { - outparam->read_only_keys.set_bit(key); - outparam->keys_for_keyread.clear_bit(key); - } - if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME)) { /* @@ -576,9 +569,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, if (field->key_length() == key_part->length && !(field->flags & BLOB_FLAG)) { - if (outparam->file->index_flags(key, i) & HA_KEYREAD_ONLY) + if (outparam->file->index_flags(key, i, 0) & HA_KEYREAD_ONLY) + { + outparam->read_only_keys.clear_bit(key); + outparam->keys_for_keyread.set_bit(key); field->part_of_key.set_bit(key); - if (outparam->file->index_flags(key, i) & HA_READ_ORDER) + } + if (outparam->file->index_flags(key, i, 1) & HA_READ_ORDER) field->part_of_sortkey.set_bit(key); } if (!(key_part->key_part_flag & HA_REVERSE_SORT) && |