Commit 87fd219d authored by monty@hundin.mysql.fi's avatar monty@hundin.mysql.fi

Fixed sleep time in mysql-test-run

Fixed bug in query cache.
Cleaned up des_crypt code.
parent 8bef3771
......@@ -11282,7 +11282,7 @@ mysql> SELECT name, birth, death,
+--------+------------+------------+------+
@end example
The query uses @code{death IS NOT NULL} rather than @code{death != NULL}
The query uses @code{death IS NOT NULL} rather than @code{death <> NULL}
because @code{NULL} is a special value. This is explained later.
@xref{Working with NULL, , Working with @code{NULL}}.
......@@ -11367,12 +11367,12 @@ The @code{NULL} value can be surprising until you get used to it.
Conceptually, @code{NULL} means missing value or unknown value and it
is treated somewhat differently than other values. To test for @code{NULL},
you cannot use the arithmetic comparison operators such as @code{=}, @code{<},
or @code{!=}. To demonstrate this for yourself, try the following query:
or @code{<>}. To demonstrate this for yourself, try the following query:
@example
mysql> SELECT 1 = NULL, 1 != NULL, 1 < NULL, 1 > NULL;
mysql> SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
+----------+-----------+----------+----------+
| 1 = NULL | 1 != NULL | 1 < NULL | 1 > NULL |
| 1 = NULL | 1 <> NULL | 1 < NULL | 1 > NULL |
+----------+-----------+----------+----------+
| NULL | NULL | NULL | NULL |
+----------+-----------+----------+----------+
......@@ -11395,7 +11395,7 @@ The default truth value from a boolean operation is 1.
This special treatment of @code{NULL} is why, in the previous section, it
was necessary to determine which animals are no longer alive using
@code{death IS NOT NULL} instead of @code{death != NULL}.
@code{death IS NOT NULL} instead of @code{death <> NULL}.
@node Pattern matching, Counting rows, Working with NULL, Retrieving data
......@@ -11413,7 +11413,7 @@ SQL pattern matching allows you to use @samp{_} to match any single
character and @samp{%} to match an arbitrary number of characters (including
zero characters). In MySQL, SQL patterns are case insensitive by
default. Some examples are shown below. Note that you do not use @code{=}
or @code{!=} when you use SQL patterns; use the @code{LIKE} or @code{NOT
or @code{<>} when you use SQL patterns; use the @code{LIKE} or @code{NOT
LIKE} comparison operators instead.
To find names beginning with @samp{b}:
......@@ -46285,6 +46285,8 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet
@item
Fixed problem with @code{GRANT} when using @code{lower_case_table_names == 1}.
@item
Changed @code{SELECT ... IN SHARE MODE} to
@code{SELECT .. LOCK IN SHARE MODE} (as in MySQL 3.23).
@item
......@@ -46,7 +46,7 @@ which ()
sleep_until_file_deleted ()
{
file=$1
loop=$SLEEP_TIME
loop=$SLEEP_TIME_FOR_DELETE
while (test $loop -gt 0)
do
sleep 1
......@@ -61,7 +61,8 @@ sleep_until_file_deleted ()
sleep_until_file_exists ()
{
file=$1
loop=60 # Should be long enough enough for all cases
loop=$2
org_time=$2
while (test $loop -gt 0)
do
sleep 1
......@@ -71,7 +72,7 @@ sleep_until_file_exists ()
fi
loop=`expr $loop - 1`
done
echo "ERROR: $file was not created in 60 seconds; Aborting"
echo "ERROR: $file was not created in $org_time seconds; Aborting"
exit 1;
}
......@@ -172,7 +173,11 @@ DO_GCOV=""
DO_GDB=""
DO_DDD=""
DO_CLIENT_GDB=""
SLEEP_TIME=10
SLEEP_TIME_FOR_DELETE=10
SLEEP_TIME_FOR_FIRST_MASTER=200 # Enough time to create innodb tables
SLEEP_TIME_FOR_SECOND_MASTER=30
SLEEP_TIME_FOR_FIRST_SLAVE=30
SLEEP_TIME_FOR_SECOND_SLAVE=30
CHARACTER_SET=latin1
DBUSER=""
START_WAIT_TIMEOUT=3
......@@ -235,7 +240,6 @@ while test $# -gt 0; do
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;;
--sleep=*)
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1"
SLEEP_TIME=`$ECHO "$1" | $SED -e "s;--sleep=;;"`
;;
--mysqld=*)
TMP=`$ECHO "$1" | $SED -e "s;--mysqld=;;"`
......@@ -260,8 +264,9 @@ while test $# -gt 0; do
fi
DO_GDB=1
# We must use manager, as things doesn't work on Linux without it
USE_MANAGER=1
USE_RUNNING_SERVER=""
# This needs to be checked properly
# USE_MANAGER=1
# USE_RUNNING_SERVER=""
;;
--client-gdb )
if [ x$BINARY_DIST = x1 ] ; then
......@@ -755,7 +760,8 @@ EOF
else
manager_launch master $MYSQLD $master_args
fi
sleep_until_file_exists $MASTER_MYPID
sleep_until_file_exists $MASTER_MYPID $wait_for_master
wait_for_master=$SLEEP_TIME_FOR_SECOND_MASTER
MASTER_RUNNING=1
}
......@@ -847,7 +853,8 @@ start_slave()
manager_launch $slave_ident $SLAVE_MYSQLD $slave_args
fi
eval "SLAVE$1_RUNNING=1"
sleep_until_file_exists $slave_pid
sleep_until_file_exists $slave_pid $wait_for_slave
wait_for_slave=$SLEEP_TIME_FOR_SECOND_SLAVE
}
mysql_start ()
......@@ -1143,6 +1150,8 @@ then
# Remove files that can cause problems
$RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/*
wait_for_master=$SLEEP_TIME_FOR_FIRST_MASTER
wait_for_slave=$SLEEP_TIME_FOR_FIRST_SLAVE
$ECHO "Installing Test Databases"
mysql_install_db
start_manager
......
......@@ -216,3 +216,50 @@ select 1+1,"a",count(*) from t1 where foo in (2);
1+1 a count(*)
2 a 0
drop table t1;
CREATE TABLE t1 (
spID int(10) unsigned,
userID int(10) unsigned,
score smallint(5) unsigned,
key (spid),
key (score)
);
INSERT INTO t1 VALUES (1,1,1),(2,2,2),(2,1,1),(3,3,3),(4,3,3),(5,3,3);
explain select userid,count(*) from t1 group by userid desc;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 6 Using temporary
select userid,count(*) from t1 group by userid desc;
userid count(*)
3 3
2 1
1 2
explain select spid,count(*) from t1 where spid between 1 and 2 group by spid desc;
table type possible_keys key key_len ref rows Extra
t1 range spID spID 5 NULL 2 where used; Using index
explain select spid,count(*) from t1 where spid between 1 and 2 group by spid;
table type possible_keys key key_len ref rows Extra
t1 range spID spID 5 NULL 2 where used; Using index
select spid,count(*) from t1 where spid between 1 and 2 group by spid;
spid count(*)
1 1
2 2
select spid,count(*) from t1 where spid between 1 and 2 group by spid desc;
spid count(*)
explain select sql_big_result spid,sum(userid) from t1 group by spid desc;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 6 Using filesort
select sql_big_result spid,sum(userid) from t1 group by spid desc;
spid sum(userid)
5 3
4 3
3 3
2 3
1 1
explain select sql_big_result score,count(*) from t1 group by score desc;
table type possible_keys key key_len ref rows Extra
t1 index NULL score 3 NULL 6 Using index
select sql_big_result score,count(*) from t1 group by score desc;
score count(*)
3 3
2 1
1 2
drop table t1;
drop table if exists t1;
set autocommit=0;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
select * from t1;
a
1
2
3
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
drop table t1;
commit;
set autocommit=1;
flush query cache;
flush query cache;
reset query cache;
flush status;
drop table if exists t1,t2,t3;
......@@ -148,20 +150,6 @@ show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
drop table t1, t2, t3;
set autocommit=0;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
select * from t1;
a
1
2
3
show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
drop table t1;
commit;
set autocommit=1;
create table t1 (a int not null);
insert into t1 values (1),(2),(3);
create table t2 (a int not null);
......
......@@ -74,6 +74,14 @@ a b
2 b
3 c
4 d
(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1);
a b
1 a
(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc;
a b
3 c
2 b
1 a
explain select a,b from t1 union all select a,b from t2;
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4
......
......@@ -35,6 +35,7 @@ select insert('txs',2,1,'hi'),insert('is ',4,0,'a'),insert('txxxxt',2,4,'es');
select replace('aaaa','a','b'),replace('aaaa','aa','b'),replace('aaaa','a','bb'),replace('aaaa','','b'),replace('bbbb','a','c');
select replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ;
select soundex(''),soundex('he'),soundex('hello all folks');
--replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l.
select password('test'),length(encrypt('test')),encrypt('test','aa');
select md5('hello');
select repeat('monty',5),concat('*',space(5),'*');
......
--set-variable=query_cache_size=1M
-- source include/have_innodb.inc
#
# Without auto_commit.
#
drop table if exists t1;
set autocommit=0;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
select * from t1;
show status like "Qcache_queries_in_cache";
drop table t1;
commit;
set autocommit=1;
-- source include/have_innodb.inc
#
# Tests with query cache
#
# Reset query cache variables.
flush query cache; # This crashed in some versions
flush query cache; # This crashed in some versions
reset query cache;
flush status;
drop table if exists t1,t2,t3;
......@@ -73,17 +73,6 @@ delete from t3 where a=10;
show status like "Qcache_queries_in_cache";
drop table t1, t2, t3;
#
# Without auto_commit.
#
set autocommit=0;
create table t1 (a int not null) type=innodb;
insert into t1 values (1),(2),(3);
select * from t1;
show status like "Qcache_queries_in_cache";
drop table t1;
commit;
set autocommit=1;
#
# FLUSH QUERY CACHE
#
create table t1 (a int not null);
......
......@@ -18,6 +18,8 @@ select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 g
#test alternate syntax for unions
(select a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 4;
(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1);
(select a,b from t1 limit 2) union all (select a,b from t2 order by a limit 1) order by b desc;
# Test some error conditions with UNION
explain select a,b from t1 union all select a,b from t2;
......
......@@ -54,30 +54,24 @@
initial value of the semaphore is 'value'
PARAMETERS
sem
pointer to an instance of sem_t
sem Pointer to an instance of sem_t
pshared
if zero, this semaphore may only be shared between
pshared If zero, this semaphore may only be shared between
threads in the same process.
if nonzero, the semaphore can be shared between
If nonzero, the semaphore can be shared between
processes
value
initial value of the semaphore counter
DESCRIPTION
This function initializes an unnamed semaphore. The
initial value of the semaphore is set to 'value'.
value Initial value of the semaphore counter
RESULTS
0 successfully created semaphore,
-1 failed, error in errno
0 Successfully created semaphore,
-1 Failed, error in errno
ERRNO
EINVAL 'sem' is not a valid semaphore,
ENOSPC a required resource has been exhausted,
ENOSYS semaphores are not supported,
EPERM the process lacks appropriate privilege
ENOSPC A required resource has been exhausted,
ENOSYS Semaphores are not supported,
EPERM The process lacks appropriate privilege
*/
......@@ -133,20 +127,15 @@ sem_init (sem_t *sem, int pshared, unsigned int value)
This function destroys an unnamed semaphore.
PARAMETERS
sem
pointer to an instance of sem_t
DESCRIPTION
This function destroys an unnamed semaphore.
sem Pointer to an instance of sem_t
RESULTS
0 successfully destroyed semaphore,
-1 failed, error in errno
0 Successfully destroyed semaphore,
-1 Failed, error in errno
ERRNO
EINVAL 'sem' is not a valid semaphore,
ENOSYS semaphores are not supported,
EBUSY threads (or processes) are currently
blocked on 'sem'
ENOSYS Semaphores are not supported,
EBUSY Threads (or processes) are currently blocked on 'sem'
*/
int
......@@ -183,27 +172,24 @@ sem_destroy (sem_t * sem)
/*
DOCPUBLIC
This function tries to wait on a semaphore.
PARAMETERS
sem
pointer to an instance of sem_t
DESCRIPTION
This function tries to wait on a semaphore. If the
semaphore value is greater than zero, it decreases
its value by one. If the semaphore value is zero, then
this function returns immediately with the error EAGAIN
PARAMETERS
sem Pointer to an instance of sem_t
RESULTS
0 successfully decreased semaphore,
-1 failed, error in errno
0 Successfully decreased semaphore,
-1 Failed, error in errno
ERRNO
EAGAIN the semaphore was already locked,
EAGAIN The semaphore was already locked,
EINVAL 'sem' is not a valid semaphore,
ENOSYS semaphores are not supported,
EINTR the function was interrupted by a signal,
EDEADLK a deadlock condition was detected.
ENOSYS Semaphores are not supported,
EINTR The function was interrupted by a signal,
EDEADLK A deadlock condition was detected.
*/
int
......@@ -267,13 +253,6 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n)
/*
------------------------------------------------------
DOCPUBLIC
This function waits on a semaphore.
PARAMETERS
sem
pointer to an instance of sem_t
DESCRIPTION
This function waits on a semaphore. If the
semaphore value is greater than zero, it decreases
its value by one. If the semaphore value is zero, then
......@@ -281,15 +260,18 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n)
successfully decrease the value or until interrupted by
a signal.
PARAMETERS
sem Pointer to an instance of sem_t
RESULTS
0 successfully decreased semaphore,
-1 failed, error in errno
ERRNO
EINVAL 'sem' is not a valid semaphore,
ENOSYS semaphores are not supported,
EINTR the function was interrupted by a signal,
EDEADLK a deadlock condition was detected.
0 Successfully decreased semaphore,
-1 Failed, error in errno
ERRNO
EINVAL 'Sem' is not a valid semaphore,
ENOSYS Semaphores are not supported,
EINTR The function was interrupted by a signal,
EDEADLK A deadlock condition was detected.
*/
int
......@@ -331,23 +313,20 @@ sem_wait(sem_t *sem)
/*
------------------------------------------------------
DOCPUBLIC
This function posts a wakeup to a semaphore.
PARAMETERS
sem
pointer to an instance of sem_t
DESCRIPTION
This function posts a wakeup to a semaphore. If there
are waiting threads (or processes), one is awakened;
otherwise, the semaphore value is incremented by one.
PARAMETERS
sem Pointer to an instance of sem_t
RESULTS
0 successfully posted semaphore,
-1 failed, error in errno
0 Successfully posted semaphore,
-1 Failed, error in errno
ERRNO
EINVAL 'sem' is not a valid semaphore,
ENOSYS semaphores are not supported,
ENOSYS Semaphores are not supported,
*/
......@@ -378,26 +357,21 @@ sem_post (sem_t * sem)
/*
------------------------------------------------------
DOCPUBLIC
This function posts multiple wakeups to a semaphore.
PARAMETERS
sem
pointer to an instance of sem_t
count
counter, must be greater than zero.
DESCRIPTION
This function posts multiple wakeups to a semaphore. If there
are waiting threads (or processes), n <= count are awakened;
the semaphore value is incremented by count - n.
PARAMETERS
sem Pointer to an instance of sem_t
count Counter, must be greater than zero.
RESULTS
0 successfully posted semaphore,
-1 failed, error in errno
0 Successfully posted semaphore,
-1 Failed, error in errno
ERRNO
EINVAL 'sem' is not a valid semaphore
or count is less than or equal to zero.
EINVAL 'sem' is not a valid semaphore or count is less
than or equal to zero.
*/
int
......
......@@ -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 ;)
*/
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))))
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 (;;)
{
goto error_noclose;
}
while(!feof(file))
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
{
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)
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 *)buf,
strlen(buf),1,(uchar *)&keyblock,ivec);
(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 */
......@@ -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
Function des_encrypt() by tonu@spam.ee & monty
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.
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())
if (arg_count == 1)
keyschedule_ptr=des_keyschedule[key_number=default_des_key];
else if (args[1]->result_type == INT_RESULT)
{
keyschedule_ptr=des_key(args[1]->val_int());
key_number= (uint) args[1]->val_int();
if (key_number > 9)
goto error;
keyschedule_ptr= des_keyschedule[key_number];
}
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->c_ptr(),
(int)keystr->length(),1,(uchar *)&keyblock,ivec);
(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 0x0..0x7 to original plaintext marking
change of string length
We add one byte with value 0x1..0x8 as the second byte 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()),
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,
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]));
}
return &tmp_value;
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));
}
}
return res;
#else
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());
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];
}
else
{
/*
We make good 24-byte (168 bit) key
from given plaintext key with MD5
*/
// 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->c_ptr(),
(int)keystr->length(),1,(uchar *)&keyblock,ivec);
/*
Here we set all 64-bit keys (56 effective) one by one
*/
(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);
}
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,
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);
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)
}
return res;
#else
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)
{
......
......@@ -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"; }
......
......@@ -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 */
......
......@@ -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 */
......
......@@ -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)
{
......
......@@ -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,6 +1341,7 @@ 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;
}
......@@ -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 */
......@@ -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);
......
......@@ -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++;
}
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);
if (mysql_bin_log.is_open())
{
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) &&
if (mysql_bin_log.write(&qinfo) &&
!some_table_is_not_transaction_safe(delete_tables))
error=1; /* Log write failed: roll back
the SQL statement */
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));
}
......
......@@ -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))
......
......@@ -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;
......
......@@ -1348,9 +1348,13 @@ table_to_table:
select:
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,8 +1647,12 @@ simple_expr:
{ $$= new Item_func_decode($3,$5.str); }
| ENCODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_encode($3,$5.str); }
| 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 ')'
......@@ -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 {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment