Merge bk-internal.mysql.com:/home/bk/mysql-5.1-new

into  mysql.com:/mnt/raid/MySQL/devel/5.1-rt-wl3158-merged
This commit is contained in:
anozdrin@mysql.com 2006-05-23 12:08:47 +04:00
commit f0a01456e5
74 changed files with 4737 additions and 2703 deletions

View file

@ -1770,3 +1770,4 @@ vio/viotest-sslconnect.cpp
vio/viotest.cpp
zlib/*.ds?
zlib/*.vcproj
libmysqld/event_scheduler.cc

View file

@ -7,7 +7,7 @@ AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line!
# remember to also change ndb version below and update version.c in ndb
AM_INIT_AUTOMAKE(mysql, 5.1.11-beta)
AM_INIT_AUTOMAKE(mysql, 5.1.12-beta)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10

View file

@ -65,7 +65,8 @@ THREAD_RETURN YASSL_API echoserver_test(void* args)
while (!shutdown) {
sockaddr_in client;
socklen_t client_len = sizeof(client);
int clientfd = accept(sockfd, (sockaddr*)&client, &client_len);
int clientfd = accept(sockfd, (sockaddr*)&client,
(ACCEPT_THIRD_T)&client_len);
if (clientfd == -1) err_sys("tcp accept failed");
SSL* ssl = SSL_new(ctx);

View file

@ -273,6 +273,7 @@ int SSL_pending(SSL*);
enum { /* ssl Constants */
SSL_WOULD_BLOCK = -8,
SSL_BAD_STAT = -7,
SSL_BAD_PATH = -6,
SSL_BAD_FILETYPE = -5,
@ -494,7 +495,7 @@ ASN1_TIME* X509_get_notAfter(X509* x);
typedef struct MD4_CTX {
void* ptr;
int buffer[32]; /* big enough to hold, check size in Init */
} MD4_CTX;
void MD4_Init(MD4_CTX*);

View file

@ -66,6 +66,7 @@ typedef unsigned char byte;
// Wraps Windows Sockets and BSD Sockets
class Socket {
socket_t socket_; // underlying socket descriptor
bool wouldBlock_; // for non-blocking data
public:
explicit Socket(socket_t s = INVALID_SOCKET);
~Socket();
@ -75,9 +76,10 @@ public:
socket_t get_fd() const;
uint send(const byte* buf, unsigned int len, int flags = 0) const;
uint receive(byte* buf, unsigned int len, int flags = 0) const;
uint receive(byte* buf, unsigned int len, int flags = 0);
bool wait() const;
bool wait();
bool WouldBlock() const;
void closeSocket();
void shutDown(int how = SD_SEND);

View file

@ -46,8 +46,10 @@ public:
// for compiler generated call, never used
static void operator delete(void*) { assert(0); }
private:
#if defined(__hpux)
// don't allow dynamic creation of exceptions
static void* operator new(size_t);
#endif
};

View file

@ -656,7 +656,7 @@ mySTL::auto_ptr<input_buffer>
DoProcessReply(SSL& ssl, mySTL::auto_ptr<input_buffer> buffered)
{
// wait for input if blocking
if (!ssl.getSocket().wait()) {
if (!ssl.useSocket().wait()) {
ssl.SetError(receive_error);
buffered.reset(0);
return buffered;
@ -673,7 +673,7 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr<input_buffer> buffered)
}
// add new data
uint read = ssl.getSocket().receive(buffer.get_buffer() + buffSz, ready);
uint read = ssl.useSocket().receive(buffer.get_buffer() + buffSz, ready);
buffer.add_size(read);
uint offset = 0;
const MessageFactory& mf = ssl.getFactory().getMessage();
@ -858,6 +858,9 @@ void sendFinished(SSL& ssl, ConnectionEnd side, BufferOutput buffer)
// send data
int sendData(SSL& ssl, const void* buffer, int sz)
{
if (ssl.GetError() == YasslError(SSL_ERROR_WANT_READ))
ssl.SetError(no_error);
ssl.verfiyHandShakeComplete();
if (ssl.GetError()) return 0;
int sent = 0;
@ -893,6 +896,9 @@ int sendAlert(SSL& ssl, const Alert& alert)
// process input data
int receiveData(SSL& ssl, Data& data)
{
if (ssl.GetError() == YasslError(SSL_ERROR_WANT_READ))
ssl.SetError(no_error);
ssl.verfiyHandShakeComplete();
if (ssl.GetError()) return 0;
@ -902,6 +908,11 @@ int receiveData(SSL& ssl, Data& data)
ssl.useLog().ShowData(data.get_length());
if (ssl.GetError()) return 0;
if (data.get_length() == 0 && ssl.getSocket().WouldBlock()) {
ssl.SetError(YasslError(SSL_ERROR_WANT_READ));
return SSL_WOULD_BLOCK;
}
return data.get_length();
}

View file

@ -58,7 +58,7 @@ namespace yaSSL {
Socket::Socket(socket_t s)
: socket_(s)
: socket_(s), wouldBlock_(false)
{}
@ -123,17 +123,21 @@ uint Socket::send(const byte* buf, unsigned int sz, int flags) const
}
uint Socket::receive(byte* buf, unsigned int sz, int flags) const
uint Socket::receive(byte* buf, unsigned int sz, int flags)
{
assert(socket_ != INVALID_SOCKET);
wouldBlock_ = false;
int recvd = ::recv(socket_, reinterpret_cast<char *>(buf), sz, flags);
// idea to seperate error from would block by arnetheduck@gmail.com
if (recvd == -1) {
if (get_lastError() == SOCKET_EWOULDBLOCK ||
get_lastError() == SOCKET_EAGAIN)
get_lastError() == SOCKET_EAGAIN) {
wouldBlock_ = true;
return 0;
}
}
else if (recvd == 0)
return static_cast<uint>(-1);
@ -142,7 +146,7 @@ uint Socket::receive(byte* buf, unsigned int sz, int flags) const
// wait if blocking for input, return false for error
bool Socket::wait() const
bool Socket::wait()
{
byte b;
return receive(&b, 1, MSG_PEEK) != static_cast<uint>(-1);
@ -166,6 +170,12 @@ int Socket::get_lastError()
}
bool Socket::WouldBlock() const
{
return wouldBlock_;
}
void Socket::set_lastError(int errorCode)
{
#ifdef _WIN32

View file

@ -37,6 +37,7 @@
#include "handshake.hpp"
#include "yassl_int.hpp"
#include "md5.hpp" // for TaoCrypt MD5 size assert
#include "md4.hpp" // for TaoCrypt MD4 size assert
#include <stdio.h>
#ifdef _WIN32
@ -1131,17 +1132,26 @@ void* X509_get_ext_d2i(X509* x, int nid, int* crit, int* idx)
void MD4_Init(MD4_CTX* md4)
{
assert(0); // not yet supported, build compat. only
// make sure we have a big enough buffer
typedef char ok[sizeof(md4->buffer) >= sizeof(TaoCrypt::MD4) ? 1 : -1];
(void) sizeof(ok);
// using TaoCrypt since no dynamic memory allocated
// and no destructor will be called
new (reinterpret_cast<yassl_pointer>(md4->buffer)) TaoCrypt::MD4();
}
void MD4_Update(MD4_CTX* md4, const void* data, unsigned long sz)
{
reinterpret_cast<TaoCrypt::MD4*>(md4->buffer)->Update(
static_cast<const byte*>(data), static_cast<unsigned int>(sz));
}
void MD4_Final(unsigned char* hash, MD4_CTX* md4)
{
reinterpret_cast<TaoCrypt::MD4*>(md4->buffer)->Final(hash);
}

View file

@ -31,6 +31,7 @@
#include "hmac.hpp"
#include "md5.hpp"
#include "sha.hpp"
#include "ripemd.hpp"
#include "openssl/ssl.h"
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION

View file

@ -26,13 +26,17 @@
#include "runtime.hpp"
#include "timer.hpp"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/time.h>
#endif
namespace yaSSL {
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
timer_d timer()
{
static bool init(false);
@ -57,8 +61,6 @@ namespace yaSSL {
#else // _WIN32
#include <sys/time.h>
timer_d timer()
{
struct timeval tv;

View file

@ -26,6 +26,7 @@
#include "runtime.hpp"
#include "yassl_error.hpp"
#include "error.hpp" // TaoCrypt error numbers
#include "openssl/ssl.h" // SSL_ERROR_WANT_READ
namespace yaSSL {
@ -117,6 +118,11 @@ void SetErrorString(YasslError error, char* buffer)
strncpy(buffer, "unable to proccess cerificate", max);
break;
// openssl errors
case SSL_ERROR_WANT_READ :
strncpy(buffer, "the read operation would block", max);
break;
// TaoCrypt errors
case NO_ERROR :
strncpy(buffer, "not in error state", max);

View file

@ -1415,15 +1415,6 @@ BulkCipher* CryptProvider::NewDesEde()
}
extern "C" void yaSSL_CleanUp()
{
TaoCrypt::CleanUp();
ysDelete(cryptProviderInstance);
ysDelete(sslFactoryInstance);
ysDelete(sessionsInstance);
}
typedef Mutex::Lock Lock;
@ -2109,9 +2100,18 @@ ASN1_STRING* StringHolder::GetString()
}
} // namespace
extern "C" void yaSSL_CleanUp()
{
TaoCrypt::CleanUp();
ysDelete(yaSSL::cryptProviderInstance);
ysDelete(yaSSL::sslFactoryInstance);
ysDelete(yaSSL::sessionsInstance);
}
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace mySTL {
template yaSSL::yassl_int_cpp_local1::SumData for_each<mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData>(mySTL::list<yaSSL::input_buffer*>::iterator, mySTL::list<yaSSL::input_buffer*>::iterator, yaSSL::yassl_int_cpp_local1::SumData);

View file

@ -2,7 +2,7 @@ INCLUDE_DIRECTORIES(../mySTL include)
ADD_LIBRARY(taocrypt src/aes.cpp src/aestables.cpp src/algebra.cpp src/arc4.cpp src/asn.cpp src/coding.cpp
src/des.cpp src/dh.cpp src/dsa.cpp src/file.cpp src/hash.cpp src/integer.cpp src/md2.cpp
src/md5.cpp src/misc.cpp src/random.cpp src/ripemd.cpp src/rsa.cpp src/sha.cpp
src/md4.cpp src/md5.cpp src/misc.cpp src/random.cpp src/ripemd.cpp src/rsa.cpp src/sha.cpp
include/aes.hpp include/algebra.hpp include/arc4.hpp include/asn.hpp include/block.hpp
include/coding.hpp include/des.hpp include/dh.hpp include/dsa.hpp include/dsa.hpp
include/error.hpp include/file.hpp include/hash.hpp include/hmac.hpp include/integer.hpp

View file

@ -96,7 +96,7 @@ public:
pointer allocate(size_type n, const void* = 0)
{
CheckSize(n);
this->CheckSize(n);
if (n == 0)
return 0;
return NEW_TC T[n];

View file

@ -0,0 +1,65 @@
/* md4.hpp
*
* Copyright (C) 2003 Sawtooth Consulting Ltd.
*
* This file is part of yaSSL.
*
* yaSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* yaSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* md4.hpp provides MD4 digest support
* WANRING: MD4 is considered insecure, only use if you have to, e.g., yaSSL
* libcurl supports needs this for NTLM authentication
*/
#ifndef TAO_CRYPT_MD4_HPP
#define TAO_CRYPT_MD4_HPP
#include "hash.hpp"
namespace TaoCrypt {
// MD4 digest
class MD4 : public HASHwithTransform {
public:
enum { BLOCK_SIZE = 64, DIGEST_SIZE = 16, PAD_SIZE = 56,
TAO_BYTE_ORDER = LittleEndianOrder }; // in Bytes
MD4() : HASHwithTransform(DIGEST_SIZE / sizeof(word32), BLOCK_SIZE)
{ Init(); }
ByteOrder getByteOrder() const { return ByteOrder(TAO_BYTE_ORDER); }
word32 getBlockSize() const { return BLOCK_SIZE; }
word32 getDigestSize() const { return DIGEST_SIZE; }
word32 getPadSize() const { return PAD_SIZE; }
MD4(const MD4&);
MD4& operator= (const MD4&);
void Init();
void Swap(MD4&);
private:
void Transform();
};
inline void swap(MD4& a, MD4& b)
{
a.Swap(b);
}
} // namespace
#endif // TAO_CRYPT_MD4_HPP

View file

@ -28,10 +28,6 @@
#ifndef yaSSL_NEW_HPP
#define yaSSL_NEW_HPP
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef __sun

View file

@ -4,7 +4,7 @@ noinst_LTLIBRARIES = libtaocrypt.la
libtaocrypt_la_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp \
asn.cpp bftables.cpp blowfish.cpp coding.cpp des.cpp dh.cpp \
dsa.cpp file.cpp hash.cpp integer.cpp md2.cpp md5.cpp misc.cpp \
dsa.cpp file.cpp hash.cpp integer.cpp md2.cpp md4.cpp md5.cpp misc.cpp \
random.cpp ripemd.cpp rsa.cpp sha.cpp template_instnt.cpp \
tftables.cpp twofish.cpp

View file

@ -0,0 +1,154 @@
/* md4.cpp
*
* Copyright (C) 2003 Sawtooth Consulting Ltd.
*
* This file is part of yaSSL.
*
* yaSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* yaSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* based on Wei Dai's md4.cpp from CryptoPP */
#include "runtime.hpp"
#include "md4.hpp"
#include "algorithm.hpp" // mySTL::swap
namespace TaoCrypt {
void MD4::Init()
{
digest_[0] = 0x67452301L;
digest_[1] = 0xefcdab89L;
digest_[2] = 0x98badcfeL;
digest_[3] = 0x10325476L;
buffLen_ = 0;
loLen_ = 0;
hiLen_ = 0;
}
MD4::MD4(const MD4& that) : HASHwithTransform(DIGEST_SIZE / sizeof(word32),
BLOCK_SIZE)
{
buffLen_ = that.buffLen_;
loLen_ = that.loLen_;
hiLen_ = that.hiLen_;
memcpy(digest_, that.digest_, DIGEST_SIZE);
memcpy(buffer_, that.buffer_, BLOCK_SIZE);
}
MD4& MD4::operator= (const MD4& that)
{
MD4 tmp(that);
Swap(tmp);
return *this;
}
void MD4::Swap(MD4& other)
{
mySTL::swap(loLen_, other.loLen_);
mySTL::swap(hiLen_, other.hiLen_);
mySTL::swap(buffLen_, other.buffLen_);
memcpy(digest_, other.digest_, DIGEST_SIZE);
memcpy(buffer_, other.buffer_, BLOCK_SIZE);
}
void MD4::Transform()
{
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
word32 A, B, C, D;
A = digest_[0];
B = digest_[1];
C = digest_[2];
D = digest_[3];
#define function(a,b,c,d,k,s) a=rotlFixed(a+F(b,c,d)+buffer_[k],s);
function(A,B,C,D, 0, 3);
function(D,A,B,C, 1, 7);
function(C,D,A,B, 2,11);
function(B,C,D,A, 3,19);
function(A,B,C,D, 4, 3);
function(D,A,B,C, 5, 7);
function(C,D,A,B, 6,11);
function(B,C,D,A, 7,19);
function(A,B,C,D, 8, 3);
function(D,A,B,C, 9, 7);
function(C,D,A,B,10,11);
function(B,C,D,A,11,19);
function(A,B,C,D,12, 3);
function(D,A,B,C,13, 7);
function(C,D,A,B,14,11);
function(B,C,D,A,15,19);
#undef function
#define function(a,b,c,d,k,s) a=rotlFixed(a+G(b,c,d)+buffer_[k]+0x5a827999,s);
function(A,B,C,D, 0, 3);
function(D,A,B,C, 4, 5);
function(C,D,A,B, 8, 9);
function(B,C,D,A,12,13);
function(A,B,C,D, 1, 3);
function(D,A,B,C, 5, 5);
function(C,D,A,B, 9, 9);
function(B,C,D,A,13,13);
function(A,B,C,D, 2, 3);
function(D,A,B,C, 6, 5);
function(C,D,A,B,10, 9);
function(B,C,D,A,14,13);
function(A,B,C,D, 3, 3);
function(D,A,B,C, 7, 5);
function(C,D,A,B,11, 9);
function(B,C,D,A,15,13);
#undef function
#define function(a,b,c,d,k,s) a=rotlFixed(a+H(b,c,d)+buffer_[k]+0x6ed9eba1,s);
function(A,B,C,D, 0, 3);
function(D,A,B,C, 8, 9);
function(C,D,A,B, 4,11);
function(B,C,D,A,12,15);
function(A,B,C,D, 2, 3);
function(D,A,B,C,10, 9);
function(C,D,A,B, 6,11);
function(B,C,D,A,14,15);
function(A,B,C,D, 1, 3);
function(D,A,B,C, 9, 9);
function(C,D,A,B, 5,11);
function(B,C,D,A,13,15);
function(A,B,C,D, 3, 3);
function(D,A,B,C,11, 9);
function(C,D,A,B, 7,11);
function(B,C,D,A,15,15);
digest_[0] += A;
digest_[1] += B;
digest_[2] += C;
digest_[3] += D;
}
} // namespace

View file

@ -30,11 +30,11 @@
#include "sha.hpp"
#include "md5.hpp"
#include "hmac.hpp"
#include "ripemd.hpp"
#include "pwdbased.hpp"
#include "algebra.hpp"
#include "vector.hpp"
#include "hash.hpp"
#include "ripemd.hpp"
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
namespace TaoCrypt {

View file

@ -146,6 +146,10 @@ SOURCE=.\src\md2.cpp
# End Source File
# Begin Source File
SOURCE=.\src\md4.cpp
# End Source File
# Begin Source File
SOURCE=.\src\md5.cpp
# End Source File
# Begin Source File
@ -246,6 +250,10 @@ SOURCE=.\include\md2.hpp
# End Source File
# Begin Source File
SOURCE=.\include\md4.hpp
# End Source File
# Begin Source File
SOURCE=.\include\md5.hpp
# End Source File
# Begin Source File

View file

@ -8,6 +8,7 @@
#include "sha.hpp"
#include "md5.hpp"
#include "md2.hpp"
#include "md4.hpp"
#include "ripemd.hpp"
#include "hmac.hpp"
#include "arc4.hpp"
@ -30,6 +31,7 @@ using TaoCrypt::word32;
using TaoCrypt::SHA;
using TaoCrypt::MD5;
using TaoCrypt::MD2;
using TaoCrypt::MD4;
using TaoCrypt::RIPEMD160;
using TaoCrypt::HMAC;
using TaoCrypt::ARC4;
@ -89,6 +91,7 @@ void file_test(int, char**);
int sha_test();
int md5_test();
int md2_test();
int md4_test();
int ripemd_test();
int hmac_test();
int arc4_test();
@ -165,6 +168,11 @@ void taocrypt_test(void* args)
else
printf( "MD2 test passed!\n");
if ( (ret = md4_test()) )
err_sys("MD4 test failed!\n", ret);
else
printf( "MD4 test passed!\n");
if ( (ret = ripemd_test()) )
err_sys("RIPEMD test failed!\n", ret);
else
@ -348,6 +356,51 @@ int md5_test()
}
int md4_test()
{
MD4 md4;
byte hash[MD4::DIGEST_SIZE];
testVector test_md4[] =
{
testVector("",
"\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89"
"\xc0"),
testVector("a",
"\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb"
"\x24"),
testVector("abc",
"\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72"
"\x9d"),
testVector("message digest",
"\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01"
"\x4b"),
testVector("abcdefghijklmnopqrstuvwxyz",
"\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d"
"\xa9"),
testVector("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345"
"6789",
"\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0"
"\xe4"),
testVector("1234567890123456789012345678901234567890123456789012345678"
"9012345678901234567890",
"\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05"
"\x36")
};
int times( sizeof(test_md4) / sizeof(testVector) );
for (int i = 0; i < times; ++i) {
md4.Update(test_md4[i].input_, test_md4[i].inLen_);
md4.Final(hash);
if (memcmp(hash, test_md4[i].output_, MD4::DIGEST_SIZE) != 0)
return -5 - i;
}
return 0;
}
int md2_test()
{
MD2 md5;

View file

@ -33,10 +33,16 @@
// HPUX doesn't use socklent_t for third parameter to accept
#if !defined(__hpux__)
#if !defined(__hpux)
typedef socklen_t* ACCEPT_THIRD_T;
#else
typedef int* ACCEPT_THIRD_T;
// HPUX does not define _POSIX_THREADS as it's not _fully_ implemented
#ifndef _POSIX_THREADS
#define _POSIX_THREADS
#endif
#endif

View file

@ -68,7 +68,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
event_executor.cc event.cc event_timed.cc \
event_scheduler.cc event.cc event_timed.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc

View file

@ -17,13 +17,13 @@ db_x
SHOW TABLES FROM db_x;
Tables_in_db_x
x_table
SET GLOBAL event_scheduler=0;
SET GLOBAL event_scheduler=2;
DROP EVENT e_x1;
DROP EVENT e_x2;
DROP DATABASE db_x;
DROP USER pauline@localhost;
USE events_test;
SET GLOBAL event_scheduler=0;
SET GLOBAL event_scheduler=2;
drop event if exists event1;
Warnings:
Note 1305 Event event1 does not exist
@ -100,7 +100,7 @@ a
800219
drop event non_qualif_ev;
drop table non_qualif;
set global event_scheduler = 0;
set global event_scheduler = 2;
create table t_event3 (a int, b float);
drop event if exists event3;
Warnings:
@ -324,18 +324,18 @@ events_test one_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
"This should show us only 3 events:";
SHOW FULL EVENTS;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test one_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
"This should show us only 2 events:";
SHOW FULL EVENTS LIKE 't%event';
SHOW EVENTS LIKE 't%event';
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
"This should show us no events:";
SHOW FULL EVENTS FROM test LIKE '%';
SHOW EVENTS FROM test LIKE '%';
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
DROP DATABASE events_test2;
"should see 1 event:";
@ -343,11 +343,8 @@ SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
"we should see 4 events now:";
SHOW FULL EVENTS;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test one_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED
events_test one_event root@localhost RECURRING NULL 10 SECOND # # ENABLED
SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT
@ -373,12 +370,12 @@ ERROR HY000: Incorrect AT value: 'definitely not a datetime'
set names utf8;
create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
drop event задачка;
set event_scheduler=0;
set event_scheduler=2;
ERROR HY000: Variable 'event_scheduler' is a GLOBAL variable and should be set with SET GLOBAL
set global event_scheduler=2;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '2'
set global event_scheduler=3;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '3'
"DISABLE the scheduler. Testing that it does not work when the variable is 0"
set global event_scheduler=0;
set global event_scheduler=2;
select definer, name, db from mysql.event;
definer name db
select get_lock("test_lock1", 20);
@ -389,9 +386,10 @@ create event закачка on schedule every 10 hour do select get_lock("test_l
select definer, name, db from mysql.event;
definer name db
root@localhost закачка events_test
"Should be 0 processes"
"Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Suspended NULL
select release_lock("test_lock1");
release_lock("test_lock1")
1
@ -409,11 +407,12 @@ get_lock("test_lock2", 20)
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
"Let some time pass to the event starts"
"Should have only 2 processes: the scheduler and the locked event"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2", 20)
"Release the mutex, the event worker should finish."
"Release the mutex, the event worker should finish."
select release_lock("test_lock2");
release_lock("test_lock2")
1
@ -423,21 +422,17 @@ select get_lock("test_lock2_1", 20);
get_lock("test_lock2_1", 20)
1
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
"Should see 1 process, locked on get_lock("
"Shutting down the scheduler, it should wait for the running event"
set global event_scheduler=0;
"Should have only 2 processes: the scheduler and the locked event"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
"Should have only 3 processes: the scheduler, our conn and the locked event"
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
"Release the lock so the child process should finish. Hence the scheduler also"
select release_lock("test_lock2_1");
release_lock("test_lock2_1")
1
"Should see 0 processes now:"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
set global event_scheduler=2;
"Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Suspended NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
drop event закачка21;
create table t_16 (s1 int);
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
@ -457,6 +452,9 @@ select 2;
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
event_schema event_name definer event_body
events_test white_space root@localhost select 2
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
event_schema event_name definer event_body
events_test white_space root@localhost select 2
drop event white_space;
create event white_space on schedule every 10 hour disable do select 3;
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';

View file

@ -35,7 +35,7 @@ create event e_55 on schedule every 10 hour starts 99990101000000 do drop table
ERROR HY000: Incorrect STARTS value: '99990101000000'
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
ERROR HY000: ENDS is either invalid or before STARTS
set global event_scheduler=0;
set global event_scheduler=2;
"Wait a bit to settle down"
delete from mysql.event;
set global event_scheduler= 1;
@ -57,7 +57,7 @@ root localhost events_test Connect User lock select get_lock('test_bug16407', 60
select release_lock('test_bug16407');
release_lock('test_bug16407')
1
set global event_scheduler= 0;
set global event_scheduler= 2;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
event_schema event_name sql_mode
events_test e_16407 REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
@ -115,7 +115,7 @@ release_lock('ee_16407_2')
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
set global event_scheduler= 0;
set global event_scheduler= 2;
select * from events_smode_test order by ev_name, a;
ev_name a
ee_16407_3 1980-02-19
@ -175,7 +175,7 @@ drop event ee_16407_5;
drop event ee_16407_6;
drop procedure ee_16407_5_pendant;
drop procedure ee_16407_6_pendant;
set global event_scheduler= 0;
set global event_scheduler= 2;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
drop database events_test;

View file

@ -8,7 +8,7 @@ BEGIN
SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%';
END|
"Check General Query Log"
SET GLOBAL event_scheduler=0;
SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
TRUNCATE mysql.general_log;
"1 row, the current statement!"
@ -22,7 +22,7 @@ user_host argument
root[root] @ localhost [localhost] SELect 'alabala', sleep(3) from dual
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=0;
SET GLOBAL event_scheduler=2;
"Check slow query log"
"Save the values"
SET @old_global_long_query_time:=(select get_value());
@ -36,14 +36,14 @@ SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
"Set new values"
SET GLOBAL long_query_time=4;
SET SESSION long_query_time=2;
SET SESSION long_query_time=1;
"Check that logging is working"
SELECT SLEEP(3);
SLEEP(3)
SELECT SLEEP(2);
SLEEP(2)
0
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
root[root] @ localhost [] SLEEPVAL events_test SELECT SLEEP(3)
root[root] @ localhost [] SLEEPVAL events_test SELECT SLEEP(2)
TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
"This won't go to the slow log"
@ -54,7 +54,7 @@ SET GLOBAL event_scheduler=1;
"Sleep some more time than the actual event run will take"
SHOW VARIABLES LIKE 'event_scheduler';
Variable_name Value
event_scheduler ON
event_scheduler 1
"Check our table. Should see 1 row"
SELECT * FROM slow_event_test;
slo_val val
@ -64,18 +64,19 @@ SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
"This should go to the slow log"
SET SESSION long_query_time=10;
SET GLOBAL long_query_time=1;
DROP EVENT long_event;
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5);
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
"Sleep some more time than the actual event run will take"
"Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
slo_val val
4 0
4 0
"Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10"
1 0
"Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
user_host query_time db sql_text
root[root] @ localhost [localhost] SLEEPVAL events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5)
root[root] @ localhost [localhost] SLEEPVAL events_test INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2)
DROP EVENT long_event2;
SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time;

View file

@ -10,50 +10,4 @@ CREATE EVENT micro_test ON SCHEDULE EVERY 100 MINUTE_MICROSECOND DO SELECT 1;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
CREATE EVENT micro_test ON SCHEDULE EVERY 100 SECOND_MICROSECOND DO SELECT 1;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
"Now create normal event and change it on SQL level"
CREATE EVENT micro_test2 ON SCHEDULE EVERY 1 MONTH DO SELECT 1;
UPDATE mysql.event SET interval_field='MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
SHOW CREATE EVENT micro_test2;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SET GLOBAL event_scheduler=0;
"Should not be running:"
SHOW VARIABLES like 'event_scheduler';
Variable_name Value
event_scheduler OFF
UPDATE mysql.event SET interval_field='DAY_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
SHOW CREATE EVENT micro_test2;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SET GLOBAL event_scheduler=0;
"Should not be running:"
SHOW VARIABLES like 'event_scheduler';
Variable_name Value
event_scheduler OFF
UPDATE mysql.event SET interval_field='SECOND_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
SHOW CREATE EVENT micro_test2;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SET GLOBAL event_scheduler=0;
"Should not be running:"
SHOW VARIABLES like 'event_scheduler';
Variable_name Value
event_scheduler OFF
UPDATE mysql.event SET interval_field='HOUR_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
SHOW CREATE EVENT micro_test2;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SET GLOBAL event_scheduler=0;
"Should not be running:"
SHOW VARIABLES like 'event_scheduler';
Variable_name Value
event_scheduler OFF
UPDATE mysql.event SET interval_field='MINUTE_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
SHOW CREATE EVENT micro_test2;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
SET GLOBAL event_scheduler=0;
"Should not be running:"
SHOW VARIABLES like 'event_scheduler';
Variable_name Value
event_scheduler OFF
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='event_scheduler';
COUNT(*)
0
DROP EVENT micro_test2;
drop database events_test;

View file

@ -14,7 +14,7 @@ ENDS NOW() + INTERVAL 6 SECOND
ON COMPLETION PRESERVE
DO INSERT INTO table_2 VALUES(1);
CREATE EVENT only_one_time ON SCHEDULE EVERY 2 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_3 VALUES(1);
CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_4 VALUES(1);
CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND ON COMPLETION PRESERVE DO INSERT INTO table_4 VALUES(1);
SELECT IF(SUM(a) >= 4, 'OK', 'ERROR') FROM table_1;
IF(SUM(a) >= 4, 'OK', 'ERROR')
OK
@ -38,9 +38,12 @@ DROP EVENT start_n_end;
"Already dropped because ended. Therefore an error."
DROP EVENT only_one_time;
ERROR HY000: Unknown event 'only_one_time'
"Already dropped because ended. Therefore an error."
"Should be preserved"
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
EVENT_NAME STATUS
E19170 ENABLED
two_time DISABLED
DROP EVENT two_time;
ERROR HY000: Unknown event 'two_time'
DROP TABLE table_1;
DROP TABLE table_2;
DROP TABLE table_3;

View file

@ -1,46 +1,61 @@
CREATE DATABASE IF NOT EXISTS events_test;
CREATE DATABASE events_test2;
USE events_test2;
CREATE DATABASE events_conn1_test2;
CREATE TABLE events_test.fill_it(test_name varchar(20), occur datetime);
CREATE USER event_user2@localhost;
CREATE DATABASE events_conn2_db;
GRANT ALL ON *.* TO event_user2@localhost;
CREATE USER event_user3@localhost;
CREATE DATABASE events_conn3_db;
GRANT ALL ON *.* TO event_user3@localhost;
"In the second connection we create some events which won't be dropped till the end"
"In the second connection we create some events which won't be dropped till the end"
USE events_conn1_test2;
CREATE EVENT ev_drop1 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop2 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop3 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
USE events_test;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS;
COUNT(*)
203
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
3
DROP DATABASE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
DROP DATABASE events_conn1_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
0
"Now testing stability - dropping db -> events while they are running"
CREATE DATABASE events_test2;
USE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
CREATE DATABASE events_conn1_test2;
USE events_conn1_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
1000
100
SET GLOBAL event_scheduler=1;
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
DROP DATABASE events_conn1_test2;
SET GLOBAL event_scheduler=2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
0
CREATE DATABASE events_test3;
USE events_test3;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
COUNT(*)
950
CREATE DATABASE events_test4;
USE events_test4;
CREATE DATABASE events_test2;
USE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
COUNT(*)
1050
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
DROP DATABASE events_test3;
CREATE DATABASE events_conn1_test3;
USE events_conn1_test3;
SET GLOBAL event_scheduler=1;
DROP DATABASE events_test4;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test3';
COUNT(*)
100
CREATE DATABASE events_conn1_test4;
USE events_conn1_test4;
CREATE DATABASE events_conn1_test2;
USE events_conn1_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
COUNT(*)
100
DROP DATABASE events_conn2_db;
DROP DATABASE events_conn3_db;
DROP DATABASE events_conn1_test2;
DROP DATABASE events_conn1_test3;
SET GLOBAL event_scheduler=2;
DROP DATABASE events_conn1_test4;
SET GLOBAL event_scheduler=1;
USE events_test;
DROP TABLE fill_it;
DROP DATABASE events_test;

View file

@ -821,144 +821,6 @@ SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
MAX(id)
NULL
DROP TABLE t1;
create table t1m (a int) engine=myisam;
create table t1i (a int) engine=innodb;
create table t2m (a int) engine=myisam;
create table t2i (a int) engine=innodb;
insert into t2m values (5);
insert into t2i values (5);
select min(a) from t1m;
min(a)
NULL
select min(7) from t1m;
min(7)
NULL
select min(7) from DUAL;
min(7)
NULL
explain select min(7) from t2m join t1m;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
select min(7) from t2m join t1m;
min(7)
NULL
select max(a) from t1m;
max(a)
NULL
select max(7) from t1m;
max(7)
NULL
select max(7) from DUAL;
max(7)
NULL
explain select max(7) from t2m join t1m;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
select max(7) from t2m join t1m;
max(7)
NULL
select 1, min(a) from t1m where a=99;
1 min(a)
1 NULL
select 1, min(a) from t1m where 1=99;
1 min(a)
1 NULL
select 1, min(1) from t1m where a=99;
1 min(1)
1 NULL
select 1, min(1) from t1m where 1=99;
1 min(1)
1 NULL
select 1, max(a) from t1m where a=99;
1 max(a)
1 NULL
select 1, max(a) from t1m where 1=99;
1 max(a)
1 NULL
select 1, max(1) from t1m where a=99;
1 max(1)
1 NULL
select 1, max(1) from t1m where 1=99;
1 max(1)
1 NULL
select min(a) from t1i;
min(a)
NULL
select min(7) from t1i;
min(7)
NULL
select min(7) from DUAL;
min(7)
NULL
explain select min(7) from t2i join t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select min(7) from t2i join t1i;
min(7)
NULL
select max(a) from t1i;
max(a)
NULL
select max(7) from t1i;
max(7)
NULL
select max(7) from DUAL;
max(7)
NULL
explain select max(7) from t2i join t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select max(7) from t2i join t1i;
max(7)
NULL
select 1, min(a) from t1i where a=99;
1 min(a)
1 NULL
select 1, min(a) from t1i where 1=99;
1 min(a)
1 NULL
select 1, min(1) from t1i where a=99;
1 min(1)
1 NULL
select 1, min(1) from t1i where 1=99;
1 min(1)
1 NULL
select 1, max(a) from t1i where a=99;
1 max(a)
1 NULL
select 1, max(a) from t1i where 1=99;
1 max(a)
1 NULL
select 1, max(1) from t1i where a=99;
1 max(1)
1 NULL
select 1, max(1) from t1i where 1=99;
1 max(1)
1 NULL
explain select count(*), min(7), max(7) from t1m, t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select count(*), min(7), max(7) from t1m, t1i;
count(*) min(7) max(7)
0 NULL NULL
explain select count(*), min(7), max(7) from t1m, t2i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
select count(*), min(7), max(7) from t1m, t2i;
count(*) min(7) max(7)
0 NULL NULL
explain select count(*), min(7), max(7) from t2m, t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2m system NULL NULL NULL NULL 1
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select count(*), min(7), max(7) from t2m, t1i;
count(*) min(7) max(7)
0 NULL NULL
drop table t1m, t1i, t2m, t2i;
create table t2 (ff double);
insert into t2 values (2.2);
select cast(sum(distinct ff) as decimal(5,2)) from t2;

View file

@ -54,3 +54,141 @@ c.c_id = 218 and expiredate is null;
slai_id
12
drop table t1, t2;
create table t1m (a int) engine=myisam;
create table t1i (a int) engine=innodb;
create table t2m (a int) engine=myisam;
create table t2i (a int) engine=innodb;
insert into t2m values (5);
insert into t2i values (5);
select min(a) from t1m;
min(a)
NULL
select min(7) from t1m;
min(7)
NULL
select min(7) from DUAL;
min(7)
NULL
explain select min(7) from t2m join t1m;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
select min(7) from t2m join t1m;
min(7)
NULL
select max(a) from t1m;
max(a)
NULL
select max(7) from t1m;
max(7)
NULL
select max(7) from DUAL;
max(7)
NULL
explain select max(7) from t2m join t1m;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
select max(7) from t2m join t1m;
max(7)
NULL
select 1, min(a) from t1m where a=99;
1 min(a)
1 NULL
select 1, min(a) from t1m where 1=99;
1 min(a)
1 NULL
select 1, min(1) from t1m where a=99;
1 min(1)
1 NULL
select 1, min(1) from t1m where 1=99;
1 min(1)
1 NULL
select 1, max(a) from t1m where a=99;
1 max(a)
1 NULL
select 1, max(a) from t1m where 1=99;
1 max(a)
1 NULL
select 1, max(1) from t1m where a=99;
1 max(1)
1 NULL
select 1, max(1) from t1m where 1=99;
1 max(1)
1 NULL
select min(a) from t1i;
min(a)
NULL
select min(7) from t1i;
min(7)
NULL
select min(7) from DUAL;
min(7)
NULL
explain select min(7) from t2i join t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select min(7) from t2i join t1i;
min(7)
NULL
select max(a) from t1i;
max(a)
NULL
select max(7) from t1i;
max(7)
NULL
select max(7) from DUAL;
max(7)
NULL
explain select max(7) from t2i join t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select max(7) from t2i join t1i;
max(7)
NULL
select 1, min(a) from t1i where a=99;
1 min(a)
1 NULL
select 1, min(a) from t1i where 1=99;
1 min(a)
1 NULL
select 1, min(1) from t1i where a=99;
1 min(1)
1 NULL
select 1, min(1) from t1i where 1=99;
1 min(1)
1 NULL
select 1, max(a) from t1i where a=99;
1 max(a)
1 NULL
select 1, max(a) from t1i where 1=99;
1 max(a)
1 NULL
select 1, max(1) from t1i where a=99;
1 max(1)
1 NULL
select 1, max(1) from t1i where 1=99;
1 max(1)
1 NULL
explain select count(*), min(7), max(7) from t1m, t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select count(*), min(7), max(7) from t1m, t1i;
count(*) min(7) max(7)
0 NULL NULL
explain select count(*), min(7), max(7) from t1m, t2i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found
1 SIMPLE t2i ALL NULL NULL NULL NULL 1
select count(*), min(7), max(7) from t1m, t2i;
count(*) min(7) max(7)
0 NULL NULL
explain select count(*), min(7), max(7) from t2m, t1i;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2m system NULL NULL NULL NULL 1
1 SIMPLE t1i ALL NULL NULL NULL NULL 1
select count(*), min(7), max(7) from t2m, t1i;
count(*) min(7) max(7)
0 NULL NULL
drop table t1m, t1i, t2m, t2i;

View file

@ -9,11 +9,10 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
events_bugs : BUG#17619 2006-02-21 andrey Race conditions
events_stress : BUG#17619 2006-02-21 andrey Race conditions
events : BUG#17619 2006-02-21 andrey Race conditions
events_scheduling : BUG#19170 2006-04-26 andrey Test case of 19170 fails on some platforms. Has to be checked.
events_logs_tests : BUG#17619 2006-05-16 andrey Test case problems
#events_bugs : BUG#17619 2006-02-21 andrey Race conditions
#events_stress : BUG#17619 2006-02-21 andrey Race conditions
#events : BUG#17619 2006-02-21 andrey Race conditions
#events_scheduling : BUG#19170 2006-04-26 andrey Test case of 19170 fails on some platforms. Has to be checked.
ndb_autodiscover : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
ndb_autodiscover2 : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog
#ndb_binlog_discover : BUG#19395 2006-04-28 tomas/knielsen mysqld does not always detect cluster shutdown

View file

@ -15,11 +15,10 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
connection default;
SHOW DATABASES LIKE 'db_x';
SET GLOBAL event_scheduler=1;
--sleep 2
--sleep 1.5
SHOW DATABASES LIKE 'db_x';
SHOW TABLES FROM db_x;
SET GLOBAL event_scheduler=0;
--sleep 1
SET GLOBAL event_scheduler=2;
connection priv_conn;
DROP EVENT e_x1;
DROP EVENT e_x2;
@ -31,8 +30,7 @@ USE events_test;
#
# END: BUG #17289 Events: missing privilege check for drop database
#
SET GLOBAL event_scheduler=0;
--sleep 1
SET GLOBAL event_scheduler=2;
drop event if exists event1;
create event event1 on schedule every 15 minute starts now() ends date_add(now(), interval 5 hour) DO begin end;
alter event event1 rename to event2 enable;
@ -92,11 +90,11 @@ drop event e_43;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
--sleep 2
--sleep 1
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
set global event_scheduler = 0;
set global event_scheduler = 2;
create table t_event3 (a int, b float);
drop event if exists event3;
@ -281,15 +279,15 @@ SHOW EVENTS;
--echo "This should show us only 3 events:";
--replace_column 8 # 9 #
SHOW FULL EVENTS;
SHOW EVENTS;
--echo "This should show us only 2 events:";
--replace_column 8 # 9 #
SHOW FULL EVENTS LIKE 't%event';
SHOW EVENTS LIKE 't%event';
--echo "This should show us no events:";
--replace_column 8 # 9 #
SHOW FULL EVENTS FROM test LIKE '%';
SHOW EVENTS FROM test LIKE '%';
#ok, we are back
connection default;
DROP DATABASE events_test2;
@ -300,7 +298,7 @@ SHOW EVENTS;
--echo "we should see 4 events now:";
--replace_column 8 # 9 #
SHOW FULL EVENTS;
SHOW EVENTS;
SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events;
connection ev_con1;
@ -330,21 +328,21 @@ create event задачка on schedule every 123 minute starts now() ends now()
drop event задачка;
# event_scheduler is a global var
--error 1229
set event_scheduler=0;
# event_scheduler could be only either 0 or 1
--error 1231
set global event_scheduler=2;
--error ER_GLOBAL_VARIABLE
set event_scheduler=2;
# event_scheduler could be only either 1 or 2
--error ER_WRONG_VALUE_FOR_VAR
set global event_scheduler=3;
--echo "DISABLE the scheduler. Testing that it does not work when the variable is 0"
set global event_scheduler=0;
set global event_scheduler=2;
select definer, name, db from mysql.event;
select get_lock("test_lock1", 20);
create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
--echo "Should return 1 row"
select definer, name, db from mysql.event;
--echo "Should be 0 processes"
--echo "Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock("test_lock1");
drop event закачка;
@ -362,7 +360,7 @@ create event закачка on schedule every 10 hour do select get_lock("test_l
--echo "Let some time pass to the event starts"
--sleep 2
--echo "Should have only 2 processes: the scheduler and the locked event"
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;--echo "Release the mutex, the event worker should finish."
--echo "Release the mutex, the event worker should finish."
select release_lock("test_lock2");
drop event закачка;
@ -379,18 +377,11 @@ set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
--sleep 1
--echo "Should see 1 process, locked on get_lock("
#select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
--echo "Shutting down the scheduler, it should wait for the running event"
set global event_scheduler=0;
--sleep 1
--echo "Should have only 2 processes: the scheduler and the locked event"
--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
set global event_scheduler=2;
--echo "Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
--echo "Release the lock so the child process should finish. Hence the scheduler also"
select release_lock("test_lock2_1");
--sleep 1
--echo "Should see 0 processes now:"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
drop event закачка21;
####
@ -418,6 +409,7 @@ create event white_space on schedule every 10 hour disable do
select 2;
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
drop event white_space;
create event white_space on schedule every 10 hour disable do select 3;
select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space';
@ -426,7 +418,7 @@ drop event white_space;
# END: BUG #17453: Creating Event crash the server
#
##set global event_scheduler=1;
#
# Bug#17403 "Events: packets out of order with show create event"
#
create event e1 on schedule every 1 year do set @a = 5;
@ -440,7 +432,7 @@ drop event e1;
##select get_lock("test_lock3", 20);
##create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20);
##select sleep(2);
##show processlist;
##select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
##drop event закачка;
##select release_lock("test_lock3");
@ -450,14 +442,14 @@ drop event e1;
##select get_lock("test_lock4", 20);
##create event закачка4 on schedule every 1 second do select get_lock("test_lock4", 20);
##select sleep(3);
##--replace_column 1 # 6 #
##select /*6*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
##drop event закачка4;
##select release_lock("test_lock4");
##set global event_scheduler=0;
##set global event_scheduler=2;
##select sleep(2);
##--replace_column 1 # 6 #
##show processlist;
##select count(*) from mysql.event;
drop database events_test;

View file

@ -30,13 +30,13 @@ set @a=3;
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
--echo "Here we used to crash!"
--error 1516
--error ER_EVENT_ALREADY_EXISTS
call p_16();
--error 1516
--error ER_EVENT_ALREADY_EXISTS
call p_16();
DROP EVENT e_16;
CALL p_16();
--error 1516
--error ER_EVENT_ALREADY_EXISTS
CALL p_16();
DROP PROCEDURE p_16;
DROP EVENT e_16;
@ -47,9 +47,9 @@ DROP EVENT e_16;
#
# Start - 16396: Events: Distant-future dates become past dates
#
--error 1504
--error ER_WRONG_VALUE
create event e_55 on schedule at 99990101000000 do drop table t;
--error 1504
--error ER_WRONG_VALUE
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
--error ER_EVENT_ENDS_BEFORE_STARTS
create event e_55 on schedule every 10 minute ends 99990101000000 do drop table t;
@ -60,7 +60,7 @@ create event e_55 on schedule every 10 minute ends 99990101000000 do drop table
#
# Start - 16407: Events: Changes in sql_mode won't be taken into account
#
set global event_scheduler=0;
set global event_scheduler=2;
--echo "Wait a bit to settle down"
--sleep 1
delete from mysql.event;
@ -79,7 +79,7 @@ delimiter ;|
--echo "Now if everything is fine the event has compiled and is locked
select /*1*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('test_bug16407');
set global event_scheduler= 0;
set global event_scheduler= 2;
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
--echo "Let's check whether we change the sql_mode on ALTER EVENT"
set sql_mode='traditional';
@ -121,9 +121,9 @@ set global event_scheduler= 1;
--sleep 1
select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_2');
--sleep 3
--sleep 2
select /*3*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
set global event_scheduler= 0;
set global event_scheduler= 2;
select * from events_smode_test order by ev_name, a;
--echo "OK, last check before we drop them"
select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name;
@ -156,7 +156,7 @@ set global event_scheduler= 1;
--echo "Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_5');
--sleep 3
--sleep 2
--echo "Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;
select * from events_smode_test order by ev_name, a;
@ -166,7 +166,7 @@ drop event ee_16407_5;
drop event ee_16407_6;
drop procedure ee_16407_5_pendant;
drop procedure ee_16407_6_pendant;
set global event_scheduler= 0;
set global event_scheduler= 2;
drop table events_smode_test;
set sql_mode=@old_sql_mode;
#

View file

@ -10,7 +10,7 @@ BEGIN
END|
delimiter ;|
--echo "Check General Query Log"
SET GLOBAL event_scheduler=0;
SET GLOBAL event_scheduler=2;
create event log_general on schedule every 1 minute do SELect 'alabala', sleep(3) from dual;
TRUNCATE mysql.general_log;
--echo "1 row, the current statement!"
@ -22,7 +22,7 @@ SET GLOBAL event_scheduler=1;
call select_general_log();
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=0;
SET GLOBAL event_scheduler=2;
--sleep 1
--echo "Check slow query log"
@ -53,10 +53,10 @@ TRUNCATE mysql.slow_log;
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
--echo "Set new values"
SET GLOBAL long_query_time=4;
SET SESSION long_query_time=2;
SET SESSION long_query_time=1;
--echo "Check that logging is working"
SELECT SLEEP(3);
--replace_regex /00:00:0[3-5]/SLEEPVAL/
SELECT SLEEP(2);
--replace_regex /00:00:0[2-4]/SLEEPVAL/
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
TRUNCATE mysql.slow_log;
CREATE TABLE slow_event_test (slo_val tinyint, val tinyint);
@ -73,14 +73,15 @@ SELECT * FROM slow_event_test;
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
--echo "This should go to the slow log"
SET SESSION long_query_time=10;
SET GLOBAL long_query_time=1;
DROP EVENT long_event;
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(5);
CREATE EVENT long_event2 ON SCHEDULE EVERY 1 MINUTE DO INSERT INTO slow_event_test SELECT @@long_query_time, SLEEP(2);
--echo "Sleep some more time than the actual event run will take"
--sleep 7
--sleep 3
--echo "Check our table. Should see 2 rows"
SELECT * FROM slow_event_test;
--echo "Check slow log. Should see 1 row because 5 is over the threshold of 4 for GLOBAL, though under SESSION which is 10"
--replace_regex /00:00:0[5-7]/SLEEPVAL/
--echo "Check slow log. Should see 1 row because 4 is over the threshold of 3 for GLOBAL, though under SESSION which is 10"
--replace_regex /00:00:0[2-4]/SLEEPVAL/
SELECT user_host, query_time, db, sql_text FROM mysql.slow_log;
DROP EVENT long_event2;
SET GLOBAL long_query_time =@old_global_long_query_time;

View file

@ -1,55 +1,15 @@
create database if not exists events_test;
use events_test;
--error 1235
--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 MICROSECOND DO SELECT 1;
--error 1235
--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 DAY_MICROSECOND DO SELECT 1;
--error 1235
--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 HOUR_MICROSECOND DO SELECT 1;
--error 1235
--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 MINUTE_MICROSECOND DO SELECT 1;
--error 1235
--error ER_NOT_SUPPORTED_YET
CREATE EVENT micro_test ON SCHEDULE EVERY 100 SECOND_MICROSECOND DO SELECT 1;
--echo "Now create normal event and change it on SQL level"
CREATE EVENT micro_test2 ON SCHEDULE EVERY 1 MONTH DO SELECT 1;
UPDATE mysql.event SET interval_field='MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
--error 1235
SHOW CREATE EVENT micro_test2;
SET GLOBAL event_scheduler=0;
--sleep 1
--echo "Should not be running:"
SHOW VARIABLES like 'event_scheduler';
UPDATE mysql.event SET interval_field='DAY_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
--error 1235
SHOW CREATE EVENT micro_test2;
SET GLOBAL event_scheduler=0;
--sleep 1
--echo "Should not be running:"
SHOW VARIABLES like 'event_scheduler';
UPDATE mysql.event SET interval_field='SECOND_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
--error 1235
SHOW CREATE EVENT micro_test2;
SET GLOBAL event_scheduler=0;
--sleep 1
--echo "Should not be running:"
SHOW VARIABLES like 'event_scheduler';
UPDATE mysql.event SET interval_field='HOUR_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
--error 1235
SHOW CREATE EVENT micro_test2;
SET GLOBAL event_scheduler=0;
--sleep 1
--echo "Should not be running:"
SHOW VARIABLES like 'event_scheduler';
UPDATE mysql.event SET interval_field='MINUTE_MICROSECOND' WHERE db=database() AND definer=user() AND name='micro_test2';
--error 1235
SHOW CREATE EVENT micro_test2;
SET GLOBAL event_scheduler=0;
--sleep 1
--echo "Should not be running:"
SHOW VARIABLES like 'event_scheduler';
SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER='event_scheduler';
DROP EVENT micro_test2;
drop database events_test;

View file

@ -15,7 +15,7 @@ CREATE EVENT start_n_end
DO INSERT INTO table_2 VALUES(1);
--sleep 5
CREATE EVENT only_one_time ON SCHEDULE EVERY 2 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_3 VALUES(1);
CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND DO INSERT INTO table_4 VALUES(1);
CREATE EVENT two_time ON SCHEDULE EVERY 1 SECOND ENDS NOW() + INTERVAL 1 SECOND ON COMPLETION PRESERVE DO INSERT INTO table_4 VALUES(1);
--sleep 5
SELECT IF(SUM(a) >= 4, 'OK', 'ERROR') FROM table_1;
SELECT IF(SUM(a) >= 5, 'OK', 'ERROR') FROM table_2;
@ -28,8 +28,8 @@ DROP EVENT start_n_end;
--echo "Already dropped because ended. Therefore an error."
--error ER_EVENT_DOES_NOT_EXIST
DROP EVENT only_one_time;
--echo "Already dropped because ended. Therefore an error."
--error ER_EVENT_DOES_NOT_EXIST
--echo "Should be preserved"
SELECT EVENT_NAME, STATUS FROM INFORMATION_SCHEMA.EVENTS;
DROP EVENT two_time;
DROP TABLE table_1;
DROP TABLE table_2;

View file

@ -2,78 +2,120 @@ CREATE DATABASE IF NOT EXISTS events_test;
#
# DROP DATABASE test start (bug #16406)
#
CREATE DATABASE events_test2;
USE events_test2;
CREATE DATABASE events_conn1_test2;
CREATE TABLE events_test.fill_it(test_name varchar(20), occur datetime);
CREATE USER event_user2@localhost;
CREATE DATABASE events_conn2_db;
GRANT ALL ON *.* TO event_user2@localhost;
CREATE USER event_user3@localhost;
CREATE DATABASE events_conn3_db;
GRANT ALL ON *.* TO event_user3@localhost;
connect (conn2,localhost,event_user2,,events_conn2_db);
--echo "In the second connection we create some events which won't be dropped till the end"
--disable_query_log
let $1= 100;
while ($1)
{
eval CREATE EVENT conn2_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn2_ev$1", NOW());
dec $1;
}
--enable_query_log
connect (conn3,localhost,event_user3,,events_conn3_db);
--echo "In the second connection we create some events which won't be dropped till the end"
--disable_query_log
let $1= 100;
while ($1)
{
eval CREATE EVENT conn3_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn3_ev$1", NOW());
dec $1;
}
--enable_query_log
connection default;
USE events_conn1_test2;
CREATE EVENT ev_drop1 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop2 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop3 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
USE events_test;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
DROP DATABASE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
DROP DATABASE events_conn1_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
--echo "Now testing stability - dropping db -> events while they are running"
CREATE DATABASE events_test2;
USE events_test2;
CREATE DATABASE events_conn1_test2;
USE events_conn1_test2;
--disable_query_log
let $1= 1000;
let $1= 100;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
eval CREATE EVENT conn1_round1_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round1_ev$1", NOW());
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
SET GLOBAL event_scheduler=1;
--sleep 4
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
--sleep 2
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
CREATE DATABASE events_test3;
USE events_test3;
--disable_query_log
let $1= 950;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
--sleep 3
CREATE DATABASE events_test4;
USE events_test4;
--disable_query_log
let $1= 860;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
CREATE DATABASE events_test2;
USE events_test2;
--disable_query_log
let $1= 1050;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
--sleep 6
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
DROP DATABASE events_test3;
DROP DATABASE events_conn1_test2;
SET GLOBAL event_scheduler=2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
CREATE DATABASE events_conn1_test3;
USE events_conn1_test3;
--disable_query_log
let $1= 100;
while ($1)
{
eval CREATE EVENT conn1_round2_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round2_ev$1", NOW());
dec $1;
}
--enable_query_log
SET GLOBAL event_scheduler=1;
DROP DATABASE events_test4;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test3';
CREATE DATABASE events_conn1_test4;
USE events_conn1_test4;
--disable_query_log
let $1= 100;
while ($1)
{
eval CREATE EVENT conn1_round3_ev$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round3_ev$1", NOW());
dec $1;
}
--enable_query_log
CREATE DATABASE events_conn1_test2;
USE events_conn1_test2;
--disable_query_log
let $1= 100;
while ($1)
{
eval CREATE EVENT ev_round4_drop$1 ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_test.fill_it VALUES("conn1_round4_ev$1", NOW());
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
--sleep 6
connection conn2;
--send
DROP DATABASE events_conn2_db;
connection conn3;
--send
DROP DATABASE events_conn3_db;
connection default;
--send
DROP DATABASE events_conn1_test2;
DROP DATABASE events_conn1_test3;
SET GLOBAL event_scheduler=2;
DROP DATABASE events_conn1_test4;
SET GLOBAL event_scheduler=1;
connection conn2;
reap;
disconnect conn2;
connection conn3;
reap;
disconnect conn3;
connection default;
USE events_test;
DROP TABLE fill_it;
#
# DROP DATABASE test end (bug #16406)
#

View file

@ -539,77 +539,6 @@ INSERT INTO t1 VALUES
SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6;
DROP TABLE t1;
#
# Bug #12882 min/max inconsistent on empty table
#
--disable_warnings
create table t1m (a int) engine=myisam;
create table t1i (a int) engine=innodb;
create table t2m (a int) engine=myisam;
create table t2i (a int) engine=innodb;
--enable_warnings
insert into t2m values (5);
insert into t2i values (5);
# test with MyISAM
select min(a) from t1m;
select min(7) from t1m;
select min(7) from DUAL;
explain select min(7) from t2m join t1m;
select min(7) from t2m join t1m;
select max(a) from t1m;
select max(7) from t1m;
select max(7) from DUAL;
explain select max(7) from t2m join t1m;
select max(7) from t2m join t1m;
select 1, min(a) from t1m where a=99;
select 1, min(a) from t1m where 1=99;
select 1, min(1) from t1m where a=99;
select 1, min(1) from t1m where 1=99;
select 1, max(a) from t1m where a=99;
select 1, max(a) from t1m where 1=99;
select 1, max(1) from t1m where a=99;
select 1, max(1) from t1m where 1=99;
# test with InnoDB
select min(a) from t1i;
select min(7) from t1i;
select min(7) from DUAL;
explain select min(7) from t2i join t1i;
select min(7) from t2i join t1i;
select max(a) from t1i;
select max(7) from t1i;
select max(7) from DUAL;
explain select max(7) from t2i join t1i;
select max(7) from t2i join t1i;
select 1, min(a) from t1i where a=99;
select 1, min(a) from t1i where 1=99;
select 1, min(1) from t1i where a=99;
select 1, min(1) from t1i where 1=99;
select 1, max(a) from t1i where a=99;
select 1, max(a) from t1i where 1=99;
select 1, max(1) from t1i where a=99;
select 1, max(1) from t1i where 1=99;
# mixed MyISAM/InnoDB test
explain select count(*), min(7), max(7) from t1m, t1i;
select count(*), min(7), max(7) from t1m, t1i;
explain select count(*), min(7), max(7) from t1m, t2i;
select count(*), min(7), max(7) from t1m, t2i;
explain select count(*), min(7), max(7) from t2m, t1i;
select count(*), min(7), max(7) from t2m, t1i;
drop table t1m, t1i, t2m, t2i;
# End of 4.1 tests
#

View file

@ -57,3 +57,75 @@ where
c.c_id = 218 and expiredate is null;
drop table t1, t2;
#
# Bug #12882 min/max inconsistent on empty table
#
--disable_warnings
create table t1m (a int) engine=myisam;
create table t1i (a int) engine=innodb;
create table t2m (a int) engine=myisam;
create table t2i (a int) engine=innodb;
--enable_warnings
insert into t2m values (5);
insert into t2i values (5);
# test with MyISAM
select min(a) from t1m;
select min(7) from t1m;
select min(7) from DUAL;
explain select min(7) from t2m join t1m;
select min(7) from t2m join t1m;
select max(a) from t1m;
select max(7) from t1m;
select max(7) from DUAL;
explain select max(7) from t2m join t1m;
select max(7) from t2m join t1m;
select 1, min(a) from t1m where a=99;
select 1, min(a) from t1m where 1=99;
select 1, min(1) from t1m where a=99;
select 1, min(1) from t1m where 1=99;
select 1, max(a) from t1m where a=99;
select 1, max(a) from t1m where 1=99;
select 1, max(1) from t1m where a=99;
select 1, max(1) from t1m where 1=99;
# test with InnoDB
select min(a) from t1i;
select min(7) from t1i;
select min(7) from DUAL;
explain select min(7) from t2i join t1i;
select min(7) from t2i join t1i;
select max(a) from t1i;
select max(7) from t1i;
select max(7) from DUAL;
explain select max(7) from t2i join t1i;
select max(7) from t2i join t1i;
select 1, min(a) from t1i where a=99;
select 1, min(a) from t1i where 1=99;
select 1, min(1) from t1i where a=99;
select 1, min(1) from t1i where 1=99;
select 1, max(a) from t1i where a=99;
select 1, max(a) from t1i where 1=99;
select 1, max(1) from t1i where a=99;
select 1, max(1) from t1i where 1=99;
# mixed MyISAM/InnoDB test
explain select count(*), min(7), max(7) from t1m, t1i;
select count(*), min(7), max(7) from t1m, t1i;
explain select count(*), min(7), max(7) from t1m, t2i;
select count(*), min(7), max(7) from t1m, t2i;
explain select count(*), min(7), max(7) from t2m, t1i;
select count(*), min(7), max(7) from t2m, t1i;
drop table t1m, t1i, t2m, t2i;

View file

@ -51,7 +51,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
rpl_tblmap.cc sql_binlog.cc event_executor.cc event_timed.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc
sql_tablespace.cc event.cc ../sql-common/my_user.c
partition_info.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc

View file

@ -66,7 +66,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h event.h event_priv.h \
sql_plugin.h authors.h sql_partition.h \
partition_info.h partition_element.h
partition_info.h partition_element.h event_scheduler.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@ -103,7 +103,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
event_executor.cc event.cc event_timed.cc \
event_scheduler.cc event.cc event_timed.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,6 @@
/* Copyright (C) 2004-2005 MySQL AB
#ifndef _EVENT_H_
#define _EVENT_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -14,66 +16,109 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _EVENT_H_
#define _EVENT_H_
#include "sp.h"
#include "sp_head.h"
#define EVEX_OK SP_OK
#define EVEX_KEY_NOT_FOUND SP_KEY_NOT_FOUND
#define EVEX_OPEN_TABLE_FAILED SP_OPEN_TABLE_FAILED
#define EVEX_WRITE_ROW_FAILED SP_WRITE_ROW_FAILED
#define EVEX_DELETE_ROW_FAILED SP_DELETE_ROW_FAILED
#define EVEX_GET_FIELD_FAILED SP_GET_FIELD_FAILED
#define EVEX_PARSE_ERROR SP_PARSE_ERROR
#define EVEX_INTERNAL_ERROR SP_INTERNAL_ERROR
#define EVEX_NO_DB_ERROR SP_NO_DB_ERROR
#define EVEX_OK 0
#define EVEX_KEY_NOT_FOUND -1
#define EVEX_OPEN_TABLE_FAILED -2
#define EVEX_WRITE_ROW_FAILED -3
#define EVEX_DELETE_ROW_FAILED -4
#define EVEX_GET_FIELD_FAILED -5
#define EVEX_PARSE_ERROR -6
#define EVEX_INTERNAL_ERROR -7
#define EVEX_NO_DB_ERROR -8
#define EVEX_COMPILE_ERROR -19
#define EVEX_GENERAL_ERROR -20
#define EVEX_BAD_IDENTIFIER SP_BAD_IDENTIFIER
#define EVEX_BODY_TOO_LONG SP_BODY_TOO_LONG
#define EVEX_BAD_PARAMS -21
#define EVEX_NOT_RUNNING -22
#define EVEX_MICROSECOND_UNSUP -23
#define EVEX_BAD_IDENTIFIER -21
#define EVEX_BODY_TOO_LONG -22
#define EVEX_BAD_PARAMS -23
#define EVEX_NOT_RUNNING -24
#define EVEX_MICROSECOND_UNSUP -25
#define EVEX_CANT_KILL -26
#define EVENT_EXEC_NO_MORE (1L << 0)
#define EVENT_NOT_USED (1L << 1)
#define EVENT_FREE_WHEN_FINISHED (1L << 2)
extern ulong opt_event_executor;
class Event_timed;
enum enum_event_on_completion
class Events
{
MYSQL_EVENT_ON_COMPLETION_DROP = 1,
MYSQL_EVENT_ON_COMPLETION_PRESERVE
public:
static ulong opt_event_scheduler;
static TYPELIB opt_typelib;
enum enum_table_field
{
FIELD_DB = 0,
FIELD_NAME,
FIELD_BODY,
FIELD_DEFINER,
FIELD_EXECUTE_AT,
FIELD_INTERVAL_EXPR,
FIELD_TRANSIENT_INTERVAL,
FIELD_CREATED,
FIELD_MODIFIED,
FIELD_LAST_EXECUTED,
FIELD_STARTS,
FIELD_ENDS,
FIELD_STATUS,
FIELD_ON_COMPLETION,
FIELD_SQL_MODE,
FIELD_COMMENT,
FIELD_COUNT /* a cool trick to count the number of fields :) */
};
static int
create_event(THD *thd, Event_timed *et, uint create_options,
uint *rows_affected);
static int
update_event(THD *thd, Event_timed *et, sp_name *new_name,
uint *rows_affected);
static int
drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
static int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
static int
show_create_event(THD *thd, sp_name *spn, LEX_STRING definer);
static int
reconstruct_interval_expression(String *buf, interval_type interval,
longlong expression);
static int
drop_schema_events(THD *thd, char *db);
static int
dump_internal_status(THD *thd);
static int
init();
static void
shutdown();
static void
init_mutexes();
static void
destroy_mutexes();
private:
/* Prevent use of these */
Events(const Events &);
void operator=(Events &);
};
enum enum_event_status
{
MYSQL_EVENT_ENABLED = 1,
MYSQL_EVENT_DISABLED
};
enum evex_table_field
{
EVEX_FIELD_DB = 0,
EVEX_FIELD_NAME,
EVEX_FIELD_BODY,
EVEX_FIELD_DEFINER,
EVEX_FIELD_EXECUTE_AT,
EVEX_FIELD_INTERVAL_EXPR,
EVEX_FIELD_TRANSIENT_INTERVAL,
EVEX_FIELD_CREATED,
EVEX_FIELD_MODIFIED,
EVEX_FIELD_LAST_EXECUTED,
EVEX_FIELD_STARTS,
EVEX_FIELD_ENDS,
EVEX_FIELD_STATUS,
EVEX_FIELD_ON_COMPLETION,
EVEX_FIELD_SQL_MODE,
EVEX_FIELD_COMMENT,
EVEX_FIELD_COUNT /* a cool trick to count the number of fields :) */
} ;
class sp_head;
class Event_timed
{
@ -82,12 +127,26 @@ class Event_timed
my_bool in_spawned_thread;
ulong locked_by_thread_id;
my_bool running;
ulong thread_id;
pthread_mutex_t LOCK_running;
pthread_cond_t COND_finished;
bool status_changed;
bool last_executed_changed;
public:
enum enum_status
{
ENABLED = 1,
DISABLED
};
enum enum_on_completion
{
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
TIME last_executed;
LEX_STRING dbname;
@ -111,8 +170,8 @@ public:
ulonglong created;
ulonglong modified;
enum enum_event_on_completion on_completion;
enum enum_event_status status;
enum enum_on_completion on_completion;
enum enum_status status;
sp_head *sphead;
ulong sql_mode;
const uchar *body_begin;
@ -153,36 +212,15 @@ public:
DBUG_ASSERT(0);
}
Event_timed();
Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
running(0), status_changed(false),
last_executed_changed(false), expression(0), created(0),
modified(0), on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
body_begin(0), dropped(false),
free_sphead_on_delete(true), flags(0)
{
pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
init();
}
~Event_timed()
{
deinit_mutexes();
if (free_sphead_on_delete)
free_sp();
}
~Event_timed();
void
init();
void
deinit_mutexes()
{
pthread_mutex_destroy(&this->LOCK_running);
}
deinit_mutexes();
int
init_definer(THD *thd);
@ -214,12 +252,12 @@ public:
bool
compute_next_execution_time();
void
mark_last_executed(THD *thd);
int
drop(THD *thd);
void
mark_last_executed(THD *thd);
bool
update_fields(THD *thd);
@ -227,142 +265,32 @@ public:
get_create_event(THD *thd, String *buf);
int
execute(THD *thd, MEM_ROOT *mem_root= NULL);
execute(THD *thd, MEM_ROOT *mem_root);
int
compile(THD *thd, MEM_ROOT *mem_root= NULL);
compile(THD *thd, MEM_ROOT *mem_root);
my_bool
is_running()
{
my_bool ret;
VOID(pthread_mutex_lock(&this->LOCK_running));
ret= running;
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
/*
Checks whether the object is being used in a spawned thread.
This method is for very basic checking. Use ::can_spawn_now_n_lock()
for most of the cases.
*/
my_bool
can_spawn_now()
{
my_bool ret;
VOID(pthread_mutex_lock(&this->LOCK_running));
ret= !in_spawned_thread;
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
/*
Checks whether this thread can lock the object for modification ->
preventing being spawned for execution, and locks if possible.
use ::can_spawn_now() only for basic checking because a race
condition may occur between the check and eventual modification (deletion)
of the object.
*/
my_bool
can_spawn_now_n_lock(THD *thd);
bool
is_running();
int
spawn_unlock(THD *thd);
int
spawn_now(void * (*thread_func)(void*));
spawn_now(void * (*thread_func)(void*), void *arg);
void
bool
spawn_thread_finish(THD *thd);
void
free_sp()
{
delete sphead;
sphead= 0;
}
protected:
free_sp();
bool
change_security_context(THD *thd, Security_context *s_ctx,
Security_context **backup);
has_equal_db(Event_timed *etn);
int
kill_thread(THD *thd);
void
restore_security_context(THD *thd, Security_context *backup);
set_thread_id(ulong tid) { thread_id= tid; }
};
int
evex_create_event(THD *thd, Event_timed *et, uint create_options,
uint *rows_affected);
int
evex_update_event(THD *thd, Event_timed *et, sp_name *new_name,
uint *rows_affected);
int
evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
int
evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
int
evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer);
int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
int
event_reconstruct_interval_expression(String *buf,
interval_type interval,
longlong expression);
int
evex_drop_db_events(THD *thd, char *db);
int
init_events();
void
shutdown_events();
// auxiliary
int
event_timed_compare(Event_timed **a, Event_timed **b);
/*
CREATE TABLE event (
db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
name char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
body longblob NOT NULL,
definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
execute_at DATETIME default NULL,
interval_value int(11) default NULL,
interval_field ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK',
'SECOND','MICROSECOND', 'YEAR_MONTH','DAY_HOUR',
'DAY_MINUTE','DAY_SECOND',
'HOUR_MINUTE','HOUR_SECOND',
'MINUTE_SECOND','DAY_MICROSECOND',
'HOUR_MICROSECOND','MINUTE_MICROSECOND',
'SECOND_MICROSECOND') default NULL,
created TIMESTAMP NOT NULL,
modified TIMESTAMP NOT NULL,
last_executed DATETIME default NULL,
starts DATETIME default NULL,
ends DATETIME default NULL,
status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED',
on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP',
comment varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '',
PRIMARY KEY (definer,db,name)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';
*/
#endif /* _EVENT_H_ */

View file

@ -13,998 +13,3 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "event_priv.h"
#include "event.h"
#include "sp.h"
#define WAIT_STATUS_READY 0
#define WAIT_STATUS_EMPTY_QUEUE 1
#define WAIT_STATUS_NEW_TOP_EVENT 2
#define WAIT_STATUS_STOP_EXECUTOR 3
/*
Make this define DBUG_FAULTY_THR to be able to put breakpoints inside
code used by the scheduler's thread(s). In this case user connections
are not possible because the scheduler thread code is ran inside the
main thread (no spawning takes place. If you want to debug client
connection then start with --one-thread and make the define
DBUG_FAULTY_THR !
*/
#define DBUG_FAULTY_THR2
extern ulong thread_created;
extern const char *my_localhost;
extern pthread_attr_t connection_attrib;
pthread_mutex_t LOCK_event_arrays, // mutex for when working with the queue
LOCK_workers_count, // mutex for when inc/dec uint workers_count
LOCK_evex_running; // mutes for managing bool evex_is_running
static pthread_mutex_t LOCK_evex_main_thread; // mutex for when working with the queue
bool scheduler_main_thread_running= false;
bool evex_is_running= false;
ulonglong evex_main_thread_id= 0;
ulong opt_event_executor;
my_bool event_executor_running_global_var;
static my_bool evex_mutexes_initted= FALSE;
static uint workers_count;
static int
evex_load_events_from_db(THD *thd);
bool
evex_print_warnings(THD *thd, Event_timed *et);
/*
TODO Andrey: Check for command line option whether to start
the main thread or not.
*/
pthread_handler_t
event_executor_worker(void *arg);
pthread_handler_t
event_executor_main(void *arg);
/*
Returns the seconds difference of 2 TIME structs
SYNOPSIS
evex_time_diff()
a - TIME struct 1
b - TIME struct 2
Returns:
the seconds difference
*/
static int
evex_time_diff(TIME *a, TIME *b)
{
return sec_since_epoch_TIME(a) - sec_since_epoch_TIME(b);
}
/*
Inits the mutexes used by the scheduler module
SYNOPSIS
evex_init_mutexes()
NOTES
The mutexes are :
LOCK_event_arrays
LOCK_workers_count
LOCK_evex_running
*/
static void
evex_init_mutexes()
{
if (evex_mutexes_initted)
return;
evex_mutexes_initted= TRUE;
pthread_mutex_init(&LOCK_event_arrays, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&LOCK_workers_count, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&LOCK_evex_running, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&LOCK_evex_main_thread, MY_MUTEX_INIT_FAST);
event_executor_running_global_var= opt_event_executor;
}
extern TABLE_FIELD_W_TYPE mysql_db_table_fields[];
extern time_t mysql_db_table_last_check;
/*
Opens mysql.db and mysql.user and checks whether
1. mysql.db has column Event_priv at column 20 (0 based);
2. mysql.user has column Event_priv at column 29 (0 based);
Synopsis
evex_check_system_tables()
*/
void
evex_check_system_tables()
{
THD *thd= current_thd;
TABLE_LIST tables;
Open_tables_state backup;
/* thd is 0x0 during boot of the server. Later it's !=0x0 */
if (!thd)
return;
thd->reset_n_backup_open_tables_state(&backup);
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "db";
tables.lock_type= TL_READ;
if (simple_open_n_lock_tables(thd, &tables))
sql_print_error("Cannot open mysql.db");
else
{
table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields,
&mysql_db_table_last_check,ER_CANNOT_LOAD_FROM_TABLE);
close_thread_tables(thd);
}
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*) "user";
tables.lock_type= TL_READ;
if (simple_open_n_lock_tables(thd, &tables))
sql_print_error("Cannot open mysql.db");
else
{
if (tables.table->s->fields < 29 ||
strncmp(tables.table->field[29]->field_name,
STRING_WITH_LEN("Event_priv")))
sql_print_error("mysql.user has no `Event_priv` column at position 29");
close_thread_tables(thd);
}
thd->restore_backup_open_tables_state(&backup);
}
/*
Inits the scheduler. Called on server start and every time the scheduler
is started with switching the event_scheduler global variable to TRUE
SYNOPSIS
init_events()
NOTES
Inits the mutexes used by the scheduler. Done at server start.
*/
int
init_events()
{
pthread_t th;
DBUG_ENTER("init_events");
DBUG_PRINT("info",("Starting events main thread"));
evex_check_system_tables();
evex_init_mutexes();
VOID(pthread_mutex_lock(&LOCK_evex_running));
evex_is_running= false;
VOID(pthread_mutex_unlock(&LOCK_evex_running));
if (event_executor_running_global_var)
{
#ifndef DBUG_FAULTY_THR
/* TODO Andrey: Change the error code returned! */
if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
DBUG_RETURN(ER_SLAVE_THREAD);
#else
event_executor_main(NULL);
#endif
}
DBUG_RETURN(0);
}
/*
Cleans up scheduler memory. Called on server shutdown.
SYNOPSIS
shutdown_events()
NOTES
Destroys the mutexes.
*/
void
shutdown_events()
{
DBUG_ENTER("shutdown_events");
if (evex_mutexes_initted)
{
evex_mutexes_initted= FALSE;
VOID(pthread_mutex_lock(&LOCK_evex_running));
VOID(pthread_mutex_unlock(&LOCK_evex_running));
pthread_mutex_destroy(&LOCK_event_arrays);
pthread_mutex_destroy(&LOCK_workers_count);
pthread_mutex_destroy(&LOCK_evex_running);
pthread_mutex_destroy(&LOCK_evex_main_thread);
}
DBUG_VOID_RETURN;
}
/*
Inits an scheduler thread handler, both the main and a worker
SYNOPSIS
init_event_thread()
thd - the THD of the thread. Has to be allocated by the caller.
NOTES
1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication.
Returns
0 - OK
-1 - Error
*/
static int
init_event_thread(THD* thd)
{
DBUG_ENTER("init_event_thread");
thd->client_capabilities= 0;
thd->security_ctx->master_access= 0;
thd->security_ctx->db_access= 0;
thd->security_ctx->host_or_ip= (char*)my_localhost;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
thd->slave_thread= 0;
thd->options|= OPTION_AUTO_IS_NULL;
thd->client_capabilities= CLIENT_LOCAL_FILES;
thd->real_id=pthread_self();
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->thread_id= thread_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
delete thd;
DBUG_RETURN(-1);
}
#if !defined(__WIN__) && !defined(__NETWARE__)
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
thd->proc_info= "Initialized";
thd->version= refresh_version;
thd->set_time();
DBUG_RETURN(0);
}
/*
This function waits till the time next event in the queue should be
executed.
Returns
WAIT_STATUS_READY There is an event to be executed right now
WAIT_STATUS_EMPTY_QUEUE No events or the last event was dropped.
WAIT_STATUS_NEW_TOP_EVENT New event has entered the queue and scheduled
on top. Restart ticking.
WAIT_STATUS_STOP_EXECUTOR The thread was killed or SET global event_scheduler=0;
*/
static int
executor_wait_till_next_event_exec(THD *thd)
{
Event_timed *et;
TIME time_now;
int t2sleep;
DBUG_ENTER("executor_wait_till_next_event_exec");
/*
now let's see how much time to sleep, we know there is at least 1
element in the queue.
*/
VOID(pthread_mutex_lock(&LOCK_event_arrays));
if (!evex_queue_num_elements(EVEX_EQ_NAME))
{
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
DBUG_RETURN(WAIT_STATUS_EMPTY_QUEUE);
}
et= evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*);
DBUG_ASSERT(et);
if (et->status == MYSQL_EVENT_DISABLED)
{
DBUG_PRINT("evex main thread",("Now it is disabled-exec no more"));
if (et->dropped)
et->drop(thd);
delete et;
evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
sql_print_information("Event found disabled, dropping.");
DBUG_RETURN(1);
}
DBUG_PRINT("evex main thread",("computing time to sleep till next exec"));
/* set the internal clock of thd */
thd->end_time();
my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
t2sleep= evex_time_diff(&et->execute_at, &time_now);
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
t2sleep*=20;
DBUG_PRINT("evex main thread",("unlocked LOCK_event_arrays"));
if (t2sleep > 0)
{
ulonglong modified= et->modified;
/*
We sleep t2sleep seconds but we check every second whether this thread
has been killed, or there is a new candidate
*/
while (t2sleep-- && !thd->killed && event_executor_running_global_var &&
evex_queue_num_elements(EVEX_EQ_NAME) &&
(evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*) == et &&
evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified ==
modified))
{
DBUG_PRINT("evex main thread",("will sleep a bit more."));
my_sleep(50000);
}
DBUG_PRINT("info",("saved_modified=%llu current=%llu", modified,
evex_queue_num_elements(EVEX_EQ_NAME)?
evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified:
(ulonglong)~0));
}
int ret= WAIT_STATUS_READY;
if (!evex_queue_num_elements(EVEX_EQ_NAME))
ret= WAIT_STATUS_EMPTY_QUEUE;
else if (evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*) != et)
ret= WAIT_STATUS_NEW_TOP_EVENT;
if (thd->killed && event_executor_running_global_var)
ret= WAIT_STATUS_STOP_EXECUTOR;
DBUG_RETURN(ret);
}
/*
The main scheduler thread. Inits the priority queue on start and
destroys it on thread shutdown. Forks child threads for every event
execution. Sleeps between thread forking and does not do a busy wait.
SYNOPSIS
event_executor_main()
arg unused
NOTES
1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication.
*/
pthread_handler_t
event_executor_main(void *arg)
{
THD *thd; /* needs to be first for thread_stack */
uint i=0, j=0;
my_ulonglong cnt= 0;
DBUG_ENTER("event_executor_main");
DBUG_PRINT("event_executor_main", ("EVEX thread started"));
pthread_mutex_lock(&LOCK_evex_main_thread);
if (!scheduler_main_thread_running)
scheduler_main_thread_running= true;
else
{
DBUG_PRINT("event_executor_main", ("already running. thd_id=%d",
evex_main_thread_id));
pthread_mutex_unlock(&LOCK_evex_main_thread);
my_thread_end();
pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here
}
pthread_mutex_unlock(&LOCK_evex_main_thread);
/* init memory root */
init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
/* needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff*/
my_thread_init();
if (sizeof(my_time_t) != sizeof(time_t))
{
sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
"The scheduler will not work correctly. Stopping.");
DBUG_ASSERT(0);
goto err_no_thd;
}
/* note that contructor of THD uses DBUG_ ! */
if (!(thd = new THD))
{
sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
goto err_no_thd;
}
thd->thread_stack = (char*)&thd; // remember where our stack is
pthread_detach_this_thread();
if (init_event_thread(thd))
goto finish;
/*
make this thread visible it has no vio -> show processlist won't see it
unless it's marked as system thread
*/
thd->system_thread= 1;
VOID(pthread_mutex_lock(&LOCK_thread_count));
threads.append(thd);
thread_count++;
thread_running++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
DBUG_PRINT("EVEX main thread", ("Initing events_queue"));
/*
eventually manifest that we are running, not to crashe because of
usage of non-initialized memory structures.
*/
VOID(pthread_mutex_lock(&LOCK_evex_running));
VOID(pthread_mutex_lock(&LOCK_event_arrays));
evex_queue_init(&EVEX_EQ_NAME);
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
evex_is_running= true;
VOID(pthread_mutex_unlock(&LOCK_evex_running));
thd->security_ctx->user= my_strdup("event_scheduler", MYF(0));
if (evex_load_events_from_db(thd))
goto finish;
evex_main_thread_id= thd->thread_id;
sql_print_information("SCHEDULER: Main thread started");
while (!thd->killed)
{
TIME time_now;
Event_timed *et;
cnt++;
DBUG_PRINT("info", ("EVEX External Loop %d thd->k", cnt));
thd->proc_info = "Sleeping";
if (!event_executor_running_global_var)
{
sql_print_information("SCHEDULER: Asked to stop.");
break;
}
if (!evex_queue_num_elements(EVEX_EQ_NAME))
{
my_sleep(100000);// sleep 0.1s
continue;
}
restart_ticking:
switch (executor_wait_till_next_event_exec(thd)) {
case WAIT_STATUS_READY: // time to execute the event on top
DBUG_PRINT("evex main thread",("time to execute an event"));
break;
case WAIT_STATUS_EMPTY_QUEUE: // no more events
DBUG_PRINT("evex main thread",("no more events"));
continue;
break;
case WAIT_STATUS_NEW_TOP_EVENT: // new event on top in the queue
DBUG_PRINT("evex main thread",("restart ticking"));
goto restart_ticking;
case WAIT_STATUS_STOP_EXECUTOR:
sql_print_information("SCHEDULER: Asked to stop.");
goto finish;
break;
default:
DBUG_ASSERT(0);
}
VOID(pthread_mutex_lock(&LOCK_event_arrays));
thd->end_time();
my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
if (!evex_queue_num_elements(EVEX_EQ_NAME))
{
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
DBUG_PRINT("evex main thread",("empty queue"));
continue;
}
et= evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*);
DBUG_PRINT("evex main thread",("got event from the queue"));
if (!et->execute_at_null && my_time_compare(&time_now,&et->execute_at) == -1)
{
DBUG_PRINT("evex main thread",("still not the time for execution"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
continue;
}
DBUG_PRINT("evex main thread",("it's right time"));
if (et->status == MYSQL_EVENT_ENABLED)
{
int fork_ret_code;
DBUG_PRINT("evex main thread", ("[%10s] this exec at [%llu]", et->name.str,
TIME_to_ulonglong_datetime(&et->execute_at)));
et->mark_last_executed(thd);
if (et->compute_next_execution_time())
{
sql_print_error("SCHEDULER: Error while computing time of %s.%s . "
"Disabling after execution.",
et->dbname.str, et->name.str);
et->status= MYSQL_EVENT_DISABLED;
}
DBUG_PRINT("evex main thread", ("[%10s] next exec at [%llu]", et->name.str,
TIME_to_ulonglong_datetime(&et->execute_at)));
et->update_fields(thd);
#ifndef DBUG_FAULTY_THR
thread_safe_increment(workers_count, &LOCK_workers_count);
switch ((fork_ret_code= et->spawn_now(event_executor_worker))) {
case EVENT_EXEC_CANT_FORK:
thread_safe_decrement(workers_count, &LOCK_workers_count);
sql_print_error("SCHEDULER: Problem while trying to create a thread");
UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_event_arrays, finish);
case EVENT_EXEC_ALREADY_EXEC:
thread_safe_decrement(workers_count, &LOCK_workers_count);
sql_print_information("SCHEDULER: %s.%s in execution. Skip this time.",
et->dbname.str, et->name.str);
break;
default:
DBUG_ASSERT(!fork_ret_code);
if (fork_ret_code)
thread_safe_decrement(workers_count, &LOCK_workers_count);
break;
}
#else
event_executor_worker((void *) et);
#endif
/*
1. For one-time event : year is > 0 and expression is 0
2. For recurring, expression is != -=> check execute_at_null in this case
*/
if ((et->execute_at.year && !et->expression) || et->execute_at_null)
et->flags |= EVENT_EXEC_NO_MORE;
if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED)
evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
else
evex_queue_first_updated(&EVEX_EQ_NAME);
}
DBUG_PRINT("evex main thread",("unlocking"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
}/* while */
finish:
/* First manifest that this thread does not work and then destroy */
VOID(pthread_mutex_lock(&LOCK_evex_running));
evex_is_running= false;
evex_main_thread_id= 0;
VOID(pthread_mutex_unlock(&LOCK_evex_running));
/*
TODO: A better will be with a conditional variable
*/
/*
Read workers_count without lock, no need for locking.
In the worst case we have to wait 1sec more.
*/
sql_print_information("SCHEDULER: Stopping. Waiting for worker threads to finish.");
while (1)
{
VOID(pthread_mutex_lock(&LOCK_workers_count));
if (!workers_count)
{
VOID(pthread_mutex_unlock(&LOCK_workers_count));
break;
}
VOID(pthread_mutex_unlock(&LOCK_workers_count));
my_sleep(1000000);// 1s
}
/*
First we free all objects ...
Lock because a DROP DATABASE could be running in parallel and it locks on these
*/
sql_print_information("SCHEDULER: Emptying the queue.");
VOID(pthread_mutex_lock(&LOCK_event_arrays));
for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
{
Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
et->free_sp();
delete et;
}
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
/* ... then we can thrash the whole queue at once */
evex_queue_destroy(&EVEX_EQ_NAME);
thd->proc_info = "Clearing";
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because we are weird
THD_CHECK_SENTRY(thd);
pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
thread_running--;
#ifndef DBUG_FAULTY_THR
THD_CHECK_SENTRY(thd);
delete thd;
#endif
pthread_mutex_unlock(&LOCK_thread_count);
err_no_thd:
VOID(pthread_mutex_lock(&LOCK_evex_running));
evex_is_running= false;
event_executor_running_global_var= false;
VOID(pthread_mutex_unlock(&LOCK_evex_running));
free_root(&evex_mem_root, MYF(0));
sql_print_information("SCHEDULER: Stopped.");
#ifndef DBUG_FAULTY_THR
pthread_mutex_lock(&LOCK_evex_main_thread);
scheduler_main_thread_running= false;
pthread_mutex_unlock(&LOCK_evex_main_thread);
my_thread_end();
pthread_exit(0);
#endif
DBUG_RETURN(0); // Can't return anything here
}
/*
Function that executes an event in a child thread. Setups the
environment for the event execution and cleans after that.
SYNOPSIS
event_executor_worker()
arg The Event_timed object to be processed
*/
pthread_handler_t
event_executor_worker(void *event_void)
{
THD *thd; /* needs to be first for thread_stack */
Event_timed *event = (Event_timed *) event_void;
MEM_ROOT worker_mem_root;
DBUG_ENTER("event_executor_worker");
init_alloc_root(&worker_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
#ifndef DBUG_FAULTY_THR
my_thread_init();
if (!(thd = new THD)) /* note that contructor of THD uses DBUG_ ! */
{
sql_print_error("SCHEDULER: Cannot create a THD structure in an worker.");
goto err_no_thd;
}
thd->thread_stack = (char*)&thd; // remember where our stack is
thd->mem_root= &worker_mem_root;
pthread_detach_this_thread();
if (init_event_thread(thd))
goto err;
thd->init_for_queries();
/* make this thread visible it has no vio -> show processlist needs this flag */
thd->system_thread= 1;
VOID(pthread_mutex_lock(&LOCK_thread_count));
threads.append(thd);
thread_count++;
thread_running++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
#else
thd= current_thd;
#endif
thd->enable_slow_log= TRUE;
{
int ret;
sql_print_information("SCHEDULER: Executing event %s.%s of %s [EXPR:%d]",
event->dbname.str, event->name.str,
event->definer.str, (int) event->expression);
ret= event->execute(thd, &worker_mem_root);
evex_print_warnings(thd, event);
sql_print_information("SCHEDULER: Executed event %s.%s of %s [EXPR:%d]. "
"RetCode=%d", event->dbname.str, event->name.str,
event->definer.str, (int) event->expression, ret);
if (ret == EVEX_COMPILE_ERROR)
sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of",
event->dbname.str, event->name.str,
event->definer.str);
else if (ret == EVEX_MICROSECOND_UNSUP)
sql_print_information("SCHEDULER: MICROSECOND is not supported");
}
event->spawn_thread_finish(thd);
err:
VOID(pthread_mutex_lock(&LOCK_thread_count));
#ifndef DBUG_FAULTY_THR
thread_count--;
thread_running--;
/*
Some extra safety, which should not been needed (normally, event deletion
should already have done these assignments (each event which sets these
variables is supposed to set them to 0 before terminating)).
*/
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->proc_info = "Clearing";
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because we are weird
THD_CHECK_SENTRY(thd);
VOID(pthread_mutex_lock(&LOCK_thread_count));
THD_CHECK_SENTRY(thd);
delete thd;
#endif
VOID(pthread_mutex_unlock(&LOCK_thread_count));
err_no_thd:
free_root(&worker_mem_root, MYF(0));
thread_safe_decrement(workers_count, &LOCK_workers_count);
#ifndef DBUG_FAULTY_THR
my_thread_end();
pthread_exit(0);
#endif
DBUG_RETURN(0); // Can't return anything here
}
/*
Loads all ENABLED events from mysql.event into the prioritized
queue. Called during scheduler main thread initialization. Compiles
the events. Creates Event_timed instances for every ENABLED event
from mysql.event.
SYNOPSIS
evex_load_events_from_db()
thd - Thread context. Used for memory allocation in some cases.
RETURNS
0 OK
!0 Error
NOTES
Reports the error to the console
*/
static int
evex_load_events_from_db(THD *thd)
{
TABLE *table;
READ_RECORD read_record_info;
int ret= -1;
uint count= 0;
DBUG_ENTER("evex_load_events_from_db");
if ((ret= evex_open_event_table(thd, TL_READ, &table)))
{
sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
}
VOID(pthread_mutex_lock(&LOCK_event_arrays));
init_read_record(&read_record_info, thd, table ,NULL,1,0);
while (!(read_record_info.read_record(&read_record_info)))
{
Event_timed *et;
if (!(et= new Event_timed))
{
DBUG_PRINT("evex_load_events_from_db", ("Out of memory"));
ret= -1;
goto end;
}
DBUG_PRINT("evex_load_events_from_db", ("Loading event from row."));
if ((ret= et->load_from_row(&evex_mem_root, table)))
{
sql_print_error("SCHEDULER: Error while loading from mysql.event. "
"Table probably corrupted");
goto end;
}
if (et->status != MYSQL_EVENT_ENABLED)
{
DBUG_PRINT("evex_load_events_from_db",("%s is disabled",et->name.str));
delete et;
continue;
}
DBUG_PRINT("evex_load_events_from_db",
("Event %s loaded from row. Time to compile", et->name.str));
switch (ret= et->compile(thd, &evex_mem_root)) {
case EVEX_MICROSECOND_UNSUP:
sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
"supported but found in mysql.event");
goto end;
case EVEX_COMPILE_ERROR:
sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
et->dbname.str, et->name.str);
goto end;
default:
break;
}
/* let's find when to be executed */
if (et->compute_next_execution_time())
{
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
" Skipping", et->dbname.str, et->name.str);
continue;
}
DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) et);
DBUG_PRINT("evex_load_events_from_db", ("%p %*s",
et, et->name.length,et->name.str));
count++;
}
ret= 0;
end:
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info);
/* Force close to free memory */
thd->version--;
close_thread_tables(thd);
if (!ret)
sql_print_information("SCHEDULER: Loaded %d event%s", count, (count == 1)?"":"s");
DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
DBUG_RETURN(ret);
}
/*
The update method of the global variable event_scheduler.
If event_scheduler is switched from 0 to 1 then the scheduler main
thread is started.
SYNOPSIS
event_executor_worker()
thd - Thread context (unused)
car - the new value
Returns
0 OK (always)
*/
bool
sys_var_event_executor::update(THD *thd, set_var *var)
{
/* here start the thread if not running. */
DBUG_ENTER("sys_var_event_executor::update");
VOID(pthread_mutex_lock(&LOCK_evex_running));
*value= var->save_result.ulong_value;
DBUG_PRINT("new_value", ("%d", *value));
if ((my_bool) *value && !evex_is_running)
{
VOID(pthread_mutex_unlock(&LOCK_evex_running));
init_events();
} else
VOID(pthread_mutex_unlock(&LOCK_evex_running));
DBUG_RETURN(0);
}
extern LEX_STRING warning_level_names[];
typedef void (*sql_print_xxx_func)(const char *format, ...);
static sql_print_xxx_func sql_print_xxx_handlers[3] =
{
sql_print_information,
sql_print_warning,
sql_print_error
};
/*
Prints the stack of infos, warnings, errors from thd to
the console so it can be fetched by the logs-into-tables and
checked later.
Synopsis
evex_print_warnings
thd - thread used during the execution of the event
et - the event itself
Returns
0 - OK (always)
*/
bool
evex_print_warnings(THD *thd, Event_timed *et)
{
MYSQL_ERROR *err;
DBUG_ENTER("evex_show_warnings");
char msg_buf[1024];
char prefix_buf[512];
String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
prefix.length(0);
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
while ((err= it++))
{
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
/* set it to 0 or we start adding at the end. That's the trick ;) */
err_msg.length(0);
if (!prefix.length())
{
prefix.append("SCHEDULER: [");
append_identifier(thd,&prefix,et->definer_user.str,et->definer_user.length);
prefix.append('@');
append_identifier(thd,&prefix,et->definer_host.str,et->definer_host.length);
prefix.append("][", 2);
append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
prefix.append('.');
append_identifier(thd,&prefix, et->name.str, et->name.length);
prefix.append("] ", 2);
}
err_msg.append(prefix);
err_msg.append(err->msg, strlen(err->msg), system_charset_info);
err_msg.append("]");
DBUG_ASSERT(err->level < 3);
(sql_print_xxx_handlers[err->level])("%*s", err_msg.length(), err_msg.c_ptr());
}
DBUG_RETURN(FALSE);
}

View file

@ -1,4 +1,6 @@
/* Copyright (C) 2004-2005 MySQL AB
#ifndef _EVENT_PRIV_H_
#define _EVENT_PRIV_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -14,8 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _EVENT_PRIV_H_
#define _EVENT_PRIV_H_
#include "mysql_priv.h"
@ -23,11 +23,6 @@
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
#define EVEX_USE_QUEUE
#define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \
{ VOID(pthread_mutex_unlock(&__mutex)); goto __label; }
#define EVEX_DB_FIELD_LEN 64
#define EVEX_NAME_FIELD_LEN 64
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
@ -44,39 +39,49 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
int
event_timed_compare_q(void *vptr, byte* a, byte *b);
int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
int
db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
int
db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
TABLE *tbl, MEM_ROOT *root);
int
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected);
int
db_drop_events_from_table(THD *thd, LEX_STRING *db);
#define EXEC_QUEUE_QUEUE_NAME executing_queue
#define EXEC_QUEUE_DARR_NAME evex_executing_queue
#define EVEX_QUEUE_TYPE QUEUE
#define EVEX_PTOQEL byte *
#define EVEX_EQ_NAME executing_queue
#define evex_queue_first_element(queue, __cast) ((__cast)queue_top(queue))
#define evex_queue_element(queue, idx, __cast) ((__cast)queue_element(queue, idx))
#define evex_queue_delete_element(queue, idx) queue_remove(queue, idx)
#define evex_queue_destroy(queue) delete_queue(queue)
#define evex_queue_first_updated(queue) queue_replaced(queue)
#define evex_queue_insert(queue, element) queue_insert_safe(queue, element);
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
/* Compares only the name part of the identifier */
bool
event_timed_name_equal(Event_timed *et, LEX_STRING *name);
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db);
/*
Compares only the definer part of the identifier. Use during DROP USER
to drop user's events. (Still not implemented)
*/
bool
event_timed_definer_equal(Event_timed *et, LEX_STRING *definer);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b);
bool
change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup);
void
evex_queue_init(EVEX_QUEUE_TYPE *queue);
#define evex_queue_num_elements(queue) queue.elements
extern bool evex_is_running;
extern MEM_ROOT evex_mem_root;
extern pthread_mutex_t LOCK_event_arrays,
LOCK_workers_count,
LOCK_evex_running;
extern ulonglong evex_main_thread_id;
extern QUEUE EVEX_EQ_NAME;
restore_security_context(THD *thd, Security_context *backup);
#endif /* _EVENT_PRIV_H_ */

2411
sql/event_scheduler.cc Normal file

File diff suppressed because it is too large Load diff

254
sql/event_scheduler.h Normal file
View file

@ -0,0 +1,254 @@
#ifndef _EVENT_SCHEDULER_H_
#define _EVENT_SCHEDULER_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class THD;
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
int
events_init();
void
events_shutdown();
class Event_scheduler
{
public:
/* Return codes */
enum enum_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
enum enum_state
{
UNINITIALIZED= 0,
INITIALIZED,
COMMENCING,
CANTSTART,
RUNNING,
SUSPENDED,
IN_SHUTDOWN
};
enum enum_suspend_or_resume
{
SUSPEND= 1,
RESUME= 2
};
/* Singleton access */
static Event_scheduler*
get_instance();
/* Methods for queue management follow */
enum enum_error_code
add_event(THD *thd, Event_timed *et, bool check_existence);
bool
drop_event(THD *thd, Event_timed *et);
enum enum_error_code
replace_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
int
drop_schema_events(THD *thd, LEX_STRING *schema);
int
drop_user_events(THD *thd, LEX_STRING *definer, uint *dropped_num)
{ DBUG_ASSERT(0); return 0;}
uint
events_count();
/* State changing methods follow */
bool
start();
enum enum_error_code
stop();
bool
start_suspended();
bool
run(THD *thd);
enum enum_error_code
suspend_or_resume(enum enum_suspend_or_resume action);
bool
init();
void
destroy();
static void
init_mutexes();
static void
destroy_mutexes();
void
report_error_during_start();
/* Information retrieving methods follow */
enum enum_state
get_state();
bool
initialized();
static int
dump_internal_status(THD *thd);
static bool
check_system_tables(THD *thd);
private:
Event_timed *
find_event(Event_timed *etn, bool remove_from_q);
uint
workers_count();
bool
is_running_or_suspended();
/* helper functions */
bool
execute_top(THD *thd);
void
clean_queue(THD *thd);
void
stop_all_running_events(THD *thd);
enum enum_error_code
load_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
int
load_events_from_db(THD *thd);
void
drop_matching_events(THD *thd, LEX_STRING *pattern,
bool (*)(Event_timed *,LEX_STRING *));
bool
check_n_suspend_if_needed(THD *thd);
bool
check_n_wait_for_non_empty_queue(THD *thd);
/* Singleton DP is used */
Event_scheduler();
enum enum_cond_vars
{
COND_NONE= -1,
/*
COND_new_work is a conditional used to signal that there is a change
of the queue that should inform the executor thread that new event should
be executed sooner than previously expected, because of add/replace event.
*/
COND_new_work= 0,
/*
COND_started is a conditional used to synchronize the thread in which
::start() was called and the spawned thread. ::start() spawns a new thread
and then waits on COND_started but also checks when awaken that `state` is
either RUNNING or CANTSTART. Then it returns back.
*/
COND_started_or_stopped,
/*
Conditional used for signalling from the scheduler thread back to the
thread that calls ::suspend() or ::resume. Synchronizing the calls.
*/
COND_suspend_or_resume,
/* Must be always last */
COND_LAST,
};
/* Singleton instance */
static Event_scheduler singleton;
/* This is the current status of the life-cycle of the manager. */
enum enum_state state;
/* Set to start the scheduler in suspended state */
bool start_scheduler_suspended;
/*
LOCK_scheduler_data is the mutex which protects the access to the
manager's queue as well as used when signalling COND_new_work,
COND_started and COND_shutdown.
*/
pthread_mutex_t LOCK_scheduler_data;
/*
Holds the thread id of the executor thread or 0 if the executor is not
running. It is used by ::shutdown() to know which thread to kill with
kill_one_thread(). The latter wake ups a thread if it is waiting on a
conditional variable and sets thd->killed to non-zero.
*/
ulong thread_id;
pthread_cond_t cond_vars[COND_LAST];
static const char * const cond_vars_names[COND_LAST];
/* The MEM_ROOT of the object */
MEM_ROOT scheduler_root;
/* The sorted queue with the Event_timed objects */
QUEUE queue;
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
const char* mutex_last_locked_in_func;
const char* mutex_last_unlocked_in_func;
enum enum_cond_vars cond_waiting_on;
bool mutex_scheduler_data_locked;
/* helper functions for working with mutexes & conditionals */
void
lock_data(const char *func, uint line);
void
unlock_data(const char *func, uint line);
int
cond_wait(enum enum_cond_vars, pthread_mutex_t *mutex);
private:
/* Prevent use of these */
Event_scheduler(const Event_scheduler &);
void operator=(Event_scheduler &);
};
#endif /* _EVENT_SCHEDULER_H_ */

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2004-2005 MySQL AB
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,7 +17,82 @@
#define MYSQL_LEX 1
#include "event_priv.h"
#include "event.h"
#include "sp.h"
#include "sp_head.h"
/*
Constructor
SYNOPSIS
Event_timed::Event_timed()
*/
Event_timed::Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
running(0), thread_id(0), status_changed(false),
last_executed_changed(false), expression(0),
created(0), modified(0),
on_completion(Event_timed::ON_COMPLETION_DROP),
status(Event_timed::ENABLED), sphead(0),
sql_mode(0), body_begin(0), dropped(false),
free_sphead_on_delete(true), flags(0)
{
pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
pthread_cond_init(&this->COND_finished, NULL);
init();
}
/*
Destructor
SYNOPSIS
Event_timed::~Event_timed()
*/
Event_timed::~Event_timed()
{
deinit_mutexes();
if (free_sphead_on_delete)
free_sp();
}
/*
Destructor
SYNOPSIS
Event_timed::~deinit_mutexes()
*/
void
Event_timed::deinit_mutexes()
{
pthread_mutex_destroy(&this->LOCK_running);
pthread_cond_destroy(&this->COND_finished);
}
/*
Checks whether the event is running
SYNOPSIS
Event_timed::is_running()
*/
bool
Event_timed::is_running()
{
bool ret;
VOID(pthread_mutex_lock(&this->LOCK_running));
ret= running;
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
/*
Init all member variables
@ -238,7 +313,7 @@ Event_timed::init_execute_at(THD *thd, Item *expr)
expr how much?
new_interval what is the interval
RETURNS
RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
EVEX_BAD_PARAMS Interval is not positive
@ -342,7 +417,7 @@ Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at
same time.
RETURNS
RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
EVEX_BAD_PARAMS starts before now
@ -408,7 +483,7 @@ Event_timed::init_starts(THD *thd, Item *new_starts)
DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at
same time.
RETURNS
RETURN VALUE
0 OK
EVEX_PARSE_ERROR fix_fields failed
ER_WRONG_VALUE starts distant date (after year 2037)
@ -492,6 +567,9 @@ Event_timed::init_comment(THD *thd, LEX_STRING *set_comment)
SYNOPSIS
Event_timed::init_definer()
RETURN VALUE
0 OK
*/
int
@ -534,6 +612,10 @@ Event_timed::init_definer(THD *thd)
SYNOPSIS
Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
RETURN VALUE
0 OK
EVEX_GET_FIELD_FAILED Error
NOTES
This method is silent on errors and should behave like that. Callers
should handle throwing of error messages. The reason is that the class
@ -555,29 +637,29 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et= this;
if (table->s->fields != EVEX_FIELD_COUNT)
if (table->s->fields != Events::FIELD_COUNT)
goto error;
if ((et->dbname.str= get_field(mem_root,
table->field[EVEX_FIELD_DB])) == NULL)
table->field[Events::FIELD_DB])) == NULL)
goto error;
et->dbname.length= strlen(et->dbname.str);
if ((et->name.str= get_field(mem_root,
table->field[EVEX_FIELD_NAME])) == NULL)
table->field[Events::FIELD_NAME])) == NULL)
goto error;
et->name.length= strlen(et->name.str);
if ((et->body.str= get_field(mem_root,
table->field[EVEX_FIELD_BODY])) == NULL)
table->field[Events::FIELD_BODY])) == NULL)
goto error;
et->body.length= strlen(et->body.str);
if ((et->definer.str= get_field(mem_root,
table->field[EVEX_FIELD_DEFINER])) == NullS)
table->field[Events::FIELD_DEFINER])) == NullS)
goto error;
et->definer.length= strlen(et->definer.str);
@ -594,69 +676,71 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
et->definer_host.length= len;
et->starts_null= table->field[EVEX_FIELD_STARTS]->is_null();
res1= table->field[EVEX_FIELD_STARTS]->get_date(&et->starts,TIME_NO_ZERO_DATE);
et->starts_null= table->field[Events::FIELD_STARTS]->is_null();
res1= table->field[Events::FIELD_STARTS]->
get_date(&et->starts,TIME_NO_ZERO_DATE);
et->ends_null= table->field[EVEX_FIELD_ENDS]->is_null();
res2= table->field[EVEX_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
et->ends_null= table->field[Events::FIELD_ENDS]->is_null();
res2= table->field[Events::FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
if (!table->field[EVEX_FIELD_INTERVAL_EXPR]->is_null())
et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int();
if (!table->field[Events::FIELD_INTERVAL_EXPR]->is_null())
et->expression= table->field[Events::FIELD_INTERVAL_EXPR]->val_int();
else
et->expression= 0;
/*
If res1 and res2 are true then both fields are empty.
Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
Hence if Events::FIELD_EXECUTE_AT is empty there is an error.
*/
et->execute_at_null= table->field[EVEX_FIELD_EXECUTE_AT]->is_null();
et->execute_at_null=
table->field[Events::FIELD_EXECUTE_AT]->is_null();
DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
et->execute_at_null));
if (!et->expression &&
table->field[EVEX_FIELD_EXECUTE_AT]->get_date(&et->execute_at,
TIME_NO_ZERO_DATE))
table->field[Events::FIELD_EXECUTE_AT]-> get_date(&et->execute_at,
TIME_NO_ZERO_DATE))
goto error;
/*
In DB the values start from 1 but enum interval_type starts
from 0
*/
if (!table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->is_null())
et->interval= (interval_type)
((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
if (!table->field[Events::FIELD_TRANSIENT_INTERVAL]->is_null())
et->interval= (interval_type) ((ulonglong)
table->field[Events::FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
else
et->interval= (interval_type) 0;
et->created= table->field[EVEX_FIELD_CREATED]->val_int();
et->modified= table->field[EVEX_FIELD_MODIFIED]->val_int();
et->created= table->field[Events::FIELD_CREATED]->val_int();
et->modified= table->field[Events::FIELD_MODIFIED]->val_int();
table->field[EVEX_FIELD_LAST_EXECUTED]->
table->field[Events::FIELD_LAST_EXECUTED]->
get_date(&et->last_executed, TIME_NO_ZERO_DATE);
last_executed_changed= false;
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS)
if ((ptr= get_field(mem_root, table->field[Events::FIELD_STATUS])) == NullS)
goto error;
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED);
et->status= (ptr[0]=='E'? Event_timed::ENABLED:Event_timed::DISABLED);
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root,
table->field[EVEX_FIELD_ON_COMPLETION])) == NullS)
table->field[Events::FIELD_ON_COMPLETION])) == NullS)
goto error;
et->on_completion= (ptr[0]=='D'? MYSQL_EVENT_ON_COMPLETION_DROP:
MYSQL_EVENT_ON_COMPLETION_PRESERVE);
et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
Event_timed::ON_COMPLETION_PRESERVE);
et->comment.str= get_field(mem_root, table->field[EVEX_FIELD_COMMENT]);
et->comment.str= get_field(mem_root, table->field[Events::FIELD_COMMENT]);
if (et->comment.str != NullS)
et->comment.length= strlen(et->comment.str);
else
et->comment.length= 0;
et->sql_mode= (ulong) table->field[EVEX_FIELD_SQL_MODE]->val_int();
et->sql_mode= (ulong) table->field[Events::FIELD_SQL_MODE]->val_int();
DBUG_RETURN(0);
error:
@ -676,7 +760,7 @@ error:
i_value quantity of time type interval to add
i_type type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
RETURNS
RETURN VALUE
0 OK
1 Error
@ -834,6 +918,10 @@ done:
SYNOPSIS
Event_timed::compute_next_execution_time()
RETURN VALUE
FALSE OK
TRUE Error
NOTES
The time is set in execute_at, if no more executions the latter is set to
0000-00-00.
@ -843,7 +931,6 @@ bool
Event_timed::compute_next_execution_time()
{
TIME time_now;
my_time_t now;
int tmp;
DBUG_ENTER("Event_timed::compute_next_execution_time");
@ -852,7 +939,7 @@ Event_timed::compute_next_execution_time()
TIME_to_ulonglong_datetime(&ends),
TIME_to_ulonglong_datetime(&last_executed)));
if (status == MYSQL_EVENT_DISABLED)
if (status == Event_timed::DISABLED)
{
DBUG_PRINT("compute_next_execution_time",
("Event %s is DISABLED", name.str));
@ -866,14 +953,15 @@ Event_timed::compute_next_execution_time()
{
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
dbname.str, name.str, definer.str));
dropped= (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP);
dropped= (on_completion == Event_timed::ON_COMPLETION_DROP);
DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped));
status= MYSQL_EVENT_DISABLED;
status= Event_timed::DISABLED;
status_changed= true;
}
goto ret;
}
current_thd->end_time();
my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start());
DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now)));
@ -885,9 +973,9 @@ Event_timed::compute_next_execution_time()
/* time_now is after ends. don't execute anymore */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
status= MYSQL_EVENT_DISABLED;
status= Event_timed::DISABLED;
status_changed= true;
goto ret;
@ -937,7 +1025,6 @@ Event_timed::compute_next_execution_time()
{
TIME next_exec;
DBUG_PRINT("info", ("Executed at least once"));
if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval))
@ -946,12 +1033,15 @@ Event_timed::compute_next_execution_time()
/* There was previous execution */
if (my_time_compare(&ends, &next_exec) == -1)
{
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
name.str));
/* Next execution after ends. No more executions */
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
status= Event_timed::DISABLED;
status_changed= true;
}
else
{
@ -1006,7 +1096,6 @@ Event_timed::compute_next_execution_time()
{
TIME next_exec;
DBUG_PRINT("info", ("Executed at least once."));
if (get_next_time(&next_exec, &starts, &time_now,
last_executed.year? &last_executed:&starts,
expression, interval))
@ -1042,7 +1131,9 @@ Event_timed::compute_next_execution_time()
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
execute_at_null= TRUE;
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
status= Event_timed::DISABLED;
status_changed= true;
if (on_completion == Event_timed::ON_COMPLETION_DROP)
dropped= true;
}
else
@ -1083,9 +1174,6 @@ Event_timed::mark_last_executed(THD *thd)
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
last_executed= time_now; /* was execute_at */
#ifdef ANDREY_0
last_executed= execute_at;
#endif
last_executed_changed= true;
}
@ -1125,7 +1213,7 @@ Event_timed::drop(THD *thd)
RETURN VALUE
0 OK
SP_OPEN_TABLE_FAILED Error while opening mysql.event for writing
EVEX_OPEN_TABLE_FAILED Error while opening mysql.event for writing
EVEX_WRITE_ROW_FAILED On error to write to disk
others return code from SE in case deletion of the event
@ -1149,9 +1237,9 @@ Event_timed::update_fields(THD *thd)
thd->reset_n_backup_open_tables_state(&backup);
if (evex_open_event_table(thd, TL_WRITE, &table))
if (Events::open_event_table(thd, TL_WRITE, &table))
{
ret= SP_OPEN_TABLE_FAILED;
ret= EVEX_OPEN_TABLE_FAILED;
goto done;
}
@ -1165,15 +1253,15 @@ Event_timed::update_fields(THD *thd)
if (last_executed_changed)
{
table->field[EVEX_FIELD_LAST_EXECUTED]->set_notnull();
table->field[EVEX_FIELD_LAST_EXECUTED]->store_time(&last_executed,
MYSQL_TIMESTAMP_DATETIME);
table->field[Events::FIELD_LAST_EXECUTED]->set_notnull();
table->field[Events::FIELD_LAST_EXECUTED]->store_time(&last_executed,
MYSQL_TIMESTAMP_DATETIME);
last_executed_changed= false;
}
if (status_changed)
{
table->field[EVEX_FIELD_STATUS]->set_notnull();
table->field[EVEX_FIELD_STATUS]->store((longlong)status, true);
table->field[Events::FIELD_STATUS]->set_notnull();
table->field[Events::FIELD_STATUS]->store((longlong)status, true);
status_changed= false;
}
@ -1215,8 +1303,8 @@ Event_timed::get_create_event(THD *thd, String *buf)
DBUG_ENTER("get_create_event");
DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str));
if (expression &&
event_reconstruct_interval_expression(&expr_buf, interval, expression))
if (expression && Events::reconstruct_interval_expression(&expr_buf, interval,
expression))
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
buf->append(STRING_WITH_LEN("CREATE EVENT "));
@ -1243,12 +1331,12 @@ Event_timed::get_create_event(THD *thd, String *buf)
buf->append(STRING_WITH_LEN("'"));
}
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
if (on_completion == Event_timed::ON_COMPLETION_DROP)
buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
else
buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
if (status == MYSQL_EVENT_ENABLED)
if (status == Event_timed::ENABLED)
buf->append(STRING_WITH_LEN("ENABLE"));
else
buf->append(STRING_WITH_LEN("DISABLE"));
@ -1273,7 +1361,7 @@ Event_timed::get_create_event(THD *thd, String *buf)
thd THD
mem_root If != NULL use it to compile the event on it
RETURNS
RETURN VALUE
0 success
-99 No rights on this.dbname.str
-100 event in execution (parallel execution is impossible)
@ -1283,7 +1371,6 @@ Event_timed::get_create_event(THD *thd, String *buf)
int
Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
{
Security_context *save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
int ret= 0;
@ -1301,16 +1388,8 @@ Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
running= true;
VOID(pthread_mutex_unlock(&this->LOCK_running));
DBUG_PRINT("info", ("master_access=%d db_access=%d",
thd->security_ctx->master_access, thd->security_ctx->db_access));
change_security_context(thd, &security_ctx, &save_ctx);
DBUG_PRINT("info", ("master_access=%d db_access=%d",
thd->security_ctx->master_access, thd->security_ctx->db_access));
if (!sphead && (ret= compile(thd, mem_root)))
goto done;
/* Now we are sure we have valid this->sphead so we can copy the context */
sphead->m_security_ctx= security_ctx;
/*
THD::~THD will clean this or if there is DROP DATABASE in the SP then
it will be free there. It should not point to our buffer which is allocated
@ -1334,12 +1413,11 @@ Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
definer_host.str, dbname.str));
ret= -99;
}
restore_security_context(thd, save_ctx);
DBUG_PRINT("info", ("master_access=%d db_access=%d",
thd->security_ctx->master_access, thd->security_ctx->db_access));
VOID(pthread_mutex_lock(&this->LOCK_running));
running= false;
/* Will compile every time a new sp_head on different root */
free_sp();
VOID(pthread_mutex_unlock(&this->LOCK_running));
done:
@ -1361,55 +1439,16 @@ done:
/*
Switches the security context
Synopsis
Event_timed::change_security_context()
thd - thread
backup - where to store the old context
RETURN
0 - OK
1 - Error (generates error too)
*/
bool
Event_timed::change_security_context(THD *thd, Security_context *s_ctx,
Security_context **backup)
{
DBUG_ENTER("Event_timed::change_security_context");
DBUG_PRINT("info",("%s@%s@%s",definer_user.str,definer_host.str, dbname.str));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
s_ctx->init();
*backup= 0;
if (acl_getroot_no_password(s_ctx, definer_user.str, definer_host.str,
definer_host.str, dbname.str))
{
my_error(ER_NO_SUCH_USER, MYF(0), definer_user.str, definer_host.str);
DBUG_RETURN(true);
}
*backup= thd->security_ctx;
thd->security_ctx= s_ctx;
#endif
DBUG_RETURN(false);
}
/*
Restores the security context
Synopsis
Event_timed::restore_security_context()
thd - thread
backup - switch to this context
Frees the memory of the sp_head object we hold
SYNOPSIS
Event_timed::free_sp()
*/
void
Event_timed::restore_security_context(THD *thd, Security_context *backup)
Event_timed::free_sp()
{
DBUG_ENTER("Event_timed::restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup)
thd->security_ctx= backup;
#endif
DBUG_VOID_RETURN;
delete sphead;
sphead= 0;
}
@ -1445,6 +1484,9 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
CHARSET_INFO *old_character_set_client,
*old_collation_connection,
*old_character_set_results;
Security_context *save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
DBUG_ENTER("Event_timed::compile");
@ -1488,8 +1530,10 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
thd->query= show_create.c_ptr();
thd->query_length= show_create.length();
DBUG_PRINT("Event_timed::compile", ("query:%s",thd->query));
DBUG_PRINT("info", ("query:%s",thd->query));
change_security_context(thd, definer_user, definer_host, dbname,
&security_ctx, &save_ctx);
thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length);
lex.et_compile_phase= TRUE;
@ -1527,6 +1571,7 @@ done:
lex.et->deinit_mutexes();
lex_end(&lex);
restore_security_context(thd, save_ctx);
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
thd->lex= old_lex;
@ -1548,72 +1593,63 @@ done:
}
/*
Checks whether this thread can lock the object for modification ->
preventing being spawned for execution, and locks if possible.
use ::can_spawn_now() only for basic checking because a race
condition may occur between the check and eventual modification (deletion)
of the object.
Returns
true - locked
false - cannot lock
*/
my_bool
Event_timed::can_spawn_now_n_lock(THD *thd)
{
my_bool ret= FALSE;
VOID(pthread_mutex_lock(&this->LOCK_running));
if (!in_spawned_thread)
{
in_spawned_thread= TRUE;
ret= TRUE;
locked_by_thread_id= thd->thread_id;
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
extern pthread_attr_t connection_attrib;
/*
Checks whether is possible and forks a thread. Passes self as argument.
Returns
EVENT_EXEC_STARTED - OK
EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working
EVENT_EXEC_CANT_FORK - Unable to spawn thread (error)
RETURN VALUE
EVENT_EXEC_STARTED OK
EVENT_EXEC_ALREADY_EXEC Thread not forked, already working
EVENT_EXEC_CANT_FORK Unable to spawn thread (error)
*/
int
Event_timed::spawn_now(void * (*thread_func)(void*))
Event_timed::spawn_now(void * (*thread_func)(void*), void *arg)
{
THD *thd= current_thd;
int ret= EVENT_EXEC_STARTED;
static uint exec_num= 0;
DBUG_ENTER("Event_timed::spawn_now");
DBUG_PRINT("info", ("this=0x%lx", this));
DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str));
VOID(pthread_mutex_lock(&this->LOCK_running));
DBUG_PRINT("info", ("SCHEDULER: execute_at of %s is %lld", name.str,
TIME_to_ulonglong_datetime(&execute_at)));
mark_last_executed(thd);
if (compute_next_execution_time())
{
sql_print_error("SCHEDULER: Error while computing time of %s.%s . "
"Disabling after execution.", dbname.str, name.str);
status= DISABLED;
}
DBUG_PRINT("evex manager", ("[%10s] next exec at [%llu]", name.str,
TIME_to_ulonglong_datetime(&execute_at)));
/*
1. For one-time event : year is > 0 and expression is 0
2. For recurring, expression is != -=> check execute_at_null in this case
*/
if ((execute_at.year && !expression) || execute_at_null)
{
sql_print_information("SCHEDULER: [%s.%s of %s] no more executions "
"after this one", dbname.str, name.str,
definer.str);
flags |= EVENT_EXEC_NO_MORE | EVENT_FREE_WHEN_FINISHED;
}
update_fields(thd);
if (!in_spawned_thread)
{
pthread_t th;
in_spawned_thread= true;
if (pthread_create(&th, &connection_attrib, thread_func, (void*)this))
if (pthread_create(&th, &connection_attrib, thread_func, arg))
{
DBUG_PRINT("info", ("problem while spawning thread"));
ret= EVENT_EXEC_CANT_FORK;
in_spawned_thread= false;
}
#ifndef DBUG_OFF
else
{
sql_print_information("SCHEDULER: Started thread %d", ++exec_num);
DBUG_PRINT("info", ("thread spawned"));
}
#endif
}
else
{
@ -1626,55 +1662,207 @@ Event_timed::spawn_now(void * (*thread_func)(void*))
}
void
bool
Event_timed::spawn_thread_finish(THD *thd)
{
bool should_free;
DBUG_ENTER("Event_timed::spawn_thread_finish");
VOID(pthread_mutex_lock(&this->LOCK_running));
VOID(pthread_mutex_lock(&LOCK_running));
in_spawned_thread= false;
if ((flags & EVENT_EXEC_NO_MORE) || status == MYSQL_EVENT_DISABLED)
{
DBUG_PRINT("info", ("%s exec no more. to drop=%d", name.str, dropped));
if (dropped)
drop(thd);
VOID(pthread_mutex_unlock(&this->LOCK_running));
delete this;
DBUG_VOID_RETURN;
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
DBUG_VOID_RETURN;
DBUG_PRINT("info", ("Sending COND_finished for thread %d", thread_id));
thread_id= 0;
if (dropped)
drop(thd);
pthread_cond_broadcast(&COND_finished);
should_free= flags & EVENT_FREE_WHEN_FINISHED;
VOID(pthread_mutex_unlock(&LOCK_running));
DBUG_RETURN(should_free);
}
/*
Unlocks the object after it has been locked with ::can_spawn_now_n_lock()
Returns
0 - ok
1 - not locked by this thread
Kills a running event
SYNOPSIS
Event_timed::kill_thread()
RETURN VALUE
0 OK
-1 EVEX_CANT_KILL
!0 Error
*/
int
Event_timed::spawn_unlock(THD *thd)
Event_timed::kill_thread(THD *thd)
{
int ret= 0;
VOID(pthread_mutex_lock(&this->LOCK_running));
if (!in_spawned_thread)
DBUG_ENTER("Event_timed::kill_thread");
pthread_mutex_lock(&LOCK_running);
DBUG_PRINT("info", ("thread_id=%lu", thread_id));
if (thread_id == thd->thread_id)
{
if (locked_by_thread_id == thd->thread_id)
{
in_spawned_thread= FALSE;
locked_by_thread_id= 0;
}
else
{
sql_print_error("A thread tries to unlock when he hasn't locked. "
"thread_id=%ld locked by %ld",
thd->thread_id, locked_by_thread_id);
DBUG_ASSERT(0);
ret= 1;
}
/*
We don't kill ourselves in cases like :
alter event e_43 do alter event e_43 do set @a = 4 because
we will never receive COND_finished.
*/
DBUG_PRINT("info", ("It's not safe to kill ourselves in self altering queries"));
ret= EVEX_CANT_KILL;
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
else if (thread_id && !(ret= kill_one_thread(thd, thread_id, false)))
{
thd->enter_cond(&COND_finished, &LOCK_running, "Waiting for finished");
DBUG_PRINT("info", ("Waiting for COND_finished from thread %d", thread_id));
while (thread_id)
pthread_cond_wait(&COND_finished, &LOCK_running);
DBUG_PRINT("info", ("Got COND_finished"));
/* This will implicitly unlock LOCK_running. Hence we return before that */
thd->exit_cond("");
DBUG_RETURN(0);
}
else if (!thread_id && in_spawned_thread)
{
/*
Because the manager thread waits for the forked thread to update thread_id
this situation is impossible.
*/
DBUG_ASSERT(0);
}
pthread_mutex_unlock(&LOCK_running);
DBUG_PRINT("exit", ("%d", ret));
DBUG_RETURN(ret);
}
/*
Checks whether two events have the same name
SYNOPSIS
event_timed_name_equal()
RETURN VALUE
TRUE names are equal
FALSE names are not equal
*/
bool
event_timed_name_equal(Event_timed *et, LEX_STRING *name)
{
return !sortcmp_lex_string(et->name, *name, system_charset_info);
}
/*
Checks whether two events are in the same schema
SYNOPSIS
event_timed_db_equal()
RETURN VALUE
TRUE schemas are equal
FALSE schemas are not equal
*/
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db)
{
return !sortcmp_lex_string(et->dbname, *db, system_charset_info);
}
/*
Checks whether two events have the same definer
SYNOPSIS
event_timed_definer_equal()
Returns
TRUE definers are equal
FALSE definers are not equal
*/
bool
event_timed_definer_equal(Event_timed *et, LEX_STRING *definer)
{
return !sortcmp_lex_string(et->definer, *definer, system_charset_info);
}
/*
Checks whether two events are equal by identifiers
SYNOPSIS
event_timed_identifier_equal()
RETURN VALUE
TRUE equal
FALSE not equal
*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b)
{
return event_timed_name_equal(a, &b->name) &&
event_timed_db_equal(a, &b->dbname) &&
event_timed_definer_equal(a, &b->definer);
}
/*
Switches the security context
SYNOPSIS
change_security_context()
thd Thread
user The user
host The host of the user
db The schema for which the security_ctx will be loaded
s_ctx Security context to load state into
backup Where to store the old context
RETURN VALUE
0 - OK
1 - Error (generates error too)
*/
bool
change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup)
{
DBUG_ENTER("change_security_context");
DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
s_ctx->init();
*backup= 0;
if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str))
{
my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
DBUG_RETURN(TRUE);
}
*backup= thd->security_ctx;
thd->security_ctx= s_ctx;
#endif
DBUG_RETURN(FALSE);
}
/*
Restores the security context
SYNOPSIS
restore_security_context()
thd - thread
backup - switch to this context
*/
void
restore_security_context(THD *thd, Security_context *backup)
{
DBUG_ENTER("restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup)
thd->security_ctx= backup;
#endif
DBUG_VOID_RETURN;
}

View file

@ -453,6 +453,7 @@ static SYMBOL symbols[] = {
{ "RTREE", SYM(RTREE_SYM)},
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
{ "SCHEDULE", SYM(SCHEDULE_SYM)},
{ "SCHEDULER", SYM(SCHEDULER_SYM)},
{ "SCHEMA", SYM(DATABASE)},
{ "SCHEMAS", SYM(DATABASES)},
{ "SECOND", SYM(SECOND_SYM)},

View file

@ -55,6 +55,14 @@ static int binlog_commit(THD *thd, bool all);
static int binlog_rollback(THD *thd, bool all);
static int binlog_prepare(THD *thd, bool all);
sql_print_message_func sql_print_message_handlers[3] =
{
sql_print_information,
sql_print_warning,
sql_print_error
};
/*
This is a POD. Please keep it that way!

View file

@ -79,7 +79,8 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs,
uint32 max_res_length,
CHARSET_INFO *to_cs, uint32 *result_length);
void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
void sql_kill(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
@ -1378,10 +1379,13 @@ bool init_errmessage(void);
#endif /* MYSQL_SERVER */
void sql_perror(const char *message);
int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
void sql_print_error(const char *format, ...);
void sql_print_warning(const char *format, ...);
void sql_print_information(const char *format, ...);
typedef void (*sql_print_message_func)(const char *format, ...);
extern sql_print_message_func sql_print_message_handlers[];
/* type of the log table */
#define QUERY_LOG_SLOW 1

View file

@ -864,8 +864,8 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
/* We skip slave threads on this first loop through. */
if (tmp->slave_thread)
/* We skip slave threads & scheduler on this first loop through. */
if (tmp->slave_thread || tmp->system_thread == SYSTEM_THREAD_EVENT_SCHEDULER)
continue;
tmp->killed= THD::KILL_CONNECTION;
@ -884,6 +884,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::shutdown();
end_slave();
if (thread_count)
@ -1299,6 +1300,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
Events::destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
@ -2854,6 +2856,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
Events::init_mutexes();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@ -2999,7 +3002,6 @@ static int init_server_components()
#ifdef HAVE_REPLICATION
init_slave_list();
#endif
init_events();
/* Setup logs */
@ -3573,6 +3575,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl)
{
Events::init();
plugin_load();
#ifdef HAVE_DLOPEN
udf_init();
@ -3674,7 +3677,6 @@ we force server id to 2, but this MySQL server will not act as a slave.");
clean_up(1);
wait_for_signal_thread_to_end();
clean_up_mutexes();
shutdown_events();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(0);
@ -4665,7 +4667,7 @@ enum options_mysqld
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
OPT_HAVE_NAMED_PIPE,
OPT_DO_PSTACK, OPT_EVENT_EXECUTOR, OPT_REPORT_HOST,
OPT_DO_PSTACK, OPT_EVENT_SCHEDULER, OPT_REPORT_HOST,
OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
OPT_SHOW_SLAVE_AUTH_INFO,
OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
@ -4998,9 +5000,9 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &global_system_variables.engine_condition_pushdown,
(gptr*) &global_system_variables.engine_condition_pushdown,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"event-scheduler", OPT_EVENT_EXECUTOR, "Enable/disable the event scheduler.",
(gptr*) &opt_event_executor, (gptr*) &opt_event_executor, 0, GET_BOOL, NO_ARG,
0/*default*/, 0/*min-value*/, 1/*max-value*/, 0, 0, 0},
{"event-scheduler", OPT_EVENT_SCHEDULER, "Enable/disable the event scheduler.",
(gptr*) &Events::opt_event_scheduler, (gptr*) &Events::opt_event_scheduler, 0, GET_STR,
REQUIRED_ARG, 2/*default*/, 0/*min-value*/, 2/*max-value*/, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
@ -7327,6 +7329,24 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
}
#endif
case OPT_EVENT_SCHEDULER:
if (!argument)
Events::opt_event_scheduler= 2;
else
{
int type;
if ((type=find_type(argument, &Events::opt_typelib, 1)) <= 0)
{
fprintf(stderr,"Unknown option to event-scheduler: %s\n",argument);
exit(1);
}
/*
type= 1 2 3 4 5 6
(OFF | 0) - (ON | 1) - (2 | SUSPEND)
*/
Events::opt_event_scheduler= (type-1) / 2;
}
break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;

View file

@ -61,12 +61,13 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
static int init_failsafe_rpl_thread(THD* thd)
{
DBUG_ENTER("init_failsafe_rpl_thread");
thd->system_thread = SYSTEM_THREAD_DELAYED_INSERT;
/*
thd->bootstrap is to report errors barely to stderr; if this code is
enable again one day, one should check if bootstrap is still needed (maybe
this thread has no other error reporting method).
*/
thd->system_thread = thd->bootstrap = 1;
thd->bootstrap = 1;
thd->security_ctx->skip_grants();
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;

View file

@ -56,6 +56,8 @@
#include <thr_alarm.h>
#include <myisam.h>
#include "event_scheduler.h"
/* WITH_BERKELEY_STORAGE_ENGINE */
extern bool berkeley_shared_data;
extern ulong berkeley_max_lock, berkeley_log_buffer_size;
@ -106,7 +108,6 @@ extern ulong ndb_report_thresh_binlog_mem_usage;
extern my_bool event_executor_running_global_var;
static HASH system_variable_hash;
const char *bool_type_names[]= { "OFF", "ON", NullS };
@ -225,9 +226,8 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout",
&delayed_insert_timeout);
sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size",
&delayed_queue_size);
sys_var_event_executor sys_event_executor("event_scheduler",
(my_bool *)
&event_executor_running_global_var);
sys_var_event_scheduler sys_event_scheduler("event_scheduler");
sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
&expire_logs_days);
sys_var_bool_ptr sys_flush("flush", &myisam_flush);
@ -768,7 +768,7 @@ SHOW_VAR init_vars[]= {
{sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS},
{sys_engine_condition_pushdown.name,
(char*) &sys_engine_condition_pushdown, SHOW_SYS},
{sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS},
{sys_event_scheduler.name, (char*) &sys_event_scheduler, SHOW_SYS},
{sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS},
{sys_flush.name, (char*) &sys_flush, SHOW_SYS},
{sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS},
@ -3632,6 +3632,69 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
return (byte*) thd->strdup(buf);
}
/*
The update method of the global variable event_scheduler.
If event_scheduler is switched from 0 to 1 then the scheduler main
thread is resumed and if from 1 to 0 the scheduler thread is suspended
SYNOPSIS
sys_var_event_scheduler::update()
thd Thread context (unused)
var The new value
Returns
FALSE OK
TRUE Error
*/
bool
sys_var_event_scheduler::update(THD *thd, set_var *var)
{
enum Event_scheduler::enum_error_code res;
Event_scheduler *scheduler= Event_scheduler::get_instance();
/* here start the thread if not running. */
DBUG_ENTER("sys_var_event_scheduler::update");
DBUG_PRINT("new_value", ("%lu", (bool)var->save_result.ulong_value));
if (!scheduler->initialized())
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=0");
DBUG_RETURN(true);
}
if (var->save_result.ulonglong_value < 1 ||
var->save_result.ulonglong_value > 2)
{
char buf[64];
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "event_scheduler",
llstr(var->save_result.ulonglong_value, buf));
DBUG_RETURN(true);
}
if ((res= scheduler->suspend_or_resume(var->save_result.ulonglong_value == 1?
Event_scheduler::RESUME :
Event_scheduler::SUSPEND)))
my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), (uint) res);
DBUG_RETURN((bool) res);
}
byte *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
LEX_STRING *base)
{
Event_scheduler *scheduler= Event_scheduler::get_instance();
if (!scheduler->initialized())
thd->sys_var_tmp.long_value= 0;
else if (scheduler->get_state() == Event_scheduler::RUNNING)
thd->sys_var_tmp.long_value= 1;
else
thd->sys_var_tmp.long_value= 2;
return (byte*) &thd->sys_var_tmp;
}
/****************************************************************************
Used templates
****************************************************************************/

View file

@ -871,13 +871,14 @@ public:
};
class sys_var_event_executor :public sys_var_bool_ptr
class sys_var_event_scheduler :public sys_var_long_ptr
{
/* We need a derived class only to have a warn_deprecated() */
public:
sys_var_event_executor(const char *name_arg, my_bool *value_arg) :
sys_var_bool_ptr(name_arg, value_arg) {};
sys_var_event_scheduler(const char *name_arg) :
sys_var_long_ptr(name_arg, NULL, NULL) {};
bool update(THD *thd, set_var *var);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
extern void fix_binlog_format_after_update(THD *thd, enum_var_type type);

View file

@ -5042,7 +5042,7 @@ ER_OPTION_PREVENTS_STATEMENT
ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen"
por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando"
spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando"
swe "MySQL är startad med --skip-grant-tables. Pga av detta kan du inte använda detta kommando"
swe "MySQL är startad med %s. Pga av detta kan du inte använda detta kommando"
ER_DUPLICATED_VALUE_IN_TYPE
eng "Column '%-.100s' has duplicated value '%-.64s' in %s"
ger "Feld '%-.100s' hat doppelten Wert '%-.64s' in %s"
@ -5842,3 +5842,7 @@ ER_WRONG_PARTITION_NAME
swe "Felaktigt partitionsnamn"
ER_CANT_CHANGE_TX_ISOLATION 25001
eng "Transaction isolation level can't be changed while a transaction is in progress"
ER_EVENT_MODIFY_QUEUE_ERROR
eng "Internal scheduler error %d"
ER_EVENT_SET_VAR_ERROR
eng "Error during starting/stopping of the scheduler. Error code %u"

View file

@ -253,7 +253,8 @@ THD::THD()
net.last_error[0]=0; // If error on boot
net.query_cache_query=0; // If error on boot
ull=0;
system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
system_thread= NON_SYSTEM_THREAD;
cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST
#ifdef HAVE_ROW_BASED_REPLICATION
transaction.m_pending_rows_event= 0;
@ -512,6 +513,8 @@ void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
void THD::awake(THD::killed_state state_to_set)
{
DBUG_ENTER("THD::awake");
DBUG_PRINT("enter", ("this=0x%lx", this));
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
@ -555,6 +558,7 @@ void THD::awake(THD::killed_state state_to_set)
}
pthread_mutex_unlock(&mysys_var->mutex);
}
DBUG_VOID_RETURN;
}
/*
@ -2031,6 +2035,13 @@ void Security_context::skip_grants()
}
bool Security_context::set_user(char *user_arg)
{
safeFree(user);
user= my_strdup(user_arg, MYF(0));
return user == 0;
}
/****************************************************************************
Handling of open and locked tables states.

View file

@ -629,6 +629,8 @@ public:
{
return (*priv_host ? priv_host : (char *)"%");
}
bool set_user(char *user_arg);
};
@ -770,6 +772,19 @@ public:
};
/* Flags for the THD::system_thread variable */
enum enum_thread_type
{
NON_SYSTEM_THREAD= 0,
SYSTEM_THREAD_DELAYED_INSERT= 1,
SYSTEM_THREAD_SLAVE_IO= 2,
SYSTEM_THREAD_SLAVE_SQL= 4,
SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
SYSTEM_THREAD_EVENT_SCHEDULER= 16,
SYSTEM_THREAD_EVENT_WORKER= 32
};
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@ -1103,7 +1118,8 @@ public:
long dbug_thread_id;
pthread_t real_id;
uint tmp_table, global_read_lock;
uint server_status,open_options,system_thread;
uint server_status,open_options;
enum enum_thread_type system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
@ -1404,11 +1420,6 @@ public:
#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;}
/* Flags for the THD::system_thread (bitmap) variable */
#define SYSTEM_THREAD_DELAYED_INSERT 1
#define SYSTEM_THREAD_SLAVE_IO 2
#define SYSTEM_THREAD_SLAVE_SQL 4
#define SYSTEM_THREAD_NDBCLUSTER_BINLOG 8
/*
Used to hold information about file and file structure in exchainge

View file

@ -871,7 +871,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
(void)evex_drop_db_events(thd, db); /* QQ Ignore errors for now */
error= Events::drop_schema_events(thd, db);
start_waiting_global_read_lock(thd);
/*
If this database was the client's selected database, we silently change the

View file

@ -40,3 +40,5 @@ void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
uint code, const char *format, ...);
void mysql_reset_errors(THD *thd, bool force);
bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
extern LEX_STRING warning_level_names[];

View file

@ -111,7 +111,8 @@ enum enum_sql_command {
SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
SQLCOM_SHOW_PLUGINS,
SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
SQLCOM_SHOW_SCHEDULER_STATUS,
/* This should be the last !!! */

View file

@ -2049,7 +2049,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id,false);
sql_kill(thd,id,false);
break;
}
case COM_SET_OPTION:
@ -3836,14 +3836,17 @@ end_with_restore_list:
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= evex_create_event(thd, lex->et, (uint) lex->create_info.options,
&rows_affected);
res= Events::create_event(thd, lex->et,
(uint) lex->create_info.options,
&rows_affected);
break;
case SQLCOM_ALTER_EVENT:
res= evex_update_event(thd, lex->et, lex->spname, &rows_affected);
res= Events::update_event(thd, lex->et, lex->spname,
&rows_affected);
break;
case SQLCOM_DROP_EVENT:
res= evex_drop_event(thd, lex->et, lex->drop_if_exists, &rows_affected);
res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
&rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
@ -3881,9 +3884,16 @@ end_with_restore_list:
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
goto error;
}
res= evex_show_create_event(thd, lex->spname, lex->et->definer);
res= Events::show_create_event(thd, lex->spname, lex->et->definer);
break;
}
#ifndef DBUG_OFF
case SQLCOM_SHOW_SCHEDULER_STATUS:
{
res= Events::dump_internal_status(thd);
break;
}
#endif
case SQLCOM_CREATE_FUNCTION: // UDF function
{
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
@ -4123,7 +4133,7 @@ end_with_restore_list:
MYF(0));
goto error;
}
kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
break;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@ -6917,22 +6927,26 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
return result;
}
/*
kill on thread
kills a thread
SYNOPSIS
kill_one_thread()
thd Thread class
id Thread id
only_kill_query Should it kill the query or the connection
NOTES
This is written such that we have a short lock on LOCK_thread_count
*/
void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
DBUG_ENTER("kill_one_thread");
DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
@ -6958,8 +6972,25 @@ void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
error=ER_KILL_DENIED_ERROR;
pthread_mutex_unlock(&tmp->LOCK_delete);
}
DBUG_PRINT("exit", ("%d", error));
DBUG_RETURN(error);
}
if (!error)
/*
kills a thread and sends response
SYNOPSIS
sql_kill()
thd Thread class
id Thread id
only_kill_query Should it kill the query or the connection
*/
void sql_kill(THD *thd, ulong id, bool only_kill_query)
{
uint error;
if (!(error= kill_one_thread(thd, id, only_kill_query)))
send_ok(thd);
else
my_error(error, MYF(0), id);

View file

@ -4063,8 +4063,9 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
/* type */
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
if (event_reconstruct_interval_expression(&show_str, et.interval,
et.expression))
if (Events::reconstruct_interval_expression(&show_str,
et.interval,
et.expression))
DBUG_RETURN(1);
sch_table->field[7]->set_notnull();
@ -4094,13 +4095,13 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
}
//status
if (et.status == MYSQL_EVENT_ENABLED)
if (et.status == Event_timed::ENABLED)
sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs);
else
sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs);
//on_completion
if (et.on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
if (et.on_completion == Event_timed::ON_COMPLETION_DROP)
sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs);
else
sch_table->field[13]->store(STRING_WITH_LEN("PRESERVE"), scs);
@ -4152,7 +4153,7 @@ int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond)
thd->reset_n_backup_open_tables_state(&backup);
if ((ret= evex_open_event_table(thd, TL_READ, &event_table)))
if ((ret= Events::open_event_table(thd, TL_READ, &event_table)))
{
sql_print_error("Table mysql.event is damaged.");
ret= 1;
@ -4161,13 +4162,10 @@ int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond)
event_table->file->ha_index_init(0, 1);
/*
see others' events only if you have PROCESS_ACL !!
thd->lex->verbose is set either if SHOW FULL EVENTS or
in case of SELECT FROM I_S.EVENTS
*/
verbose= (thd->lex->verbose
&& (thd->security_ctx->master_access & PROCESS_ACL));
/* see others' events only if you have PROCESS_ACL !! */
verbose= ((thd->lex->verbose ||
thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS) &&
(thd->security_ctx->master_access & PROCESS_ACL));
if (verbose && thd->security_ctx->user)
{
@ -4176,12 +4174,13 @@ int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond)
}
else
{
event_table->field[EVEX_FIELD_DEFINER]->store(definer, strlen(definer), scs);
event_table->field[Events::FIELD_DEFINER]->
store(definer, strlen(definer), scs);
key_len= event_table->key_info->key_part[0].store_length;
if (thd->lex->select_lex.db)
{
event_table->field[EVEX_FIELD_DB]->
event_table->field[Events::FIELD_DB]->
store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
key_len+= event_table->key_info->key_part[1].store_length;
}

View file

@ -568,6 +568,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token RTREE_SYM
%token SAVEPOINT_SYM
%token SCHEDULE_SYM
%token SCHEDULER_SYM
%token SECOND_MICROSECOND_SYM
%token SECOND_SYM
%token SECURITY_SYM
@ -1401,7 +1402,7 @@ opt_ev_status: /* empty */ { $$= 0; }
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->status= MYSQL_EVENT_ENABLED;
lex->et->status= Event_timed::ENABLED;
$$= 1;
}
| DISABLE_SYM
@ -1409,7 +1410,7 @@ opt_ev_status: /* empty */ { $$= 0; }
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->status= MYSQL_EVENT_DISABLED;
lex->et->status= Event_timed::DISABLED;
$$= 1;
}
;
@ -1473,14 +1474,14 @@ ev_on_completion:
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->on_completion= MYSQL_EVENT_ON_COMPLETION_PRESERVE;
lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
$$= 1;
}
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
{
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->on_completion= MYSQL_EVENT_ON_COMPLETION_DROP;
lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
$$= 1;
}
;
@ -8067,15 +8068,24 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
YYABORT;
}
| opt_full EVENTS_SYM opt_db wild_and_where
| EVENTS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_EVENTS;
lex->select_lex.db= $3;
lex->select_lex.db= $2;
if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
YYABORT;
}
| SCHEDULER_SYM STATUS_SYM
{
#ifndef DBUG_OFF
Lex->sql_command= SQLCOM_SHOW_SCHEDULER_STATUS;
#else
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
#endif
}
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
@ -9512,6 +9522,7 @@ keyword_sp:
| ROW_SYM {}
| RTREE_SYM {}
| SCHEDULE_SYM {}
| SCHEDULER_SYM {}
| SECOND_SYM {}
| SERIAL_SYM {}
| SERIALIZABLE_SYM {}

View file

@ -2401,9 +2401,7 @@ table_check_intact(TABLE *table, uint table_f_count,
table running on a old server will be valid.
*/
field->sql_type(sql_type);
if (sql_type.length() < table_def->type.length - 1 ||
strncmp(sql_type.ptr(),
table_def->type.str,
if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
table_def->type.length - 1))
{
sql_print_error("(%s) Expected field %s at position %d to have type "

View file

@ -849,16 +849,6 @@ extern "C" {
enum ndb_mgm_event_category category,
int level,
struct ndb_mgm_reply* reply);
/**
* Returns the port number where statistics information is sent
*
* @param handle NDB management handle.
* @param reply Reply message.
* @return -1 on error.
*/
int ndb_mgm_get_stat_port(NdbMgmHandle handle,
struct ndb_mgm_reply* reply);
#endif
/**

View file

@ -48,58 +48,66 @@ read_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
extern "C"
int
readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
char * buf, int buflen){
if(buflen <= 1)
return 0;
int sock_flags= fcntl(socket, F_GETFL);
if(fcntl(socket, F_SETFL, sock_flags | O_NONBLOCK) == -1)
return -1;
fd_set readset;
FD_ZERO(&readset);
FD_SET(socket, &readset);
struct timeval timeout;
timeout.tv_sec = (timeout_millis / 1000);
timeout.tv_usec = (timeout_millis % 1000) * 1000;
const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
if(selectRes == 0)
if(selectRes == 0){
return 0;
}
if(selectRes == -1){
fcntl(socket, F_SETFL, sock_flags);
return -1;
}
int pos = 0; buf[pos] = 0;
while(true){
const int t = recv(socket, &buf[pos], 1, 0);
if(t != 1){
return -1;
}
if(buf[pos] == '\n'){
buf[pos] = 0;
if(pos > 0 && buf[pos-1] == '\r'){
pos--;
buf[pos] = 0;
buf[0] = 0;
const int t = recv(socket, buf, buflen, MSG_PEEK);
if(t < 1)
{
fcntl(socket, F_SETFL, sock_flags);
return -1;
}
for(int i=0; i< t;i++)
{
if(buf[i] == '\n'){
recv(socket, buf, i+1, 0);
buf[i] = 0;
if(i > 0 && buf[i-1] == '\r'){
i--;
buf[i] = 0;
}
return pos;
}
pos++;
if(pos == (buflen - 1)){
buf[pos] = 0;
return buflen;
}
FD_ZERO(&readset);
FD_SET(socket, &readset);
timeout.tv_sec = (timeout_millis / 1000);
timeout.tv_usec = (timeout_millis % 1000) * 1000;
const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
if(selectRes != 1){
return -1;
fcntl(socket, F_SETFL, sock_flags);
return t;
}
}
if(t == (buflen - 1)){
recv(socket, buf, t, 0);
buf[t] = 0;
fcntl(socket, F_SETFL, sock_flags);
return buflen;
}
return 0;
}
extern "C"

View file

@ -827,7 +827,7 @@ void Qmgr::execCM_REGCONF(Signal* signal)
ptrCheckGuard(myNodePtr, MAX_NDB_NODES, nodeRec);
ndbrequire(c_start.m_gsn == GSN_CM_REGREQ);
ndbrequire(myNodePtr.p->phase = ZSTARTING);
ndbrequire(myNodePtr.p->phase == ZSTARTING);
cpdistref = cmRegConf->presidentBlockRef;
cpresident = cmRegConf->presidentNodeId;

View file

@ -49,7 +49,9 @@ extern EventLogger g_eventLogger;
enum ndbd_options {
OPT_INITIAL = NDB_STD_OPTIONS_LAST,
OPT_NODAEMON,
OPT_FOREGROUND
OPT_FOREGROUND,
OPT_NOWAIT_NODES,
OPT_INITIAL_START
};
NDB_STD_OPTS_VARS;
@ -88,11 +90,11 @@ static struct my_option my_long_options[] =
" (implies --nodaemon)",
(gptr*) &_foreground, (gptr*) &_foreground, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "nowait-nodes", NO_ARG,
{ "nowait-nodes", OPT_NOWAIT_NODES,
"Nodes that will not be waited for during start",
(gptr*) &_nowait_nodes, (gptr*) &_nowait_nodes, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "initial-start", NO_ARG,
{ "initial-start", OPT_INITIAL_START,
"Perform initial start",
(gptr*) &_initialstart, (gptr*) &_initialstart, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },

View file

@ -1306,33 +1306,6 @@ ndb_mgm_listen_event(NdbMgmHandle handle, const int filter[])
return ndb_mgm_listen_event_internal(handle,filter,0);
}
extern "C"
int
ndb_mgm_get_stat_port(NdbMgmHandle handle, struct ndb_mgm_reply* /*reply*/)
{
SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_stat_port");
const ParserRow<ParserDummy> stat_reply[] = {
MGM_CMD("error", NULL, ""),
MGM_ARG("result", String, Mandatory, "Error message"),
MGM_CMD("get statport reply", NULL, ""),
MGM_ARG("tcpport", Int, Mandatory, "TCP port for statistics"),
MGM_END()
};
CHECK_HANDLE(handle, -1);
CHECK_CONNECTED(handle, -1);
Properties args;
const Properties *reply;
reply = ndb_mgm_call(handle, stat_reply, "get statport", &args);
CHECK_REPLY(reply, -1);
Uint32 port;
reply->get("tcpport", &port);
delete reply;
return port;
}
extern "C"
int
ndb_mgm_dump_state(NdbMgmHandle handle, int nodeId, int* _args,

View file

@ -121,8 +121,6 @@ static const unsigned int MAX_WRITE_TIMEOUT = 100 ;
const
ParserRow<MgmApiSession> commands[] = {
MGM_CMD("get statport", &MgmApiSession::getStatPort, ""),
MGM_CMD("get config", &MgmApiSession::getConfig, ""),
MGM_ARG("version", Int, Mandatory, "Configuration version number"),
MGM_ARG("node", Int, Optional, "Node ID"),
@ -649,15 +647,6 @@ MgmApiSession::getConfig_common(Parser_t::Context &,
return;
}
void
MgmApiSession::getStatPort(Parser_t::Context &,
const class Properties &) {
m_output->println("get statport reply");
m_output->println("tcpport: %d", 0);
m_output->println("");
}
void
MgmApiSession::insertError(Parser<MgmApiSession>::Context &,
Properties const &args) {

View file

@ -53,7 +53,6 @@ public:
virtual ~MgmApiSession();
void runSession();
void getStatPort(Parser_t::Context &ctx, const class Properties &args);
void getConfig(Parser_t::Context &ctx, const class Properties &args);
#ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT
void getConfig_old(Parser_t::Context &ctx);