summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@mashka.mysql.fi>2003-10-08 22:12:32 +0300
committerunknown <monty@mashka.mysql.fi>2003-10-08 22:12:32 +0300
commit1a8bdb002369bc351659fe9e07ae93605cd7f858 (patch)
tree9974b278f962fdebee44503151a92f7319332982 /sql
parentc5808f554567b118d5ed653a56e490cfb5aafad2 (diff)
parent1c9f6fd50998a6fa8ab537ac54da87508393906c (diff)
downloadmariadb-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.cc8
-rw-r--r--sql/item_func.cc220
-rw-r--r--sql/item_func.h8
-rw-r--r--sql/item_strfunc.cc34
-rw-r--r--sql/log.cc8
-rw-r--r--sql/log_event.cc106
-rw-r--r--sql/mini_client.cc2
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/mysqld.cc12
-rw-r--r--sql/slave.h3
-rw-r--r--sql/sql_base.cc14
-rw-r--r--sql/sql_class.h5
-rw-r--r--sql/sql_load.cc44
-rw-r--r--sql/sql_select.cc71
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;
}