diff options
author | unknown <monty@mashka.mysql.fi> | 2003-10-08 22:12:32 +0300 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2003-10-08 22:12:32 +0300 |
commit | 1a8bdb002369bc351659fe9e07ae93605cd7f858 (patch) | |
tree | 9974b278f962fdebee44503151a92f7319332982 /sql | |
parent | c5808f554567b118d5ed653a56e490cfb5aafad2 (diff) | |
parent | 1c9f6fd50998a6fa8ab537ac54da87508393906c (diff) | |
download | mariadb-git-1a8bdb002369bc351659fe9e07ae93605cd7f858.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-4.0
into mashka.mysql.fi:/home/my/mysql-4.0
Diffstat (limited to 'sql')
-rw-r--r-- | sql/des_key_file.cc | 8 | ||||
-rw-r--r-- | sql/item_func.cc | 220 | ||||
-rw-r--r-- | sql/item_func.h | 8 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 34 | ||||
-rw-r--r-- | sql/log.cc | 8 | ||||
-rw-r--r-- | sql/log_event.cc | 106 | ||||
-rw-r--r-- | sql/mini_client.cc | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 9 | ||||
-rw-r--r-- | sql/mysqld.cc | 12 | ||||
-rw-r--r-- | sql/slave.h | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 14 | ||||
-rw-r--r-- | sql/sql_class.h | 5 | ||||
-rw-r--r-- | sql/sql_load.cc | 44 | ||||
-rw-r--r-- | sql/sql_select.cc | 71 |
14 files changed, 333 insertions, 211 deletions
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc index 891cf18ee53..619691d183e 100644 --- a/sql/des_key_file.cc +++ b/sql/des_key_file.cc @@ -76,16 +76,16 @@ load_des_key_file(const char *file_name) if (start != end) { - des_cblock ivec; + DES_cblock ivec; bzero((char*) &ivec,sizeof(ivec)); // We make good 24-byte (168 bit) key from given plaintext key with MD5 EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, (uchar *) start, (int) (end-start),1, (uchar *) &keyblock, ivec); - des_set_key_unchecked(&keyblock.key1,des_keyschedule[(int)offset].ks1); - des_set_key_unchecked(&keyblock.key2,des_keyschedule[(int)offset].ks2); - des_set_key_unchecked(&keyblock.key3,des_keyschedule[(int)offset].ks3); + DES_set_key_unchecked(&keyblock.key1,&(des_keyschedule[(int)offset].ks1)); + DES_set_key_unchecked(&keyblock.key2,&(des_keyschedule[(int)offset].ks2)); + DES_set_key_unchecked(&keyblock.key3,&(des_keyschedule[(int)offset].ks3)); if (des_default_key == 15) des_default_key= (uint) offset; // use first as def. } diff --git a/sql/item_func.cc b/sql/item_func.cc index 3b1a35e4d08..fd6d17d0cf2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1835,8 +1835,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables) if (Item_func::fix_fields(thd,tables) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; - entry->type= cached_result_type; - entry->update_query_id=thd->query_id; + entry->update_query_id= thd->query_id; + cached_result_type= args[0]->result_type(); return 0; } @@ -1847,10 +1847,10 @@ Item_func_set_user_var::fix_length_and_dec() maybe_null=args[0]->maybe_null; max_length=args[0]->max_length; decimals=args[0]->decimals; - cached_result_type=args[0]->result_type(); } -void Item_func_set_user_var::update_hash(void *ptr, uint length, + +bool Item_func_set_user_var::update_hash(const void *ptr, uint length, Item_result type) { if ((null_value=args[0]->null_value)) @@ -1863,6 +1863,8 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length, } else { + if (type == STRING_RESULT) + length++; // Store strings with end \0 if (length <= extra_size) { /* Save value in value struct */ @@ -1887,64 +1889,151 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length, goto err; } } + if (type == STRING_RESULT) + { + length--; // Fix length change above + entry->value[length]= 0; // Store end \0 + } memcpy(entry->value,ptr,length); entry->length= length; entry->type=type; } - return; + return 0; err: current_thd->fatal_error=1; // Probably end of memory null_value=1; - return; + return 1; // Error +} + + +/* Get the value of a variable as a double */ + +double user_var_entry::val(my_bool *null_value) +{ + if ((*null_value= (value == 0))) + return 0.0; + + switch (type) { + case REAL_RESULT: + return *(double*) value; + case INT_RESULT: + return (double) *(longlong*) value; + case STRING_RESULT: + return atof(value); // This is null terminated + } + return 0.0; // Impossible +} + + +/* Get the value of a variable as an integer */ + +longlong user_var_entry::val_int(my_bool *null_value) +{ + if ((*null_value= (value == 0))) + return LL(0); + + switch (type) { + case REAL_RESULT: + return (longlong) *(double*) value; + case INT_RESULT: + return *(longlong*) value; + case STRING_RESULT: + return strtoull(value,NULL,10); // String is null terminated + } + return LL(0); // Impossible +} + + +/* Get the value of a variable as a string */ + +String *user_var_entry::val_str(my_bool *null_value, String *str, + uint decimals) +{ + if ((*null_value= (value == 0))) + return (String*) 0; + + switch (type) { + case REAL_RESULT: + str->set(*(double*) value, decimals); + break; + case INT_RESULT: + str->set(*(longlong*) value); + break; + case STRING_RESULT: + if (str->copy(value, length)) + str= 0; // EOM error + } + return(str); } +/* + This functions is invoked on SET @variable or @variable:= expression. + + SYNOPSIS + Item_func_set_user_var::update() + + NOTES + We have to store the expression as such in the variable, independent of + the value method used by the user + + RETURN + 0 Ok + 1 EOM Error + +*/ + + bool Item_func_set_user_var::update() { + bool res; + DBUG_ENTER("Item_func_set_user_var::update"); + LINT_INIT(res); + switch (cached_result_type) { case REAL_RESULT: - (void) val(); + { + double value=args[0]->val(); + res= update_hash((void*) &value,sizeof(value), REAL_RESULT); break; + } case INT_RESULT: - (void) val_int(); + { + longlong value=args[0]->val_int(); + res= update_hash((void*) &value,sizeof(longlong), INT_RESULT); break; + } case STRING_RESULT: - char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer,sizeof(buffer)); - (void) val_str(&tmp); + String *tmp; + tmp=args[0]->val_str(&value); + if (!tmp) // Null value + res= update_hash((void*) 0,0,STRING_RESULT); + else + res= update_hash((void*) tmp->ptr(),tmp->length(),STRING_RESULT); break; } - return current_thd->fatal_error; + DBUG_RETURN(res); } -double -Item_func_set_user_var::val() +double Item_func_set_user_var::val() { - double value=args[0]->val(); - update_hash((void*) &value,sizeof(value), REAL_RESULT); - return value; + update(); // Store expression + return entry->val(&null_value); } -longlong -Item_func_set_user_var::val_int() +longlong Item_func_set_user_var::val_int() { - longlong value=args[0]->val_int(); - update_hash((void*) &value,sizeof(longlong),INT_RESULT); - return value; + update(); // Store expression + return entry->val_int(&null_value); } -String * -Item_func_set_user_var::val_str(String *str) +String *Item_func_set_user_var::val_str(String *str) { - String *res=args[0]->val_str(str); - if (!res) // Null value - update_hash((void*) 0,0,STRING_RESULT); - else - update_hash(res->c_ptr(),res->length()+1,STRING_RESULT); - return res; + update(); // Store expression + return entry->val_str(&null_value, str, decimals); } @@ -1958,74 +2047,30 @@ void Item_func_set_user_var::print(String *str) } -user_var_entry *Item_func_get_user_var::get_entry() -{ - if (!var_entry || ! var_entry->value) - { - null_value=1; - return 0; - } - null_value=0; - return var_entry; -} - String * Item_func_get_user_var::val_str(String *str) { - user_var_entry *entry=get_entry(); - if (!entry) - return NULL; - switch (entry->type) { - case REAL_RESULT: - str->set(*(double*) entry->value,decimals); - break; - case INT_RESULT: - str->set(*(longlong*) entry->value); - break; - case STRING_RESULT: - if (str->copy(entry->value, entry->length-1)) - { - null_value=1; - return NULL; - } - break; - } - return str; + DBUG_ENTER("Item_func_get_user_var::val_str"); + if (!var_entry) + return (String*) 0; // No such variable + DBUG_RETURN(var_entry->val_str(&null_value, str, decimals)); } double Item_func_get_user_var::val() { - user_var_entry *entry=get_entry(); - if (!entry) - return 0.0; - switch (entry->type) { - case REAL_RESULT: - return *(double*) entry->value; - case INT_RESULT: - return (double) *(longlong*) entry->value; - case STRING_RESULT: - return atof(entry->value); // This is null terminated - } - return 0.0; // Impossible + if (!var_entry) + return 0.0; // No such variable + return (var_entry->val(&null_value)); } longlong Item_func_get_user_var::val_int() { - user_var_entry *entry=get_entry(); - if (!entry) - return LL(0); - switch (entry->type) { - case REAL_RESULT: - return (longlong) *(double*) entry->value; - case INT_RESULT: - return *(longlong*) entry->value; - case STRING_RESULT: - return strtoull(entry->value,NULL,10); // String is null terminated - } - return LL(0); // Impossible + if (!var_entry) + return LL(0); // No such variable + return (var_entry->val_int(&null_value)); } @@ -2035,12 +2080,15 @@ void Item_func_get_user_var::fix_length_and_dec() maybe_null=1; decimals=NOT_FIXED_DEC; max_length=MAX_BLOB_WIDTH; - var_entry= get_variable(&thd->user_vars, name, 0); + if (!(var_entry= get_variable(&thd->user_vars, name, 0))) + null_value= 1; } bool Item_func_get_user_var::const_item() const -{ return var_entry && current_thd->query_id != var_entry->update_query_id; } +{ + return var_entry && current_thd->query_id != var_entry->update_query_id; +} enum Item_result Item_func_get_user_var::result_type() const diff --git a/sql/item_func.h b/sql/item_func.h index bccd0ca7adb..09aba9694dd 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -888,13 +888,16 @@ class Item_func_set_user_var :public Item_func enum Item_result cached_result_type; LEX_STRING name; user_var_entry *entry; + char buffer[MAX_FIELD_WIDTH]; + String value; public: - Item_func_set_user_var(LEX_STRING a,Item *b): Item_func(b), name(a) {} + Item_func_set_user_var(LEX_STRING a,Item *b): + Item_func(b), name(a), value(buffer,sizeof(buffer)) {} double val(); longlong val_int(); String *val_str(String *str); - void update_hash(void *ptr, uint length, enum Item_result type); + bool update_hash(const void *ptr, uint length, enum Item_result type); bool update(); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd,struct st_table_list *tables); @@ -913,7 +916,6 @@ class Item_func_get_user_var :public Item_func public: Item_func_get_user_var(LEX_STRING a): Item_func(), name(a) {} - user_var_entry *get_entry(); double val(); longlong val_int(); String *val_str(String* str); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 8cc3d24f7d9..fe9c8b9e099 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -330,7 +330,7 @@ void Item_func_concat::fix_length_and_dec() String *Item_func_des_encrypt::val_str(String *str) { #ifdef HAVE_OPENSSL - des_cblock ivec; + DES_cblock ivec; struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; const char *append_str="********"; @@ -370,9 +370,9 @@ String *Item_func_des_encrypt::val_str(String *str) EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, (uchar*) keystr->ptr(), (int) keystr->length(), 1, (uchar*) &keyblock,ivec); - des_set_key_unchecked(&keyblock.key1,keyschedule.ks1); - des_set_key_unchecked(&keyblock.key2,keyschedule.ks2); - des_set_key_unchecked(&keyblock.key3,keyschedule.ks3); + DES_set_key_unchecked(&keyblock.key1,&keyschedule.ks1); + DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); + DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } /* @@ -393,12 +393,12 @@ String *Item_func_des_encrypt::val_str(String *str) tmp_value[0]=(char) (128 | key_number); // Real encryption bzero((char*) &ivec,sizeof(ivec)); - des_ede3_cbc_encrypt((const uchar*) (res->ptr()), + DES_ede3_cbc_encrypt((const uchar*) (res->ptr()), (uchar*) (tmp_value.ptr()+1), res_length, - keyschedule.ks1, - keyschedule.ks2, - keyschedule.ks3, + &keyschedule.ks1, + &keyschedule.ks2, + &keyschedule.ks3, &ivec, TRUE); return &tmp_value; @@ -412,8 +412,8 @@ error: String *Item_func_des_decrypt::val_str(String *str) { #ifdef HAVE_OPENSSL - des_key_schedule ks1, ks2, ks3; - des_cblock ivec; + DES_key_schedule ks1, ks2, ks3; + DES_cblock ivec; struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; String *res= args[0]->val_str(str); @@ -447,20 +447,20 @@ String *Item_func_des_decrypt::val_str(String *str) (uchar*) keystr->ptr(),(int) keystr->length(), 1,(uchar*) &keyblock,ivec); // Here we set all 64-bit keys (56 effective) one by one - des_set_key_unchecked(&keyblock.key1,keyschedule.ks1); - des_set_key_unchecked(&keyblock.key2,keyschedule.ks2); - des_set_key_unchecked(&keyblock.key3,keyschedule.ks3); + DES_set_key_unchecked(&keyblock.key1,&keyschedule.ks1); + DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); + DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } if (tmp_value.alloc(length-1)) goto error; bzero((char*) &ivec,sizeof(ivec)); - des_ede3_cbc_encrypt((const uchar*) res->ptr()+1, + DES_ede3_cbc_encrypt((const uchar*) res->ptr()+1, (uchar*) (tmp_value.ptr()), length-1, - keyschedule.ks1, - keyschedule.ks2, - keyschedule.ks3, + &keyschedule.ks1, + &keyschedule.ks2, + &keyschedule.ks3, &ivec, FALSE); /* Restore old length of key */ if ((tail=(uint) (uchar) tmp_value[length-2]) > 8) diff --git a/sql/log.cc b/sql/log.cc index bd5aeb02121..33ca82aa14f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -870,7 +870,7 @@ void MYSQL_LOG::new_file(bool need_lock) close(LOG_CLOSE_TO_BE_OPENED); /* - Note that at this point, log_type == LOG_CLOSED (important for is_open()). + Note that at this point, log_type != LOG_CLOSED (important for is_open()). */ open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type, @@ -1315,9 +1315,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback) /* Now this Query_log_event has artificial log_pos 0. It must be adjusted to reflect the real position in the log. Not doing it would confuse the - slave: it would prevent this one from knowing where he is in the master's - binlog, which would result in wrong positions being shown to the user, - MASTER_POS_WAIT undue waiting etc. + slave: it would prevent this one from knowing where he is in the + master's binlog, which would result in wrong positions being shown to + the user, MASTER_POS_WAIT undue waiting etc. */ qinfo.set_log_pos(this); if (qinfo.write(&log_file)) diff --git a/sql/log_event.cc b/sql/log_event.cc index 82e9c5950a7..3e9064a78ea 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -140,11 +140,6 @@ Log_event::Log_event() /* Delete all temporary files used for SQL_LOAD. - - TODO - - When we get a 'server start' event, we should only remove - the files associated with the server id that just started. - Easily fixable by adding server_id as a prefix to the log files. */ static void cleanup_load_tmpdir() @@ -152,13 +147,30 @@ static void cleanup_load_tmpdir() MY_DIR *dirp; FILEINFO *file; uint i; + char fname[FN_REFLEN]; + char prefbuf[31]; + char *p; + if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) return; - char fname[FN_REFLEN]; + + /* + When we are deleting temporary files, we should only remove + the files associated with the server id of our server. + We don't use event_server_id here because since we've disabled + direct binlogging of Create_file/Append_file/Exec_load events + we cannot meet Start_log event in the middle of events from one + LOAD DATA. + */ + p= strmake(prefbuf,"SQL_LOAD-",9); + p= int10_to_str(::server_id, p, 10); + *(p++)= '-'; + *p= 0; + for (i=0 ; i < (uint)dirp->number_off_files; i++) { file=dirp->dir_entry+i; - if (is_prefix(file->name,"SQL_LOAD-")) + if (is_prefix(file->name, prefbuf)) { fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME); my_delete(fname, MYF(0)); @@ -232,9 +244,9 @@ void Query_log_event::pack_info(String* packet) tmp.length(0); if (db && db_len) { - tmp.append("use "); + tmp.append("use `",5); tmp.append(db, db_len); - tmp.append("; ", 2); + tmp.append("`; ", 3); } if (query && q_len) @@ -2079,6 +2091,23 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) */ close_temporary_tables(thd); cleanup_load_tmpdir(); + /* + As a transaction NEVER spans on 2 or more binlogs: + if we have an active transaction at this point, the master died while + writing the transaction to the binary log, i.e. while flushing the binlog + cache to the binlog. As the write was started, the transaction had been + committed on the master, so we lack of information to replay this + transaction on the slave; all we can do is stop with error. + */ + if (rli->inside_transaction) + { + slave_print_error(rli, 0, + "\ +Rolling back unfinished transaction (no COMMIT or ROLLBACK) from relay log. \ +Probably cause is that the master died while writing the transaction to it's \ +binary log."); + return(1); + } break; /* Now the older formats; in that case load_tmpdir is cleaned up by the I/O @@ -2154,51 +2183,34 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli) We can't rotate the slave as this will cause infinitive rotations in a A -> B -> A setup. - NOTES - As a transaction NEVER spans on 2 or more binlogs: - if we have an active transaction at this point, the master died while - writing the transaction to the binary log, i.e. while flushing the binlog - cache to the binlog. As the write was started, the transaction had been - committed on the master, so we lack of information to replay this - transaction on the slave; all we can do is stop with error. - If we didn't detect it, then positions would start to become garbage (as we - are incrementing rli->relay_log_pos whereas we are in a transaction: the new - rli->relay_log_pos will be - relay_log_pos of the BEGIN + size of the Rotate event = garbage. - - Since MySQL 4.0.14, the master ALWAYS sends a Rotate event when it starts - sending the next binlog, so we are sure to receive a Rotate event just - after the end of the "dead master"'s binlog; so this exec_event() is the - right place to catch the problem. If we would wait until - Start_log_event::exec_event() it would be too late, rli->relay_log_pos would - already be garbage. - RETURN VALUES 0 ok */ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) { - char* log_name = rli->master_log_name; DBUG_ENTER("Rotate_log_event::exec_event"); pthread_mutex_lock(&rli->data_lock); - - if (rli->inside_transaction) + /* + If we are in a transaction: the only normal case is when the I/O thread was + copying a big transaction, then it was stopped and restarted: we have this + in the relay log: + BEGIN + ... + ROTATE (a fake one) + ... + COMMIT or ROLLBACK + In that case, we don't want to touch the coordinates which correspond to the + beginning of the transaction. + */ + if (!rli->inside_transaction) { - slave_print_error(rli, 0, - "there is an unfinished transaction in the relay log \ -(could find neither COMMIT nor ROLLBACK in the relay log); it could be that \ -the master died while writing the transaction to its binary log. Now the slave \ -is rolling back the transaction."); - pthread_mutex_unlock(&rli->data_lock); - DBUG_RETURN(1); + memcpy(rli->master_log_name, new_log_ident, ident_len+1); + rli->master_log_pos= pos; + DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) rli->master_log_pos)); } - - memcpy(log_name, new_log_ident, ident_len+1); - rli->master_log_pos = pos; rli->relay_log_pos += get_event_len(); - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos)); pthread_mutex_unlock(&rli->data_lock); pthread_cond_broadcast(&rli->data_cond); flush_relay_log_info(rli); @@ -2382,6 +2394,16 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) } goto err; } + /* + We have an open file descriptor to the .info file; we need to close it + or Windows will refuse to delete the file in my_delete(). + */ + if (fd >= 0) + { + my_close(fd, MYF(0)); + end_io_cache(&file); + fd= -1; + } (void) my_delete(fname, MYF(MY_WME)); memcpy(p, ".data", 6); (void) my_delete(fname, MYF(MY_WME)); diff --git a/sql/mini_client.cc b/sql/mini_client.cc index 9993951d8e9..f204c38c18c 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -547,7 +547,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user, { char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info; my_socket sock; - ulong ip_addr; + uint32 ip_addr; struct sockaddr_in sock_addr; ulong pkt_length; NET *net= &mysql->net; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 22c92a5473b..23cf4952e3d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -29,7 +29,12 @@ #undef write /* remove pthread.h macro definition for EMX */ #endif +#ifdef BIG_JOINS +typedef ulonglong table_map; /* Used for table bits in join */ +#else typedef ulong table_map; /* Used for table bits in join */ +#endif /* BIG_JOINS */ + typedef ulong key_map; /* Used for finding keys */ typedef ulong key_part_map; /* Used for finding key parts */ @@ -474,11 +479,11 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, #include <openssl/des.h> struct st_des_keyblock { - des_cblock key1, key2, key3; + DES_cblock key1, key2, key3; }; struct st_des_keyschedule { - des_key_schedule ks1, ks2, ks3; + DES_key_schedule ks1, ks2, ks3; }; extern char *des_key_file; extern struct st_des_keyschedule des_keyschedule[10]; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index bcf115feccc..1bb51ea8e91 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -55,7 +55,9 @@ char pstack_file_name[80]; #endif /* __linux__ */ -#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ) +/* We have HAVE_purify below as this speeds up the shutdown of MySQL */ + +#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ) || defined(HAVE_purify) && defined(__linux__) #define HAVE_CLOSE_SERVER_SOCK 1 #endif @@ -534,12 +536,14 @@ static void close_connections(void) struct timespec abstime; int error; LINT_INIT(error); + DBUG_PRINT("info",("Waiting for select_thread")); + #ifndef DONT_USE_THR_ALARM if (pthread_kill(select_thread,THR_CLIENT_ALARM)) break; // allready dead #endif set_timespec(abstime, 2); - for (uint tmp=0 ; tmp < 10 ; tmp++) + for (uint tmp=0 ; tmp < 10 && select_thread_in_use; tmp++) { error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count, &abstime); @@ -700,8 +704,8 @@ static void close_server_sock() VOID(shutdown(tmp_sock,2)); #if defined(__NETWARE__) /* - The following code is disabled for normal systems as it causes MySQL - AIX 4.3 during shutdown (not tested, but likely) + The following code is disabled for normal systems as it may cause MySQL + to hang on AIX 4.3 during shutdown */ DBUG_PRINT("info",("calling closesocket on unix/IP socket")); VOID(closesocket(tmp_sock)); diff --git a/sql/slave.h b/sql/slave.h index f61891acc91..778ddf2ec72 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -170,7 +170,8 @@ typedef struct st_relay_log_info /* Handling of the relay_log_space_limit optional constraint. ignore_log_space_limit is used to resolve a deadlock between I/O and SQL - threads, it makes the I/O thread temporarily forget about the constraint + threads, the SQL thread sets it to unblock the I/O thread and make it + temporarily forget about the constraint. */ ulonglong log_space_limit,log_space_total; bool ignore_log_space_limit; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 43718e5d93b..1010378825f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -561,15 +561,13 @@ void close_temporary_tables(THD *thd) { // skip temporary tables not created directly by the user if (table->real_name[0] != '#') - { - /* - Here we assume table_cache_key always starts - with \0 terminated db name - */ found_user_tables = 1; - } - end = strxmov(end,table->table_cache_key,".", - table->real_name,",", NullS); + /* + Here we assume table_cache_key always starts + with \0 terminated db name + */ + end = strxmov(end,"`",table->table_cache_key,"`", + ".`",table->real_name,"`,", NullS); } next=table->next; close_temporary(table); diff --git a/sql/sql_class.h b/sql/sql_class.h index 8aa3d48bc35..2ed9cb7b877 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -783,8 +783,13 @@ class user_var_entry char *value; ulong length, update_query_id; Item_result type; + + double val(my_bool *null_value); + longlong val_int(my_bool *null_value); + String *val_str(my_bool *null_value, String *str, uint decimals); }; + /* Class for unique (removing of duplicates) */ class Unique :public Sql_alloc diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0ae6ccb4c4a..e692e7b8dab 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -282,22 +282,31 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ha_autocommit_or_rollback(thd,error); if (!opt_old_rpl_compat && mysql_bin_log.is_open()) { + /* + Make sure last block (the one which caused the error) gets logged. + This is needed because otherwise after write of + (to the binlog, not to read_info (which is a cache)) + Delete_file_log_event the bad block will remain in read_info (because + pre_read is not called at the end of the last block; remember pre_read + is called whenever a new block is read from disk). + At the end of mysql_load(), the destructor of read_info will call + end_io_cache() which will flush read_info, so we will finally have + this in the binlog: + Append_block # The last successfull block + Delete_file + Append_block # The failing block + which is nonsense. + Or could also be (for a small file) + Create_file # The failing block + which is nonsense (Delete_file is not written in this case, because: + Create_file has not been written, so Delete_file is not written, then + when read_info is destroyed end_io_cache() is called which writes + Create_file. + */ + read_info.end_io_cache(); + /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) { - /* - Make sure last block (the one which caused the error) gets logged. - This is needed because otherwise after write of - (to the binlog, not to read_info (which is a cache)) - Delete_file_log_event the bad block will remain in read_info. - At the end of mysql_load(), the destructor of read_info will call - end_io_cache() which will flush read_info, so we will finally have - this in the binlog: - Append_block # The last successfull block - Delete_file - Append_block # The failing block - which is nonsense. - */ - read_info.end_io_cache(); Delete_file_log_event d(thd, db, log_delayed); mysql_bin_log.write(&d); } @@ -327,7 +336,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } else { - read_info.end_io_cache(); // make sure last block gets logged + /* + As already explained above, we need to call end_io_cache() or the last + block will be logged only after Execute_load_log_event (which is wrong), + when read_info is destroyed. + */ + read_info.end_io_cache(); if (lf_info.wrote_create_file) { Execute_load_log_event e(thd, db, log_delayed); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6f6d21f1f8b..bffe3cd7968 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1898,7 +1898,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, best=best_time=records=DBL_MAX; KEYUSE *best_key=0; uint best_max_key_part=0; - my_bool found_constrain= 0; + my_bool found_constraint= 0; if (s->keyuse) { /* Use key if possible */ @@ -1979,7 +1979,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, } else { - found_constrain= 1; + found_constraint= 1; /* Check if we found full key */ @@ -2133,29 +2133,50 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, s->table->used_keys && best_key) && !(s->table->force_index && best_key)) { // Check full join - ha_rows rnd_records= s->found_records; - if (s->on_expr) - { - tmp=rows2double(rnd_records); // Can't use read cache - } - else - { - tmp=(double) s->read_time; - /* Calculate time to read previous rows through cache */ - tmp*=(1.0+floor((double) cache_record_length(join,idx)* - record_count / - (double) thd->variables.join_buff_size)); - } - - /* - If there is a restriction on the table, assume that 25% of the - rows can be skipped on next part. - This is to force tables that this table depends on before this - table - */ - if (found_constrain) - rnd_records-= rnd_records/4; + ha_rows rnd_records= s->found_records; + /* Estimate cost of reading table. */ + tmp= s->table->file->scan_time(); + /* + If there is a restriction on the table, assume that 25% of the + rows can be skipped on next part. + This is to force tables that this table depends on before this + table + */ + if (found_constraint) + rnd_records-= rnd_records/4; + + if (s->on_expr) // Can't use join cache + { + tmp= record_count * + /* We have to read the whole table for each record */ + (tmp + + /* + And we have to skip rows which does not satisfy join + condition for each record. + */ + (s->records - rnd_records)/(double) TIME_FOR_COMPARE); + } + else + { + /* We read the table as many times as join buffer becomes full. */ + tmp*= (1.0 + floor((double) cache_record_length(join,idx) * + record_count / + (double) thd->variables.join_buff_size)); + /* + We don't make full cartesian product between rows in the scanned + table and existing records because we skip all rows from the + scanned table, which does not satisfy join condition when + we read the table (see flush_cached_records for details). Here we + take into account cost to read and skip these records. + */ + tmp+= (s->records - rnd_records)/(double) TIME_FOR_COMPARE; + } + /* + We estimate the cost of evaluating WHERE clause for found records + as record_count * rnd_records + TIME_FOR_COMPARE. This cost plus + tmp give us total cost of using TABLE SCAN + */ if (best == DBL_MAX || (tmp + record_count/(double) TIME_FOR_COMPARE*rnd_records < best + record_count/(double) TIME_FOR_COMPARE*records)) @@ -3685,6 +3706,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, new_field->field_name=item->name; if (org_field->maybe_null()) new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join + if (org_field->type()==FIELD_TYPE_VAR_STRING) + table->db_create_options|= HA_OPTION_PACK_RECORD; } return new_field; } |