Commit 33a09682 authored by unknown's avatar unknown

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
parent f0f71acc
...@@ -11282,7 +11282,7 @@ mysql> SELECT name, birth, death, ...@@ -11282,7 +11282,7 @@ mysql> SELECT name, birth, death,
+--------+------------+------------+------+ +--------+------------+------------+------+
@end example @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. because @code{NULL} is a special value. This is explained later.
@xref{Working with NULL, , Working with @code{NULL}}. @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. ...@@ -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 Conceptually, @code{NULL} means missing value or unknown value and it
is treated somewhat differently than other values. To test for @code{NULL}, is treated somewhat differently than other values. To test for @code{NULL},
you cannot use the arithmetic comparison operators such as @code{=}, @code{<}, 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 @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 | | NULL | NULL | NULL | NULL |
+----------+-----------+----------+----------+ +----------+-----------+----------+----------+
...@@ -11395,7 +11395,7 @@ The default truth value from a boolean operation is 1. ...@@ -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 This special treatment of @code{NULL} is why, in the previous section, it
was necessary to determine which animals are no longer alive using 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 @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 ...@@ -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 character and @samp{%} to match an arbitrary number of characters (including
zero characters). In MySQL, SQL patterns are case insensitive by zero characters). In MySQL, SQL patterns are case insensitive by
default. Some examples are shown below. Note that you do not use @code{=} 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. LIKE} comparison operators instead.
To find names beginning with @samp{b}: 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}. ...@@ -46285,6 +46285,8 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
@itemize @bullet @itemize @bullet
@item @item
Fixed problem with @code{GRANT} when using @code{lower_case_table_names == 1}.
@item
Changed @code{SELECT ... IN SHARE MODE} to Changed @code{SELECT ... IN SHARE MODE} to
@code{SELECT .. LOCK IN SHARE MODE} (as in MySQL 3.23). @code{SELECT .. LOCK IN SHARE MODE} (as in MySQL 3.23).
@item @item
...@@ -46,7 +46,7 @@ which () ...@@ -46,7 +46,7 @@ which ()
sleep_until_file_deleted () sleep_until_file_deleted ()
{ {
file=$1 file=$1
loop=$SLEEP_TIME loop=$SLEEP_TIME_FOR_DELETE
while (test $loop -gt 0) while (test $loop -gt 0)
do do
sleep 1 sleep 1
...@@ -61,7 +61,8 @@ sleep_until_file_deleted () ...@@ -61,7 +61,8 @@ sleep_until_file_deleted ()
sleep_until_file_exists () sleep_until_file_exists ()
{ {
file=$1 file=$1
loop=60 # Should be long enough enough for all cases loop=$2
org_time=$2
while (test $loop -gt 0) while (test $loop -gt 0)
do do
sleep 1 sleep 1
...@@ -71,7 +72,7 @@ sleep_until_file_exists () ...@@ -71,7 +72,7 @@ sleep_until_file_exists ()
fi fi
loop=`expr $loop - 1` loop=`expr $loop - 1`
done done
echo "ERROR: $file was not created in 60 seconds; Aborting" echo "ERROR: $file was not created in $org_time seconds; Aborting"
exit 1; exit 1;
} }
...@@ -172,7 +173,11 @@ DO_GCOV="" ...@@ -172,7 +173,11 @@ DO_GCOV=""
DO_GDB="" DO_GDB=""
DO_DDD="" DO_DDD=""
DO_CLIENT_GDB="" 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 CHARACTER_SET=latin1
DBUSER="" DBUSER=""
START_WAIT_TIMEOUT=3 START_WAIT_TIMEOUT=3
...@@ -235,7 +240,6 @@ while test $# -gt 0; do ...@@ -235,7 +240,6 @@ while test $# -gt 0; do
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;; EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" ;;
--sleep=*) --sleep=*)
EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1" EXTRA_MYSQL_TEST_OPT="$EXTRA_MYSQL_TEST_OPT $1"
SLEEP_TIME=`$ECHO "$1" | $SED -e "s;--sleep=;;"`
;; ;;
--mysqld=*) --mysqld=*)
TMP=`$ECHO "$1" | $SED -e "s;--mysqld=;;"` TMP=`$ECHO "$1" | $SED -e "s;--mysqld=;;"`
...@@ -260,8 +264,9 @@ while test $# -gt 0; do ...@@ -260,8 +264,9 @@ while test $# -gt 0; do
fi fi
DO_GDB=1 DO_GDB=1
# We must use manager, as things doesn't work on Linux without it # We must use manager, as things doesn't work on Linux without it
USE_MANAGER=1 # This needs to be checked properly
USE_RUNNING_SERVER="" # USE_MANAGER=1
# USE_RUNNING_SERVER=""
;; ;;
--client-gdb ) --client-gdb )
if [ x$BINARY_DIST = x1 ] ; then if [ x$BINARY_DIST = x1 ] ; then
...@@ -755,7 +760,8 @@ EOF ...@@ -755,7 +760,8 @@ EOF
else else
manager_launch master $MYSQLD $master_args manager_launch master $MYSQLD $master_args
fi 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 MASTER_RUNNING=1
} }
...@@ -847,7 +853,8 @@ start_slave() ...@@ -847,7 +853,8 @@ start_slave()
manager_launch $slave_ident $SLAVE_MYSQLD $slave_args manager_launch $slave_ident $SLAVE_MYSQLD $slave_args
fi fi
eval "SLAVE$1_RUNNING=1" 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 () mysql_start ()
...@@ -1143,6 +1150,8 @@ then ...@@ -1143,6 +1150,8 @@ then
# Remove files that can cause problems # Remove files that can cause problems
$RM -f $MYSQL_TEST_DIR/var/run/* $MYSQL_TEST_DIR/var/tmp/* $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" $ECHO "Installing Test Databases"
mysql_install_db mysql_install_db
start_manager start_manager
......
...@@ -216,3 +216,50 @@ select 1+1,"a",count(*) from t1 where foo in (2); ...@@ -216,3 +216,50 @@ select 1+1,"a",count(*) from t1 where foo in (2);
1+1 a count(*) 1+1 a count(*)
2 a 0 2 a 0
drop table t1; 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; reset query cache;
flush status; flush status;
drop table if exists t1,t2,t3; drop table if exists t1,t2,t3;
...@@ -148,20 +150,6 @@ show status like "Qcache_queries_in_cache"; ...@@ -148,20 +150,6 @@ show status like "Qcache_queries_in_cache";
Variable_name Value Variable_name Value
Qcache_queries_in_cache 0 Qcache_queries_in_cache 0
drop table t1, t2, t3; 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); create table t1 (a int not null);
insert into t1 values (1),(2),(3); insert into t1 values (1),(2),(3);
create table t2 (a int not null); create table t2 (a int not null);
......
...@@ -74,6 +74,14 @@ a b ...@@ -74,6 +74,14 @@ a b
2 b 2 b
3 c 3 c
4 d 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; explain select a,b from t1 union all select a,b from t2;
table type possible_keys key key_len ref rows Extra table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4 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'); ...@@ -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('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 replace(concat(lcase(concat('THIS',' ','IS',' ','A',' ')),ucase('false'),' ','test'),'FALSE','REAL') ;
select soundex(''),soundex('he'),soundex('hello all folks'); select soundex(''),soundex('he'),soundex('hello all folks');
--replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l.
select password('test'),length(encrypt('test')),encrypt('test','aa'); select password('test'),length(encrypt('test')),encrypt('test','aa');
select md5('hello'); select md5('hello');
select repeat('monty',5),concat('*',space(5),'*'); 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 # Tests with query cache
# #
# Reset query cache variables. # Reset query cache variables.
flush query cache; # This crashed in some versions
flush query cache; # This crashed in some versions
reset query cache; reset query cache;
flush status; flush status;
drop table if exists t1,t2,t3; drop table if exists t1,t2,t3;
...@@ -73,17 +73,6 @@ delete from t3 where a=10; ...@@ -73,17 +73,6 @@ delete from t3 where a=10;
show status like "Qcache_queries_in_cache"; show status like "Qcache_queries_in_cache";
drop table t1, t2, t3; 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 # FLUSH QUERY CACHE
# #
create table t1 (a int not null); 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 ...@@ -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 #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 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 # Test some error conditions with UNION
explain select a,b from t1 union all select a,b from t2; explain select a,b from t1 union all select a,b from t2;
......
...@@ -54,30 +54,24 @@ ...@@ -54,30 +54,24 @@
initial value of the semaphore is 'value' initial value of the semaphore is 'value'
PARAMETERS PARAMETERS
sem sem Pointer to an instance of sem_t
pointer to an instance of sem_t
pshared pshared If zero, this semaphore may only be shared between
if zero, this semaphore may only be shared between
threads in the same process. threads in the same process.
if nonzero, the semaphore can be shared between If nonzero, the semaphore can be shared between
processes processes
value value Initial value of the semaphore counter
initial value of the semaphore counter
DESCRIPTION
This function initializes an unnamed semaphore. The
initial value of the semaphore is set to 'value'.
RESULTS RESULTS
0 successfully created semaphore, 0 Successfully created semaphore,
-1 failed, error in errno -1 Failed, error in errno
ERRNO ERRNO
EINVAL 'sem' is not a valid semaphore, EINVAL 'sem' is not a valid semaphore,
ENOSPC a required resource has been exhausted, ENOSPC A required resource has been exhausted,
ENOSYS semaphores are not supported, ENOSYS Semaphores are not supported,
EPERM the process lacks appropriate privilege EPERM The process lacks appropriate privilege
*/ */
...@@ -133,20 +127,15 @@ sem_init (sem_t *sem, int pshared, unsigned int value) ...@@ -133,20 +127,15 @@ sem_init (sem_t *sem, int pshared, unsigned int value)
This function destroys an unnamed semaphore. This function destroys an unnamed semaphore.
PARAMETERS PARAMETERS
sem sem Pointer to an instance of sem_t
pointer to an instance of sem_t
DESCRIPTION
This function destroys an unnamed semaphore.
RESULTS RESULTS
0 successfully destroyed semaphore, 0 Successfully destroyed semaphore,
-1 failed, error in errno -1 Failed, error in errno
ERRNO ERRNO
EINVAL 'sem' is not a valid semaphore, EINVAL 'sem' is not a valid semaphore,
ENOSYS semaphores are not supported, ENOSYS Semaphores are not supported,
EBUSY threads (or processes) are currently EBUSY Threads (or processes) are currently blocked on 'sem'
blocked on 'sem'
*/ */
int int
...@@ -183,27 +172,24 @@ sem_destroy (sem_t * sem) ...@@ -183,27 +172,24 @@ sem_destroy (sem_t * sem)
/* /*
DOCPUBLIC 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 This function tries to wait on a semaphore. If the
semaphore value is greater than zero, it decreases semaphore value is greater than zero, it decreases
its value by one. If the semaphore value is zero, then its value by one. If the semaphore value is zero, then
this function returns immediately with the error EAGAIN this function returns immediately with the error EAGAIN
PARAMETERS
sem Pointer to an instance of sem_t
RESULTS RESULTS
0 successfully decreased semaphore, 0 Successfully decreased semaphore,
-1 failed, error in errno -1 Failed, error in errno
ERRNO ERRNO
EAGAIN the semaphore was already locked, EAGAIN The semaphore was already locked,
EINVAL 'sem' is not a valid semaphore, EINVAL 'sem' is not a valid semaphore,
ENOSYS semaphores are not supported, ENOSYS Semaphores are not supported,
EINTR the function was interrupted by a signal, EINTR The function was interrupted by a signal,
EDEADLK a deadlock condition was detected. EDEADLK A deadlock condition was detected.
*/ */
int int
...@@ -267,13 +253,6 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n) ...@@ -267,13 +253,6 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n)
/* /*
------------------------------------------------------ ------------------------------------------------------
DOCPUBLIC 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 This function waits on a semaphore. If the
semaphore value is greater than zero, it decreases semaphore value is greater than zero, it decreases
its value by one. If the semaphore value is zero, then its value by one. If the semaphore value is zero, then
...@@ -281,15 +260,18 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n) ...@@ -281,15 +260,18 @@ ptw32_increase_semaphore(sem_t * sem, unsigned int n)
successfully decrease the value or until interrupted by successfully decrease the value or until interrupted by
a signal. a signal.
PARAMETERS
sem Pointer to an instance of sem_t
RESULTS RESULTS
0 successfully decreased semaphore, 0 Successfully decreased semaphore,
-1 failed, error in errno -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.
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 int
...@@ -331,23 +313,20 @@ sem_wait(sem_t *sem) ...@@ -331,23 +313,20 @@ sem_wait(sem_t *sem)
/* /*
------------------------------------------------------ ------------------------------------------------------
DOCPUBLIC 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 This function posts a wakeup to a semaphore. If there
are waiting threads (or processes), one is awakened; are waiting threads (or processes), one is awakened;
otherwise, the semaphore value is incremented by one. otherwise, the semaphore value is incremented by one.
PARAMETERS
sem Pointer to an instance of sem_t
RESULTS RESULTS
0 successfully posted semaphore, 0 Successfully posted semaphore,
-1 failed, error in errno -1 Failed, error in errno
ERRNO ERRNO
EINVAL 'sem' is not a valid semaphore, 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) ...@@ -378,26 +357,21 @@ sem_post (sem_t * sem)
/* /*
------------------------------------------------------ ------------------------------------------------------
DOCPUBLIC 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 This function posts multiple wakeups to a semaphore. If there
are waiting threads (or processes), n <= count are awakened; are waiting threads (or processes), n <= count are awakened;
the semaphore value is incremented by count - n. 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 RESULTS
0 successfully posted semaphore, 0 Successfully posted semaphore,
-1 failed, error in errno -1 Failed, error in errno
ERRNO ERRNO
EINVAL 'sem' is not a valid semaphore EINVAL 'sem' is not a valid semaphore or count is less
or count is less than or equal to zero. than or equal to zero.
*/ */
int int
......
...@@ -15,72 +15,80 @@ ...@@ -15,72 +15,80 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <mysql_priv.h> #include <mysql_priv.h>
#include <m_ctype.h>
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
/* /*
Function which loads DES keys from plaintext file Function which loads DES keys from plaintext file into memory on MySQL
into memory on MySQL server startup and on command server startup and on command FLUSH DES_KEYS. Blame tonu@spam.ee on bugs ;)
FLUSH DES_KEYS. Blame tonu@spam.ee on bugs ;)
*/ */
struct st_des_keyschedule des_keyschedule[10];
uint default_des_key;
void void
load_des_key_file(const char *file_name) load_des_key_file(const char *file_name)
{ {
FILE *file; File file;
int ret=0;
char offset;
char buf[1024];
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 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"); DBUG_ENTER("load_des_key_file");
VOID(pthread_mutex_lock(&LOCK_open));
DBUG_PRINT("enter",("name: %s",file_name)); 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; char *start, *end;
} char buf[1024];
while(!feof(file)) 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) offset=(char) (offset - '0');
goto error_close; // Remove newline and possible other control characters
fgets(buf,sizeof(buf),file); for (start=buf+1 ; isspace(*start) ; start++) ;
int len=strlen(buf); end=buf+length;
if (len-->=1) for (end=strend(buf) ; end > start && iscntrl(end[-1]) ; end--) ;
buf[len]='\0';
/* We make good 24-byte (168 bit) key from given plaintext key with MD5 */ if (start != end)
offset-='0';
if (offset >= 0 && offset <=9)
{ {
// We make good 24-byte (168 bit) key from given plaintext key with MD5
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *)buf, (uchar *) start, (int) (end-start),1,
strlen(buf),1,(uchar *)&keyblock,ivec); (uchar *) &keyblock,
ivec);
des_set_key_unchecked(&keyblock.key1,des_keyschedule[(int)offset].ks1); 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.key2,des_keyschedule[(int)offset].ks2);
des_set_key_unchecked(&keyblock.key3,des_keyschedule[(int)offset].ks3); 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 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:
error_noclose: if (file >= 0)
{
my_close(file,MYF(0));
end_io_cache(&io);
}
VOID(pthread_mutex_unlock(&LOCK_open)); VOID(pthread_mutex_unlock(&LOCK_open));
/* if (ret)
do something; */
DBUG_VOID_RETURN; 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 */ #endif /* HAVE_OPENSSL */
...@@ -75,7 +75,11 @@ String *Item_func_md5::val_str(String *str) ...@@ -75,7 +75,11 @@ String *Item_func_md5::val_str(String *str)
my_MD5Init (&context); my_MD5Init (&context);
my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length()); my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length());
my_MD5Final (digest, &context); 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(), sprintf((char *) str->ptr(),
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3], digest[0], digest[1], digest[2], digest[3],
...@@ -201,162 +205,150 @@ void Item_func_concat::fix_length_and_dec() ...@@ -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. Works only if compiled with OpenSSL library support.
Output always starts with magic char "1" and all This returns a binary string where first character is
encrypted output is encoded into ASCII-protected CHAR(128 | tail-length << 4 | key-number).
container. If one uses a string key key_number is 0.
Original input is returned as output if input string
begins with magic "1". Credit card number always begin
with 4,5 or 6.
Encryption result is longer than original by formula: 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 *Item_func_des_encrypt::val_str(String *str)
{ {
String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
struct st_des_keyblock keyblock; struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule; struct st_des_keyschedule keyschedule;
struct st_des_keyschedule *keyschedule_ptr=&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)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 0) if (res->length() == 0)
return &empty_string; return &empty_string;
if(res->c_ptr()[0]!='1') // Skip encryption if already encrypted
{ if (arg_count == 1)
if (args[1]->val_int()) 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 else
{ {
const char *append_str="********";
uint tail,res_length;
String *keystr=args[1]->val_str(&tmp_value); 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 */ /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *)keystr->c_ptr(), (uchar*) keystr->ptr(), (int) keystr->length(),
(int)keystr->length(),1,(uchar *)&keyblock,ivec); 1, (uchar*) &keyblock,ivec);
des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1); des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2); des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3); des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
} }
/* /*
The problem: DES algorithm requires original data to be in 8-bytes The problem: DES algorithm requires original data to be in 8-bytes
chunks. Missing bytes get filled with zeros and result of encryption chunks. Missing bytes get filled with zeros and result of encryption
can be up to 7 bytes longer than original string. When decrypted, can be up to 7 bytes longer than original string. When decrypted,
we do not know the size of original string :( we do not know the size of original string :(
We add one byte with value 0x0..0x7 to original plaintext marking We add one byte with value 0x1..0x8 as the second byte to original
change of string length 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('*'); tail= (7-(res->length()+7) % 8); // 0..7 marking extra length
res->append(tail); // Write tail length 0..7 to last pos res_length=res->length()+tail+1;
str->length(res->length()); if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length))
for (uint j=0; j < res->length() ; ++j) goto err;
{
DBUG_PRINT("info",("## res->c_ptr()[%d]='%c'",j,res->c_ptr()[j])); tmp_value.length(res_length);
} tmp_value.[0]=(char) (128 | tail << 4 | key_number);
des_ede3_cbc_encrypt( // Real encryption // Real encryption
(const uchar*)(res->c_ptr()), des_ede3_cbc_encrypt((const uchar*) (res->ptr()),
(uchar*)(str->c_ptr()), (uchar*) (tmp_value->ptr()+1),
res->length(), res->length(),
keyschedule_ptr->ks1, keyschedule_ptr->ks2, keyschedule_ptr->ks3, keyschedule_ptr->ks1,
keyschedule_ptr->ks2,
keyschedule_ptr->ks3,
&ivec, TRUE); &ivec, TRUE);
for (uint j=0; j < res->length() ; ++j) return &tmp_value;
{
DBUG_PRINT("info",("## str->c_ptr()[%d]='%c'",j,str->c_ptr()[j]));
}
res->set((const char*)"1",(uint)1); error:
for(uint i=0 ; i < str->length() ; ++i) #endif /* HAVE_OPENSSL */
{
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
null_value=1; null_value=1;
return 0; return 0;
#endif /* HAVE_OPENSSL */
} }
String *Item_func_des_decrypt::val_str(String *str) String *Item_func_des_decrypt::val_str(String *str)
{ {
String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
des_key_schedule ks1, ks2, ks3; des_key_schedule ks1, ks2, ks3;
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
struct st_des_keyblock keyblock; struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule; struct st_des_keyschedule keyschedule;
struct st_des_keyschedule *keyschedule_ptr=&keyschedule; struct st_des_keyschedule *keyschedule_ptr=&keyschedule;
String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value)) if ((null_value=args[0]->null_value))
return 0; return 0;
if (res->length() == 0) if (res->length(0) < 9 || (res->length()) % 8 != 1 || !(res->[0] & 128))
return &empty_string; 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); uint key_number=res->[0] & 15;
for(uint i=1 ; i < res->length() ; i+=2) // Check if automatic key and that we have privilege to uncompress using it
{ if (!(current_thd->master_access & PROCESS_ACL) || key_number > 9)
str->append((ascii_to_bin(res->c_ptr()[i])) goto error;
| (ascii_to_bin(res->c_ptr()[i+1]) << 5 )); keyschedule_ptr=des_keyschedule[key_number-1];
}
if (args[1]->val_int())
{
keyschedule_ptr=des_key(args[1]->val_int());
} }
else 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); String *keystr=args[1]->val_str(&tmp_value);
if (!key_str)
goto error;
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *)keystr->c_ptr(), (uchar*) keystr->ptr(),(int) keystr->length(),
(int)keystr->length(),1,(uchar *)&keyblock,ivec); 1,(uchar*) &keyblock,ivec);
/* // Here we set all 64-bit keys (56 effective) one by one
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.key1,keyschedule_ptr->ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2); des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3); des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
} }
res->length(str->length()); if (tmp_value.alloc(res->length()-1))
goto err;
des_ede3_cbc_encrypt( // Real decryption /* Restore old length of key */
(const uchar*)(str->c_ptr()), tmp_value.length(res->length()-1-(((uchar) res->[0] >> 4) & 7));
(uchar*)(res->c_ptr()), des_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
str->length(), (uchar*) (tmp_value->ptr()),
keyschedule_ptr->ks1, keyschedule_ptr->ks2, keyschedule_ptr->ks3, res->length()-1,
keyschedule_ptr->ks1,
keyschedule_ptr->ks2,
keyschedule_ptr->ks3,
&ivec, FALSE); &ivec, FALSE);
uchar tail=(res->c_ptr()[res->length()-1]) & 0x7; return &tmp_value;
if ((res->length() > ((uint)1+tail))) // We should avoid negative length
res->length(res->length()-1-tail); // (can happen with wrong key) error:
} #endif /* HAVE_OPENSSL */
return res;
#else
null_value=1; null_value=1;
return 0; return 0;
#endif /* HAVE_OPENSSL */
} }
/* /*
** concat with separator. First arg is the separator concat with separator. First arg is the separator
** concat_ws takes at least two arguments. concat_ws takes at least two arguments.
*/ */
String *Item_func_concat_ws::val_str(String *str) String *Item_func_concat_ws::val_str(String *str)
...@@ -1146,6 +1138,7 @@ String *Item_func_password::val_str(String *str) ...@@ -1146,6 +1138,7 @@ String *Item_func_password::val_str(String *str)
return 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) String *Item_func_encrypt::val_str(String *str)
{ {
......
...@@ -228,9 +228,9 @@ class Item_func_des_encrypt :public Item_str_func ...@@ -228,9 +228,9 @@ class Item_func_des_encrypt :public Item_str_func
public: public:
Item_func_des_encrypt(Item *a) :Item_str_func(a) {} 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_str_func(a,b) {}
Item_func_des_encrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
String *val_str(String *); 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"; } const char *func_name() const { return "des_encrypt"; }
}; };
...@@ -240,7 +240,6 @@ class Item_func_des_decrypt :public Item_str_func ...@@ -240,7 +240,6 @@ class Item_func_des_decrypt :public Item_str_func
public: public:
Item_func_des_decrypt(Item *a) :Item_str_func(a) {} 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_str_func(a,b) {}
Item_func_des_decrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {}
String *val_str(String *); 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; }
const char *func_name() const { return "des_decrypt"; } const char *func_name() const { return "des_decrypt"; }
......
...@@ -405,9 +405,9 @@ struct st_des_keyschedule ...@@ -405,9 +405,9 @@ struct st_des_keyschedule
{ {
des_key_schedule ks1, ks2, ks3; 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); void load_des_key_file(const char *file_name);
struct st_des_keyschedule * des_key(int);
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
/* sql_list.c */ /* sql_list.c */
......
...@@ -243,7 +243,6 @@ static char glob_hostname[FN_REFLEN]; ...@@ -243,7 +243,6 @@ static char glob_hostname[FN_REFLEN];
#include "sslopt-vars.h" #include "sslopt-vars.h"
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
static char * des_key_file = 0; static char * des_key_file = 0;
struct st_des_keyschedule des_keyschedule[10];
struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0; struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0;
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
...@@ -1751,8 +1750,6 @@ int main(int argc, char **argv) ...@@ -1751,8 +1750,6 @@ int main(int argc, char **argv)
opt_use_ssl = 0; opt_use_ssl = 0;
/* having ssl_acceptor_fd != 0 signals the use of SSL */ /* 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) if (des_key_file)
load_des_key_file(des_key_file); load_des_key_file(des_key_file);
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
......
...@@ -698,12 +698,17 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip, ...@@ -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; uint host_access,db_access,i,key_length;
db_access=0; host_access= ~0; db_access=0; host_access= ~0;
char key[ACL_KEY_LENGTH],*end; char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry; acl_entry *entry;
VOID(pthread_mutex_lock(&acl_cache->lock)); VOID(pthread_mutex_lock(&acl_cache->lock));
memcpy_fixed(&key,bin_ip,sizeof(struct in_addr)); 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); key_length=(uint) (end-key);
if ((entry=(acl_entry*) acl_cache->search(key,key_length))) if ((entry=(acl_entry*) acl_cache->search(key,key_length)))
{ {
...@@ -1377,6 +1382,11 @@ public: ...@@ -1377,6 +1382,11 @@ public:
db = strdup_root(&memex,d); db = strdup_root(&memex,d);
user = strdup_root(&memex,u); user = strdup_root(&memex,u);
tname= strdup_root(&memex,t); 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; key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length); hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
...@@ -1398,7 +1408,13 @@ public: ...@@ -1398,7 +1408,13 @@ public:
privs = cols = 0; /* purecov: inspected */ privs = cols = 0; /* purecov: inspected */
return; /* 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); hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (uint) form->field[6]->val_int(); 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, ...@@ -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); List_iterator <LEX_USER> str_list (list);
LEX_USER *Str; LEX_USER *Str;
char what; char what,tmp_db[NAME_LEN+1];
bool create_new_users=0; bool create_new_users=0;
TABLE_LIST tables[2]; TABLE_LIST tables[2];
DBUG_ENTER("mysql_grant"); DBUG_ENTER("mysql_grant");
...@@ -2002,6 +2018,12 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights, ...@@ -2002,6 +2018,12 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
} }
what = (revoke_grant) ? 'N' : 'Y'; 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 */ /* open the mysql.user and mysql.db tables */
...@@ -2220,8 +2242,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables, ...@@ -2220,8 +2242,8 @@ bool check_grant(THD *thd, uint want_access, TABLE_LIST *tables,
table->grant.want_privilege=0; table->grant.want_privilege=0;
continue; // Already checked continue; // Already checked
} }
const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,
GRANT_TABLE *grant_table = table_hash_search(thd->host,thd->ip,db,user, table->db,user,
table->real_name,0); table->real_name,0);
if (!grant_table) if (!grant_table)
{ {
......
...@@ -201,7 +201,7 @@ stored in Query_cache_memory_bin_step structure. ...@@ -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 Free memory blocks are sorted in bins in lists with size-ascending order
(more small blocks needed frequently then bigger one). (more small blocks needed frequently then bigger one).
6. Packing cache. 7. Packing cache.
Query cache packing is divided into two operation: Query cache packing is divided into two operation:
- pack_cache - pack_cache
...@@ -305,7 +305,8 @@ If join_results allocated new block(s) then we need call pack_cache again. ...@@ -305,7 +305,8 @@ If join_results allocated new block(s) then we need call pack_cache again.
#define BLOCK_UNLOCK_RD(B) { \ #define BLOCK_UNLOCK_RD(B) { \
DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\ DBUG_PRINT("lock", ("%d UNLOCK_RD 0x%lx",\
__LINE__,(ulong)(B)));B->query()->unlock_reading();} __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 #else
#define MUTEX_LOCK(M) pthread_mutex_lock(M) #define MUTEX_LOCK(M) pthread_mutex_lock(M)
#define MUTEX_UNLOCK(M) pthread_mutex_unlock(M) #define MUTEX_UNLOCK(M) pthread_mutex_unlock(M)
...@@ -581,6 +582,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length) ...@@ -581,6 +582,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
else else
STRUCT_UNLOCK(&query_cache.structure_guard_mutex); STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
} }
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -609,6 +611,7 @@ void query_cache_abort(NET *net) ...@@ -609,6 +611,7 @@ void query_cache_abort(NET *net)
} }
STRUCT_UNLOCK(&query_cache.structure_guard_mutex); STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
} }
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -656,12 +659,14 @@ void query_cache_end_of_result(NET *net) ...@@ -656,12 +659,14 @@ void query_cache_end_of_result(NET *net)
} }
net->query_cache_query=0; net->query_cache_query=0;
} }
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(););
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
void query_cache_invalidate_by_MyISAM_filename(const char *filename) void query_cache_invalidate_by_MyISAM_filename(const char *filename)
{ {
query_cache.invalidate_by_MyISAM_filename(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) ...@@ -1321,6 +1326,7 @@ void Query_cache::free_cache(my_bool destruction)
if (bins[0].free_blocks == 0) if (bins[0].free_blocks == 0)
{ {
wreck(__LINE__,"no free memory found in (bins[0].free_blocks"); wreck(__LINE__,"no free memory found in (bins[0].free_blocks");
DBUG_VOID_RETURN;
} }
#endif #endif
...@@ -1335,6 +1341,7 @@ void Query_cache::free_cache(my_bool destruction) ...@@ -1335,6 +1341,7 @@ void Query_cache::free_cache(my_bool destruction)
hash_free(&tables); hash_free(&tables);
if (!destruction) if (!destruction)
STRUCT_UNLOCK(&structure_guard_mutex); STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_EXECUTE("check_querycache",check_integrity(););
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1501,7 +1508,6 @@ Query_cache::append_result_data(Query_cache_block **current_block, ...@@ -1501,7 +1508,6 @@ Query_cache::append_result_data(Query_cache_block **current_block,
DBUG_PRINT("qcache", ("size limit reached %lu > %lu", DBUG_PRINT("qcache", ("size limit reached %lu > %lu",
query_block->query()->length(), query_block->query()->length(),
query_cache_limit)); query_cache_limit));
*current_block=0; // Mark error
DBUG_RETURN(0); DBUG_RETURN(0);
} }
if (*current_block == 0) if (*current_block == 0)
...@@ -1550,8 +1556,8 @@ Query_cache::append_result_data(Query_cache_block **current_block, ...@@ -1550,8 +1556,8 @@ Query_cache::append_result_data(Query_cache_block **current_block,
query_block, query_block,
Query_cache_block::RES_CONT); Query_cache_block::RES_CONT);
/* /*
new_block may be not 0 even !success (if write_result_data new_block may be != 0 even !success (if write_result_data
allocate small block but failed allocate continue allocate a small block but failed to allocate continue)
*/ */
if (new_block != 0) if (new_block != 0)
double_linked_list_join(last_block, new_block); 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) ...@@ -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) 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; block->used=0;
DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx", DBUG_PRINT("qcache",("first_block 0x%lx, block 0x%lx, pnext 0x%lx pprev 0x%lx",
(ulong) first_block, (ulong) block,block->pnext, (ulong) first_block, (ulong) block,block->pnext,
...@@ -2069,7 +2075,7 @@ my_bool Query_cache::append_next_free_block(Query_cache_block *block, ...@@ -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, DBUG_PRINT("enter", ("block 0x%lx, add_size %lu", (ulong) block,
add_size)); add_size));
if (next_block->is_free()) if (next_block != first_block && next_block->is_free())
{ {
ulong old_len = block->length; ulong old_len = block->length;
exclude_from_free_memory_list(next_block); exclude_from_free_memory_list(next_block);
...@@ -2404,7 +2410,7 @@ my_bool Query_cache::move_by_type(byte **border, ...@@ -2404,7 +2410,7 @@ my_bool Query_cache::move_by_type(byte **border,
char *data = (char*) block->data(); char *data = (char*) block->data();
byte *key; byte *key;
uint key_length; 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); hash_search(&tables, (byte*) key, key_length);
block->destroy(); block->destroy();
...@@ -2452,7 +2458,7 @@ my_bool Query_cache::move_by_type(byte **border, ...@@ -2452,7 +2458,7 @@ my_bool Query_cache::move_by_type(byte **border,
block->data())->result(); block->data())->result();
byte *key; byte *key;
uint key_length; 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); hash_search(&queries, (byte*) key, key_length);
memcpy((char*) new_block->table(0), (char*) block->table(0), memcpy((char*) new_block->table(0), (char*) block->table(0),
...@@ -2682,8 +2688,9 @@ void Query_cache::wreck(uint line, const char *message) ...@@ -2682,8 +2688,9 @@ void Query_cache::wreck(uint line, const char *message)
DBUG_PRINT("warning", ("==================================")); DBUG_PRINT("warning", ("=================================="));
if (thd) if (thd)
thd->killed = 1; thd->killed = 1;
bins_dump();
cache_dump(); cache_dump();
/* check_integrity(); */ /* Can't call it here because of locks */
bins_dump();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2821,4 +2828,347 @@ void Query_cache::tables_dump() ...@@ -2821,4 +2828,347 @@ void Query_cache::tables_dump()
} }
DBUG_PRINT("qcache", ("--------------------")); 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 */ #endif /* DBUG_OFF */
...@@ -379,6 +379,10 @@ protected: ...@@ -379,6 +379,10 @@ protected:
void cache_dump(); void cache_dump();
void queries_dump(); void queries_dump();
void tables_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 #endif
friend void query_cache_insert(NET *net, const char *packet, ulong length); friend void query_cache_insert(NET *net, const char *packet, ulong length);
friend void query_cache_end_of_result(NET *net); friend void query_cache_end_of_result(NET *net);
......
...@@ -384,6 +384,13 @@ void multi_delete::send_error(uint errcode,const char *err) ...@@ -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 multi_delete::do_deletes (bool from_send_error)
{ {
int error = 0, counter = 0; int error = 0, counter = 0;
...@@ -420,7 +427,8 @@ int multi_delete::do_deletes (bool from_send_error) ...@@ -420,7 +427,8 @@ int multi_delete::do_deletes (bool from_send_error)
{ {
TABLE_LIST table_list; TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(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.table=table;
table_list.grant=table->grant; table_list.grant=table->grant;
table_list.db = table_being_deleted->db; table_list.db = table_being_deleted->db;
...@@ -432,23 +440,20 @@ int multi_delete::do_deletes (bool from_send_error) ...@@ -432,23 +440,20 @@ int multi_delete::do_deletes (bool from_send_error)
#endif /* USE_REGENERATE_TABLE */ #endif /* USE_REGENERATE_TABLE */
READ_RECORD info; READ_RECORD info;
error=0;
init_read_record(&info,thd,table,NULL,0,0); init_read_record(&info,thd,table,NULL,0,0);
bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables); bool not_trans_safe = some_table_is_not_transaction_safe(delete_tables);
while (!(error=info.read_record(&info)) && while (!(error=info.read_record(&info)) &&
(!thd->killed || from_send_error || not_trans_safe)) (!thd->killed || from_send_error || not_trans_safe))
{ {
error=table->file->delete_row(table->record[0]); if ((error=table->file->delete_row(table->record[0])))
if (error)
{ {
table->file->print_error(error,MYF(0)); table->file->print_error(error,MYF(0));
break; break;
} }
else
deleted++; deleted++;
} }
end_read_record(&info); end_read_record(&info);
if (error == -1) if (error == -1) // End of file
error = 0; error = 0;
} }
return error; return error;
...@@ -464,7 +469,6 @@ bool multi_delete::send_eof() ...@@ -464,7 +469,6 @@ bool multi_delete::send_eof()
/* reset used flags */ /* reset used flags */
delete_tables->table->no_keyread=0; delete_tables->table->no_keyread=0;
if (error == -1) error = 0;
thd->proc_info="end"; thd->proc_info="end";
if (error) if (error)
{ {
...@@ -477,22 +481,17 @@ bool multi_delete::send_eof() ...@@ -477,22 +481,17 @@ bool multi_delete::send_eof()
was a non-transaction-safe table involved, since was a non-transaction-safe table involved, since
modifications in it cannot be rolled back. */ modifications in it cannot be rolled back. */
if (deleted && if (deleted || some_table_is_not_transaction_safe(delete_tables))
(!error || some_table_is_not_transaction_safe(delete_tables)))
{ {
mysql_update_log.write(thd,thd->query,thd->query_length); mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query); Query_log_event qinfo(thd, thd->query);
if (mysql_bin_log.write(&qinfo) &&
/* 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)) !some_table_is_not_transaction_safe(delete_tables))
error=1; /* Log write failed: roll back error=1; // Log write failed: roll back the SQL statement
the SQL statement */ }
/* Commit or rollback the current SQL statement */ /* Commit or rollback the current SQL statement */
VOID(ha_autocommit_or_rollback(thd,error > 0)); VOID(ha_autocommit_or_rollback(thd,error > 0));
} }
......
...@@ -2423,7 +2423,6 @@ mysql_init_query(THD *thd) ...@@ -2423,7 +2423,6 @@ mysql_init_query(THD *thd)
thd->fatal_error=0; // Safety thd->fatal_error=0; // Safety
thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0; thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
thd->sent_row_count=thd->examined_row_count=0; thd->sent_row_count=thd->examined_row_count=0;
thd->lex.sql_command=SQLCOM_SELECT;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -2860,13 +2859,17 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, ...@@ -2860,13 +2859,17 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (!alias) /* Alias is case sensitive */ if (!alias) /* Alias is case sensitive */
if (!(alias_str=thd->memdup(alias_str,table->table.length+1))) if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0); DBUG_RETURN(0);
if (lower_case_table_names)
casedn_str(table->table.str);
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */ DBUG_RETURN(0); /* purecov: inspected */
ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) ""); ptr->db= table->db.str ? table->db.str : (thd->db ? thd->db : (char*) "");
ptr->real_name=table->table.str;
ptr->name=alias_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->lock_type=flags;
ptr->updating=updating; ptr->updating=updating;
if (use_index) if (use_index)
...@@ -2879,7 +2882,8 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, ...@@ -2879,7 +2882,8 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
/* check that used name is unique */ /* check that used name is unique */
if (flags != TL_IGNORE) 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) tables=tables->next)
{ {
if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db)) if (!strcmp(alias_str,tables->name) && !strcmp(ptr->db, tables->db))
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
int mysql_union(THD *thd, LEX *lex,select_result *result) 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; ORDER *order;
List<Item> item_list; List<Item> item_list;
TABLE *table; TABLE *table;
...@@ -38,7 +38,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -38,7 +38,10 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_ENTER("mysql_union"); DBUG_ENTER("mysql_union");
/* Fix tables 'to-be-unioned-from' list to point at opened tables */ /* 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; for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
cursor; cursor;
...@@ -46,19 +49,27 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -46,19 +49,27 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
cursor->table= ((TABLE_LIST*) cursor->table)->table; cursor->table= ((TABLE_LIST*) cursor->table)->table;
} }
/* last_sel now points at the last select where the ORDER BY is stored */
if (sl) if (sl)
{ {
lex_sl=*sl; /*
sl=(SELECT_LEX *)NULL; The found SL is an extra SELECT_LEX argument that contains
if (last_sl) last_sl->next=sl; 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 else
lex_sl.linkage=UNSPECIFIED_TYPE; {
lex_sl=0;
/* Find last select part as it's here ORDER BY and GROUP BY is stored */ order=0;
for (last_sl= &lex->select_lex; }
last_sl->next;
last_sl=last_sl->next) ;
if (lex->select_lex.options & SELECT_DESCRIBE) if (lex->select_lex.options & SELECT_DESCRIBE)
{ {
...@@ -68,7 +79,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -68,7 +79,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first, res=mysql_select(thd, (TABLE_LIST*) sl->table_list.first,
sl->item_list, sl->item_list,
sl->where, 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, (ORDER*) sl->group_list.first,
sl->having, sl->having,
(ORDER*) NULL, (ORDER*) NULL,
...@@ -79,8 +91,6 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -79,8 +91,6 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_RETURN(0); 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; Item *item;
List_iterator<Item> it(lex->select_lex.item_list); List_iterator<Item> it(lex->select_lex.item_list);
...@@ -162,11 +172,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -162,11 +172,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
} }
if (!thd->fatal_error) // Check if EOM 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->offset_limit=lex_sl->offset_limit;
thd->select_limit=lex_sl.select_limit+lex_sl.offset_limit; thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit;
if (thd->select_limit < lex_sl.select_limit) if (thd->select_limit < lex_sl->select_limit)
thd->select_limit= HA_POS_ERROR; // no limit thd->select_limit= HA_POS_ERROR; // no limit
if (thd->select_limit == HA_POS_ERROR) if (thd->select_limit == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS; thd->options&= ~OPTION_FOUND_ROWS;
......
...@@ -1348,9 +1348,13 @@ table_to_table: ...@@ -1348,9 +1348,13 @@ table_to_table:
select: select:
select_init { Lex->sql_command=SQLCOM_SELECT; }
select_init:
SELECT_SYM select_part2 { Select->braces=false; } union 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: select_part2:
{ {
...@@ -1643,8 +1647,12 @@ simple_expr: ...@@ -1643,8 +1647,12 @@ simple_expr:
{ $$= new Item_func_decode($3,$5.str); } { $$= new Item_func_decode($3,$5.str); }
| ENCODE_SYM '(' expr ',' TEXT_STRING ')' | ENCODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_encode($3,$5.str); } { $$= new Item_func_encode($3,$5.str); }
| DES_DECRYPT '(' expr ')'
{ $$= new Item_func_des_decrypt($3); }
| DES_DECRYPT '(' expr ',' expr ')' | DES_DECRYPT '(' expr ',' expr ')'
{ $$= new Item_func_des_decrypt($3,$5); } { $$= new Item_func_des_decrypt($3,$5); }
| DES_ENCRYPT '(' expr ')'
{ $$= new Item_func_des_encrypt($3); }
| DES_ENCRYPT '(' expr ',' expr ')' | DES_ENCRYPT '(' expr ',' expr ')'
{ $$= new Item_func_des_encrypt($3,$5); } { $$= new Item_func_des_encrypt($3,$5); }
| EXPORT_SET '(' expr ',' expr ',' expr ')' | EXPORT_SET '(' expr ',' expr ',' expr ')'
...@@ -3573,12 +3581,12 @@ union_list: ...@@ -3573,12 +3581,12 @@ union_list:
net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO"); net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
YYABORT; YYABORT;
} }
if (lex->select->linkage==NOT_A_SELECT) if (lex->select->linkage == NOT_A_SELECT)
YYABORT; YYABORT;
mysql_new_select(lex); mysql_new_select(lex);
lex->select->linkage=UNION_TYPE; lex->select->linkage=UNION_TYPE;
} }
select select_init
union_opt: union_opt:
union {} 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