summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@hundin.mysql.fi>2001-12-13 02:31:19 +0200
committerunknown <monty@hundin.mysql.fi>2001-12-13 02:31:19 +0200
commit33a096829b0f2a294b162e11ad81df788732c384 (patch)
tree47a4c1a60e94a3e70ea5564124a296f7cd71605e /sql
parentf0f71accfc2b6fcc6dfeaa1ac4b8b73d071ff3a1 (diff)
downloadmariadb-git-33a096829b0f2a294b162e11ad81df788732c384.tar.gz
Fixed sleep time in mysql-test-run
Fixed bug in query cache. Cleaned up des_crypt code. BitKeeper/deleted/.del-fsck.mysql~87170d4358b50d60: Delete: fs/fsck.mysql Docs/manual.texi: Changed != to <> mysql-test/mysql-test-run.sh: Fix sleep times to take into account creation of InnoDB tables. mysql-test/r/group_by.result: More tests mysql-test/r/query_cache.result: More tests mysql-test/r/union.result: More tests mysql-test/t/func_str.test: Fix for FreeBSD mysql-test/t/query_cache.test: More tests mysql-test/t/union.test: More tests mysys/my_winsem.c: Cleanup comments sql/des_key_file.cc: Cleanup des_crypt code sql/item_strfunc.cc: Cleanup des_crypt code sql/item_strfunc.h: Cleanup des_crypt code sql/mysql_priv.h: Cleanup des_crypt code sql/mysqld.cc: Cleanup des_crypt code sql/sql_acl.cc: For for GRANT and lower-case-table names sql/sql_cache.cc: Function for integrity checking. Fixed bug when merging blocks. sql/sql_cache.h: Function for integrity checking. sql/sql_delete.cc: Cleanup sql/sql_parse.cc: For for GRANT and lower-case-table names sql/sql_union.cc: Cleanup & fixed bug in LIMIT handling sql/sql_yacc.yy: C
Diffstat (limited to 'sql')
-rw-r--r--sql/des_key_file.cc108
-rw-r--r--sql/item_strfunc.cc223
-rw-r--r--sql/item_strfunc.h5
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/mysqld.cc3
-rw-r--r--sql/sql_acl.cc34
-rw-r--r--sql/sql_cache.cc372
-rw-r--r--sql/sql_cache.h4
-rw-r--r--sql/sql_delete.cc41
-rw-r--r--sql/sql_parse.cc14
-rw-r--r--sql/sql_union.cc46
-rw-r--r--sql/sql_yacc.yy24
12 files changed, 636 insertions, 242 deletions
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index 253a8ea7516..164c2ab706e 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -15,72 +15,80 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <mysql_priv.h>
+#include <m_ctype.h>
#ifdef HAVE_OPENSSL
+
/*
- Function which loads DES keys from plaintext file
- into memory on MySQL server startup and on command
- FLUSH DES_KEYS. Blame tonu@spam.ee on bugs ;)
+ Function which loads DES keys from plaintext file into memory on MySQL
+ server startup and on command FLUSH DES_KEYS. Blame tonu@spam.ee on bugs ;)
*/
-void
+
+struct st_des_keyschedule des_keyschedule[10];
+uint default_des_key;
+
+void
load_des_key_file(const char *file_name)
{
- FILE *file;
- int ret=0;
- char offset;
- char buf[1024];
+ File file;
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- st_des_keyblock keyblock;
+ char offset;
+ IO_CACHE io;
DBUG_ENTER("load_des_key_file");
- VOID(pthread_mutex_lock(&LOCK_open));
DBUG_PRINT("enter",("name: %s",file_name));
- if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME))))
- {
- goto error_noclose;
- }
- while(!feof(file))
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
+ init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME)))
+ goto error;
+
+ bzero((char*) des_keyschedule,sizeof(struct st_des_keyschedule) * 10);
+ default_des_key=15; // Impossible key
+ for (;;)
{
- if ((my_fread(file, &offset, 1, MY_WME)) != 1)
- goto error_close;
- fgets(buf,sizeof(buf),file);
- int len=strlen(buf);
- if (len-->=1)
- buf[len]='\0';
- /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
- offset-='0';
- if (offset >= 0 && offset <=9)
+ char *start, *end;
+ char buf[1024];
+ st_des_keyblock keyblock;
+ uint length;
+
+ if (!(length=my_b_gets(&io,buf,sizeof(buf)-1)))
+ break; // End of file
+ offset=buf[0];
+ if (offset >= '0' && offset <= '9') // If ok key
{
- EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
- (uchar *)buf,
- strlen(buf),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);
- }
+ offset=(char) (offset - '0');
+ // Remove newline and possible other control characters
+ for (start=buf+1 ; isspace(*start) ; start++) ;
+ end=buf+length;
+ for (end=strend(buf) ; end > start && iscntrl(end[-1]) ; end--) ;
+
+ if (start != end)
+ {
+ // 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);
+ if (default_des_key == 15)
+ default_des_key= (uint) offset; // use first as def.
+ }
+ }
else
{
- DBUG_PRINT("des",("wrong offset: %d",offset));
+ DBUG_PRINT("des",("wrong offset: %c",offset));
}
}
-error_close:
- (void) my_fclose(file,MYF(MY_WME));
-error_noclose:
+
+error:
+ if (file >= 0)
+ {
+ my_close(file,MYF(0));
+ end_io_cache(&io);
+ }
VOID(pthread_mutex_unlock(&LOCK_open));
- /* if (ret)
- do something; */
DBUG_VOID_RETURN;
}
-
-/*
- This function is used to load right key with DES_ENCRYPT(text,integer)
-*/
-st_des_keyschedule *
-des_key(int key)
-{
- DBUG_ENTER("des_key");
- DBUG_PRINT("exit",("return: %x",&des_keyschedule[key]));
- DBUG_RETURN(&des_keyschedule[key]);
-}
-
#endif /* HAVE_OPENSSL */
-
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index ddecc62b749..004acd2d5ec 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -75,7 +75,11 @@ String *Item_func_md5::val_str(String *str)
my_MD5Init (&context);
my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length());
my_MD5Final (digest, &context);
- str->alloc(32); // Ensure that memory is free
+ if (str->alloc(32)) // Ensure that memory is free
+ {
+ null_value=1;
+ return 0;
+ }
sprintf((char *) str->ptr(),
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
@@ -201,162 +205,150 @@ void Item_func_concat::fix_length_and_dec()
}
}
-#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
-#define ascii_to_bin(c) ((c)<=57 ? (c)-46 : (c)<=90 ? (c)-53 : (c)-59)
-
/*
- Function des_encrypt() by tonu@spam.ee
- Works only if compiled with OpenSSL library support.
- Output always starts with magic char "1" and all
- encrypted output is encoded into ASCII-protected
- container.
- Original input is returned as output if input string
- begins with magic "1". Credit card number always begin
- with 4,5 or 6.
+ Function des_encrypt() by tonu@spam.ee & monty
+ Works only if compiled with OpenSSL library support.
+ This returns a binary string where first character is
+ CHAR(128 | tail-length << 4 | key-number).
+ If one uses a string key key_number is 0.
Encryption result is longer than original by formula:
- new_length=(8-(original_length % 8))*2+1
+ new_length= (8-(original_length % 8))+1
*/
String *Item_func_des_encrypt::val_str(String *str)
{
- String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
struct st_des_keyschedule *keyschedule_ptr=&keyschedule;
+ uint key_number=15;
+ String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return &empty_string;
- if(res->c_ptr()[0]!='1') // Skip encryption if already encrypted
- {
- if (args[1]->val_int())
- {
- keyschedule_ptr=des_key(args[1]->val_int());
- }
- else
- {
- String *keystr=args[1]->val_str(&tmp_value);
- /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
- EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
- (uchar *)keystr->c_ptr(),
- (int)keystr->length(),1,(uchar *)&keyblock,ivec);
- des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1);
- des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
- des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
- }
- /*
- The problem: DES algorithm requires original data to be in 8-bytes
- chunks. Missing bytes get filled with zeros and result of encryption
- can be up to 7 bytes longer than original string. When decrypted,
- we do not know the size of original string :(
- We add one byte with value 0x0..0x7 to original plaintext marking
- change of string length
- */
- uchar tail= 7-( res->length() %8); // 0..7 marking real offsets 1..8
- for(int i=0 ; i < tail ; ++i) res->append('*');
- res->append(tail); // Write tail length 0..7 to last pos
- str->length(res->length());
- for (uint j=0; j < res->length() ; ++j)
- {
- DBUG_PRINT("info",("## res->c_ptr()[%d]='%c'",j,res->c_ptr()[j]));
- }
- des_ede3_cbc_encrypt( // Real encryption
- (const uchar*)(res->c_ptr()),
- (uchar*)(str->c_ptr()),
- res->length(),
- keyschedule_ptr->ks1, keyschedule_ptr->ks2, keyschedule_ptr->ks3,
- &ivec, TRUE);
- for (uint j=0; j < res->length() ; ++j)
- {
- DBUG_PRINT("info",("## str->c_ptr()[%d]='%c'",j,str->c_ptr()[j]));
- }
- res->set((const char*)"1",(uint)1);
- for(uint i=0 ; i < str->length() ; ++i)
- {
- res->append(bin_to_ascii((uchar)str->c_ptr()[i] & 0x3f));
- res->append(bin_to_ascii(((uchar)str->c_ptr()[i] >> 5 ) & 0x3f));
- }
+ if (arg_count == 1)
+ keyschedule_ptr=des_keyschedule[key_number=default_des_key];
+ else if (args[1]->result_type == INT_RESULT)
+ {
+ key_number= (uint) args[1]->val_int();
+ if (key_number > 9)
+ goto error;
+ keyschedule_ptr= des_keyschedule[key_number];
}
- return res;
-#else
+ else
+ {
+ const char *append_str="********";
+ uint tail,res_length;
+ String *keystr=args[1]->val_str(&tmp_value);
+ if (!keystr)
+ goto error;
+
+ /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
+ 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_ptr->ks1);
+ des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
+ des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
+ }
+
+ /*
+ The problem: DES algorithm requires original data to be in 8-bytes
+ chunks. Missing bytes get filled with zeros and result of encryption
+ can be up to 7 bytes longer than original string. When decrypted,
+ we do not know the size of original string :(
+ We add one byte with value 0x1..0x8 as the second byte to original
+ plaintext marking change of string length.
+ */
+
+ tail= (7-(res->length()+7) % 8); // 0..7 marking extra length
+ res_length=res->length()+tail+1;
+ if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length))
+ goto err;
+
+ tmp_value.length(res_length);
+ tmp_value.[0]=(char) (128 | tail << 4 | key_number);
+ // Real encryption
+ des_ede3_cbc_encrypt((const uchar*) (res->ptr()),
+ (uchar*) (tmp_value->ptr()+1),
+ res->length(),
+ keyschedule_ptr->ks1,
+ keyschedule_ptr->ks2,
+ keyschedule_ptr->ks3,
+ &ivec, TRUE);
+ return &tmp_value;
+
+error:
+#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
-#endif /* HAVE_OPENSSL */
}
+
String *Item_func_des_decrypt::val_str(String *str)
{
- String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL
des_key_schedule ks1, ks2, ks3;
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
struct st_des_keyschedule *keyschedule_ptr=&keyschedule;
+ String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
- if (res->length() == 0)
- return &empty_string;
+ if (res->length(0) < 9 || (res->length()) % 8 != 1 || !(res->[0] & 128))
+ return res; // Skip decryption if not encrypted
- if(res->c_ptr()[0]=='1') // Skip decryption if not encrypted
+ if (arg_count == 1) // If automatic uncompression
{
- str->set((const char*)0,(uint)0);
- for(uint i=1 ; i < res->length() ; i+=2)
- {
- str->append((ascii_to_bin(res->c_ptr()[i]))
- | (ascii_to_bin(res->c_ptr()[i+1]) << 5 ));
- }
-
- if (args[1]->val_int())
- {
- keyschedule_ptr=des_key(args[1]->val_int());
- }
- else
- {
- /*
- We make good 24-byte (168 bit) key
- from given plaintext key with MD5
- */
- String *keystr=args[1]->val_str(&tmp_value);
- EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
- (uchar *)keystr->c_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_ptr->ks1);
- des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
- des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
- }
- res->length(str->length());
-
- des_ede3_cbc_encrypt( // Real decryption
- (const uchar*)(str->c_ptr()),
- (uchar*)(res->c_ptr()),
- str->length(),
- keyschedule_ptr->ks1, keyschedule_ptr->ks2, keyschedule_ptr->ks3,
- &ivec, FALSE);
- uchar tail=(res->c_ptr()[res->length()-1]) & 0x7;
- if ((res->length() > ((uint)1+tail))) // We should avoid negative length
- res->length(res->length()-1-tail); // (can happen with wrong key)
+ uint key_number=res->[0] & 15;
+ // Check if automatic key and that we have privilege to uncompress using it
+ if (!(current_thd->master_access & PROCESS_ACL) || key_number > 9)
+ goto error;
+ keyschedule_ptr=des_keyschedule[key_number-1];
}
- return res;
-#else
+ else
+ {
+ // We make good 24-byte (168 bit) key from given plaintext key with MD5
+ String *keystr=args[1]->val_str(&tmp_value);
+ if (!key_str)
+ goto error;
+ EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
+ (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_ptr->ks1);
+ des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
+ des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
+ }
+ if (tmp_value.alloc(res->length()-1))
+ goto err;
+ /* Restore old length of key */
+ tmp_value.length(res->length()-1-(((uchar) res->[0] >> 4) & 7));
+ des_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
+ (uchar*) (tmp_value->ptr()),
+ res->length()-1,
+ keyschedule_ptr->ks1,
+ keyschedule_ptr->ks2,
+ keyschedule_ptr->ks3,
+ &ivec, FALSE);
+ return &tmp_value;
+
+error:
+#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
-#endif /* HAVE_OPENSSL */
}
-
/*
-** concat with separator. First arg is the separator
-** concat_ws takes at least two arguments.
+ concat with separator. First arg is the separator
+ concat_ws takes at least two arguments.
*/
String *Item_func_concat_ws::val_str(String *str)
@@ -1146,6 +1138,7 @@ String *Item_func_password::val_str(String *str)
return str;
}
+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
String *Item_func_encrypt::val_str(String *str)
{
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 31c832c8ddb..ba2d6ffc3f0 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -228,9 +228,9 @@ class Item_func_des_encrypt :public Item_str_func
public:
Item_func_des_encrypt(Item *a) :Item_str_func(a) {}
Item_func_des_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
- Item_func_des_encrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
String *val_str(String *);
- void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
+ void fix_length_and_dec()
+ { maybe_null=1; max_length = args[0]->max_length+8; }
const char *func_name() const { return "des_encrypt"; }
};
@@ -240,7 +240,6 @@ class Item_func_des_decrypt :public Item_str_func
public:
Item_func_des_decrypt(Item *a) :Item_str_func(a) {}
Item_func_des_decrypt(Item *a, Item *b): Item_str_func(a,b) {}
- Item_func_des_decrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
const char *func_name() const { return "des_decrypt"; }
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 20f7b8c3d7b..dad5f27a3e0 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -405,9 +405,9 @@ struct st_des_keyschedule
{
des_key_schedule ks1, ks2, ks3;
};
-extern struct st_des_keyschedule des_keyschedule[10];
+extern struct st_des_keyschedule des_keyschedule[9];
+extern uint des_default_key;
void load_des_key_file(const char *file_name);
-struct st_des_keyschedule * des_key(int);
#endif /* HAVE_OPENSSL */
/* sql_list.c */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9bbdc7b8859..a8b9a799c56 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -243,7 +243,6 @@ static char glob_hostname[FN_REFLEN];
#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
static char * des_key_file = 0;
-struct st_des_keyschedule des_keyschedule[10];
struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0;
#endif /* HAVE_OPENSSL */
@@ -1751,8 +1750,6 @@ int main(int argc, char **argv)
opt_use_ssl = 0;
/* having ssl_acceptor_fd != 0 signals the use of SSL */
}
- bzero(des_keyschedule,sizeof(struct st_des_keyschedule) * 10);
- DBUG_PRINT("des",("initializing %d bytes of %x",sizeof(struct st_des_keyschedule) * 10, des_keyschedule));
if (des_key_file)
load_des_key_file(des_key_file);
#endif /* HAVE_OPENSSL */
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 6a54e3b2b16..0d2568e8c5e 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -698,12 +698,17 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip,
{
uint host_access,db_access,i,key_length;
db_access=0; host_access= ~0;
- char key[ACL_KEY_LENGTH],*end;
+ char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
VOID(pthread_mutex_lock(&acl_cache->lock));
memcpy_fixed(&key,bin_ip,sizeof(struct in_addr));
- end=strmov(strmov(key+sizeof(struct in_addr),user)+1,db);
+ end=strmov((tmp_db=strmov(key+sizeof(struct in_addr),user)+1),db);
+ if (lower_case_table_names)
+ {
+ casedn_str(tmp_db);
+ db=tmp_db;
+ }
key_length=(uint) (end-key);
if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
{
@@ -1377,6 +1382,11 @@ public:
db = strdup_root(&memex,d);
user = strdup_root(&memex,u);
tname= strdup_root(&memex,t);
+ if (lower_case_table_names)
+ {
+ casedn_str(db);
+ casedn_str(tname);
+ }
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
@@ -1398,7 +1408,13 @@ public:
privs = cols = 0; /* purecov: inspected */
return; /* purecov: inspected */
}
- key_length = (uint) strlen(db) + (uint) strlen(user) + (uint) strlen (tname) + 3;
+ if (lower_case_table_names)
+ {
+ casedn_str(db);
+ casedn_str(tname);
+ }
+ key_length = ((uint) strlen(db) + (uint) strlen(user) +
+ (uint) strlen(tname) + 3);
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (uint) form->field[6]->val_int();
@@ -1990,7 +2006,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str;
- char what;
+ char what,tmp_db[NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
DBUG_ENTER("mysql_grant");
@@ -2002,6 +2018,12 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
}
what = (revoke_grant) ? 'N' : 'Y';
+ if (lower_case_table_names && db)
+ {
+ strmov(tmp_db,db);
+ casedn_str(tmp_db);
+ db=tmp_db;
+ }
/* open the mysql.user and mysql.db tables */
@@ -2220,8 +2242,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
table->grant.want_privilege=0;
continue; // Already checked
}
- const char *db = table->db ? table->db : thd->db;
- GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,db,user,
+ GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
+ table->db,user,
table->real_name,0);
if (!grant_table)
{
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 4417af44907..7f3bb97c7d6 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -201,7 +201,7 @@ stored in Query_cache_memory_bin_step structure.
Free memory blocks are sorted in bins in lists with size-ascending order
(more small blocks needed frequently then bigger one).
-6. Packing cache.
+7. Packing cache.
Query cache packing is divided into two operation:
- pack_cache
@@ -305,7 +305,8 @@ If join_results allocated new block(s) then we need call pack_cache again.
#define BLOCK_UNLOCK_RD(B) { \
DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\
__LINE__,(ulong)(B)));B->query()->unlock_reading();}
-#define DUMP(C) DBUG_EXECUTE("qcache", {(C)->queries_dump();(C)->tables_dump();})
+#define DUMP(C) DBUG_EXECUTE("qcache", {\
+ (C)->cache_dump(); (C)->queries_dump();(C)->tables_dump();})
#else
#define MUTEX_LOCK(M) pthread_mutex_lock(M)
#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
@@ -581,6 +582,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
else
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
}
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
DBUG_VOID_RETURN;
}
@@ -609,6 +611,7 @@ void query_cache_abort(NET *net)
}
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
}
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
DBUG_VOID_RETURN;
}
@@ -656,12 +659,14 @@ void query_cache_end_of_result(NET *net)
}
net->query_cache_query=0;
}
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
DBUG_VOID_RETURN;
}
void query_cache_invalidate_by_MyISAM_filename(const char *filename)
{
query_cache.invalidate_by_MyISAM_filename(filename);
+ DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
}
@@ -1321,6 +1326,7 @@ void Query_cache::free_cache(my_bool destruction)
if (bins[0].free_blocks == 0)
{
wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
+ DBUG_VOID_RETURN;
}
#endif
@@ -1335,12 +1341,13 @@ void Query_cache::free_cache(my_bool destruction)
hash_free(&tables);
if (!destruction)
STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_EXECUTE("check_querycache",check_integrity(););
}
DBUG_VOID_RETURN;
}
/*****************************************************************************
- Free block data
+ Free block data
*****************************************************************************/
/*
@@ -1501,7 +1508,6 @@ Query_cache::append_result_data(Query_cache_block **current_block,
DBUG_PRINT("qcache", ("size limit reached %lu > %lu",
query_block->query()->length(),
query_cache_limit));
- *current_block=0; // Mark error
DBUG_RETURN(0);
}
if (*current_block == 0)
@@ -1550,8 +1556,8 @@ Query_cache::append_result_data(Query_cache_block **current_block,
query_block,
Query_cache_block::RES_CONT);
/*
- new_block may be not 0 even !success (if write_result_data
- allocate small block but failed allocate continue
+ new_block may be != 0 even !success (if write_result_data
+ allocate a small block but failed to allocate continue)
*/
if (new_block != 0)
double_linked_list_join(last_block, new_block);
@@ -1999,7 +2005,7 @@ Query_cache::get_free_block(ulong len, my_bool not_less, ulong min)
void Query_cache::free_memory_block(Query_cache_block *block)
{
- DBUG_ENTER("Query_cache::free_n_unlock_memory_block");
+ DBUG_ENTER("Query_cache::free_memory_block");
block->used=0;
DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
(ulong) first_block, (ulong) block,block->pnext,
@@ -2069,7 +2075,7 @@ my_bool Query_cache::append_next_free_block(Query_cache_block *block,
DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
add_size));
- if (next_block->is_free())
+ if (next_block != first_block && next_block->is_free())
{
ulong old_len = block->length;
exclude_from_free_memory_list(next_block);
@@ -2404,7 +2410,7 @@ my_bool Query_cache::move_by_type(byte **border,
char *data = (char*) block->data();
byte *key;
uint key_length;
- key=query_cache_table_get_key((byte*) block, &key_length,0);
+ key=query_cache_table_get_key((byte*) block, &key_length, 0);
hash_search(&tables, (byte*) key, key_length);
block->destroy();
@@ -2452,7 +2458,7 @@ my_bool Query_cache::move_by_type(byte **border,
block->data())->result();
byte *key;
uint key_length;
- key=query_cache_query_get_key((byte*) block, &key_length,0);
+ key=query_cache_query_get_key((byte*) block, &key_length, 0);
hash_search(&queries, (byte*) key, key_length);
memcpy((char*) new_block->table(0), (char*) block->table(0),
@@ -2682,8 +2688,9 @@ void Query_cache::wreck(uint line, const char *message)
DBUG_PRINT("warning", ("=================================="));
if (thd)
thd->killed = 1;
- bins_dump();
cache_dump();
+ /* check_integrity(); */ /* Can't call it here because of locks */
+ bins_dump();
DBUG_VOID_RETURN;
}
@@ -2821,4 +2828,347 @@ void Query_cache::tables_dump()
}
DBUG_PRINT("qcache", ("--------------------"));
}
+
+
+my_bool Query_cache::check_integrity()
+{
+ my_bool result = 0;
+ uint i;
+ STRUCT_LOCK(&structure_guard_mutex);
+
+ if (hash_check(&queries))
+ {
+ DBUG_PRINT("error", ("queries hash is damaged"));
+ result = 1;
+ }
+
+ if (hash_check(&tables))
+ {
+ DBUG_PRINT("error", ("tables hash is damaged"));
+ result = 1;
+ }
+
+ DBUG_PRINT("qcache", ("physical address check ..."));
+ ulong free=0, used=0;
+ Query_cache_block * block = first_block;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ // Check memory allocation
+ if (block->pnext == first_block) // Is it last block?
+ {
+ if ( ((byte*)block) + block->length !=
+ ((byte*)first_block) + query_cache_size )
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx, type %u, ended at 0x%lx, but cache ended at 0x%lx",
+ (ulong) block, (uint) block->type,
+ (ulong) (((byte*)block) + block->length),
+ (ulong) (((byte*)first_block) + query_cache_size)));
+ result = 1;
+ }
+ }
+ else
+ if (((byte*)block) + block->length != ((byte*)block->pnext))
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx, type %u, ended at 0x%lx, but next block begining at 0x%lx",
+ (ulong) block, (uint) block->type,
+ (ulong) (((byte*)block) + block->length),
+ (ulong) ((byte*)block->pnext)));
+ }
+ if (block->type == Query_cache_block::FREE)
+ free+=block->length;
+ else
+ used+=block->length;
+ switch(block->type) {
+ case Query_cache_block::FREE:
+ {
+ Query_cache_memory_bin *bin = *((Query_cache_memory_bin **)
+ block->data());
+ //is it correct pointer?
+ if ( ((byte*)bin) < ((byte*)bins) ||
+ ((byte*)bin) >= ((byte*)first_block))
+ {
+ DBUG_PRINT("error",
+ ("free block 0x%lx have bin pointer 0x%lx beyaond of bins array bounds [0x%lx,0x%lx]",
+ (ulong) block,
+ (ulong) bin,
+ (ulong) bins,
+ (ulong) first_block));
+ result = 1;
+ }
+ else
+ {
+ int idx = (((byte*)bin) - ((byte*)bins)) /
+ sizeof(Query_cache_memory_bin);
+ if (in_list(bins[idx].free_blocks, block, "free memory"))
+ result = 1;
+ }
+ break;
+ }
+ case Query_cache_block::TABLE:
+ if (in_list(tables_blocks[block->table()->type()], block, "tables"))
+ result = 1;
+ break;
+ case Query_cache_block::QUERY:
+ if (in_list(queries_blocks, block, "query"))
+ result = 1;
+ break;
+ case Query_cache_block::RES_INCOMPLETE:
+ case Query_cache_block::RES_BEG:
+ case Query_cache_block::RES_CONT:
+ case Query_cache_block::RESULT:
+ {
+ Query_cache_block * query_block = block->result()->parent();
+ if ( ((byte*)query_block) < ((byte*)first_block) ||
+ ((byte*)query_block) >= (((byte*)first_block) + query_cache_size))
+ {
+ DBUG_PRINT("error",
+ ("result block 0x%lx have query block pointer 0x%lx beyaond of block pool bounds [0x%lx,0x%lx]",
+ (ulong) block,
+ (ulong) query_block,
+ (ulong) first_block,
+ (ulong) (((byte*)first_block) + query_cache_size)));
+ result = 1;
+ }
+ else
+ {
+ if (in_list(queries_blocks, query_block, "query from results"))
+ result = 1;
+ if (in_list(query_block->query()->result(), block,
+ "results"))
+ result = 1;
+ }
+ break;
+ }
+ default:
+ DBUG_PRINT("error",
+ ("block 0x%lx have incorrect type %u",
+ block, block->type));
+ result = 1;
+ }
+
+ block = block->pnext;
+ } while (block != first_block);
+
+ if (used + free != query_cache_size)
+ {
+ DBUG_PRINT("error",
+ ("used memory (%lu) + free memory (%lu) != query_cache_size (%lu)",
+ used, free, query_cache_size));
+ result = 1;
+ }
+
+ if (free != free_memory)
+ {
+ DBUG_PRINT("error",
+ ("free memory (%lu) != free_memory (%lu)",
+ free, free_memory));
+ result = 1;
+ }
+
+ DBUG_PRINT("qcache", ("check queries ..."));
+ if ((block = queries_blocks))
+ {
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_query_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&queries, key, length);
+ if (((gptr)block) != val)
+ {
+ DBUG_PRINT("error", ("block 0x%lx found in queries hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+ if (in_blocks(block))
+ result = 1;
+ Query_cache_block * results = block->query()->result();
+ if (results)
+ {
+ Query_cache_block * result_block = results;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ if (in_blocks(result_block))
+ result = 1;
+
+ result_block = result_block->next;
+ } while (result_block != results);
+ }
+ block = block->next;
+ } while (block != queries_blocks);
+ }
+
+ DBUG_PRINT("qcache", ("check tables ..."));
+ for (i=0 ; (int) i < (int) Query_cache_table::TYPES_NUMBER; i++)
+ {
+ if ((block = tables_blocks[i]))
+ {
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ uint length;
+ byte *key = query_cache_table_get_key((byte*) block, &length, 0);
+ gptr val = hash_search(&tables, key, length);
+ if (((gptr)block) != val)
+ {
+ DBUG_PRINT("error", ("block 0x%lx found in tables hash like 0x%lx",
+ (ulong) block, (ulong) val));
+ }
+
+ if (in_blocks(block))
+ result = 1;
+ block=block->next;
+ } while (block != tables_blocks[i]);
+ }
+ }
+
+ DBUG_PRINT("qcache", ("check free blocks"));
+ for (i = 0; i < mem_bin_num; i++)
+ {
+ if ((block = bins[i].free_blocks))
+ {
+ uint count = 0;
+ do
+ {
+ DBUG_PRINT("qcache", ("block 0x%lx, type %u...",
+ (ulong) block, (uint) block->type));
+ if (in_blocks(block))
+ result = 1;
+
+ count++;
+ block=block->next;
+ } while (block != bins[i].free_blocks);
+ if (count != bins[i].number)
+ {
+ DBUG_PRINT("qcache", ("bin[%d].number is %d, but bin have %d blocks",
+ bins[i].number, count));
+ result = 1;
+ }
+ }
+ }
+ DBUG_ASSERT(result == 0);
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ return result;
+}
+
+
+my_bool Query_cache::in_blocks(Query_cache_block * point)
+{
+ my_bool result = 0;
+ Query_cache_block *block = point;
+ //back
+ do
+ {
+ if (block->pprev->pnext != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in physical list is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
+ (ulong) block, (ulong) block->pprev,
+ (ulong) block->pprev->pnext,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->pnext)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err1;
+ }
+ block = block->pprev;
+ } while (block != first_block && block != point);
+ if (block != first_block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx (0x%lx<-->0x%lx) not owned by pysical list",
+ (ulong) block, (ulong) block->pprev, (ulong )block->pnext));
+ return 1;
+ }
+
+err1:
+ //forward
+ block = point;
+ do
+ {
+ if (block->pnext->pprev != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in physicel list is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
+ (ulong) block, (ulong) block->pnext,
+ (ulong) block->pnext->pprev,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->pprev)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err2;
+ }
+ block = block->pnext;
+ } while (block != first_block);
+err2:
+ return result;
+}
+
+
+my_bool Query_cache::in_list(Query_cache_block * root,
+ Query_cache_block * point,
+ const char *name)
+{
+ my_bool result = 0;
+ Query_cache_block *block = point;
+ //back
+ do
+ {
+ if (block->prev->next != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in list '%s' 0x%lx is incorrect linked, prev block 0x%lx refered as next to 0x%lx (check from 0x%lx)",
+ (ulong) block, name, (ulong) root, (ulong) block->prev,
+ (ulong) block->prev->next,
+ (ulong) point));
+ //back trace
+ for(; block != point; block = block->next)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err1;
+ }
+ block = block->prev;
+ } while (block != root && block != point);
+ if (block != root)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx (0x%lx<-->0x%lx) not owned by list '%s' 0x%lx",
+ (ulong) block,
+ (ulong) block->prev, (ulong) block->next,
+ name, (ulong) root));
+ return 1;
+ }
+err1:
+ // forward
+ block = point;
+ do
+ {
+ if (block->next->prev != block)
+ {
+ DBUG_PRINT("error",
+ ("block 0x%lx in list '%s' 0x%lx is incorrect linked, next block 0x%lx refered as prev to 0x%lx (check from 0x%lx)",
+ (ulong) block, name, (ulong) root, (ulong) block->next,
+ (ulong) block->next->prev,
+ (ulong) point));
+ //back trace
+ for (; block != point; block = block->prev)
+ DBUG_PRINT("error", ("back trace 0x%lx", (ulong) block));
+ result = 1;
+ goto err2;
+ }
+ block = block->next;
+ } while (block != root);
+err2:
+ return result;
+}
+
#endif /* DBUG_OFF */
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index c01ea1e21d4..d04fc29a8d9 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -379,6 +379,10 @@ protected:
void cache_dump();
void queries_dump();
void tables_dump();
+ my_bool check_integrity();
+ my_bool in_list(Query_cache_block * root, Query_cache_block * point,
+ const char *name);
+ my_bool in_blocks(Query_cache_block * point);
#endif
friend void query_cache_insert(NET *net, const char *packet, ulong length);
friend void query_cache_end_of_result(NET *net);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index c0c0e4244d9..eed6e4e5f81 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -384,6 +384,13 @@ void multi_delete::send_error(uint errcode,const char *err)
}
+/*
+ Do delete from other tables.
+ Returns values:
+ 0 ok
+ 1 error
+*/
+
int multi_delete::do_deletes (bool from_send_error)
{
int error = 0, counter = 0;
@@ -420,7 +427,8 @@ int multi_delete::do_deletes (bool from_send_error)
{
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
- table_list.name=table->table_name; table_list.real_name=table_being_deleted->real_name;
+ table_list.name=table->table_name;
+ table_list.real_name=table_being_deleted->real_name;
table_list.table=table;
table_list.grant=table->grant;
table_list.db = table_being_deleted->db;
@@ -432,23 +440,20 @@ int multi_delete::do_deletes (bool from_send_error)
#endif /* USE_REGENERATE_TABLE */
READ_RECORD info;
- error=0;
init_read_record(&info,thd,table,NULL,0,0);
bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables);
while (!(error=info.read_record(&info)) &&
(!thd->killed || from_send_error || not_trans_safe))
{
- error=table->file->delete_row(table->record[0]);
- if (error)
+ if ((error=table->file->delete_row(table->record[0])))
{
table->file->print_error(error,MYF(0));
break;
}
- else
- deleted++;
+ deleted++;
}
end_read_record(&info);
- if (error == -1)
+ if (error == -1) // End of file
error = 0;
}
return error;
@@ -464,7 +469,6 @@ bool multi_delete::send_eof()
/* reset used flags */
delete_tables->table->no_keyread=0;
- if (error == -1) error = 0;
thd->proc_info="end";
if (error)
{
@@ -477,22 +481,17 @@ bool multi_delete::send_eof()
was a non-transaction-safe table involved, since
modifications in it cannot be rolled back. */
- if (deleted &&
- (!error || some_table_is_not_transaction_safe(delete_tables)))
+ if (deleted || some_table_is_not_transaction_safe(delete_tables))
{
mysql_update_log.write(thd,thd->query,thd->query_length);
- Query_log_event qinfo(thd, thd->query);
-
- /* mysql_bin_log is not open if binlogging or replication
- is not used */
-
- if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
- !some_table_is_not_transaction_safe(delete_tables))
- error=1; /* Log write failed: roll back
- the SQL statement */
-
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query);
+ if (mysql_bin_log.write(&qinfo) &&
+ !some_table_is_not_transaction_safe(delete_tables))
+ error=1; // Log write failed: roll back the SQL statement
+ }
/* Commit or rollback the current SQL statement */
-
VOID(ha_autocommit_or_rollback(thd,error > 0));
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 669eee1df4a..12646f0737f 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2423,7 +2423,6 @@ mysql_init_query(THD *thd)
thd->fatal_error=0; // Safety
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
thd->sent_row_count=thd->examined_row_count=0;
- thd->lex.sql_command=SQLCOM_SELECT;
DBUG_VOID_RETURN;
}
@@ -2860,13 +2859,17 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (!alias) /* Alias is case sensitive */
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
- if (lower_case_table_names)
- casedn_str(table->table.str);
+
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) "");
- ptr->real_name=table->table.str;
ptr->name=alias_str;
+ if (lower_case_table_names)
+ {
+ casedn_str(ptr->db);
+ casedn_str(table->table.str);
+ }
+ ptr->real_name=table->table.str;
ptr->lock_type=flags;
ptr->updating=updating;
if (use_index)
@@ -2879,7 +2882,8 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
/* check that used name is unique */
if (flags != TL_IGNORE)
{
- for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ; tables ;
+ for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
+ tables ;
tables=tables->next)
{
if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db))
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index b2ffb97fa81..0d8a41e9966 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -27,7 +27,7 @@
int mysql_union(THD *thd, LEX *lex,select_result *result)
{
- SELECT_LEX *sl, *last_sl=(SELECT_LEX *)NULL, lex_sl;
+ SELECT_LEX *sl, *last_sl, *lex_sl;
ORDER *order;
List<Item> item_list;
TABLE *table;
@@ -38,7 +38,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_ENTER("mysql_union");
/* Fix tables 'to-be-unioned-from' list to point at opened tables */
- for (sl=&lex->select_lex; sl && sl->linkage != NOT_A_SELECT; last_sl=sl, sl=sl->next)
+ last_sl= &lex->select_lex;
+ for (sl= last_sl;
+ sl && sl->linkage != NOT_A_SELECT;
+ last_sl=sl, sl=sl->next)
{
for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
cursor;
@@ -46,19 +49,27 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
cursor->table= ((TABLE_LIST*) cursor->table)->table;
}
+ /* last_sel now points at the last select where the ORDER BY is stored */
if (sl)
{
- lex_sl=*sl;
- sl=(SELECT_LEX *)NULL;
- if (last_sl) last_sl->next=sl;
+ /*
+ The found SL is an extra SELECT_LEX argument that contains
+ the ORDER BY and LIMIT parameter for the whole UNION
+ */
+ lex_sl= sl;
+ last_sl->next=0; // Remove this extra element
+ order= (ORDER *) lex_sl->order_list.first;
+ }
+ else if (!last_sl->braces)
+ {
+ lex_sl= last_sl; // ORDER BY is here
+ order= (ORDER *) lex_sl->order_list.first;
}
else
- lex_sl.linkage=UNSPECIFIED_TYPE;
-
- /* Find last select part as it's here ORDER BY and GROUP BY is stored */
- for (last_sl= &lex->select_lex;
- last_sl->next;
- last_sl=last_sl->next) ;
+ {
+ lex_sl=0;
+ order=0;
+ }
if (lex->select_lex.options & SELECT_DESCRIBE)
{
@@ -68,7 +79,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first,
sl->item_list,
sl->where,
- (sl->braces) ? (ORDER *) sl->order_list.first : (ORDER *) 0,
+ ((sl->braces) ?
+ (ORDER *) sl->order_list.first : (ORDER *) 0),
(ORDER*) sl->group_list.first,
sl->having,
(ORDER*) NULL,
@@ -79,8 +91,6 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_RETURN(0);
}
- order = (lex_sl.linkage == UNSPECIFIED_TYPE) ? ( (last_sl->braces) ? (ORDER *) 0 : (ORDER *) last_sl->order_list.first) : (ORDER *) lex_sl.order_list.first;
-
{
Item *item;
List_iterator<Item> it(lex->select_lex.item_list);
@@ -162,11 +172,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
}
if (!thd->fatal_error) // Check if EOM
{
- if (lex_sl.linkage == NOT_A_SELECT && ( lex_sl.select_limit || lex_sl.offset_limit))
+ if (lex_sl)
{
- thd->offset_limit=lex_sl.offset_limit;
- thd->select_limit=lex_sl.select_limit+lex_sl.offset_limit;
- if (thd->select_limit < lex_sl.select_limit)
+ thd->offset_limit=lex_sl->offset_limit;
+ thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit;
+ if (thd->select_limit < lex_sl->select_limit)
thd->select_limit= HA_POS_ERROR; // no limit
if (thd->select_limit == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1d4c39823ca..1dbdda28ffc 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1348,9 +1348,13 @@ table_to_table:
select:
- SELECT_SYM select_part2 { Select->braces=false; } union
+ select_init { Lex->sql_command=SQLCOM_SELECT; }
+
+select_init:
+ SELECT_SYM select_part2 { Select->braces=false; } union
|
- '(' SELECT_SYM select_part2 ')' {Select->braces=true;} union_opt
+ '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt
+
select_part2:
{
@@ -1643,10 +1647,14 @@ simple_expr:
{ $$= new Item_func_decode($3,$5.str); }
| ENCODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_encode($3,$5.str); }
- | DES_DECRYPT '(' expr ',' expr ')'
- { $$= new Item_func_des_decrypt($3,$5); }
- | DES_ENCRYPT '(' expr ',' expr ')'
- { $$= new Item_func_des_encrypt($3,$5); }
+ | DES_DECRYPT '(' expr ')'
+ { $$= new Item_func_des_decrypt($3); }
+ | DES_DECRYPT '(' expr ',' expr ')'
+ { $$= new Item_func_des_decrypt($3,$5); }
+ | DES_ENCRYPT '(' expr ')'
+ { $$= new Item_func_des_encrypt($3); }
+ | DES_ENCRYPT '(' expr ',' expr ')'
+ { $$= new Item_func_des_encrypt($3,$5); }
| EXPORT_SET '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_export_set($3, $5, $7); }
| EXPORT_SET '(' expr ',' expr ',' expr ',' expr ')'
@@ -3573,12 +3581,12 @@ union_list:
net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
YYABORT;
}
- if (lex->select->linkage==NOT_A_SELECT)
+ if (lex->select->linkage == NOT_A_SELECT)
YYABORT;
mysql_new_select(lex);
lex->select->linkage=UNION_TYPE;
}
- select
+ select_init
union_opt:
union {}