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;
......
......@@ -4,10 +4,10 @@
* Module: my_semaphore.c (Original: semaphore.c from pthreads library)
*
* Purpose:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
* Semaphores aren't actually part of the PThreads standard.
* They are defined by the POSIX Standard:
*
* POSIX 1003.1b-1993 (POSIX.1b)
* POSIX 1003.1b-1993 (POSIX.1b)
*
* -------------------------------------------------------------
*
......@@ -52,33 +52,27 @@
DOCPUBLIC
This function initializes an unnamed semaphore. the
initial value of the semaphore is 'value'
PARAMETERS
sem
pointer to an instance of sem_t
pshared
if zero, this semaphore may only be shared between
threads in the same process.
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'.
sem Pointer to an instance of sem_t
pshared If zero, this semaphore may only be shared between
threads in the same process.
If nonzero, the semaphore can be shared between
processes
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
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
*/
int
......@@ -111,10 +105,10 @@ sem_init (sem_t *sem, int pshared, unsigned int value)
InitializeCriticalSection(&sem->sem_lock_cs);
}
#else /* HAVE_CREATESEMAPHORE */
*sem = CreateSemaphore (NULL, /* Always NULL */
value, /* Initial value */
*sem = CreateSemaphore (NULL, /* Always NULL */
value, /* Initial value */
0x7FFFFFFFL, /* Maximum value */
NULL); /* Name */
NULL); /* Name */
if (!*sem)
result = ENOSPC;
#endif /* HAVE_CREATESEMAPHORE */
......@@ -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'
EINVAL 'sem' is not a valid semaphore,
ENOSYS Semaphores are not supported,
EBUSY Threads (or processes) are currently blocked on 'sem'
*/
int
......@@ -154,7 +143,7 @@ sem_destroy (sem_t * sem)
{
int result = 0;
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if (sem == NULL || *sem == NULL)
{
errno=EINVAL;
......@@ -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,
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.
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.
*/
int
......@@ -214,7 +200,7 @@ sem_trywait(sem_t * sem)
int errno = EINVAL;
return -1;
#else /* HAVE_CREATESEMAPHORE */
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if (sem == NULL || *sem == NULL)
{
errno=EINVAL;
......@@ -234,7 +220,7 @@ sem_trywait(sem_t * sem)
#ifndef HAVE_CREATESEMAPHORE
static void
static void
ptw32_decrease_semaphore(sem_t * sem)
{
EnterCriticalSection(&sem->sem_lock_cs);
......@@ -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
......@@ -297,7 +279,7 @@ sem_wait(sem_t *sem)
{
int result;
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if (sem == NULL || *sem == NULL)
{
errno=EINVAL;
......@@ -331,30 +313,27 @@ 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,
EINVAL 'sem' is not a valid semaphore,
ENOSYS Semaphores are not supported,
*/
int
sem_post (sem_t * sem)
{
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if (sem == NULL || *sem == NULL)
{
errno=EINVAL;
......@@ -378,32 +357,27 @@ 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
sem_post_multiple (sem_t * sem, int count )
{
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
if (sem == NULL || *sem == NULL || count <= 0)
{
errno=EINVAL;
......
......@@ -15,72 +15,80 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <mysql_priv.h>
#include <m_ctype.h>
#ifdef HAVE_OPENSSL
/*
Function which loads DES keys from plaintext file
into memory on MySQL server startup and on command
FLUSH DES_KEYS. Blame tonu@spam.ee on bugs ;)
Function which loads DES keys from plaintext file into memory on MySQL
server startup and on command FLUSH DES_KEYS. Blame tonu@spam.ee on bugs ;)
*/
void
struct st_des_keyschedule des_keyschedule[10];
uint default_des_key;
void
load_des_key_file(const char *file_name)
{
FILE *file;
int ret=0;
char offset;
char buf[1024];
File file;
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
st_des_keyblock keyblock;
char offset;
IO_CACHE io;
DBUG_ENTER("load_des_key_file");
VOID(pthread_mutex_lock(&LOCK_open));
DBUG_PRINT("enter",("name: %s",file_name));
if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME))))
{
goto error_noclose;
}
while(!feof(file))
VOID(pthread_mutex_lock(&LOCK_open));
if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME)))
goto error;
bzero((char*) des_keyschedule,sizeof(struct st_des_keyschedule) * 10);
default_des_key=15; // Impossible key
for (;;)
{
if ((my_fread(file, &offset, 1, MY_WME)) != 1)
goto error_close;
fgets(buf,sizeof(buf),file);
int len=strlen(buf);
if (len-->=1)
buf[len]='\0';
/* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
offset-='0';
if (offset >= 0 && offset <=9)
char *start, *end;
char buf[1024];
st_des_keyblock keyblock;
uint length;
if (!(length=my_b_gets(&io,buf,sizeof(buf)-1)))
break; // End of file
offset=buf[0];
if (offset >= '0' && offset <= '9') // If ok key
{
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *)buf,
strlen(buf),1,(uchar *)&keyblock,ivec);
des_set_key_unchecked(&keyblock.key1,des_keyschedule[(int)offset].ks1);
des_set_key_unchecked(&keyblock.key2,des_keyschedule[(int)offset].ks2);
des_set_key_unchecked(&keyblock.key3,des_keyschedule[(int)offset].ks3);
}
offset=(char) (offset - '0');
// Remove newline and possible other control characters
for (start=buf+1 ; isspace(*start) ; start++) ;
end=buf+length;
for (end=strend(buf) ; end > start && iscntrl(end[-1]) ; end--) ;
if (start != end)
{
// We make good 24-byte (168 bit) key from given plaintext key with MD5
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *) start, (int) (end-start),1,
(uchar *) &keyblock,
ivec);
des_set_key_unchecked(&keyblock.key1,des_keyschedule[(int)offset].ks1);
des_set_key_unchecked(&keyblock.key2,des_keyschedule[(int)offset].ks2);
des_set_key_unchecked(&keyblock.key3,des_keyschedule[(int)offset].ks3);
if (default_des_key == 15)
default_des_key= (uint) offset; // use first as def.
}
}
else
{
DBUG_PRINT("des",("wrong offset: %d",offset));
DBUG_PRINT("des",("wrong offset: %c",offset));
}
}
error_close:
(void) my_fclose(file,MYF(MY_WME));
error_noclose:
error:
if (file >= 0)
{
my_close(file,MYF(0));
end_io_cache(&io);
}
VOID(pthread_mutex_unlock(&LOCK_open));
/* if (ret)
do something; */
DBUG_VOID_RETURN;
}
/*
This function is used to load right key with DES_ENCRYPT(text,integer)
*/
st_des_keyschedule *
des_key(int key)
{
DBUG_ENTER("des_key");
DBUG_PRINT("exit",("return: %x",&des_keyschedule[key]));
DBUG_RETURN(&des_keyschedule[key]);
}
#endif /* HAVE_OPENSSL */
......@@ -75,7 +75,11 @@ String *Item_func_md5::val_str(String *str)
my_MD5Init (&context);
my_MD5Update (&context,(unsigned char *) sptr->ptr(), sptr->length());
my_MD5Final (digest, &context);
str->alloc(32); // Ensure that memory is free
if (str->alloc(32)) // Ensure that memory is free
{
null_value=1;
return 0;
}
sprintf((char *) str->ptr(),
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1], digest[2], digest[3],
......@@ -201,162 +205,150 @@ void Item_func_concat::fix_length_and_dec()
}
}
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
#define ascii_to_bin(c) ((c)<=57 ? (c)-46 : (c)<=90 ? (c)-53 : (c)-59)
/*
Function des_encrypt() by tonu@spam.ee
Works only if compiled with OpenSSL library support.
Output always starts with magic char "1" and all
encrypted output is encoded into ASCII-protected
container.
Original input is returned as output if input string
begins with magic "1". Credit card number always begin
with 4,5 or 6.
Function des_encrypt() by tonu@spam.ee & monty
Works only if compiled with OpenSSL library support.
This returns a binary string where first character is
CHAR(128 | tail-length << 4 | key-number).
If one uses a string key key_number is 0.
Encryption result is longer than original by formula:
new_length=(8-(original_length % 8))*2+1
new_length= (8-(original_length % 8))+1
*/
String *Item_func_des_encrypt::val_str(String *str)
{
String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
struct st_des_keyschedule *keyschedule_ptr=&keyschedule;
uint key_number=15;
String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return &empty_string;
if(res->c_ptr()[0]!='1') // Skip encryption if already encrypted
{
if (args[1]->val_int())
{
keyschedule_ptr=des_key(args[1]->val_int());
}
else
{
String *keystr=args[1]->val_str(&tmp_value);
/* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *)keystr->c_ptr(),
(int)keystr->length(),1,(uchar *)&keyblock,ivec);
des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
}
/*
The problem: DES algorithm requires original data to be in 8-bytes
chunks. Missing bytes get filled with zeros and result of encryption
can be up to 7 bytes longer than original string. When decrypted,
we do not know the size of original string :(
We add one byte with value 0x0..0x7 to original plaintext marking
change of string length
*/
uchar tail= 7-( res->length() %8); // 0..7 marking real offsets 1..8
for(int i=0 ; i < tail ; ++i) res->append('*');
res->append(tail); // Write tail length 0..7 to last pos
str->length(res->length());
for (uint j=0; j < res->length() ; ++j)
{
DBUG_PRINT("info",("## res->c_ptr()[%d]='%c'",j,res->c_ptr()[j]));
}
des_ede3_cbc_encrypt( // Real encryption
(const uchar*)(res->c_ptr()),
(uchar*)(str->c_ptr()),
res->length(),
keyschedule_ptr->ks1, keyschedule_ptr->ks2, keyschedule_ptr->ks3,
&ivec, TRUE);
for (uint j=0; j < res->length() ; ++j)
{
DBUG_PRINT("info",("## str->c_ptr()[%d]='%c'",j,str->c_ptr()[j]));
}
res->set((const char*)"1",(uint)1);
for(uint i=0 ; i < str->length() ; ++i)
{
res->append(bin_to_ascii((uchar)str->c_ptr()[i] & 0x3f));
res->append(bin_to_ascii(((uchar)str->c_ptr()[i] >> 5 ) & 0x3f));
}
if (arg_count == 1)
keyschedule_ptr=des_keyschedule[key_number=default_des_key];
else if (args[1]->result_type == INT_RESULT)
{
key_number= (uint) args[1]->val_int();
if (key_number > 9)
goto error;
keyschedule_ptr= des_keyschedule[key_number];
}
return res;
#else
else
{
const char *append_str="********";
uint tail,res_length;
String *keystr=args[1]->val_str(&tmp_value);
if (!keystr)
goto error;
/* We make good 24-byte (168 bit) key from given plaintext key with MD5 */
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar*) keystr->ptr(), (int) keystr->length(),
1, (uchar*) &keyblock,ivec);
des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
}
/*
The problem: DES algorithm requires original data to be in 8-bytes
chunks. Missing bytes get filled with zeros and result of encryption
can be up to 7 bytes longer than original string. When decrypted,
we do not know the size of original string :(
We add one byte with value 0x1..0x8 as the second byte to original
plaintext marking change of string length.
*/
tail= (7-(res->length()+7) % 8); // 0..7 marking extra length
res_length=res->length()+tail+1;
if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length))
goto err;
tmp_value.length(res_length);
tmp_value.[0]=(char) (128 | tail << 4 | key_number);
// Real encryption
des_ede3_cbc_encrypt((const uchar*) (res->ptr()),
(uchar*) (tmp_value->ptr()+1),
res->length(),
keyschedule_ptr->ks1,
keyschedule_ptr->ks2,
keyschedule_ptr->ks3,
&ivec, TRUE);
return &tmp_value;
error:
#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
#endif /* HAVE_OPENSSL */
}
String *Item_func_des_decrypt::val_str(String *str)
{
String *res =args[0]->val_str(str);
#ifdef HAVE_OPENSSL
des_key_schedule ks1, ks2, ks3;
des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
struct st_des_keyblock keyblock;
struct st_des_keyschedule keyschedule;
struct st_des_keyschedule *keyschedule_ptr=&keyschedule;
String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return &empty_string;
if (res->length(0) < 9 || (res->length()) % 8 != 1 || !(res->[0] & 128))
return res; // Skip decryption if not encrypted
if(res->c_ptr()[0]=='1') // Skip decryption if not encrypted
if (arg_count == 1) // If automatic uncompression
{
str->set((const char*)0,(uint)0);
for(uint i=1 ; i < res->length() ; i+=2)
{
str->append((ascii_to_bin(res->c_ptr()[i]))
| (ascii_to_bin(res->c_ptr()[i+1]) << 5 ));
}
if (args[1]->val_int())
{
keyschedule_ptr=des_key(args[1]->val_int());
}
else
{
/*
We make good 24-byte (168 bit) key
from given plaintext key with MD5
*/
String *keystr=args[1]->val_str(&tmp_value);
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar *)keystr->c_ptr(),
(int)keystr->length(),1,(uchar *)&keyblock,ivec);
/*
Here we set all 64-bit keys (56 effective) one by one
*/
des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
}
res->length(str->length());
des_ede3_cbc_encrypt( // Real decryption
(const uchar*)(str->c_ptr()),
(uchar*)(res->c_ptr()),
str->length(),
keyschedule_ptr->ks1, keyschedule_ptr->ks2, keyschedule_ptr->ks3,
&ivec, FALSE);
uchar tail=(res->c_ptr()[res->length()-1]) & 0x7;
if ((res->length() > ((uint)1+tail))) // We should avoid negative length
res->length(res->length()-1-tail); // (can happen with wrong key)
uint key_number=res->[0] & 15;
// Check if automatic key and that we have privilege to uncompress using it
if (!(current_thd->master_access & PROCESS_ACL) || key_number > 9)
goto error;
keyschedule_ptr=des_keyschedule[key_number-1];
}
return res;
#else
else
{
// We make good 24-byte (168 bit) key from given plaintext key with MD5
String *keystr=args[1]->val_str(&tmp_value);
if (!key_str)
goto error;
EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL,
(uchar*) keystr->ptr(),(int) keystr->length(),
1,(uchar*) &keyblock,ivec);
// Here we set all 64-bit keys (56 effective) one by one
des_set_key_unchecked(&keyblock.key1,keyschedule_ptr->ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule_ptr->ks2);
des_set_key_unchecked(&keyblock.key3,keyschedule_ptr->ks3);
}
if (tmp_value.alloc(res->length()-1))
goto err;
/* Restore old length of key */
tmp_value.length(res->length()-1-(((uchar) res->[0] >> 4) & 7));
des_ede3_cbc_encrypt((const uchar*) res->ptr()+1,
(uchar*) (tmp_value->ptr()),
res->length()-1,
keyschedule_ptr->ks1,
keyschedule_ptr->ks2,
keyschedule_ptr->ks3,
&ivec, FALSE);
return &tmp_value;
error:
#endif /* HAVE_OPENSSL */
null_value=1;
return 0;
#endif /* HAVE_OPENSSL */
}
/*
** concat with separator. First arg is the separator
** concat_ws takes at least two arguments.
concat with separator. First arg is the separator
concat_ws takes at least two arguments.
*/
String *Item_func_concat_ws::val_str(String *str)
......@@ -1146,6 +1138,7 @@ String *Item_func_password::val_str(String *str)
return str;
}
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
String *Item_func_encrypt::val_str(String *str)
{
......
......@@ -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)
{
......
This diff is collapsed.
......@@ -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++;
deleted++;
}
end_read_record(&info);
if (error == -1)
if (error == -1) // End of file
error = 0;
}
return error;
......@@ -464,7 +469,6 @@ bool multi_delete::send_eof()
/* reset used flags */
delete_tables->table->no_keyread=0;
if (error == -1) error = 0;
thd->proc_info="end";
if (error)
{
......@@ -477,22 +481,17 @@ bool multi_delete::send_eof()
was a non-transaction-safe table involved, since
modifications in it cannot be rolled back. */
if (deleted &&
(!error || some_table_is_not_transaction_safe(delete_tables)))
if (deleted || some_table_is_not_transaction_safe(delete_tables))
{
mysql_update_log.write(thd,thd->query,thd->query_length);
Query_log_event qinfo(thd, thd->query);
/* mysql_bin_log is not open if binlogging or replication
is not used */
if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
!some_table_is_not_transaction_safe(delete_tables))
error=1; /* Log write failed: roll back
the SQL statement */
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query);
if (mysql_bin_log.write(&qinfo) &&
!some_table_is_not_transaction_safe(delete_tables))
error=1; // Log write failed: roll back the SQL statement
}
/* Commit or rollback the current SQL statement */
VOID(ha_autocommit_or_rollback(thd,error > 0));
}
......
......@@ -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_SYM select_part2 { Select->braces=false; } union
select_init { Lex->sql_command=SQLCOM_SELECT; }
select_init:
SELECT_SYM select_part2 { Select->braces=false; } union
|
'(' SELECT_SYM select_part2 ')' {Select->braces=true;} union_opt
'(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt
select_part2:
{
......@@ -1643,10 +1647,14 @@ simple_expr:
{ $$= new Item_func_decode($3,$5.str); }
| ENCODE_SYM '(' expr ',' TEXT_STRING ')'
{ $$= new Item_func_encode($3,$5.str); }
| DES_DECRYPT '(' expr ',' expr ')'
{ $$= new Item_func_des_decrypt($3,$5); }
| DES_ENCRYPT '(' expr ',' expr ')'
{ $$= new Item_func_des_encrypt($3,$5); }
| DES_DECRYPT '(' expr ')'
{ $$= new Item_func_des_decrypt($3); }
| DES_DECRYPT '(' expr ',' expr ')'
{ $$= new Item_func_des_decrypt($3,$5); }
| DES_ENCRYPT '(' expr ')'
{ $$= new Item_func_des_encrypt($3); }
| DES_ENCRYPT '(' expr ',' expr ')'
{ $$= new Item_func_des_encrypt($3,$5); }
| EXPORT_SET '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_export_set($3, $5, $7); }
| EXPORT_SET '(' expr ',' expr ',' expr ',' expr ')'
......@@ -3573,12 +3581,12 @@ union_list:
net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
YYABORT;
}
if (lex->select->linkage==NOT_A_SELECT)
if (lex->select->linkage == NOT_A_SELECT)
YYABORT;
mysql_new_select(lex);
lex->select->linkage=UNION_TYPE;
}
select
select_init
union_opt:
union {}
......
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