diff --git a/.bzrignore b/.bzrignore
index 095c04b36eeef000183e08348613cd06b4007da1..57fcbdd8f737cd5f4ea089cfc36c187cbac9e08f 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1770,3 +1770,4 @@ vio/viotest-sslconnect.cpp
 vio/viotest.cpp
 zlib/*.ds?
 zlib/*.vcproj
+libmysqld/event_scheduler.cc
diff --git a/client/get_password.c b/client/get_password.c
index 1b7b4e65a9ff25b287784814fc68eadcadfafae5..b643b760718c953c5430f2a67599cdd4bff2189d 100644
--- a/client/get_password.c
+++ b/client/get_password.c
@@ -64,7 +64,7 @@
 /* were just going to fake it here and get input from
    the keyboard */
 
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
 {
   char to[80];
   char *pos=to,*end=to+sizeof(to)-1;
@@ -150,7 +150,7 @@ static void get_password(char *to,uint length,int fd,bool echo)
 #endif /* ! HAVE_GETPASS */
 
 
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
 {
 #ifdef HAVE_GETPASS
   char *passbuff;
diff --git a/configure.in b/configure.in
index 64886892e2efa1ffe86d6d84298b27b8b85572df..0f0649fd3bcc53227b94ab08556cb57e144baa16 100644
--- a/configure.in
+++ b/configure.in
@@ -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
diff --git a/extra/yassl/examples/echoserver/echoserver.cpp b/extra/yassl/examples/echoserver/echoserver.cpp
index 3243cc21a7cfa532ccfae039202bebbe75a6ab67..8e23ead20aba31b6d469eeccb64423a6ae7695c8 100644
--- a/extra/yassl/examples/echoserver/echoserver.cpp
+++ b/extra/yassl/examples/echoserver/echoserver.cpp
@@ -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);
diff --git a/extra/yassl/include/openssl/ssl.h b/extra/yassl/include/openssl/ssl.h
index a7eca9138a29fba8e54cf964a062033cb8cc04b2..23e48d2011f287275b5c304d88b1a6af824aacf0 100644
--- a/extra/yassl/include/openssl/ssl.h
+++ b/extra/yassl/include/openssl/ssl.h
@@ -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*);
diff --git a/extra/yassl/include/socket_wrapper.hpp b/extra/yassl/include/socket_wrapper.hpp
index d2258a937237df6f7d6f2a2e2920b4ede8b19f87..16db142b3a2d92ac3ee918b4c5c7ca513af695ea 100644
--- a/extra/yassl/include/socket_wrapper.hpp
+++ b/extra/yassl/include/socket_wrapper.hpp
@@ -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);
diff --git a/extra/yassl/mySTL/stdexcept.hpp b/extra/yassl/mySTL/stdexcept.hpp
index 33ea43bf0e068e81609a7c2a5b244f57ef594c39..b50dd35edae495493c5e83a72fdf041700ba0186 100644
--- a/extra/yassl/mySTL/stdexcept.hpp
+++ b/extra/yassl/mySTL/stdexcept.hpp
@@ -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
 };
 
 
diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp
index 2603365e41ae59bb5c6e428c7cf44356a5fd388e..2b099af930cf4bc41e90a709175066b859acb5b3 100644
--- a/extra/yassl/src/handshake.cpp
+++ b/extra/yassl/src/handshake.cpp
@@ -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(); 
 }
 
diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp
index c6611803421720e0c5b41a629b04a5dc802d7176..803f4b01249749ad51551cf692e985125092dad4 100644
--- a/extra/yassl/src/socket_wrapper.cpp
+++ b/extra/yassl/src/socket_wrapper.cpp
@@ -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
diff --git a/extra/yassl/src/ssl.cpp b/extra/yassl/src/ssl.cpp
index 66196514a876284f1fd6698e7795fd4abc9632ea..747305730dfb232dbf14bb1f7c16b0a9b20b504d 100644
--- a/extra/yassl/src/ssl.cpp
+++ b/extra/yassl/src/ssl.cpp
@@ -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);
 }
 
 
diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp
index 43b80d59a4d7b88d44e7ba937cf8d2637e9129d5..134deb00c756ea572baacb9dc6eda3ea661b435b 100644
--- a/extra/yassl/src/template_instnt.cpp
+++ b/extra/yassl/src/template_instnt.cpp
@@ -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
diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp
index 4fe0d3aa4f9c33138cd7d137080da6f827a1814e..8b7d2d17a84f2e81550b3fe5abb44b0ca54445e6 100644
--- a/extra/yassl/src/timer.cpp
+++ b/extra/yassl/src/timer.cpp
@@ -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;
diff --git a/extra/yassl/src/yassl_error.cpp b/extra/yassl/src/yassl_error.cpp
index 59113d7438c4cb3ad8877432454c8fc35ba9ed66..1973c54d781a7a3baadc67b36aa7951d3a0ba5ba 100644
--- a/extra/yassl/src/yassl_error.cpp
+++ b/extra/yassl/src/yassl_error.cpp
@@ -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);
diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp
index f7fb1abfa3f97b2906837d90e55fa157c907374b..a715d32f282048aa135fb66a35a573ea48067edf 100644
--- a/extra/yassl/src/yassl_int.cpp
+++ b/extra/yassl/src/yassl_int.cpp
@@ -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);
diff --git a/extra/yassl/taocrypt/CMakeLists.txt b/extra/yassl/taocrypt/CMakeLists.txt
index 3ad9195b3727d1738def0cc4a0273bb9e8e2710a..0af0a242e5d3e3e8b4615e32d30f6af89a153f0e 100644
--- a/extra/yassl/taocrypt/CMakeLists.txt
+++ b/extra/yassl/taocrypt/CMakeLists.txt
@@ -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 
diff --git a/extra/yassl/taocrypt/include/block.hpp b/extra/yassl/taocrypt/include/block.hpp
index 4c262e1a5401cf35931c850258e4376a63e284ab..76836615ce63c33a46324ecd50cb32485eaa9464 100644
--- a/extra/yassl/taocrypt/include/block.hpp
+++ b/extra/yassl/taocrypt/include/block.hpp
@@ -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];
diff --git a/extra/yassl/taocrypt/include/md4.hpp b/extra/yassl/taocrypt/include/md4.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..aac930d74988daee24c476a3fc3eaed0b44b62a8
--- /dev/null
+++ b/extra/yassl/taocrypt/include/md4.hpp
@@ -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
+
diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp
index 09ca7524ef356a288f9e1ddfbaa2fb9456aa5630..3a5cf62865af0fd9edecf86ebb531ad18157e96c 100644
--- a/extra/yassl/taocrypt/include/runtime.hpp
+++ b/extra/yassl/taocrypt/include/runtime.hpp
@@ -28,10 +28,6 @@
 #ifndef yaSSL_NEW_HPP
 #define yaSSL_NEW_HPP
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 
 #ifdef __sun
  
diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am
index d3e72346110c4b853b91365030290bcf084a02f7..1110ed335b8e9bf2a0ab31a3c050389baf6c6b83 100644
--- a/extra/yassl/taocrypt/src/Makefile.am
+++ b/extra/yassl/taocrypt/src/Makefile.am
@@ -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
 
diff --git a/extra/yassl/taocrypt/src/md4.cpp b/extra/yassl/taocrypt/src/md4.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dfc2b079141411d7bd998e5ab1784399c5818b19
--- /dev/null
+++ b/extra/yassl/taocrypt/src/md4.cpp
@@ -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
+
diff --git a/extra/yassl/taocrypt/src/template_instnt.cpp b/extra/yassl/taocrypt/src/template_instnt.cpp
index 5efd2d32a10387ff2bed5abb1aa06d87ea40cfed..12bcd8238f293318ea5bbd7616f00cc588bcb6b0 100644
--- a/extra/yassl/taocrypt/src/template_instnt.cpp
+++ b/extra/yassl/taocrypt/src/template_instnt.cpp
@@ -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 {
diff --git a/extra/yassl/taocrypt/taocrypt.dsp b/extra/yassl/taocrypt/taocrypt.dsp
index b741cef009616cb0844e94778b874440153fb143..19edf7b2f22dbf6288a1f257986d6d447f722ae7 100644
--- a/extra/yassl/taocrypt/taocrypt.dsp
+++ b/extra/yassl/taocrypt/taocrypt.dsp
@@ -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
diff --git a/extra/yassl/taocrypt/test/test.cpp b/extra/yassl/taocrypt/test/test.cpp
index b8618b18d473571a9674a60cee92bd4fa95eeace..28ef73dfac8f20b5e658da4a9f982ee8c4289a3b 100644
--- a/extra/yassl/taocrypt/test/test.cpp
+++ b/extra/yassl/taocrypt/test/test.cpp
@@ -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;
diff --git a/extra/yassl/testsuite/test.hpp b/extra/yassl/testsuite/test.hpp
index 259975fba0b3f87472c512fac5710a1caf0bdaac..c80e3ad23da536d37f0afda76d658f6cb98469e4 100644
--- a/extra/yassl/testsuite/test.hpp
+++ b/extra/yassl/testsuite/test.hpp
@@ -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
 
 
diff --git a/include/m_string.h b/include/m_string.h
index ce34c303c22099c44df04712c27c223c22960c7c..9f7ec220f2c5b211ab9e82746272bb4202ed6a13 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -240,4 +240,22 @@ extern int my_snprintf(char* to, size_t n, const char* fmt, ...);
 #if defined(__cplusplus)
 }
 #endif
+
+/*
+  LEX_STRING -- a pair of a C-string and its length.
+
+  NOTE: this exactly form of declaration is required for some C-compilers
+  (for one, Sun C 5.7 2005/01/07). Unfortunatelt with such declaration
+  LEX_STRING can not be forward declared.
+*/
+
+typedef struct
+{
+  char *str;
+  uint length;
+} LEX_STRING;
+
+#define STRING_WITH_LEN(X) (X), ((uint) (sizeof(X) - 1))
+#define C_STRING_WITH_SIZE(X) ((char *) (X)), ((uint) (sizeof(X) - 1))
+
 #endif
diff --git a/include/my_sys.h b/include/my_sys.h
index 3a4895f5dc5b0decec32c42996b53a9c4faba2a2..5024505a8219ec5a4c8c3b242a8da1b98ad52145 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -77,6 +77,10 @@ extern int NEAR my_errno;		/* Last error in mysys */
 #define MY_GIVE_INFO	2	/* Give time info about process*/
 #define MY_DONT_FREE_DBUG 4     /* Do not call DBUG_END() in my_end() */
 
+#define MY_REMOVE_NONE    0     /* Params for modify_defaults_file */
+#define MY_REMOVE_OPTION  1
+#define MY_REMOVE_SECTION 2
+
 #define ME_HIGHBYTE	8	/* Shift for colours */
 #define ME_NOCUR	1	/* Don't use curses message */
 #define ME_OLDWIN	2	/* Use old window */
diff --git a/include/mysql_com.h b/include/mysql_com.h
index 2af0fb869060c769fbc6c3029f629ac14ea13317..bff5fcc47d24a5a186d264588911a8f1b2a1bea7 100644
--- a/include/mysql_com.h
+++ b/include/mysql_com.h
@@ -423,17 +423,11 @@ char *octet2hex(char *to, const char *str, unsigned int len);
 
 /* end of password.c */
 
-char *get_tty_password(char *opt_message);
+char *get_tty_password(const char *opt_message);
 const char *mysql_errno_to_sqlstate(unsigned int mysql_errno);
 
 /* Some other useful functions */
 
-my_bool my_init(void);
-extern int modify_defaults_file(const char *file_location, const char *option,
-                                const char *option_value,
-                                const char *section_name, int remove_option);
-int load_defaults(const char *conf_file, const char **groups,
-		  int *argc, char ***argv);
 my_bool my_thread_init(void);
 void my_thread_end(void);
 
diff --git a/libmysql/get_password.c b/libmysql/get_password.c
index a48cb6d7a6ec3e4455ad2e959fc63eb0878447b3..4c251677a6615aa78e13a7e763c998324e7cf34c 100644
--- a/libmysql/get_password.c
+++ b/libmysql/get_password.c
@@ -75,7 +75,7 @@
 #define _cputs(A) putstring(A)
 #endif
 
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
 {
   char to[80];
   char *pos=to,*end=to+sizeof(to)-1;
@@ -159,7 +159,7 @@ static void get_password(char *to,uint length,int fd,bool echo)
 #endif /* ! HAVE_GETPASS */
 
 
-char *get_tty_password(char *opt_message)
+char *get_tty_password(const char *opt_message)
 {
 #ifdef HAVE_GETPASS
   char *passbuff;
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index 8d1591282db13f7d637cdd87d838fb4215a5565b..a3af2d43bd5283b9a4ff6a1f5484ff10abdf8bd0 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -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
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 0591c24e914c6bf6a0789ad5ab5b7d471c767ab8..8923c032dffa0c816bbc44c6aa376b6e56e9a74f 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -1220,9 +1220,12 @@ sub environment_setup () {
   $ENV{'NDBCLUSTER_PORT_SLAVE'}=$opt_ndbcluster_port_slave;
   $ENV{'NDB_STATUS_OK'}=      "YES";
 
+  $ENV{'IM_EXE'}=             $exe_im;
   $ENV{'IM_PATH_PID'}=        $instance_manager->{path_pid};
   $ENV{'IM_PATH_ANGEL_PID'}=  $instance_manager->{path_angel_pid};
   $ENV{'IM_PORT'}=            $instance_manager->{port};
+  $ENV{'IM_DEFAULTS_PATH'}=   $instance_manager->{defaults_file};
+  $ENV{'IM_PASSWORD_PATH'}=   $instance_manager->{password_file};
 
   $ENV{'IM_MYSQLD1_SOCK'}=    $instance_manager->{instances}->[0]->{path_sock};
   $ENV{'IM_MYSQLD1_PORT'}=    $instance_manager->{instances}->[0]->{port};
diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result
index 01d206be7cb570de5a2542ae485b1c656135ff68..d02a2af3c9fa790dcf4db47b351648a195ebe990 100644
--- a/mysql-test/r/events.result
+++ b/mysql-test/r/events.result
@@ -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';
diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result
index ef1ccfadecb35b36fed68a8a116710374d86fc53..bc89c692f9ab682e9e9503c0807ee34d05ec6aa8 100644
--- a/mysql-test/r/events_bugs.result
+++ b/mysql-test/r/events_bugs.result
@@ -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;
diff --git a/mysql-test/r/events_logs_tests.result b/mysql-test/r/events_logs_tests.result
index ab1666fefb98cb1be939768929c3d93d36e26766..911bc8b2d600a7d829f459b856a065f929fef63a 100644
--- a/mysql-test/r/events_logs_tests.result
+++ b/mysql-test/r/events_logs_tests.result
@@ -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;
diff --git a/mysql-test/r/events_microsec.result b/mysql-test/r/events_microsec.result
index ed15b066b9362f794111228d7eaafd97e7403afd..b96bd55151150ccdce58c24629ce291ec7cfbe45 100644
--- a/mysql-test/r/events_microsec.result
+++ b/mysql-test/r/events_microsec.result
@@ -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;
diff --git a/mysql-test/r/events_scheduling.result b/mysql-test/r/events_scheduling.result
index 8b1f29d320fe522d735da8ee315c2e5be60282be..aec2053f0e721aedf1b76871568492dfb9a35508 100644
--- a/mysql-test/r/events_scheduling.result
+++ b/mysql-test/r/events_scheduling.result
@@ -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;
diff --git a/mysql-test/r/events_stress.result b/mysql-test/r/events_stress.result
index 9f95cfad75d8d21849469358f116e930b1c95f3b..ead618e8136785847907263f01241fd32dc5e7d3 100644
--- a/mysql-test/r/events_stress.result
+++ b/mysql-test/r/events_stress.result
@@ -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(*)
+103
+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
+50
 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';
+CREATE DATABASE events_conn1_test3;
+USE events_conn1_test3;
+SET GLOBAL event_scheduler=1;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_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';
+50
+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(*)
-1050
-DROP DATABASE events_test2;
-SET GLOBAL event_scheduler=0;
-DROP DATABASE events_test3;
-SET GLOBAL event_scheduler=1;
-DROP DATABASE events_test4;
+50
+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;
diff --git a/mysql-test/r/im_cmd_line.result b/mysql-test/r/im_cmd_line.result
new file mode 100644
index 0000000000000000000000000000000000000000..5b289549a3fb4fe8ae6da0a4566f37add88b8997
--- /dev/null
+++ b/mysql-test/r/im_cmd_line.result
@@ -0,0 +1,40 @@
+--> Listing users...
+im_admin
+
+==> Adding user 'testuser'...
+
+--> IM password file:
+testuser:*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
+im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
+--> EOF
+
+--> Printing out line for 'testuser'...
+testuser:*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
+
+--> Listing users...
+im_admin
+testuser
+
+==> Changing the password of 'testuser'...
+
+--> IM password file:
+im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
+testuser:*39C549BDECFBA8AFC3CE6B948C9359A0ECE08DE2
+--> EOF
+
+--> Printing out line for 'testuser'...
+testuser:*39C549BDECFBA8AFC3CE6B948C9359A0ECE08DE2
+
+--> Listing users...
+testuser
+im_admin
+
+==> Dropping user 'testuser'...
+
+--> IM password file:
+im_admin:*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295
+--> EOF
+
+--> Listing users...
+im_admin
+
diff --git a/mysql-test/r/im_daemon_life_cycle.result b/mysql-test/r/im_daemon_life_cycle.result
index d0a76b450feca44c532960056f625ac1992a8489..29c9ea2047d9a8cf00e0298bfa4cf8ba42d8e56e 100644
--- a/mysql-test/r/im_daemon_life_cycle.result
+++ b/mysql-test/r/im_daemon_life_cycle.result
@@ -1,5 +1,5 @@
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
 Killing the process...
diff --git a/mysql-test/r/im_instance_conf.result b/mysql-test/r/im_instance_conf.result
new file mode 100644
index 0000000000000000000000000000000000000000..efda9439f383c65e17f32423821603e0866f3437
--- /dev/null
+++ b/mysql-test/r/im_instance_conf.result
@@ -0,0 +1,196 @@
+--------------------------------------------------------------------
+server_id           = 1
+server_id           = 2
+--------------------------------------------------------------------
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+
+---> connection: mysql1_con
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+
+---> connection: default
+CREATE INSTANCE mysqld3;
+SHOW INSTANCES;
+instance_name	state
+mysqld3	offline
+mysqld2	offline
+mysqld1	online
+--------------------------------------------------------------------
+server_id           = 1
+server_id           = 2
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld1;
+ERROR HY000: Instance already exists
+CREATE INSTANCE mysqld2;
+ERROR HY000: Instance already exists
+CREATE INSTANCE mysqld3;
+ERROR HY000: Instance already exists
+--------------------------------------------------------------------
+nonguarded
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld4 nonguarded;
+SHOW INSTANCES;
+instance_name	state
+mysqld3	offline
+mysqld4	offline
+mysqld1	online
+mysqld2	offline
+--------------------------------------------------------------------
+nonguarded
+nonguarded
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld5 test-A = 000, test-B = test;
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld4	offline
+mysqld5	offline
+mysqld2	offline
+mysqld3	offline
+--------------------------------------------------------------------
+test-A=000
+--------------------------------------------------------------------
+test-B=test
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld6  test-C1  =  10  ,  test-C2  =  02  ;
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+--------------------------------------------------------------------
+test-C1=10
+--------------------------------------------------------------------
+test-C2=02
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld7  test-D  =  test-D-value  ;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+CREATE INSTANCE mysqld8  test-E  0  ;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+CREATE INSTANCE mysqld8  test-F  =  ;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE mysqld9 test-1=" hello world ", test-2='  ';
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+mysqld9	offline
+CREATE INSTANCE mysqld9a test-3='\b\babc\sdef';
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld9a	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+mysqld9	offline
+mysqld2	offline
+CREATE INSTANCE mysqld9b test-4='abc\tdef', test-5='abc\ndef';
+SHOW INSTANCES;
+instance_name	state
+mysqld9b	offline
+mysqld9a	offline
+mysqld5	offline
+mysqld6	offline
+mysqld3	offline
+mysqld4	offline
+mysqld9	offline
+mysqld2	offline
+mysqld1	online
+CREATE INSTANCE mysqld9c test-6="abc\rdef", test-7="abc\\def";
+SHOW INSTANCES;
+instance_name	state
+mysqld9b	offline
+mysqld6	offline
+mysqld5	offline
+mysqld9c	offline
+mysqld3	offline
+mysqld4	offline
+mysqld9	offline
+mysqld2	offline
+mysqld1	online
+mysqld9a	offline
+CREATE INSTANCE mysqld10 test-bad=' \ ';
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SHOW INSTANCES;
+instance_name	state
+mysqld9b	offline
+mysqld6	offline
+mysqld5	offline
+mysqld9c	offline
+mysqld3	offline
+mysqld4	offline
+mysqld9	offline
+mysqld2	offline
+mysqld1	online
+mysqld9a	offline
+--------------------------------------------------------------------
+test-1= hello world 
+--------------------------------------------------------------------
+test-2=  
+--------------------------------------------------------------------
+test-3=abc def
+--------------------------------------------------------------------
+test-4=abc	def
+--------------------------------------------------------------------
+test-5=abc
+--------------------------------------------------------------------
+test-6=abc
def
+--------------------------------------------------------------------
+test-7=abc\def
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+CREATE INSTANCE qqq1;
+ERROR HY000: Malformed instance name.
diff --git a/mysql-test/r/im_life_cycle.result b/mysql-test/r/im_life_cycle.result
index e208ccb9f0052194acc3bbdcf8bbf0ee671e5fca..876fbb38eee0a69d62c73664110dbb057994abbd 100644
--- a/mysql-test/r/im_life_cycle.result
+++ b/mysql-test/r/im_life_cycle.result
@@ -1,69 +1,93 @@
+
+--------------------------------------------------------------------
+-- 1.1.1.
+--------------------------------------------------------------------
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
-SHOW INSTANCE STATUS mysqld1;
-instance_name	status	version_number	version
-mysqld1	online	VERSION_NUMBER	VERSION
-SHOW INSTANCE STATUS mysqld2;
-instance_name	status	version_number	version
-mysqld2	offline	VERSION_NUMBER	VERSION
+
+--------------------------------------------------------------------
+-- 1.1.2.
+--------------------------------------------------------------------
 START INSTANCE mysqld2;
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	online
-SHOW INSTANCE STATUS mysqld1;
-instance_name	status	version_number	version
-mysqld1	online	VERSION_NUMBER	VERSION
-SHOW INSTANCE STATUS mysqld2;
-instance_name	status	version_number	version
-mysqld2	online	VERSION_NUMBER	VERSION
 SHOW VARIABLES LIKE 'port';
 Variable_name	Value
-port	IM_MYSQLD1_PORT
+port	IM_MYSQLD2_PORT
+
+--------------------------------------------------------------------
+-- 1.1.3.
+--------------------------------------------------------------------
 STOP INSTANCE mysqld2;
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
 SHOW INSTANCE STATUS mysqld1;
-instance_name	status	version_number	version
-mysqld1	online	VERSION_NUMBER	VERSION
+instance_name	state	version_number	version	mysqld_compatible
+mysqld1	online	VERSION_NUMBER	VERSION	no
 SHOW INSTANCE STATUS mysqld2;
-instance_name	status	version_number	version
-mysqld2	offline	VERSION_NUMBER	VERSION
+instance_name	state	version_number	version	mysqld_compatible
+mysqld2	offline	VERSION_NUMBER	VERSION	no
+
+--------------------------------------------------------------------
+-- 1.1.4.
+--------------------------------------------------------------------
 START INSTANCE mysqld3;
 ERROR HY000: Bad instance name. Check that the instance with such a name exists
 START INSTANCE mysqld1;
 ERROR HY000: The instance is already started
+
+--------------------------------------------------------------------
+-- 1.1.5.
+--------------------------------------------------------------------
 STOP INSTANCE mysqld3;
 ERROR HY000: Bad instance name. Check that the instance with such a name exists
+
+--------------------------------------------------------------------
+-- 1.1.6.
+--------------------------------------------------------------------
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
 Killing the process...
 Sleeping...
 Success: the process was restarted.
+
+--------------------------------------------------------------------
+-- 1.1.7.
+--------------------------------------------------------------------
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
 START INSTANCE mysqld2;
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	online
 Killing the process...
 Sleeping...
 Success: the process was killed.
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
+
+--------------------------------------------------------------------
+-- 1.1.8.
+--------------------------------------------------------------------
 SHOW INSTANCE STATUS;
 ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+
+--------------------------------------------------------------------
+-- BUG#12813
+--------------------------------------------------------------------
 START INSTANCE mysqld1,mysqld2,mysqld3;
 ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
 STOP INSTANCE mysqld1,mysqld2,mysqld3;
diff --git a/mysql-test/r/im_options.result b/mysql-test/r/im_options.result
new file mode 100644
index 0000000000000000000000000000000000000000..8039333b7d9580cc71314767b667e6c0f29c1e48
--- /dev/null
+++ b/mysql-test/r/im_options.result
@@ -0,0 +1,150 @@
+--------------------------------------------------------------------
+server_id           = 1
+server_id           = 2
+--------------------------------------------------------------------
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SHOW INSTANCES;
+instance_name	state
+mysqld1	starting
+mysqld2	offline
+UNSET mysqld1.server_id;
+ERROR HY000: The instance is active. Stop the instance first
+SET mysqld1.server_id = 11;
+ERROR HY000: The instance is active. Stop the instance first
+CREATE INSTANCE mysqld3 datadir = '/';
+START INSTANCE mysqld3;
+UNSET mysqld3.server_id;
+ERROR HY000: The instance is active. Stop the instance first
+SET mysqld3.server_id = 11;
+ERROR HY000: The instance is active. Stop the instance first
+STOP INSTANCE mysqld3;
+SHOW INSTANCE STATUS mysqld3;
+instance_name	state	version_number	version	mysqld_compatible
+mysqld3	offline	VERSION_NUMBER	VERSION	no
+UNSET mysqld2.server_id;
+UNSET mysqld2.server_id;
+SHOW INSTANCE OPTIONS mysqld2;
+option_name	value
+instance_name	option_value
+socket	option_value
+pid-file	option_value
+port	option_value
+datadir	option_value
+log	option_value
+log-error	option_value
+log-slow-queries	option_value
+language	option_value
+character-sets-dir	option_value
+basedir	option_value
+skip-stack-trace	option_value
+skip-innodb	option_value
+skip-bdb	option_value
+skip-ndbcluster	option_value
+nonguarded	option_value
+log-output	option_value
+SET mysqld2.server_id = 2;
+SET mysqld2.server_id = 2;
+SHOW INSTANCE OPTIONS mysqld2;
+option_name	value
+instance_name	option_value
+socket	option_value
+pid-file	option_value
+port	option_value
+datadir	option_value
+log	option_value
+log-error	option_value
+log-slow-queries	option_value
+language	option_value
+character-sets-dir	option_value
+basedir	option_value
+skip-stack-trace	option_value
+skip-innodb	option_value
+skip-bdb	option_value
+skip-ndbcluster	option_value
+nonguarded	option_value
+log-output	option_value
+server_id	option_value
+UNSET mysqld2.server_id = 11;
+ERROR 42000: You have an error in your command syntax. Check the manual that corresponds to your MySQL Instance Manager version for the right syntax to use
+SET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc = 0010, mysqld3.ddd = 0020;
+--------------------------------------------------------------------
+aaa
+--------------------------------------------------------------------
+bbb
+--------------------------------------------------------------------
+ccc=0010
+--------------------------------------------------------------------
+ddd=0020
+--------------------------------------------------------------------
+UNSET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc, mysqld3.ddd;
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+SET mysqld2.aaa, mysqld3.bbb, mysqld.ccc = 0010;
+ERROR HY000: Bad instance name. Check that the instance with such a name exists
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+SET mysqld2.aaa, mysqld3.bbb, mysqld1.ccc = 0010;
+ERROR HY000: The instance is active. Stop the instance first
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld.ccc;
+ERROR HY000: Bad instance name. Check that the instance with such a name exists
+--------------------------------------------------------------------
+server_id           = 1
+server_id=2
+--------------------------------------------------------------------
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld1.ccc;
+ERROR HY000: The instance is active. Stop the instance first
+--------------------------------------------------------------------
+server_id           = 1
+server_id=2
+--------------------------------------------------------------------
+DROP INSTANCE mysqld3;
+SET mysqld2.server_id=222;
+SET mysqld2.server_id = 222;
+SET   mysqld2.server_id   =  222  ;
+SET   mysqld2  .  server_id  =  222  ;
+SET   mysqld2  .  server_id  =  222  , mysqld2  .  aaa  , mysqld2  .  bbb  ;
+--------------------------------------------------------------------
+server_id           = 1
+server_id=222
+--------------------------------------------------------------------
+aaa
+--------------------------------------------------------------------
+bbb
+--------------------------------------------------------------------
+UNSET mysqld2  . aaa  ,  mysqld2  .  bbb ;
+--------------------------------------------------------------------
+server_id           = 1
+server_id=222
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+--------------------------------------------------------------------
+server_id           = 1
+server_id=222
+--------------------------------------------------------------------
+SHOW VARIABLES LIKE 'server_id';
+Variable_name	Value
+server_id	1
+SHOW INSTANCES;
+instance_name	state
+mysqld1	online
+mysqld2	offline
+FLUSH INSTANCES;
+ERROR HY000: At least one instance is active. Stop all instances first
+STOP INSTANCE mysqld1;
+SHOW INSTANCES;
+instance_name	state
+mysqld1	offline
+mysqld2	offline
+FLUSH INSTANCES;
diff --git a/mysql-test/r/im_options_set.result b/mysql-test/r/im_options_set.result
deleted file mode 100644
index 5e6c740624ee73b1697fc7975e362d4b15a74d73..0000000000000000000000000000000000000000
--- a/mysql-test/r/im_options_set.result
+++ /dev/null
@@ -1,20 +0,0 @@
-server_id           = 1
-server_id           = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name	Value
-server_id	1
-SET mysqld1.server_id = 11;
-server_id =11
-server_id           = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name	Value
-server_id	1
-SET mysqld2.server_id = 12;
-server_id =11
-server_id =12
-FLUSH INSTANCES;
-server_id =11
-server_id =12
-SHOW VARIABLES LIKE 'server_id';
-Variable_name	Value
-server_id	1
diff --git a/mysql-test/r/im_options_unset.result b/mysql-test/r/im_options_unset.result
deleted file mode 100644
index bf54025edb7ef5a7dcf61e17c89d37d8d774e2c5..0000000000000000000000000000000000000000
--- a/mysql-test/r/im_options_unset.result
+++ /dev/null
@@ -1,15 +0,0 @@
-server_id           = 1
-server_id           = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name	Value
-server_id	1
-UNSET mysqld1.server_id;
-server_id           = 2
-SHOW VARIABLES LIKE 'server_id';
-Variable_name	Value
-server_id	1
-UNSET mysqld2.server_id;
-FLUSH INSTANCES;
-SHOW VARIABLES LIKE 'server_id';
-Variable_name	Value
-server_id	1
diff --git a/mysql-test/r/im_utils.result b/mysql-test/r/im_utils.result
index 504b2efe4afd8e16739d9312de0d67dec8e96120..ae8e03bf8ea306263d23b5fcc35abb454a094633 100644
--- a/mysql-test/r/im_utils.result
+++ b/mysql-test/r/im_utils.result
@@ -1,11 +1,10 @@
 SHOW INSTANCES;
-instance_name	status
+instance_name	state
 mysqld1	online
 mysqld2	offline
 SHOW INSTANCE OPTIONS mysqld1;
 option_name	value
 instance_name	VALUE
-mysqld-path	VALUE
 socket	VALUE
 pid-file	VALUE
 port	VALUE
@@ -25,8 +24,6 @@ log-output	VALUE
 SHOW INSTANCE OPTIONS mysqld2;
 option_name	value
 instance_name	VALUE
-mysqld-path	VALUE
-nonguarded	VALUE
 socket	VALUE
 pid-file	VALUE
 port	VALUE
@@ -42,6 +39,7 @@ skip-stack-trace	VALUE
 skip-innodb	VALUE
 skip-bdb	VALUE
 skip-ndbcluster	VALUE
+nonguarded	VALUE
 log-output	VALUE
 START INSTANCE mysqld2;
 STOP INSTANCE mysqld2;
diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result
index 2164c18823fe240b434be126a1a5e3002309bb6f..0b43024cb0ff4b5fa9454148f0f1cd6130086272 100644
--- a/mysql-test/r/log_tables.result
+++ b/mysql-test/r/log_tables.result
@@ -2,14 +2,14 @@ use mysql;
 truncate table general_log;
 select * from general_log;
 event_time	user_host	thread_id	server_id	command_type	argument
-TIMESTAMP	root[root] @ localhost []	1	1	Query	select * from general_log
+TIMESTAMP	root[root] @ localhost []	THREAD_ID	1	Query	select * from general_log
 truncate table slow_log;
 select * from slow_log;
 start_time	user_host	query_time	lock_time	rows_sent	rows_examined	db	last_insert_id	insert_id	server_id	sql_text
 truncate table general_log;
 select * from general_log where argument like '%general_log%';
 event_time	user_host	thread_id	server_id	command_type	argument
-TIMESTAMP	root[root] @ localhost []	1	1	Query	select * from general_log where argument like '%general_log%'
+TIMESTAMP	root[root] @ localhost []	THREAD_ID	1	Query	select * from general_log where argument like '%general_log%'
 create table join_test (verbose_comment varchar (80), command_type varchar(64));
 insert into join_test values ("User performed a usual SQL query", "Query");
 insert into join_test values ("New DB connection was registered", "Connect");
@@ -59,10 +59,10 @@ create table bug16905 (s char(15) character set utf8 default 'пусто');
 insert into bug16905 values ('новое');
 select * from mysql.general_log;
 event_time	user_host	thread_id	server_id	command_type	argument
-TIMESTAMP	root[root] @ localhost []	2	1	Query	set names utf8
-TIMESTAMP	root[root] @ localhost []	2	1	Query	create table bug16905 (s char(15) character set utf8 default 'пусто')
-TIMESTAMP	root[root] @ localhost []	2	1	Query	insert into bug16905 values ('новое')
-TIMESTAMP	root[root] @ localhost []	2	1	Query	select * from mysql.general_log
+TIMESTAMP	root[root] @ localhost []	THREAD_ID	1	Query	set names utf8
+TIMESTAMP	root[root] @ localhost []	THREAD_ID	1	Query	create table bug16905 (s char(15) character set utf8 default 'пусто')
+TIMESTAMP	root[root] @ localhost []	THREAD_ID	1	Query	insert into bug16905 values ('новое')
+TIMESTAMP	root[root] @ localhost []	THREAD_ID	1	Query	select * from mysql.general_log
 drop table bug16905;
 truncate table mysql.slow_log;
 set session long_query_time=1;
diff --git a/mysql-test/r/not_embedded_server.result b/mysql-test/r/not_embedded_server.result
index e471b5a3afaf79923099be5edd0d186fae76c108..7cbe91b3753cf447f0bd6b703ad290faf9dc6e87 100644
--- a/mysql-test/r/not_embedded_server.result
+++ b/mysql-test/r/not_embedded_server.result
@@ -1,5 +1,6 @@
 prepare stmt1 from ' show full processlist ';
 execute stmt1;
 Id	User	Host	db	Command	Time	State	Info
+number	event_scheduler	localhost	NULL	Connect	time	Suspended	NULL
 number	root	localhost	test	Query	time	NULL	show full processlist
 deallocate prepare stmt1;
diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result
index d0b773dfe3479a04fffc5ecdd0ebf3a99887599d..1a1d64324119203a8e22f10135ad7ca26375b5f1 100644
--- a/mysql-test/r/ps_1general.result
+++ b/mysql-test/r/ps_1general.result
@@ -299,7 +299,7 @@ t9	MyISAM	10	Dynamic	2	216	432	#	2048	0	NULL	#	#	#	latin1_swedish_ci	NULL
 prepare stmt4 from ' show status like ''Threads_running'' ';
 execute stmt4;
 Variable_name	Value
-Threads_running	1
+Threads_running	2
 prepare stmt4 from ' show variables like ''sql_mode'' ';
 execute stmt4;
 Variable_name	Value
diff --git a/mysql-test/r/skip_name_resolve.result b/mysql-test/r/skip_name_resolve.result
index 8ef52e752385d0605bbe64ef71f9205fed445c53..855876825addade7e64397b1d7babfc9a32927ca 100644
--- a/mysql-test/r/skip_name_resolve.result
+++ b/mysql-test/r/skip_name_resolve.result
@@ -10,5 +10,6 @@ user()
 #
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
+<id>	event_scheduler	<host>	NULL	<command>	<time>	<state>	<info>
 <id>	root	<host>	test	<command>	<time>	<state>	<info>
 <id>	root	<host>	test	<command>	<time>	<state>	<info>
diff --git a/mysql-test/r/sp-threads.result b/mysql-test/r/sp-threads.result
index c516d7a643f06f739f868e0d311363e2b3fc4b70..3cba437e0a63e4d0be883c87ed7c870de79a8912 100644
--- a/mysql-test/r/sp-threads.result
+++ b/mysql-test/r/sp-threads.result
@@ -34,6 +34,7 @@ lock tables t2 write;
  call bug9486();
 show processlist;
 Id	User	Host	db	Command	Time	State	Info
+#	event_scheduler	localhost	NULL	Connect	#	Suspended	NULL
 #	root	localhost	test	Sleep	#		NULL
 #	root	localhost	test	Query	#	Locked	update t1, t2 set val= 1 where id1=id2
 #	root	localhost	test	Query	#	NULL	show processlist
diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result
index c8cafe5ace148c53194980519771ca2c81b5f110..c5d60446e0aabaf79e7ad41c248e9f6fbdcf295c 100644
--- a/mysql-test/r/sp_notembedded.result
+++ b/mysql-test/r/sp_notembedded.result
@@ -18,9 +18,11 @@ show processlist;
 end|
 call bug4902_2()|
 Id	User	Host	db	Command	Time	State	Info
+#	event_scheduler	localhost	NULL	Connect	#	Suspended	NULL
 #	root	localhost	test	Query	#	NULL	show processlist
 call bug4902_2()|
 Id	User	Host	db	Command	Time	State	Info
+#	event_scheduler	localhost	NULL	Connect	#	Suspended	NULL
 #	root	localhost	test	Query	#	NULL	show processlist
 drop procedure bug4902_2|
 drop function if exists bug5278|
diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result
index ca21b333a6a0f29cff1267bea4469bf8d6c09f45..e83ade78cf63603eac98a507ab9357070419b2e2 100644
--- a/mysql-test/r/status.result
+++ b/mysql-test/r/status.result
@@ -26,20 +26,20 @@ Last_query_cost	0.000000
 FLUSH STATUS;
 SHOW STATUS LIKE 'max_used_connections';
 Variable_name	Value
-Max_used_connections	1
+Max_used_connections	2
 SET @save_thread_cache_size=@@thread_cache_size;
 SET GLOBAL thread_cache_size=3;
 SHOW STATUS LIKE 'max_used_connections';
 Variable_name	Value
-Max_used_connections	3
+Max_used_connections	4
 FLUSH STATUS;
 SHOW STATUS LIKE 'max_used_connections';
 Variable_name	Value
-Max_used_connections	2
-SHOW STATUS LIKE 'max_used_connections';
-Variable_name	Value
 Max_used_connections	3
 SHOW STATUS LIKE 'max_used_connections';
 Variable_name	Value
 Max_used_connections	4
+SHOW STATUS LIKE 'max_used_connections';
+Variable_name	Value
+Max_used_connections	5
 SET GLOBAL thread_cache_size=@save_thread_cache_size;
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index 562006c76875c95ecc1e7728cca186c471b06826..d6083ab8bfe51355ba3c597b79396f5567ff9c00 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -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
diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test
index fbcd4924d561a6e9deba94c15a2edeee5f9fd9cf..819d64ccf14de2e56e37a1215d2af74877790527 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -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;
-
diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test
index 3f339ff039891a561dca2b86fb956c611e4f2291..e3b79a6bd13e98435287d8534c37b8ea22d9b369 100644
--- a/mysql-test/t/events_bugs.test
+++ b/mysql-test/t/events_bugs.test
@@ -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;
 #
diff --git a/mysql-test/t/events_logs_tests.test b/mysql-test/t/events_logs_tests.test
index 21adc17d5b8708880502d3fa9448d6b2a89d252f..a468685ddc638eab4b52708adcd62199e79fbf93 100644
--- a/mysql-test/t/events_logs_tests.test
+++ b/mysql-test/t/events_logs_tests.test
@@ -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;
diff --git a/mysql-test/t/events_microsec.test b/mysql-test/t/events_microsec.test
index 34855fdadff75bc8517090fd1f9b5b416e5c860a..e01120a0756b0743887e98bb4c013be9d3735151 100644
--- a/mysql-test/t/events_microsec.test
+++ b/mysql-test/t/events_microsec.test
@@ -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;
diff --git a/mysql-test/t/events_scheduling.test b/mysql-test/t/events_scheduling.test
index ae3cc7d5fac06abf0105503924219d308e4250db..a73d25cd8eef972382f92ca50336dff5cf902137 100644
--- a/mysql-test/t/events_scheduling.test
+++ b/mysql-test/t/events_scheduling.test
@@ -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;
diff --git a/mysql-test/t/events_stress.test b/mysql-test/t/events_stress.test
index f6eed79425c848d106ff897454751602c443b2c5..8d0034c232e418253584f2a0804a1cdd14d22f46 100644
--- a/mysql-test/t/events_stress.test
+++ b/mysql-test/t/events_stress.test
@@ -2,78 +2,124 @@ 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= 50;
+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= 50;
+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= 50;
 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;
+--sleep 6
+DROP DATABASE events_conn1_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;
+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= 950;
+let $1= 50;
 while ($1)
 {
-  eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $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
-SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
---sleep 3
-CREATE DATABASE events_test4;
-USE events_test4;
+SET GLOBAL event_scheduler=1;
+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= 860;
+let $1= 50;
 while ($1)
 {
-  eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $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_test2;
-USE events_test2;
+CREATE DATABASE events_conn1_test2;
+USE events_conn1_test2;
 --disable_query_log
-let $1= 1050;
+let $1= 50;
 while ($1)
 {
-  eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $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_test2';
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
 --sleep 6
-DROP DATABASE events_test2;
-SET GLOBAL event_scheduler=0;
-DROP DATABASE events_test3;
-SET GLOBAL event_scheduler=1;
-DROP DATABASE events_test4;
+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;
+--disable_query_log
+DROP USER event_user2@localhost;
+DROP USER event_user3@localhost;
+--enable_query_log
 #
 # DROP DATABASE test end (bug #16406)
 #
diff --git a/mysql-test/t/im_cmd_line.imtest b/mysql-test/t/im_cmd_line.imtest
new file mode 100644
index 0000000000000000000000000000000000000000..00e8351535e00dd42044c275ae673ebb0c850970
--- /dev/null
+++ b/mysql-test/t/im_cmd_line.imtest
@@ -0,0 +1,68 @@
+###########################################################################
+#
+# Tests for user-management command-line options.
+#
+###########################################################################
+
+--source include/im_check_os.inc
+
+###########################################################################
+
+# List users so we are sure about starting conditions.
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
+
+# Add a new user.
+
+--echo ==> Adding user 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --add-user --username=testuser --password=abc 2>&1 >/dev/null
+--echo
+
+--echo --> IM password file:
+--exec cat $IM_PASSWORD_PATH
+--echo --> EOF
+--echo
+
+--echo --> Printing out line for 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --passwd --username=testuser --password=abc | tail -1
+--echo
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
+
+# Edit user's attributes.
+
+--echo ==> Changing the password of 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --edit-user --username=testuser --password=xyz 2>&1 >/dev/null
+--echo
+
+--echo --> IM password file:
+--exec cat $IM_PASSWORD_PATH
+--echo --> EOF
+--echo
+
+--echo --> Printing out line for 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --passwd --username=testuser --password=xyz | tail -1
+--echo
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
+
+# Drop user.
+
+--echo ==> Dropping user 'testuser'...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --drop-user --username=testuser 2>&1 >/dev/null
+--echo
+
+--echo --> IM password file:
+--exec cat $IM_PASSWORD_PATH
+--echo --> EOF
+--echo
+
+--echo --> Listing users...
+--exec $IM_EXE --defaults-file="$IM_DEFAULTS_PATH" --list-users 2>&1 >/dev/null
+--echo
diff --git a/mysql-test/t/im_daemon_life_cycle-im.opt b/mysql-test/t/im_daemon_life_cycle-im.opt
index 21c01191e4c8e52240ba916d9b02c7b3aa20ffd9..3a45c7a41f7af62efb101ae41a54c559af49fe19 100644
--- a/mysql-test/t/im_daemon_life_cycle-im.opt
+++ b/mysql-test/t/im_daemon_life_cycle-im.opt
@@ -1,2 +1,3 @@
 --run-as-service
 --log=$MYSQLTEST_VARDIR/log/im.log
+--monitoring-interval=1
diff --git a/mysql-test/t/im_daemon_life_cycle.imtest b/mysql-test/t/im_daemon_life_cycle.imtest
index 87388d7c1e6620503bf7d0853e2d14cad508bbbb..d173ce2a6e2c64b23005667d26db81fdd54f4ee7 100644
--- a/mysql-test/t/im_daemon_life_cycle.imtest
+++ b/mysql-test/t/im_daemon_life_cycle.imtest
@@ -10,6 +10,9 @@
 
 ###########################################################################
 
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
 SHOW INSTANCES;
 
 --exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_PATH_PID restarted
diff --git a/mysql-test/t/im_instance_conf-im.opt b/mysql-test/t/im_instance_conf-im.opt
new file mode 100644
index 0000000000000000000000000000000000000000..34b74ce0c958eadb9ee408f2928ec95f2b2d01e8
--- /dev/null
+++ b/mysql-test/t/im_instance_conf-im.opt
@@ -0,0 +1 @@
+--monitoring-interval=1
diff --git a/mysql-test/t/im_instance_conf.imtest b/mysql-test/t/im_instance_conf.imtest
new file mode 100644
index 0000000000000000000000000000000000000000..17703fdd303df74ab01fba8635da3150fe227fa6
--- /dev/null
+++ b/mysql-test/t/im_instance_conf.imtest
@@ -0,0 +1,228 @@
+###########################################################################
+#
+# This test suite checks the following statements:
+#   - CREATE INSTANCE <instance_name> [option1[=option1_value], ...];
+#   - DROP INSTANCE <instance_name>;
+#
+# For CREATE INSTANCE we check that:
+#   - CREATE INSTANCE succeeds for non-existing instance;
+#   - CREATE INSTANCE fails for existing instance;
+#   - CREATE INSTANCE can get additional options with and w/o values;
+#   - CREATE INSTANCE parses options and handles grammar errors correctly.
+#     Check that strings with spaces are handled correctly, unknown (for
+#     mysqld) options should also be handled;
+#   - CREATE INSTANCE updates both config file and internal configuration cache;
+#   - CREATE INSTANCE allows to create instances only with properly formed
+#     names (mysqld*);
+#
+# For DROP INSTANCE we check that:
+#   - DROP INSTANCE succeeds for existing instance;
+#   - DROP INSTANCE fails for non-existing instance;
+#   - DROP INSTANCE fails for active instance.
+#   - DROP INSTANCE updates both config file and internal configuration cache;
+#
+###########################################################################
+
+--source include/im_check_os.inc
+
+###########################################################################
+#
+# Check starting conditions.
+#
+###########################################################################
+
+# Check that the configuration file contains only instances that we expect.
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+# Check that mysqld1 is reported as running.
+
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
+SHOW INSTANCES;
+
+# Check that the expected mysqld instance is actually run (check that we can
+# connect and execute something).
+
+--echo
+--echo ---> connection: mysql1_con
+--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
+--connection mysql1_con
+
+SHOW VARIABLES LIKE 'server_id';
+
+--disconnect mysql1_con
+
+--echo
+--echo ---> connection: default
+--connection default
+
+###########################################################################
+#
+# CREATE INSTANCE tests.
+#
+###########################################################################
+
+# Check that CREATE INSTANCE succeeds for non-existing instance and also check
+# that both config file and internal configuration cache have been updated.
+
+CREATE INSTANCE mysqld3;
+
+SHOW INSTANCES;
+ 
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+# Check that CREATE INSTANCE fails for existing instance. Let's all three
+# existing instances (running one, stopped one and just created one). Just in
+# case...
+
+--error 3012 # ER_CREATE_EXISTING_INSTANCE
+CREATE INSTANCE mysqld1;
+
+--error 3012 # ER_CREATE_EXISTING_INSTANCE
+CREATE INSTANCE mysqld2;
+
+--error 3012 # ER_CREATE_EXISTING_INSTANCE
+CREATE INSTANCE mysqld3;
+
+# Check that CREATE INSTANCE can get additional options with and w/o values.
+# Ensure that config file is updated properly.
+
+#   - without values;
+
+--echo --------------------------------------------------------------------
+--exec grep nonguarded $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld4 nonguarded;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep nonguarded $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+#   - with value;
+
+--echo --------------------------------------------------------------------
+--exec grep test-A $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-B $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld5 test-A = 000, test-B = test;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-A $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-B $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+# Check that CREATE INSTANCE parses options and handles grammar errors
+# correctly. Check that strings with spaces are handled correctly,
+# unknown (for mysqld) options should also be handled.
+
+#   - check handling of extra spaces;
+
+--echo --------------------------------------------------------------------
+--exec grep test-C $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld6  test-C1  =  10  ,  test-C2  =  02  ;
+
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-C1 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-C2 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+#   - check handling of grammar error;
+
+--echo --------------------------------------------------------------------
+--exec grep test-D $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-E $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld7  test-D  =  test-D-value  ;
+SHOW INSTANCES;
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld8  test-E  0  ;
+SHOW INSTANCES;
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld8  test-F  =  ;
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-D $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-E $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+#   - check parsing of string option values
+
+--echo --------------------------------------------------------------------
+--exec grep test-1 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-2 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-3 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep test-4 $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+CREATE INSTANCE mysqld9 test-1=" hello world ", test-2='  ';
+SHOW INSTANCES;
+
+CREATE INSTANCE mysqld9a test-3='\b\babc\sdef';
+# test-3='abc def'
+SHOW INSTANCES;
+
+CREATE INSTANCE mysqld9b test-4='abc\tdef', test-5='abc\ndef';
+SHOW INSTANCES;
+
+CREATE INSTANCE mysqld9c test-6="abc\rdef", test-7="abc\\def";
+# test-6=abc
+SHOW INSTANCES;
+
+--error ER_SYNTAX_ERROR
+CREATE INSTANCE mysqld10 test-bad=' \ ';
+SHOW INSTANCES;
+
+--echo --------------------------------------------------------------------
+--exec grep test-1 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-2 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-3 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-4 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-5 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-6 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-7 $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+--exec grep test-bad $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+
+# Check that CREATE INSTANCE allows to create instances only with properly
+# formed names (mysqld*).
+
+--error 3014 # ER_MALFORMED_INSTANCE_NAME
+CREATE INSTANCE qqq1;
+
diff --git a/mysql-test/t/im_life_cycle-im.opt b/mysql-test/t/im_life_cycle-im.opt
new file mode 100644
index 0000000000000000000000000000000000000000..34b74ce0c958eadb9ee408f2928ec95f2b2d01e8
--- /dev/null
+++ b/mysql-test/t/im_life_cycle-im.opt
@@ -0,0 +1 @@
+--monitoring-interval=1
diff --git a/mysql-test/t/im_life_cycle.imtest b/mysql-test/t/im_life_cycle.imtest
index 246843a022bd6deed0ba32a49eaa0a10275f11db..d71cdc86624a3590a7e70807d97236887db4baae 100644
--- a/mysql-test/t/im_life_cycle.imtest
+++ b/mysql-test/t/im_life_cycle.imtest
@@ -17,11 +17,15 @@
 #
 ###########################################################################
 
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.1.
+--echo --------------------------------------------------------------------
+
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
 SHOW INSTANCES;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld1;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld2;
 
 ###########################################################################
 #
@@ -33,20 +37,22 @@ SHOW INSTANCE STATUS mysqld2;
 #
 ###########################################################################
 
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.2.
+--echo --------------------------------------------------------------------
+
 START INSTANCE mysqld2;
-# FIXME
+# FIXME: START INSTANCE should be synchronous.
 --sleep 3
+# should be longer than monitoring interval and enough to start instance.
 
 SHOW INSTANCES;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld1;
---replace_column 3 VERSION_NUMBER 4 VERSION
-SHOW INSTANCE STATUS mysqld2;
 
---connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
+--connect (mysql_con,localhost,root,,mysql,$IM_MYSQLD2_PORT,$IM_MYSQLD2_SOCK)
 --connection mysql_con
 
---replace_result $IM_MYSQLD1_PORT IM_MYSQLD1_PORT
+--replace_result $IM_MYSQLD2_PORT IM_MYSQLD2_PORT
 SHOW VARIABLES LIKE 'port';
 
 --connection default
@@ -61,9 +67,15 @@ SHOW VARIABLES LIKE 'port';
 #
 ###########################################################################
 
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.3.
+--echo --------------------------------------------------------------------
+
 STOP INSTANCE mysqld2;
-# FIXME
+# FIXME: STOP INSTANCE should be synchronous.
 --sleep 3
+# should be longer than monitoring interval and enough to stop instance.
 
 SHOW INSTANCES;
 --replace_column 3 VERSION_NUMBER 4 VERSION
@@ -81,16 +93,17 @@ SHOW INSTANCE STATUS mysqld2;
 #
 ###########################################################################
 
---error 3000
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.4.
+--echo --------------------------------------------------------------------
+
+--error 3000 # ER_BAD_INSTANCE_NAME
 START INSTANCE mysqld3;
 
---error 3002
+--error 3002 # ER_INSTANCE_ALREADY_STARTED
 START INSTANCE mysqld1;
 
-# FIXME TODO
-# BUG#12813: START/STOP INSTANCE commands accept a list as argument
-# START INSTANCE mysqld1, mysqld2;
-
 ###########################################################################
 #
 # 1.1.5. Check that Instance Manager reports correct errors for 'STOP INSTANCE'
@@ -101,39 +114,54 @@ START INSTANCE mysqld1;
 #
 ###########################################################################
 
---error 3000
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.5.
+--echo --------------------------------------------------------------------
+
+--error 3000 # ER_BAD_INSTANCE_NAME
 STOP INSTANCE mysqld3;
 
 # TODO: IM should be fixed.
 # BUG#12673: Instance Manager allows to stop the instance many times
-# --error 3002
+# --error 3002 # ER_INSTANCE_ALREADY_STARTED
 # STOP INSTANCE mysqld2;
 
-# FIXME TODO
-# BUG#12813: START/STOP INSTANCE commands accept a list as argument
-# STOP INSTANCE mysqld1, mysqld2;
-
 ###########################################################################
 #
 # 1.1.6. Check that Instance Manager is able to restart guarded instances.
 #
 ###########################################################################
 
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.6.
+--echo --------------------------------------------------------------------
+
 SHOW INSTANCES;
 
 --exec $MYSQL_TEST_DIR/t/kill_n_check.sh $IM_MYSQLD1_PATH_PID restarted
 
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
 ###########################################################################
 #
 # 1.1.7. Check that Instance Manager does not restart non-guarded instance.
 #
 ###########################################################################
 
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.7.
+--echo --------------------------------------------------------------------
+
 SHOW INSTANCES;
 
 START INSTANCE mysqld2;
-# FIXME
+# FIXME: START INSTANCE should be synchronous.
 --sleep 3
+# should be longer than monitoring interval and enough to start instance.
 
 SHOW INSTANCES;
 
@@ -147,7 +175,13 @@ SHOW INSTANCES;
 # incomplete SHOW INSTANCE STATUS command.
 #
 ###########################################################################
---error 1149
+
+--echo
+--echo --------------------------------------------------------------------
+--echo -- 1.1.8.
+--echo --------------------------------------------------------------------
+
+--error ER_SYNTAX_ERROR
 SHOW INSTANCE STATUS;
 
 #
@@ -159,8 +193,13 @@ SHOW INSTANCE STATUS;
 #                                 a list as argument.
 #
 
---error 1149
+--echo
+--echo --------------------------------------------------------------------
+--echo -- BUG#12813
+--echo --------------------------------------------------------------------
+
+--error ER_SYNTAX_ERROR
 START INSTANCE mysqld1,mysqld2,mysqld3;
 
---error 1149
+--error ER_SYNTAX_ERROR
 STOP INSTANCE mysqld1,mysqld2,mysqld3;
diff --git a/mysql-test/t/im_options.imtest b/mysql-test/t/im_options.imtest
new file mode 100644
index 0000000000000000000000000000000000000000..cd905416cda42b355f41e03b3b89555dc65778d5
--- /dev/null
+++ b/mysql-test/t/im_options.imtest
@@ -0,0 +1,268 @@
+###########################################################################
+#
+# This test suite checks the following statements:
+#   - SET <instance id>.<option name> = <option value>;
+#   - UNSET <instance id>.<option name> = <option value>;
+#   - FLUSH INSTANCES;
+#
+# For SET/UNSET we check that:
+#   - SET ignores spaces correctly;
+#   - UNSET does not allow option-value part (= <option value>);
+#   - SET/UNSET can be applied several times w/o error;
+#   - SET/UNSET is allowed only for stopped instances;
+#   - SET/UNSET updates both the configuration cache in IM and
+#     the configuration file;
+#
+# For FLUSH INSTANCES we check that:
+#   - FLUSH INSTANCES is allowed only when all instances are stopped;
+#
+# According to the IM implementation details, we should play at least with the
+# following options:
+#   - server_id
+#   - port
+#   - nonguarded
+
+# Let's test SET statement on the option 'server_id'. It's expected that
+# originally the instances have the following server ids and states:
+#  - mysqld1: server_id: 1; running (online)
+#  - mysqld2: server_id: 2; stopped (offline)
+#
+###########################################################################
+
+--source include/im_check_os.inc
+
+###########################################################################
+#
+# Check starting conditions.
+#
+###########################################################################
+
+# - check the configuration file;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+# - check the running instances.
+
+--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
+
+--connection mysql1_con
+
+SHOW VARIABLES LIKE 'server_id';
+
+--connection default
+
+# - check the internal cache.
+
+SHOW INSTANCES;
+
+###########################################################################
+#
+# Check that SET/UNSET is allowed only for stopped instances.
+#
+###########################################################################
+
+# - check that SET/UNSET is denied for running instances;
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+UNSET mysqld1.server_id;
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+SET mysqld1.server_id = 11;
+
+# - check that SET/UNSET is denied for active instances:
+#   - create dummy misconfigured instance;
+#   - start it;
+#   - try to set/unset options;
+
+CREATE INSTANCE mysqld3 datadir = '/';
+START INSTANCE mysqld3;
+
+# FIXME: START INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
+# NOTE: We can not analyze state of the instance here -- it can be Failed or
+# Starting because Instance Manager is trying to start the misconfigured
+# instance several times.
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+UNSET mysqld3.server_id;
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+SET mysqld3.server_id = 11;
+
+STOP INSTANCE mysqld3;
+
+# FIXME: STOP INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to stop instance.
+
+--replace_column 3 VERSION_NUMBER 4 VERSION
+SHOW INSTANCE STATUS mysqld3;
+
+# - check that SET/UNSET succeed for stopped instances;
+# - check that SET/UNSET can be applied multiple times;
+
+UNSET mysqld2.server_id;
+UNSET mysqld2.server_id;
+
+--replace_column 2 option_value
+SHOW INSTANCE OPTIONS mysqld2;
+
+SET mysqld2.server_id = 2;
+SET mysqld2.server_id = 2;
+
+--replace_column 2 option_value
+SHOW INSTANCE OPTIONS mysqld2;
+
+# - check that UNSET does not allow option-value part (= <option value>);
+
+--error ER_SYNTAX_ERROR
+UNSET mysqld2.server_id = 11;
+
+# - check that SET/UNSET working properly with multiple options;
+
+SET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc = 0010, mysqld3.ddd = 0020;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep ddd $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+UNSET mysqld2.aaa, mysqld3.bbb, mysqld2.ccc, mysqld3.ddd;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ddd $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+# - check that if some instance name is invalid or the active is active,
+#   whole SET-statement will not be executed;
+
+--error 3000 # ER_BAD_INSTANCE_NAME
+SET mysqld2.aaa, mysqld3.bbb, mysqld.ccc = 0010;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+SET mysqld2.aaa, mysqld3.bbb, mysqld1.ccc = 0010;
+
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep ccc $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+# - check that if some instance name is invalid or the active is active,
+#   whole UNSET-statement will not be executed;
+
+--error 3000 # ER_BAD_INSTANCE_NAME
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld.ccc;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+--error 3015 # ER_INSTANCE_IS_ACTIVE
+UNSET mysqld2.server_id, mysqld3.server_id, mysqld1.ccc;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf;
+--echo --------------------------------------------------------------------
+
+DROP INSTANCE mysqld3;
+
+# - check that spaces are handled correctly;
+
+SET mysqld2.server_id=222;
+SET mysqld2.server_id = 222;
+SET   mysqld2.server_id   =  222  ;
+SET   mysqld2  .  server_id  =  222  ;
+SET   mysqld2  .  server_id  =  222  , mysqld2  .  aaa  , mysqld2  .  bbb  ;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+UNSET mysqld2  . aaa  ,  mysqld2  .  bbb ;
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+--exec grep aaa $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+--exec grep bbb $MYSQLTEST_VARDIR/im.cnf || true;
+--echo --------------------------------------------------------------------
+
+###########################################################################
+#
+# Check that SET/UNSET updates both the configuration cache in IM and
+# the configuration file.
+#
+###########################################################################
+
+#   - check that the configuration file has been updated (i.e. contains
+#     server_id=SERVER_ID for mysqld2);
+
+--echo --------------------------------------------------------------------
+--exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
+--echo --------------------------------------------------------------------
+
+#   - (for mysqld1) check that the running instance has not been affected:
+#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
+#     returns zero;
+
+--connection mysql1_con
+
+SHOW VARIABLES LIKE 'server_id';
+
+--connection default
+
+#   - check that internal cache of Instance Manager has been affected;
+#     TODO: we should check only server_id option here.
+
+# SHOW INSTANCE OPTIONS mysqld2;
+
+###########################################################################
+#
+# Check that FLUSH INSTANCES is allowed only when all instances are stopped.
+#
+###########################################################################
+
+SHOW INSTANCES;
+
+--error 3016 # ER_THERE_IS_ACTIVE_INSTACE
+FLUSH INSTANCES;
+
+STOP INSTANCE mysqld1;
+# FIXME: STOP INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to stop instance.
+
+SHOW INSTANCES;
+
+FLUSH INSTANCES;
diff --git a/mysql-test/t/im_options_set.imtest b/mysql-test/t/im_options_set.imtest
deleted file mode 100644
index a9b64861f9960b51e614e895491b944f95cf12eb..0000000000000000000000000000000000000000
--- a/mysql-test/t/im_options_set.imtest
+++ /dev/null
@@ -1,142 +0,0 @@
-###########################################################################
-#
-# This file contains test for (3) test suite.
-#
-# Consult WL#2789 for more information.
-#
-###########################################################################
-
-#
-# Check the options-management commands:
-#  - SET;
-#  - FLUSH INSTANCES;
-#
-# Let's test the commands on the option 'server_id'. It's expected that
-# originally the instances have the following server ids:
-#  - mysqld1: 1
-#  - mysqld2: 2
-#
-#  1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12.
-#   1.1. check that the configuration file has been updated (i.e.  contains
-#     server_id=SERVER_ID for the instance);
-#   1.2. (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns zero;
-#   1.3. check that internal cache of Instance Manager has not been affected
-#     (i.e.  SHOW INSTANCE OPTIONS <instance> does not contain updated value).
-#
-#  2. FLUSH INSTANCES;
-#   2.1. check that the configuration file has not been updated;
-#   2.2. (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns zero value;
-#   2.3. check that internal cache of Instance Manager has been updated (i.e.
-#     SHOW INSTANCE OPTIONS <instance> contains 'server_id=SERVER_ID' line).
-#
-#  3. Restore options.
-#
-
-###########################################################################
-
---source include/im_check_os.inc
-
-###########################################################################
-#
-# 0. Check starting conditions.
-#
-###########################################################################
-
-# - check the configuration file;
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - check the running instances.
-
---connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check the internal cache.
-#   TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-#  1. SET <instance_id>.server_id= SERVER_ID); where SERVER_ID is 11 or 12.
-#
-###########################################################################
-
-# * mysqld1
-
-SET mysqld1.server_id = 11;
-
-#   - check that the configuration file has been updated (i.e. contains
-#     server_id=SERVER_ID for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-#   - (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns zero;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-#   - check that internal cache of Instance Manager has not been affected
-#     (i.e.  SHOW INSTANCE OPTIONS <instance> does not contain updated value).
-#     TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-
-# * mysqld2
-
-SET mysqld2.server_id = 12;
-
-#   - check that the configuration file has been updated (i.e.  contains
-#     server_id=SERVER_ID for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-#   - check that internal cache of Instance Manager has not been affected
-#     (i.e.  SHOW INSTANCE OPTIONS <instance> does not contain updated value).
-#     TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 2. FLUSH INSTANCES;
-#
-###########################################################################
-
-FLUSH INSTANCES;
-
-#   - check that the configuration file has not been updated;
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-#   - (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns zero value;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-#   - check that internal cache of Instance Manager has been updated (i.e.
-#     SHOW INSTANCE OPTIONS <instance> contains 'server_id=' line).
-#     TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
diff --git a/mysql-test/t/im_options_unset.imtest b/mysql-test/t/im_options_unset.imtest
deleted file mode 100644
index 40629805d455ade1eb668025165e7e14af6a42d2..0000000000000000000000000000000000000000
--- a/mysql-test/t/im_options_unset.imtest
+++ /dev/null
@@ -1,150 +0,0 @@
-###########################################################################
-#
-# This file contains test for (3) test suite.
-#
-# Consult WL#2789 for more information.
-#
-###########################################################################
-
-#
-# Check the options-management commands:
-#  - UNSET;
-#  - FLUSH INSTANCES;
-#
-# Let's test the commands on the option 'server_id'. It's expected that
-# originally the instances have the following server ids:
-#  - mysqld1: 1
-#  - mysqld2: 2
-#
-# The test case:
-#
-#  1. UNSET <instance_id>.server_id;
-#
-#   Do the step for both instances.
-#
-#   1.1. check that the configuration file has been updated (i.e.  does not
-#     contain 'server_id=' line for the instance);
-#   1.2. (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns non-zero value;
-#   1.3. check that internal cache of Instance Manager is not affected (i.e.
-#     SHOW INSTANCE OPTIONS <instance> contains non-zero value for server_id);
-#
-#  2. FLUSH INSTANCES;
-#
-#   Do the step for both instances.
-#
-#   2.1. check that the configuration file has not been updated (i.e.  does not
-#     contain 'server_id=' for the instance);
-#   2.2. (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns non-zero value;
-#   2.3. check that internal cache of Instance Manager has been updated (i.e.
-#     SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line).
-#
-
-###########################################################################
-
---source include/im_check_os.inc
-
-###########################################################################
-#
-# 0. Check starting conditions.
-#
-###########################################################################
-
-# - check the configuration file;
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-# - check the running instances.
-
---connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-# - check the internal cache.
-#   TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 1. UNSET <instance_id>.server_id;
-#
-###########################################################################
-
-# * mysqld1
-
-UNSET mysqld1.server_id;
-
-#   - check that the configuration file has been updated (i.e.  does not
-#     contain 'server_id=' line for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf ;
-
-#   - check that the running instance has not been affected: connect to the
-#     instance and check that 'SHOW VARIABLES LIKE 'server_id'' returns non-zero
-#     value;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-#   - check that internal cache of Instance Manager is not affected (i.e.  SHOW
-#     INSTANCE OPTIONS <instance> contains non-zero value for server_id);
-#     TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-
-# * mysqld2
-
-UNSET mysqld2.server_id;
-
-#   - check that the configuration file has been updated (i.e.  does not
-#     contain 'server_id=' line for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf || true;
-
-#   - check that internal cache of Instance Manager is not affected (i.e.  SHOW
-#     INSTANCE OPTIONS <instance> contains non-zero value for server_id);
-#     TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld2;
-
-###########################################################################
-#
-# 2. FLUSH INSTANCES;
-#
-###########################################################################
-
-FLUSH INSTANCES;
-
-#   - check that the configuration file has not been updated (i.e.  does not
-#     contain 'server_id=' for the instance);
-
---exec grep server_id $MYSQLTEST_VARDIR/im.cnf || true;
-
-#   - (for mysqld1) check that the running instance has not been affected:
-#     connect to the instance and check that 'SHOW VARIABLES LIKE 'server_id''
-#     returns non-zero value;
-
---connection mysql1_con
-
-SHOW VARIABLES LIKE 'server_id';
-
---connection default
-
-#   - check that internal cache of Instance Manager has been updated (i.e.
-#     SHOW INSTANCE OPTIONS <instance> does not contain 'server_id=' line).
-#     TODO: we should check only server_id option here.
-
-# SHOW INSTANCE OPTIONS mysqld1;
-# SHOW INSTANCE OPTIONS mysqld2;
diff --git a/mysql-test/t/im_utils-im.opt b/mysql-test/t/im_utils-im.opt
new file mode 100644
index 0000000000000000000000000000000000000000..34b74ce0c958eadb9ee408f2928ec95f2b2d01e8
--- /dev/null
+++ b/mysql-test/t/im_utils-im.opt
@@ -0,0 +1 @@
+--monitoring-interval=1
diff --git a/mysql-test/t/im_utils.imtest b/mysql-test/t/im_utils.imtest
index dc6fb93c4ffb54de9260cfe9f65a9e3a8b02477b..8e8d475cfeeb39a0ed16a856abae914ed9236cc5 100644
--- a/mysql-test/t/im_utils.imtest
+++ b/mysql-test/t/im_utils.imtest
@@ -17,6 +17,9 @@
 #  - the second instance is offline;
 #
 
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
+
 SHOW INSTANCES;
 
 #
@@ -41,8 +44,9 @@ SHOW INSTANCE OPTIONS mysqld2;
 
 START INSTANCE mysqld2;
 
-# FIXME
--- sleep 3
+# FIXME: START INSTANCE should be synchronous.
+--sleep 3
+# should be longer than monitoring interval and enough to start instance.
 
 STOP INSTANCE mysqld2;
 
diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test
index 048da802d02d3e559215b66423ef89737c73b292..ef172f6b138e45765e924d922535aca276c4d803 100644
--- a/mysql-test/t/log_tables.test
+++ b/mysql-test/t/log_tables.test
@@ -16,7 +16,7 @@ use mysql;
 #
 
 truncate table general_log;
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 3 THREAD_ID
 select * from general_log;
 truncate table slow_log;
 --replace_column 1 TIMESTAMP
@@ -31,7 +31,7 @@ select * from slow_log;
 #
 
 truncate table general_log;
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 3 THREAD_ID
 select * from general_log where argument like '%general_log%';
 
 
@@ -156,7 +156,7 @@ truncate table mysql.general_log;
 set names utf8;
 create table bug16905 (s char(15) character set utf8 default 'пусто');
 insert into bug16905 values ('новое');
---replace_column 1 TIMESTAMP
+--replace_column 1 TIMESTAMP 3 THREAD_ID
 select * from mysql.general_log;
 drop table bug16905;
 
diff --git a/mysys/default.c b/mysys/default.c
index 580bcc19eca8e545809ed5f484f35d7e82fb93ab..3a80d7b37b9de3773e9051efcc9475d213c9b719 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -244,7 +244,8 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv,
                             handle_option_ctx structure.
     group_name              The name of the group the option belongs to.
     option                  The very option to be processed. It is already
-                            prepared to be used in argv (has -- prefix)
+                            prepared to be used in argv (has -- prefix). If it
+                            is NULL, we are handling a new group (section).
 
   DESCRIPTION
     This handler checks whether a group is one of the listed and adds an option
@@ -263,6 +264,9 @@ static int handle_default_option(void *in_ctx, const char *group_name,
   char *tmp;
   struct handle_option_ctx *ctx= (struct handle_option_ctx *) in_ctx;
 
+  if (!option)
+    return 0;
+
   if (find_type((char *)group_name, ctx->group, 3))
   {
     if (!(tmp= alloc_root(ctx->alloc, (uint) strlen(option) + 1)))
@@ -719,6 +723,10 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
       end[0]=0;
 
       strnmov(curr_gr, ptr, min((uint) (end-ptr)+1, 4096));
+
+      /* signal that a new group is found */
+      opt_handler(handler_ctx, curr_gr, NULL);
+
       continue;
     }
     if (!found_group)
diff --git a/mysys/default_modify.c b/mysys/default_modify.c
index 0f58b8a930c7b00a1961edf561a775aaab298697..8dbcac699eace1c75d15bb364bbe603109bcb4f5 100644
--- a/mysys/default_modify.c
+++ b/mysys/default_modify.c
@@ -40,11 +40,13 @@ static char *add_option(char *dst, const char *option_value,
   SYNOPSYS
     modify_defaults_file()
     file_location     The location of configuration file to edit
-    option            option to look for
-    option value      The value of the option we would like to set
-    section_name      the name of the section
-    remove_option     This is true if we want to remove the option.
-                      False otherwise.
+    option            The name of the option to look for (can be NULL)
+    option value      The value of the option we would like to set (can be NULL)
+    section_name      The name of the section (must be NOT NULL)
+    remove_option     This defines what we want to remove:
+                        - MY_REMOVE_NONE -- nothing to remove;
+                        - MY_REMOVE_OPTION -- remove the specified option;
+                        - MY_REMOVE_SECTION -- remove the specified section;
   IMPLEMENTATION
     We open the option file first, then read the file line-by-line,
     looking for the section we need. At the same time we put these lines
@@ -67,7 +69,9 @@ int modify_defaults_file(const char *file_location, const char *option,
   FILE *cnf_file;
   MY_STAT file_stat;
   char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
-  uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size;
+  uint opt_len= 0;
+  uint optval_len= 0;
+  uint sect_len, nr_newlines= 0, buffer_size;
   my_bool in_section= FALSE, opt_applied= 0;
   uint reserve_extended;
   uint new_opt_len;
@@ -81,8 +85,11 @@ int modify_defaults_file(const char *file_location, const char *option,
   if (my_fstat(fileno(cnf_file), &file_stat, MYF(0)))
     goto malloc_err;
 
-  opt_len= (uint) strlen(option);
-  optval_len= (uint) strlen(option_value);
+  if (option && option_value)
+  {
+    opt_len= (uint) strlen(option);
+    optval_len= (uint) strlen(option_value);
+  }
 
   new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
 
@@ -119,8 +126,8 @@ int modify_defaults_file(const char *file_location, const char *option,
       continue;
     }
 
-    /* correct the option */
-    if (in_section && !strncmp(src_ptr, option, opt_len) &&
+    /* correct the option (if requested) */
+    if (option && in_section && !strncmp(src_ptr, option, opt_len) &&
         (*(src_ptr + opt_len) == '=' ||
          my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) ||
          *(src_ptr + opt_len) == '\0'))
@@ -143,7 +150,12 @@ int modify_defaults_file(const char *file_location, const char *option,
     }
     else
     {
-      /* If going to new group and we have option to apply, do it now */
+      /*
+        If we are going to the new group and have an option to apply, do
+        it now. If we are removing a single option or the whole section
+        this will only trigger opt_applied flag.
+      */
+
       if (in_section && !opt_applied && *src_ptr == '[')
       {
         dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
@@ -153,7 +165,10 @@ int modify_defaults_file(const char *file_location, const char *option,
 
       for (; nr_newlines; nr_newlines--)
         dst_ptr= strmov(dst_ptr, NEWLINE);
-      dst_ptr= strmov(dst_ptr, linebuff);
+
+      /* Skip the section if MY_REMOVE_SECTION was given */
+      if (!in_section || remove_option != MY_REMOVE_SECTION)
+        dst_ptr= strmov(dst_ptr, linebuff);
     }
     /* Look for a section */
     if (*src_ptr == '[')
@@ -167,18 +182,31 @@ int modify_defaults_file(const char *file_location, const char *option,
         {}
 
         if (*src_ptr != ']')
+        {
+          in_section= FALSE;
           continue; /* Missing closing parenthesis. Assume this was no group */
+        }
+
+        if (remove_option == MY_REMOVE_SECTION)
+          dst_ptr= dst_ptr - strlen(linebuff);
+
         in_section= TRUE;
       }
       else
         in_section= FALSE; /* mark that this section is of no interest to us */
     }
   }
-  /* File ended. */
-  if (!opt_applied && !remove_option && in_section)
+
+  /*
+    File ended. Apply an option or set opt_applied flag (in case of
+    MY_REMOVE_SECTION) so that the changes are saved. Do not do anything
+    if we are removing non-existent option.
+  */
+
+  if (!opt_applied && in_section && (remove_option != MY_REMOVE_OPTION))
   {
     /* New option still remains to apply at the end */
-    if (*(dst_ptr - 1) != '\n')
+    if (!remove_option && *(dst_ptr - 1) != '\n')
       dst_ptr= strmov(dst_ptr, NEWLINE);
     dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
     opt_applied= 1;
diff --git a/server-tools/instance-manager/CMakeLists.txt b/server-tools/instance-manager/CMakeLists.txt
index c20b9c7f9dfeee7a371abc1176a52fb7e441ed79..1983d459ce28cdf2cac4162a9ebc2bc0ad28583e 100644
--- a/server-tools/instance-manager/CMakeLists.txt
+++ b/server-tools/instance-manager/CMakeLists.txt
@@ -9,6 +9,7 @@ ADD_EXECUTABLE(mysqlmanager buffer.cc command.cc commands.cc guardian.cc instanc
                             instance_options.cc listener.cc log.cc manager.cc messages.cc mysql_connection.cc
                             mysqlmanager.cc options.cc parse.cc parse_output.cc priv.cc protocol.cc
                             thread_registry.cc user_map.cc imservice.cpp windowsservice.cpp
+                            user_management_commands.cc
                             ../../sql/net_serv.cc ../../sql-common/pack.c ../../sql/password.c
                             ../../sql/sql_state.c ../../sql-common/client.c ../../libmysql/get_password.c
                             ../../libmysql/errmsg.c)
diff --git a/server-tools/instance-manager/IMService.cpp b/server-tools/instance-manager/IMService.cpp
index b7ea8e7eb8132daac8016368cdfdf8a188e1561f..f9ea7ee471d6caa05633d057d3557f6323b4a1e3 100644
--- a/server-tools/instance-manager/IMService.cpp
+++ b/server-tools/instance-manager/IMService.cpp
@@ -20,7 +20,7 @@ IMService::~IMService(void)
 void IMService::Stop()
 {
   ReportStatus(SERVICE_STOP_PENDING);
-  
+
   // stop the IM work
   raise(SIGTERM);
 }
@@ -30,15 +30,14 @@ void IMService::Run(DWORD argc, LPTSTR *argv)
   // report to the SCM that we're about to start
   ReportStatus((DWORD)SERVICE_START_PENDING);
 
-  Options o;
-  o.load(argc, argv);
-  
+  Options::load(argc, argv);
+
   // init goes here
   ReportStatus((DWORD)SERVICE_RUNNING);
 
   // wait for main loop to terminate
-  manager(o);
-  o.cleanup();
+  manager();
+  Options::cleanup();
 }
 
 void IMService::Log(const char *msg)
@@ -46,13 +45,13 @@ void IMService::Log(const char *msg)
   log_info(msg);
 }
 
-int HandleServiceOptions(Options options)
+int HandleServiceOptions()
 {
   int ret_val= 0;
 
   IMService winService;
 
-  if (options.install_as_service)
+  if (Options::Service::install_as_service)
   {
     if (winService.IsInstalled())
       log_info("Service is already installed");
@@ -64,7 +63,7 @@ int HandleServiceOptions(Options options)
       ret_val= 1;
     }
   }
-  else if (options.remove_service)
+  else if (Options::Service::remove_service)
   {
     if (! winService.IsInstalled())
       log_info("Service is not installed");
@@ -77,6 +76,19 @@ int HandleServiceOptions(Options options)
     }
   }
   else
-    ret_val= !winService.Init();
+  {
+    log_info("Initializing Instance Manager service...");
+
+    if (!winService.Init())
+    {
+      log_info("Service failed to initialize.");
+      fprintf(stderr,
+              "The service should be started by Windows Service Manager.\n"
+              "The MySQL Manager should be started with '--standalone'\n"
+              "to run from command line.");
+      ret_val= 1;
+    }
+  }
+
   return ret_val;
 }
diff --git a/server-tools/instance-manager/IMService.h b/server-tools/instance-manager/IMService.h
index cad38bebdafbed4632b624a71a3374863ad1a4d7..94d59c2af317a7e5e279a25af0fd093a77ad74e9 100644
--- a/server-tools/instance-manager/IMService.h
+++ b/server-tools/instance-manager/IMService.h
@@ -1,3 +1,21 @@
+/*
+   Copyright (C) 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
+*/
+
 #pragma once
 #include "windowsservice.h"
 
@@ -12,3 +30,5 @@ class IMService : public WindowsService
   void Stop();
   void Run(DWORD argc, LPTSTR *argv);
 };
+
+extern int HandleServiceOptions();
diff --git a/server-tools/instance-manager/Makefile.am b/server-tools/instance-manager/Makefile.am
index 6ab5c3d1bfc41b33b68da53eec4d0ef62aea48cc..4139bf2eb105fbbe5d143e45bcb80f009882870e 100644
--- a/server-tools/instance-manager/Makefile.am
+++ b/server-tools/instance-manager/Makefile.am
@@ -76,7 +76,10 @@ mysqlmanager_SOURCES=	command.cc command.h mysqlmanager.cc \
 			guardian.cc guardian.h \
 			parse_output.cc parse_output.h \
                         mysql_manager_error.h \
-                        portability.h
+                        portability.h \
+			exit_codes.h \
+			user_management_commands.h \
+			user_management_commands.cc
 
 mysqlmanager_LDADD=	@CLIENT_EXTRA_LDFLAGS@ \
 			liboptions.la \
diff --git a/server-tools/instance-manager/WindowsService.cpp b/server-tools/instance-manager/WindowsService.cpp
index 192045b7a4c5a056a562ed4ce048bf2e697045b3..8a36a2f2fdd965a08f2f724d2043b0d9412931b3 100644
--- a/server-tools/instance-manager/WindowsService.cpp
+++ b/server-tools/instance-manager/WindowsService.cpp
@@ -7,9 +7,9 @@ static WindowsService *gService;
 WindowsService::WindowsService(void) :
   statusCheckpoint(0),
   serviceName(NULL),
-  inited(false),
+  inited(FALSE),
   dwAcceptedControls(SERVICE_ACCEPT_STOP),
-  debugging(false)
+  debugging(FALSE)
 {
   gService= this;
   status.dwServiceType= SERVICE_WIN32_OWN_PROCESS;
@@ -22,11 +22,12 @@ WindowsService::~WindowsService(void)
 
 BOOL WindowsService::Install()
 {
-  bool ret_val= false;
+  bool ret_val= FALSE;
   SC_HANDLE newService;
   SC_HANDLE scm;
 
-  if (IsInstalled()) return true;
+  if (IsInstalled())
+    return TRUE;
 
   // determine the name of the currently executing file
   char szFilePath[_MAX_PATH];
@@ -34,7 +35,7 @@ BOOL WindowsService::Install()
 
   // open a connection to the SCM
   if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE)))
-    return false;
+    return FALSE;
 
   newService= CreateService(scm, serviceName, displayName,
                             SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
@@ -45,7 +46,7 @@ BOOL WindowsService::Install()
   if (newService)
   {
     CloseServiceHandle(newService);
-    ret_val= true;
+    ret_val= TRUE;
   }
 
   CloseServiceHandle(scm);
@@ -56,34 +57,35 @@ BOOL WindowsService::Init()
 {
   assert(serviceName != NULL);
 
-  if (inited) return true;
+  if (inited)
+    return TRUE;
 
   SERVICE_TABLE_ENTRY stb[] =
   {
     { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
     { NULL, NULL }
   };
-  inited= true;
+  inited= TRUE;
   return StartServiceCtrlDispatcher(stb); //register with the Service Manager
 }
 
 BOOL WindowsService::Remove()
 {
-  bool  ret_val= false;
+  bool ret_val= FALSE;
 
-  if (! IsInstalled())
-    return true;
+  if (!IsInstalled())
+    return TRUE;
 
   // open a connection to the SCM
   SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE);
-  if (! scm)
-    return false;
+  if (!scm)
+    return FALSE;
 
   SC_HANDLE service= OpenService(scm, serviceName, DELETE);
   if (service)
   {
     if (DeleteService(service))
-      ret_val= true;
+      ret_val= TRUE;
     DWORD dw= ::GetLastError();
     CloseServiceHandle(service);
   }
@@ -116,7 +118,8 @@ void WindowsService::SetAcceptedControls(DWORD acceptedControls)
 BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint,
                                   DWORD dwError)
 {
-  if(debugging) return TRUE;
+  if (debugging)
+    return TRUE;
 
   if(currentState == SERVICE_START_PENDING)
     status.dwControlsAccepted= 0;
diff --git a/server-tools/instance-manager/WindowsService.h b/server-tools/instance-manager/WindowsService.h
index 1a034ce13518da4f6bf760e4cc2227ad4c23e91b..3af7cdf39a7bacd1ce4b3e22584376f180661149 100644
--- a/server-tools/instance-manager/WindowsService.h
+++ b/server-tools/instance-manager/WindowsService.h
@@ -1,3 +1,21 @@
+/*
+   Copyright (C) 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
+*/
+
 #pragma once
 
 class WindowsService
diff --git a/server-tools/instance-manager/command.h b/server-tools/instance-manager/command.h
index b84cc6a8e9e918dbf9086e83f3f55d60b2d2a6c5..f31ea4048670de6be4126a81c83ee351262654fc 100644
--- a/server-tools/instance-manager/command.h
+++ b/server-tools/instance-manager/command.h
@@ -22,10 +22,12 @@
 #pragma interface
 #endif
 
-/* Class responsible for allocation of im commands. */
+/* Class responsible for allocation of IM commands. */
 
 class Instance_map;
 
+struct st_net;
+
 /*
   Command - entry point for any command.
   GangOf4: 'Command' design pattern
@@ -37,8 +39,18 @@ class Command
   Command(Instance_map *instance_map_arg= 0);
   virtual ~Command();
 
-  /* method of executing: */
-  virtual int execute(struct st_net *net, ulong connection_id) = 0;
+  /*
+    This operation incapsulates behaviour of the command.
+
+    SYNOPSYS
+      net             The network connection to the client.
+      connection_id   Client connection ID
+
+    RETURN
+      0               On success
+      non 0           On error. Client error code is returned.
+  */
+  virtual int execute(st_net *net, ulong connection_id) = 0;
 
 protected:
   Instance_map *instance_map;
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc
index 7b999f615038abfc36c5d7ecbd218d5915a7a358..07e1e9a18f3a8254c3ccf5324368bb7a56cdc041 100644
--- a/server-tools/instance-manager/commands.cc
+++ b/server-tools/instance-manager/commands.cc
@@ -14,36 +14,53 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
+#pragma implementation
+#endif
+
 #include "commands.h"
 
+#include <my_global.h>
+#include <m_ctype.h>
+#include <mysql.h>
+#include <my_dir.h>
+
+#include "buffer.h"
+#include "guardian.h"
 #include "instance_map.h"
+#include "log.h"
+#include "manager.h"
 #include "messages.h"
 #include "mysqld_error.h"
 #include "mysql_manager_error.h"
-#include "protocol.h"
-#include "buffer.h"
 #include "options.h"
+#include "priv.h"
+#include "protocol.h"
 
-#include <m_string.h>
-#include <m_ctype.h>
-#include <mysql.h>
-#include <my_dir.h>
+
+/*
+  modify_defaults_to_im_error -- a map of error codes of
+  mysys::modify_defaults_file() into Instance Manager error codes.
+*/
+
+static const int modify_defaults_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
+                                                  ER_ACCESS_OPTION_FILE };
 
 
 /*
-  Add a string to a buffer
+  Add a string to a buffer.
 
   SYNOPSYS
     put_to_buff()
     buff              buffer to add the string
     str               string to add
-    uint              offset in the buff to add a string
+    position          offset in the buff to add a string
 
   DESCRIPTION
 
   Function to add a string to the buffer. It is different from
-  store_to_protocol_packet, which is used in the protocol.cc. The last
-  one also stores the length of the string in a special way.
+  store_to_protocol_packet, which is used in the protocol.cc.
+  The last one also stores the length of the string in a special way.
   This is required for MySQL client/server protocol support only.
 
   RETURN
@@ -51,7 +68,6 @@
     1 - error occured
 */
 
-
 static inline int put_to_buff(Buffer *buff, const char *str, uint *position)
 {
   uint len= strlen(str);
@@ -88,749 +104,1615 @@ static int parse_version_number(const char *version_str, char *version,
 }
 
 
-/* implementation for Show_instances: */
+/**************************************************************************
+ Implementation of Instance_name.
+**************************************************************************/
 
+Instance_name::Instance_name(const LEX_STRING *name)
+{
+  str.str= str_buffer;
+  str.length= name->length;
 
-/*
-  The method sends a list of instances in the instance map to the client.
+  if (str.length > MAX_INSTANCE_NAME_SIZE - 1)
+    str.length= MAX_INSTANCE_NAME_SIZE - 1;
 
-  SYNOPSYS
-    Show_instances::execute()
-    net                    The network connection to the client.
-    connection_id          Client connection ID
+  strmake(str.str, name->str, str.length);
+}
 
-  RETURN
-    0 - ok
-    1 - error occured
+/**************************************************************************
+ Implementation of Show_instances.
+**************************************************************************/
+
+/*
+  Implementation of SHOW INSTANCES statement.
+
+  Possible error codes:
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
 */
 
-int Show_instances::execute(struct st_net *net, ulong connection_id)
+int Show_instances::execute(st_net *net, ulong connection_id)
 {
-  Buffer send_buff;  /* buffer for packets */
-  LIST name, status;
-  NAME_WITH_LENGTH name_field, status_field;
+  int err_code;
+
+  if ((err_code= write_header(net)) ||
+      (err_code= write_data(net)))
+    return err_code;
+
+  if (send_eof(net) || net_flush(net))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}
+
+
+int Show_instances::write_header(st_net *net)
+{
+  LIST name, state;
+  LEX_STRING name_field, state_field;
   LIST *field_list;
-  uint position=0;
 
-  name_field.name= (char*) "instance_name";
+  name_field.str= (char *) "instance_name";
   name_field.length= DEFAULT_FIELD_LENGTH;
   name.data= &name_field;
-  status_field.name= (char*) "status";
-  status_field.length= DEFAULT_FIELD_LENGTH;
-  status.data= &status_field;
-  field_list= list_add(NULL, &status);
+
+  state_field.str= (char *) "state";
+  state_field.length= DEFAULT_FIELD_LENGTH;
+  state.data= &state_field;
+
+  field_list= list_add(NULL, &state);
   field_list= list_add(field_list, &name);
 
-  send_fields(net, field_list);
+  return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+
+int Show_instances::write_data(st_net *net)
+{
+  my_bool err_status= FALSE;
+
+  Instance *instance;
+  Instance_map::Iterator iterator(instance_map);
+
+  instance_map->guardian->lock();
+  instance_map->lock();
 
+  while ((instance= iterator.next()))
   {
-    Instance *instance;
-    Instance_map::Iterator iterator(instance_map);
+    Buffer send_buf;  /* buffer for packets */
+    uint pos= 0;
+
+    const char *instance_name= instance->options.instance_name.str;
+    const char *state_name= instance_map->get_instance_state_name(instance);
 
-    instance_map->lock();
-    while ((instance= iterator.next()))
+    if (store_to_protocol_packet(&send_buf, instance_name, &pos) ||
+        store_to_protocol_packet(&send_buf, state_name, &pos) ||
+        my_net_write(net, send_buf.buffer, pos))
     {
-      position= 0;
-      store_to_protocol_packet(&send_buff, instance->options.instance_name,
-                               &position);
-      if (instance->is_running())
-        store_to_protocol_packet(&send_buff, (char*) "online", &position);
-      else
-        store_to_protocol_packet(&send_buff, (char*) "offline", &position);
-      if (my_net_write(net, send_buff.buffer, (uint) position))
-        goto err;
+      err_status= TRUE;
+      break;
     }
-    instance_map->unlock();
   }
-  if (send_eof(net))
-    goto err;
-  if (net_flush(net))
-    goto err;
 
-  return 0;
-err:
-  return ER_OUT_OF_RESOURCES;
+  instance_map->unlock();
+  instance_map->guardian->unlock();
+
+  return err_status ? ER_OUT_OF_RESOURCES : 0;
 }
 
 
-/* implementation for Flush_instances: */
+/**************************************************************************
+ Implementation of Flush_instances.
+**************************************************************************/
+
+/*
+  Implementation of FLUSH INSTANCES statement.
+
+  Possible error codes:
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+    ER_THERE_IS_ACTIVE_INSTACE  If there is an active instance
+*/
 
-int Flush_instances::execute(struct st_net *net, ulong connection_id)
+int Flush_instances::execute(st_net *net, ulong connection_id)
 {
-  if (instance_map->flush_instances() ||
-      net_send_ok(net, connection_id, NULL))
+  instance_map->guardian->lock();
+  instance_map->lock();
+
+  if (instance_map->is_there_active_instance())
+  {
+    instance_map->unlock();
+    instance_map->guardian->unlock();
+    return ER_THERE_IS_ACTIVE_INSTACE;
+  }
+
+  if (instance_map->flush_instances())
+  {
+    instance_map->unlock();
+    instance_map->guardian->unlock();
     return ER_OUT_OF_RESOURCES;
+  }
 
-  return 0;
+  instance_map->unlock();
+  instance_map->guardian->unlock();
+
+  return net_send_ok(net, connection_id, NULL) ? ER_OUT_OF_RESOURCES : 0;
 }
 
 
-/* implementation for Show_instance_status: */
+/**************************************************************************
+ Implementation of Abstract_instance_cmd.
+**************************************************************************/
 
-Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
-                                           const char *name, uint len)
-  :Command(instance_map_arg)
+Abstract_instance_cmd::Abstract_instance_cmd(
+  Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
+  :Command(instance_map_arg),
+  instance_name(instance_name_arg)
 {
-  Instance *instance;
+  /*
+    MT-NOTE: we can not make a search for Instance object here,
+    because it can dissappear after releasing the lock.
+  */
+}
+
+
+int Abstract_instance_cmd::execute(st_net *net, ulong connection_id)
+{
+  int err_code;
+
+  instance_map->lock();
+
+  {
+    Instance *instance= instance_map->find(get_instance_name());
+
+    if (!instance)
+    {
+      instance_map->unlock();
+      return ER_BAD_INSTANCE_NAME;
+    }
+
+    err_code= execute_impl(net, instance);
+  }
+
+  instance_map->unlock();
 
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-    instance_name= instance->options.instance_name;
-  else
-    instance_name= NULL;
+  if (!err_code)
+    err_code= send_ok_response(net, connection_id);
+
+  return err_code;
 }
 
 
-/*
-  The method sends a table with a status of requested instance to the client.
+/**************************************************************************
+ Implementation of Show_instance_status.
+**************************************************************************/
 
-  SYNOPSYS
-    Show_instance_status::do_command()
-    net               The network connection to the client.
-    instance_name     The name of the instance.
+Show_instance_status::Show_instance_status(Instance_map *instance_map_arg,
+                                           const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
 
-  RETURN
-    0 - ok
-    1 - error occured
+
+/*
+  Implementation of SHOW INSTANCE STATUS statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
 */
 
+int Show_instance_status::execute_impl(st_net *net, Instance *instance)
+{
+  int err_code;
+
+  if ((err_code= write_header(net)) ||
+      (err_code= write_data(net, instance)))
+    return err_code;
+
+  return 0;
+}
 
-int Show_instance_status::execute(struct st_net *net,
-                                  ulong connection_id)
+
+int Show_instance_status::send_ok_response(st_net *net, ulong connection_id)
 {
-  enum { MAX_VERSION_LENGTH= 40 };
-  Buffer send_buff;  /* buffer for packets */
-  LIST name, status, version, version_number;
+  if (send_eof(net) || net_flush(net))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}
+
+
+int Show_instance_status::write_header(st_net *net)
+{
+  LIST name, state, version, version_number, mysqld_compatible;
   LIST *field_list;
-  NAME_WITH_LENGTH name_field, status_field, version_field,
-                   version_number_field;
-  uint position=0;
+  LEX_STRING name_field, state_field, version_field,
+                   version_number_field, mysqld_compatible_field;
 
-  if (!instance_name)
-    return ER_BAD_INSTANCE_NAME;
+  /* Create list of the fileds to be passed to send_fields(). */
 
-  /* create list of the fileds to be passed to send_fields */
-  name_field.name= (char*) "instance_name";
+  name_field.str= (char *) "instance_name";
   name_field.length= DEFAULT_FIELD_LENGTH;
   name.data= &name_field;
-  status_field.name= (char*) "status";
-  status_field.length= DEFAULT_FIELD_LENGTH;
-  status.data= &status_field;
-  version_field.name= (char*) "version";
+
+  state_field.str= (char *) "state";
+  state_field.length= DEFAULT_FIELD_LENGTH;
+  state.data= &state_field;
+
+  version_field.str= (char *) "version";
   version_field.length= MAX_VERSION_LENGTH;
   version.data= &version_field;
-  version_number_field.name= (char*) "version_number";
+
+  version_number_field.str= (char *) "version_number";
   version_number_field.length= MAX_VERSION_LENGTH;
   version_number.data= &version_number_field;
-  field_list= list_add(NULL, &version);
+
+  mysqld_compatible_field.str= (char *) "mysqld_compatible";
+  mysqld_compatible_field.length= DEFAULT_FIELD_LENGTH;
+  mysqld_compatible.data= &mysqld_compatible_field;
+
+  field_list= list_add(NULL, &mysqld_compatible);
+  field_list= list_add(field_list, &version);
   field_list= list_add(field_list, &version_number);
-  field_list= list_add(field_list, &status);
+  field_list= list_add(field_list, &state);
   field_list= list_add(field_list, &name);
 
-  send_fields(net, field_list);
+  return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
 
-  {
-    Instance *instance;
 
-    store_to_protocol_packet(&send_buff, (char*) instance_name, &position);
-    if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
-      goto err;
-    if (instance->is_running())
-      store_to_protocol_packet(&send_buff, (char*) "online", &position);
-    else
-      store_to_protocol_packet(&send_buff, (char*) "offline", &position);
+int Show_instance_status::write_data(st_net *net, Instance *instance)
+{
+  Buffer send_buf;  /* buffer for packets */
+  char version_num_buf[MAX_VERSION_LENGTH];
+  uint pos= 0;
 
-    if (instance->options.mysqld_version)
-    {
-      char parsed_version[MAX_VERSION_LENGTH];
+  const char *state_name;
+  const char *version_tag= "unknown";
+  const char *version_num= "unknown";
+  const char *mysqld_compatible_status;
 
-      parse_version_number(instance->options.mysqld_version, parsed_version,
-                           sizeof(parsed_version));
-      store_to_protocol_packet(&send_buff, parsed_version, &position);
+  instance_map->guardian->lock();
+  state_name= instance_map->get_instance_state_name(instance);
+  mysqld_compatible_status= instance->is_mysqld_compatible() ? "yes" : "no";
+  instance_map->guardian->unlock();
 
-      store_to_protocol_packet(&send_buff, instance->options.mysqld_version,
-                               &position);
-    }
-    else
-    {
-      store_to_protocol_packet(&send_buff, (char*) "unknown", &position);
-      store_to_protocol_packet(&send_buff, (char*) "unknown", &position);
-    }
+  if (instance->options.mysqld_version)
+  {
 
+    if (parse_version_number(instance->options.mysqld_version, version_num_buf,
+                             sizeof(version_num_buf)))
+      return ER_OUT_OF_RESOURCES;
 
-    if (send_buff.is_error() ||
-        my_net_write(net, send_buff.buffer, (uint) position))
-      goto err;
+    version_num= version_num_buf;
+    version_tag= instance->options.mysqld_version;
   }
 
-  if (send_eof(net) || net_flush(net))
-    goto err;
+  if (store_to_protocol_packet(&send_buf, get_instance_name()->str, &pos) ||
+      store_to_protocol_packet(&send_buf, state_name, &pos) ||
+      store_to_protocol_packet(&send_buf, version_num, &pos) ||
+      store_to_protocol_packet(&send_buf, version_tag, &pos) ||
+      store_to_protocol_packet(&send_buf, mysqld_compatible_status, &pos) ||
+      my_net_write(net, send_buf.buffer, (uint) pos))
+  {
+    return ER_OUT_OF_RESOURCES;
+  }
 
   return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Show_instance_options.
+**************************************************************************/
 
-err:
-  return ER_OUT_OF_RESOURCES;
+Show_instance_options::Show_instance_options(
+  Instance_map *instance_map_arg, const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
 }
 
 
-/* Implementation for Show_instance_options */
+/*
+  Implementation of SHOW INSTANCE OPTIONS statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
 
-Show_instance_options::Show_instance_options(Instance_map *instance_map_arg,
-                                             const char *name, uint len):
-  Command(instance_map_arg)
+int Show_instance_options::execute_impl(st_net *net, Instance *instance)
 {
-  Instance *instance;
+  int err_code;
+
+  if ((err_code= write_header(net)) ||
+      (err_code= write_data(net, instance)))
+    return err_code;
+
+  return 0;
+}
+
+
+int Show_instance_options::send_ok_response(st_net *net, ulong connection_id)
+{
+  if (send_eof(net) || net_flush(net))
+    return ER_OUT_OF_RESOURCES;
 
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-    instance_name= instance->options.instance_name;
-  else
-    instance_name= NULL;
+  return 0;
 }
 
 
-int Show_instance_options::execute(struct st_net *net, ulong connection_id)
+int Show_instance_options::write_header(st_net *net)
 {
-  Buffer send_buff;  /* buffer for packets */
   LIST name, option;
   LIST *field_list;
-  NAME_WITH_LENGTH name_field, option_field;
-  uint position=0;
+  LEX_STRING name_field, option_field;
 
-  if (!instance_name)
-    return ER_BAD_INSTANCE_NAME;
+  /* Create list of the fileds to be passed to send_fields(). */
 
-  /* create list of the fileds to be passed to send_fields */
-  name_field.name= (char*) "option_name";
+  name_field.str= (char *) "option_name";
   name_field.length= DEFAULT_FIELD_LENGTH;
   name.data= &name_field;
-  option_field.name= (char*) "value";
+
+  option_field.str= (char *) "value";
   option_field.length= DEFAULT_FIELD_LENGTH;
   option.data= &option_field;
+
   field_list= list_add(NULL, &option);
   field_list= list_add(field_list, &name);
 
-  send_fields(net, field_list);
+  return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+
+int Show_instance_options::write_data(st_net *net, Instance *instance)
+{
+  Buffer send_buff;  /* buffer for packets */
+  uint pos= 0;
 
+  if (store_to_protocol_packet(&send_buff, "instance_name", &pos) ||
+      store_to_protocol_packet(&send_buff, get_instance_name()->str, &pos) ||
+      my_net_write(net, send_buff.buffer, pos))
   {
-    Instance *instance;
-
-    if (!(instance= instance_map->find(instance_name, strlen(instance_name))))
-      goto err;
-    store_to_protocol_packet(&send_buff, (char*) "instance_name", &position);
-    store_to_protocol_packet(&send_buff, (char*) instance_name, &position);
-    if (my_net_write(net, send_buff.buffer, (uint) position))
-      goto err;
-    if ((instance->options.mysqld_path))
-    {
-      position= 0;
-      store_to_protocol_packet(&send_buff, (char*) "mysqld-path", &position);
-      store_to_protocol_packet(&send_buff,
-                               (char*) instance->options.mysqld_path,
-                               &position);
-      if (send_buff.is_error() ||
-          my_net_write(net, send_buff.buffer, (uint) position))
-        goto err;
-    }
+    return ER_OUT_OF_RESOURCES;
+  }
 
-    if ((instance->options.nonguarded))
-    {
-      position= 0;
-      store_to_protocol_packet(&send_buff, (char*) "nonguarded", &position);
-      store_to_protocol_packet(&send_buff, "", &position);
-      if (send_buff.is_error() ||
-          my_net_write(net, send_buff.buffer, (uint) position))
-        goto err;
-    }
+  /* Loop through the options. */
 
-    /* loop through the options stored in DYNAMIC_ARRAY */
-    for (uint i= 0; i < instance->options.options_array.elements; i++)
-    {
-      char *tmp_option, *option_value;
-      get_dynamic(&(instance->options.options_array), (gptr) &tmp_option, i);
-      option_value= strchr(tmp_option, '=');
-      /* split the option string into two parts if it has a value */
+  for (int i= 0; i < instance->options.get_num_options(); i++)
+  {
+    Named_value option= instance->options.get_option(i);
+    const char *option_value= option.get_value()[0] ? option.get_value() : "";
 
-      position= 0;
-      if (option_value != NULL)
-      {
-        *option_value= 0;
-        store_to_protocol_packet(&send_buff, tmp_option + 2, &position);
-        store_to_protocol_packet(&send_buff, option_value + 1, &position);
-        /* join name and the value into the same option again */
-        *option_value= '=';
-      }
-      else
-      {
-        store_to_protocol_packet(&send_buff, tmp_option + 2, &position);
-        store_to_protocol_packet(&send_buff, "", &position);
-      }
+    pos= 0;
 
-      if (send_buff.is_error() ||
-          my_net_write(net, send_buff.buffer, (uint) position))
-        goto err;
+    if (store_to_protocol_packet(&send_buff, option.get_name(), &pos) ||
+        store_to_protocol_packet(&send_buff, option_value, &pos) ||
+        my_net_write(net, send_buff.buffer, pos))
+    {
+      return ER_OUT_OF_RESOURCES;
     }
   }
 
-  if (send_eof(net) || net_flush(net))
-    goto err;
-
   return 0;
-
-err:
-  return ER_OUT_OF_RESOURCES;
 }
 
 
-/* Implementation for Start_instance */
+/**************************************************************************
+ Implementation of Start_instance.
+**************************************************************************/
 
 Start_instance::Start_instance(Instance_map *instance_map_arg,
-                               const char *name, uint len)
-  :Command(instance_map_arg)
+                               const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
 {
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-    instance_name= instance->options.instance_name;
 }
 
 
-int Start_instance::execute(struct st_net *net, ulong connection_id)
+/*
+  Implementation of START INSTANCE statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
+
+int Start_instance::execute_impl(st_net *net, Instance *instance)
 {
-  uint err_code;
-  if (instance == 0)
-    return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
-  else
-  {
-    if ((err_code= instance->start()))
-      return err_code;
+  int err_code;
 
-    if (!(instance->options.nonguarded))
-        instance_map->guardian->guard(instance);
+  if ((err_code= instance->start()))
+    return err_code;
 
-    net_send_ok(net, connection_id, "Instance started");
-    return 0;
-  }
+  if (!(instance->options.nonguarded))
+    instance_map->guardian->guard(instance);
+
+  return 0;
 }
 
 
-/* implementation for Show_instance_log: */
+int Start_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+  if (net_send_ok(net, connection_id, "Instance started"))
+    return ER_OUT_OF_RESOURCES;
 
-Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
-                                     const char *name, uint len,
-                                     Log_type log_type_arg,
-                                     const char *size_arg,
-                                     const char *offset_arg)
-  :Command(instance_map_arg)
+  return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Stop_instance.
+**************************************************************************/
+
+Stop_instance::Stop_instance(Instance_map *instance_map_arg,
+                             const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
 {
-  Instance *instance;
+}
+
+
+/*
+  Implementation of STOP INSTANCE statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
+
+int Stop_instance::execute_impl(st_net *net, Instance *instance)
+{
+  int err_code;
+
+  if (!(instance->options.nonguarded))
+    instance_map->guardian->stop_guard(instance);
+
+  if ((err_code= instance->stop()))
+    return err_code;
+
+  return 0;
+}
+
 
-  if (offset_arg != NULL)
-    offset= atoi(offset_arg);
-  else
-    offset= 0;
-  size= atoi(size_arg);
-  log_type= log_type_arg;
+int Stop_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+  if (net_send_ok(net, connection_id, NULL))
+    return ER_OUT_OF_RESOURCES;
 
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-    instance_name= instance->options.instance_name;
-  else
-    instance_name= NULL;
+  return 0;
 }
 
 
+/**************************************************************************
+ Implementation for Create_instance.
+**************************************************************************/
+
+Create_instance::Create_instance(Instance_map *instance_map_arg,
+                                 const LEX_STRING *instance_name_arg)
+  :Command(instance_map_arg),
+  instance_name(instance_name_arg)
+{
+}
+
 
 /*
-  Open the logfile, read requested part of the log and send the info
-  to the client.
+  This operation initializes Create_instance object.
 
   SYNOPSYS
-    Show_instance_log::execute()
-    net                 The network connection to the client.
-    connection_id       Client connection ID
+    text            [IN/OUT] a pointer to the text containing instance options.
 
-  DESCRIPTION
+  RETURN
+    FALSE           On success.
+    TRUE            On error.
+*/
+
+bool Create_instance::init(const char **text)
+{
+  return options.init() || parse_args(text);
+}
+
+
+/*
+  This operation parses CREATE INSTANCE options.
 
-    Send a table with the content of the log requested. The function also
-    deals with errro handling, to be verbose.
+  SYNOPSYS
+    text            [IN/OUT] a pointer to the text containing instance options.
 
   RETURN
-   ER_OFFSET_ERROR      We were requested to read negative number of bytes
-                        from the log
-   ER_NO_SUCH_LOG       The kind log being read is not enabled in the instance
-   ER_GUESS_LOGFILE     IM wasn't able to figure out the log placement, while
-                        it is enabled. Probably user should specify the path
-                        to the logfile explicitly.
-   ER_OPEN_LOGFILE      Cannot open the logfile
-   ER_READ_FILE         Cannot read the logfile
-   ER_OUT_OF_RESOURCES  We weren't able to allocate some resources
+    FALSE           On success.
+    TRUE            On syntax error.
 */
 
-int Show_instance_log::execute(struct st_net *net, ulong connection_id)
+bool Create_instance::parse_args(const char **text)
 {
-  Buffer send_buff;  /* buffer for packets */
-  LIST name;
-  LIST *field_list;
-  NAME_WITH_LENGTH name_field;
-  uint position= 0;
+  uint len;
 
-  /* create list of the fileds to be passed to send_fields */
-  name_field.name= (char*) "Log";
-  name_field.length= DEFAULT_FIELD_LENGTH;
-  name.data= &name_field;
-  field_list= list_add(NULL, &name);
+  /* Check if we have something (and trim leading spaces). */
 
-  if (!instance_name)
-    return ER_BAD_INSTANCE_NAME;
+  get_word(text, &len, NONSPACE);
 
-  /* cannot read negative number of bytes */
-  if (offset > size)
-    return ER_OFFSET_ERROR;
+  if (len == 0)
+    return FALSE; /* OK: no option. */
 
-  send_fields(net, field_list);
+  /* Main parsing loop. */
 
+  while (TRUE)
   {
-    Instance *instance;
-    const char *logpath;
-    File fd;
+    LEX_STRING option_name;
+    char *option_name_str;
+    char *option_value_str= NULL;
+
+    /* Looking for option name. */
 
-    if ((instance= instance_map->find(instance_name,
-                                      strlen(instance_name))) == NULL)
-      goto err;
+    get_word(text, &option_name.length, OPTION_NAME);
 
-    logpath= instance->options.logs[log_type];
+    if (option_name.length == 0)
+      return TRUE; /* Syntax error: option name expected. */
 
-    /* Instance has no such log */
-    if (logpath == NULL)
-      return ER_NO_SUCH_LOG;
+    option_name.str= (char *) *text;
+    *text+= option_name.length;
 
-    if (*logpath == '\0')
-      return ER_GUESS_LOGFILE;
+    /* Looking for equal sign. */
 
+    skip_spaces(text);
 
-    if ((fd= my_open(logpath, O_RDONLY | O_BINARY,  MYF(MY_WME))) >= 0)
+    if (**text == '=')
     {
-      size_t buff_size;
-      int read_len;
-      /* calculate buffer size */
-      MY_STAT file_stat;
-      Buffer read_buff;
+      ++(*text); /* Skip an equal sign. */
 
-      /* my_fstat doesn't use the flag parameter */
-      if (my_fstat(fd, &file_stat, MYF(0)))
-        goto err;
+      /* Looking for option value. */
 
-      buff_size= (size - offset);
+      skip_spaces(text);
 
-      read_buff.reserve(0, buff_size);
+      if (!**text)
+        return TRUE; /* Syntax error: EOS when option value expected. */
 
-      /* read in one chunk */
-      read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
+      if (**text != '\'' && **text != '"')
+      {
+        /* Option value is a simple token. */
 
-      if ((read_len= my_read(fd, (byte*) read_buff.buffer,
-                             buff_size, MYF(0))) < 0)
-        return ER_READ_FILE;
-      store_to_protocol_packet(&send_buff, read_buff.buffer,
-                               &position, read_len);
-      close(fd);
-    }
-    else
-      return ER_OPEN_LOGFILE;
+        LEX_STRING option_value;
 
-    if (my_net_write(net, send_buff.buffer, (uint) position))
-      goto err;
-  }
+        get_word(text, &option_value.length, ALPHANUM);
 
-  if (send_eof(net) ||  net_flush(net))
-    goto err;
+        if (option_value.length == 0)
+          return TRUE; /* internal parser error. */
 
-  return 0;
+        option_value.str= (char *) *text;
+        *text+= option_value.length;
 
-err:
-  return ER_OUT_OF_RESOURCES;
-}
+        if (!(option_value_str= Named_value::alloc_str(&option_value)))
+          return TRUE; /* out of memory during parsing. */
+      }
+      else
+      {
+        /* Option value is a string. */
 
+        if (parse_option_value(*text, &len, &option_value_str))
+          return TRUE; /* Syntax error: invalid string specification. */
 
-/* implementation for Show_instance_log_files: */
+        *text+= len;
+      }
+    }
 
-Show_instance_log_files::Show_instance_log_files
-              (Instance_map *instance_map_arg, const char *name, uint len)
-  :Command(instance_map_arg)
-{
-  Instance *instance;
+    if (!option_value_str)
+    {
+      LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
 
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-    instance_name= instance->options.instance_name;
-  else
-    instance_name= NULL;
+      if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+        return TRUE; /* out of memory during parsing. */
+    }
+
+    if (!(option_name_str= Named_value::alloc_str(&option_name)))
+    {
+      Named_value::free_str(&option_value_str);
+      return TRUE; /* out of memory during parsing. */
+    }
+
+    {
+      Named_value option(option_name_str, option_value_str);
+
+      if (options.add_element(&option))
+      {
+        option.free();
+        return TRUE; /* out of memory during parsing. */
+      }
+    }
+
+    skip_spaces(text);
+
+    if (!**text)
+      return FALSE; /* OK: end of options. */
+
+    if (**text != ',')
+      return TRUE; /* Syntax error: comma expected. */
+
+    ++(*text);
+  }
 }
 
 
 /*
-  The method sends a table with a list of log files
-  used by the instance.
+  Implementation of CREATE INSTANCE statement.
 
-  SYNOPSYS
-    Show_instance_log_files::execute()
-    net               The network connection to the client.
-    connection_id     The ID of the client connection
+  Possible error codes:
+    ER_MALFORMED_INSTANCE_NAME  Instance name is malformed
+    ER_CREATE_EXISTING_INSTANCE There is an instance with the given name
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
 
-  RETURN
-    ER_BAD_INSTANCE_NAME  The instance name specified is not valid
-    ER_OUT_OF_RESOURCES   some error occured
-    0 - ok
+int Create_instance::execute(st_net *net, ulong connection_id)
+{
+  int err_code;
+
+  /* Check that the name is valid and there is no instance with such name. */
+
+  if (!Instance::is_name_valid(get_instance_name()))
+    return ER_MALFORMED_INSTANCE_NAME;
+
+  /*
+    NOTE: In order to prevent race condition, we should perform all operations
+    on under acquired lock.
+  */
+
+  instance_map->lock();
+
+  if (instance_map->find(get_instance_name()))
+  {
+    instance_map->unlock();
+    return ER_CREATE_EXISTING_INSTANCE;
+  }
+
+  if ((err_code= instance_map->create_instance(get_instance_name(), &options)))
+  {
+    instance_map->unlock();
+    return err_code;
+  }
+
+  if ((err_code= create_instance_in_file(get_instance_name(), &options)))
+  {
+    Instance *instance= instance_map->find(get_instance_name());
+
+    if (instance)
+      instance_map->remove_instance(instance); /* instance is deleted here. */
+
+    instance_map->unlock();
+    return err_code;
+  }
+
+  /* That's all. */
+
+  instance_map->unlock();
+
+  /* Send the result. */
+
+  if (net_send_ok(net, connection_id, NULL))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}
+
+
+/**************************************************************************
+ Implementation for Drop_instance.
+**************************************************************************/
+
+Drop_instance::Drop_instance(Instance_map *instance_map_arg,
+                             const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
+
+
+/*
+  Implementation of DROP INSTANCE statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_DROP_ACTIVE_INSTANCE     The specified instance is active
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
 */
 
-int Show_instance_log_files::execute(struct st_net *net, ulong connection_id)
+int Drop_instance::execute_impl(st_net *net, Instance *instance)
+{
+  int err_code;
+
+  /* Check that the instance is offline. */
+
+  if (instance_map->guardian->is_active(instance))
+    return ER_DROP_ACTIVE_INSTANCE;
+
+  err_code= modify_defaults_file(Options::Main::config_file, NULL, NULL,
+                                 get_instance_name()->str, MY_REMOVE_SECTION);
+  DBUG_ASSERT(err_code >= 0 && err_code <= 2);
+
+  if (err_code)
+  {
+    log_error("Can not remove instance '%s' from defaults file (%s). "
+              "Original error code: %d.",
+              (const char *) get_instance_name()->str,
+              (const char *) Options::Main::config_file,
+              (int) err_code);
+  }
+
+  if (err_code)
+    return modify_defaults_to_im_error[err_code];
+
+  /* Remove instance from the instance map hash and Guardian's list. */
+
+  if (!instance->options.nonguarded)
+    instance_map->guardian->stop_guard(instance);
+
+  if ((err_code= instance->stop()))
+    return err_code;
+
+  instance_map->remove_instance(instance);
+
+  return 0;
+}
+
+
+int Drop_instance::send_ok_response(st_net *net, ulong connection_id)
+{
+  if (net_send_ok(net, connection_id, "Instance dropped"))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}
+
+
+/**************************************************************************
+ Implementation for Show_instance_log.
+**************************************************************************/
+
+Show_instance_log::Show_instance_log(Instance_map *instance_map_arg,
+                                     const LEX_STRING *instance_name_arg,
+                                     Log_type log_type_arg,
+                                     uint size_arg, uint offset_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg),
+  log_type(log_type_arg),
+  size(size_arg),
+  offset(offset_arg)
+{
+}
+
+
+/*
+  Implementation of SHOW INSTANCE LOG statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_OFFSET_ERROR             We were requested to read negative number of
+                                bytes from the log
+    ER_NO_SUCH_LOG              The specified type of log is not available for
+                                the given instance
+    ER_GUESS_LOGFILE            IM wasn't able to figure out the log
+                                placement, while it is enabled. Probably user
+                                should specify the path to the logfile
+                                explicitly.
+    ER_OPEN_LOGFILE             Cannot open the logfile
+    ER_READ_FILE                Cannot read the logfile
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
+
+int Show_instance_log::execute_impl(st_net *net, Instance *instance)
+{
+  int err_code;
+
+  if ((err_code= check_params(instance)))
+    return err_code;
+
+  if ((err_code= write_header(net)) ||
+      (err_code= write_data(net, instance)))
+    return err_code;
+
+  return 0;
+}
+
+
+int Show_instance_log::send_ok_response(st_net *net, ulong connection_id)
+{
+  if (send_eof(net) || net_flush(net))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}
+
+
+int Show_instance_log::check_params(Instance *instance)
+{
+  const char *logpath= instance->options.logs[log_type];
+
+  /* Cannot read negative number of bytes. */
+
+  if (offset > size)
+    return ER_OFFSET_ERROR;
+
+  /* Instance has no such log. */
+
+  if (logpath == NULL)
+    return ER_NO_SUCH_LOG;
+
+  if (*logpath == '\0')
+    return ER_GUESS_LOGFILE;
+
+  return 0;
+}
+
+
+int Show_instance_log::write_header(st_net *net)
+{
+  LIST name;
+  LIST *field_list;
+  LEX_STRING name_field;
+
+  /* Create list of the fields to be passed to send_fields(). */
+
+  name_field.str= (char *) "Log";
+  name_field.length= DEFAULT_FIELD_LENGTH;
+
+  name.data= &name_field;
+
+  field_list= list_add(NULL, &name);
+
+  return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
+
+
+int Show_instance_log::write_data(st_net *net, Instance *instance)
 {
   Buffer send_buff;  /* buffer for packets */
+  uint pos= 0;
+
+  const char *logpath= instance->options.logs[log_type];
+  File fd;
+
+  size_t buff_size;
+  int read_len;
+
+  MY_STAT file_stat;
+  Buffer read_buff;
+
+  if ((fd= my_open(logpath, O_RDONLY | O_BINARY,  MYF(MY_WME))) <= 0)
+    return ER_OPEN_LOGFILE;
+
+  /* my_fstat doesn't use the flag parameter */
+  if (my_fstat(fd, &file_stat, MYF(0)))
+  {
+    close(fd);
+    return ER_OUT_OF_RESOURCES;
+  }
+
+  /* calculate buffer size */
+  buff_size= (size - offset);
+
+  read_buff.reserve(0, buff_size);
+
+  /* read in one chunk */
+  read_len= (int)my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0));
+
+  if ((read_len= my_read(fd, (byte*) read_buff.buffer,
+                         buff_size, MYF(0))) < 0)
+  {
+    close(fd);
+    return ER_READ_FILE;
+  }
+
+  close(fd);
+
+  if (store_to_protocol_packet(&send_buff, read_buff.buffer, &pos, read_len) ||
+      my_net_write(net, send_buff.buffer, pos))
+  {
+    return ER_OUT_OF_RESOURCES;
+  }
+
+  return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Show_instance_log_files.
+**************************************************************************/
+
+Show_instance_log_files::Show_instance_log_files
+              (Instance_map *instance_map_arg,
+               const LEX_STRING *instance_name_arg)
+  :Abstract_instance_cmd(instance_map_arg, instance_name_arg)
+{
+}
+
+
+/*
+  Implementation of SHOW INSTANCE LOG FILES statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
+
+int Show_instance_log_files::execute_impl(st_net *net, Instance *instance)
+{
+  int err_code;
+
+  if ((err_code= write_header(net)) ||
+      (err_code= write_data(net, instance)))
+    return err_code;
+
+  return 0;
+}
+
+
+int Show_instance_log_files::send_ok_response(st_net *net, ulong connection_id)
+{
+  if (send_eof(net) || net_flush(net))
+    return ER_OUT_OF_RESOURCES;
+
+  return 0;
+}
+
+
+int Show_instance_log_files::write_header(st_net *net)
+{
   LIST name, path, size;
   LIST *field_list;
-  NAME_WITH_LENGTH name_field, path_field, size_field;
-  uint position= 0;
+  LEX_STRING name_field, path_field, size_field;
 
-  if (!instance_name)
-    return ER_BAD_INSTANCE_NAME;
+  /* Create list of the fileds to be passed to send_fields(). */
 
-  /* create list of the fileds to be passed to send_fields */
-  name_field.name= (char*) "Logfile";
+  name_field.str= (char *) "Logfile";
   name_field.length= DEFAULT_FIELD_LENGTH;
   name.data= &name_field;
-  path_field.name= (char*) "Path";
+
+  path_field.str= (char *) "Path";
   path_field.length= DEFAULT_FIELD_LENGTH;
   path.data= &path_field;
-  size_field.name= (char*) "File size";
+
+  size_field.str= (char *) "File size";
   size_field.length= DEFAULT_FIELD_LENGTH;
   size.data= &size_field;
+
   field_list= list_add(NULL, &size);
   field_list= list_add(field_list, &path);
   field_list= list_add(field_list, &name);
 
-  send_fields(net, field_list);
+  return send_fields(net, field_list) ? ER_OUT_OF_RESOURCES : 0;
+}
 
-  Instance *instance;
 
-  if ((instance= instance_map->
-                 find(instance_name, strlen(instance_name))) == NULL)
-    goto err;
+int Show_instance_log_files::write_data(st_net *net, Instance *instance)
+{
+  Buffer send_buff;  /* buffer for packets */
 
+  /*
+    We have alike structure in instance_options.cc. We use such to be able
+    to loop through the options, which we need to handle in some common way.
+  */
+  struct log_files_st
+  {
+    const char *name;
+    const char *value;
+  } logs[]=
   {
+    {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]},
+    {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]},
+    {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]},
+    {NULL, NULL}
+  };
+  struct log_files_st *log_files;
+
+  for (log_files= logs; log_files->name; log_files++)
+  {
+    if (!log_files->value)
+      continue;
+
+    struct stat file_stat;
     /*
-      We have alike structure in instance_options.cc. We use such to be able
-      to loop through the options, which we need to handle in some common way.
+      Save some more space for the log file names. In fact all
+      we need is strlen("GENERAL_LOG") + 1
     */
-    struct log_files_st
-    {
-      const char *name;
-      const char *value;
-    } logs[]=
-    {
-      {"ERROR LOG", instance->options.logs[IM_LOG_ERROR]},
-      {"GENERAL LOG", instance->options.logs[IM_LOG_GENERAL]},
-      {"SLOW LOG", instance->options.logs[IM_LOG_SLOW]},
-      {NULL, NULL}
-    };
-    struct log_files_st *log_files;
-
-    for (log_files= logs; log_files->name; log_files++)
+    enum { LOG_NAME_BUFFER_SIZE= 20 };
+    char buff[LOG_NAME_BUFFER_SIZE];
+
+    uint pos= 0;
+
+    const char *log_path= "";
+    const char *log_size= "0";
+
+    if (!stat(log_files->value, &file_stat) &&
+        MY_S_ISREG(file_stat.st_mode))
     {
-      if (log_files->value != NULL)
-      {
-        struct stat file_stat;
-        /*
-          Save some more space for the log file names. In fact all
-          we need is srtlen("GENERAL_LOG") + 1
-        */
-        enum { LOG_NAME_BUFFER_SIZE= 20 };
-        char buff[LOG_NAME_BUFFER_SIZE];
-
-        position= 0;
-        /* store the type of the log in the send buffer */
-        store_to_protocol_packet(&send_buff, log_files->name, &position);
-        if (stat(log_files->value, &file_stat))
-        {
-          store_to_protocol_packet(&send_buff, "", &position);
-          store_to_protocol_packet(&send_buff, (char*) "0", &position);
-        }
-        else if (MY_S_ISREG(file_stat.st_mode))
-        {
-          store_to_protocol_packet(&send_buff,
-                                   (char*) log_files->value,
-                                   &position);
-          int10_to_str(file_stat.st_size, buff, 10);
-          store_to_protocol_packet(&send_buff, (char*) buff, &position);
-        }
-
-        if (my_net_write(net, send_buff.buffer, (uint) position))
-          goto err;
-      }
+      int10_to_str(file_stat.st_size, buff, 10);
+
+      log_path= log_files->value;
+      log_size= buff;
     }
-  }
 
-  if (send_eof(net) || net_flush(net))
-    goto err;
+    if (store_to_protocol_packet(&send_buff, log_files->name, &pos) ||
+        store_to_protocol_packet(&send_buff, log_path, &pos) ||
+        store_to_protocol_packet(&send_buff, log_size, &pos) ||
+        my_net_write(net, send_buff.buffer, pos))
+      return ER_OUT_OF_RESOURCES;
+  }
 
   return 0;
-
-err:
-  return ER_OUT_OF_RESOURCES;
 }
 
 
-/* implementation for SET instance_name.option=option_value: */
+/**************************************************************************
+ Implementation of Abstract_option_cmd.
+**************************************************************************/
 
-Set_option::Set_option(Instance_map *instance_map_arg,
-                       const char *name, uint len,
-                       const char *option_arg, uint option_len_arg,
-                       const char *option_value_arg, uint option_value_len_arg)
-  :Command(instance_map_arg)
+/*
+  Instance_options_list -- a data class representing a list of options for
+  some instance.
+*/
+
+class Instance_options_list
 {
-  Instance *instance;
+public:
+  Instance_options_list(const LEX_STRING *instance_name_arg);
 
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-  {
-    instance_name= instance->options.instance_name;
+public:
+  bool init();
 
-     /* add prefix for add_option */
-    if ((option_len_arg < MAX_OPTION_LEN - 1) ||
-        (option_value_len_arg < MAX_OPTION_LEN - 1))
-    {
-      strmake(option, option_arg, option_len_arg);
-      strmake(option_value, option_value_arg, option_value_len_arg);
-    }
-    else
-    {
-      option[0]= 0;
-      option_value[0]= 0;
-    }
-    instance_name_len= len;
-  }
-  else
+  const LEX_STRING *get_instance_name() const
   {
-    instance_name= NULL;
-    instance_name_len= 0;
+    return instance_name.get_str();
   }
+
+public:
+  /*
+    This member is set and used only in Abstract_option_cmd::execute_impl().
+    Normally it is not used (and should not).
+
+    The problem is that construction and execution of commands are made not
+    in one transaction (not under one lock session). So, we can not initialize
+    instance in constructor and use it in execution.
+  */
+  Instance *instance;
+
+  Named_value_arr options;
+
+private:
+  Instance_name instance_name;
+};
+
+
+/**************************************************************************/
+
+Instance_options_list::Instance_options_list(
+  const LEX_STRING *instance_name_arg)
+  :instance(NULL),
+  instance_name(instance_name_arg)
+{
 }
 
 
-/*
-  The method sends a table with a list of log files
-  used by the instance.
+bool Instance_options_list::init()
+{
+  return options.init();
+}
 
-  SYNOPSYS
-    Set_option::correct_file()
-    skip     Skip the option, being searched while writing the result file.
-             That is, to delete it.
 
-  DESCRIPTION
+/**************************************************************************/
+
+C_MODE_START
+
+static byte* get_item_key(const byte* item, uint* len,
+                          my_bool __attribute__((unused)) t)
+{
+  const Instance_options_list *lst= (const Instance_options_list *) item;
+  *len= lst->get_instance_name()->length;
+  return (byte *) lst->get_instance_name()->str;
+}
+
+static void delete_item(void *item)
+{
+  delete (Instance_options_list *) item;
+}
+
+C_MODE_END
+
+
+/**************************************************************************/
+
+Abstract_option_cmd::Abstract_option_cmd(Instance_map *instance_map_arg)
+  :Command(instance_map_arg),
+  initialized(FALSE)
+{
+}
+
+
+Abstract_option_cmd::~Abstract_option_cmd()
+{
+  if (initialized)
+    hash_free(&instance_options_map);
+}
 
+
+bool Abstract_option_cmd::add_option(const LEX_STRING *instance_name,
+                                     Named_value *option)
+{
+  Instance_options_list *lst= get_instance_options_list(instance_name);
+
+  if (!lst)
+    return TRUE;
+
+  lst->options.add_element(option);
+
+  return FALSE;
+}
+
+
+bool Abstract_option_cmd::init(const char **text)
+{
+  static const int INITIAL_HASH_SIZE= 16;
+
+  if (hash_init(&instance_options_map, default_charset_info,
+                INITIAL_HASH_SIZE, 0, 0, get_item_key, delete_item, 0))
+    return TRUE;
+
+  if (parse_args(text))
+    return TRUE;
+
+  initialized= TRUE;
+
+  return FALSE;
+}
+
+
+/*
   Correct the option file. The "skip" option is used to remove the found
   option.
 
+  SYNOPSYS
+  Abstract_option_cmd::correct_file()
+    skip     Skip the option, being searched while writing the result file.
+             That is, to delete it.
+
   RETURN
-    ER_OUT_OF_RESOURCES     out of resources
+    0                       Success
+    ER_OUT_OF_RESOURCES     Not enough resources to complete the operation
     ER_ACCESS_OPTION_FILE   Cannot access the option file
-    0 - ok
 */
 
-int Set_option::correct_file(int skip)
+int Abstract_option_cmd::correct_file(Instance *instance, Named_value *option,
+                                      bool skip)
 {
-  static const int mysys_to_im_error[]= { 0, ER_OUT_OF_RESOURCES,
-                                             ER_ACCESS_OPTION_FILE };
-  int error;
+  int err_code= modify_defaults_file(Options::Main::config_file,
+                                     option->get_name(),
+                                     option->get_value(),
+                                     instance->get_name()->str,
+                                     skip);
+
+  DBUG_ASSERT(err_code >= 0 && err_code <= 2);
 
-  error= modify_defaults_file(Options::config_file, option,
-                              option_value, instance_name, skip);
-  DBUG_ASSERT(error >= 0 && error <= 2);
+  if (err_code)
+  {
+    log_error("Can not modify option (%s) in defaults file (%s). "
+              "Original error code: %d.",
+              (const char *) option->get_name(),
+              (const char *) Options::Main::config_file,
+              (int) err_code);
+  }
 
-  return mysys_to_im_error[error];
+  return modify_defaults_to_im_error[err_code];
 }
 
 
 /*
-  The method sets an option in the the default config file (/etc/my.cnf).
-
-  SYNOPSYS
-    Set_option::do_command()
-    net               The network connection to the client.
-
-  RETURN
-    0 - ok
-    1 - error occured
+  Implementation of SET statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance with the given name does not exist
+    ER_INCOMPATIBLE_OPTION      The specified option can not be set for
+                                mysqld-compatible instance
+    ER_INSTANCE_IS_ACTIVE       The specified instance is active
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
 */
 
-int Set_option::do_command(struct st_net *net)
+int Abstract_option_cmd::execute(st_net *net, ulong connection_id)
 {
-  int error;
+  int err_code;
 
-  /* we must hold the instance_map mutex while changing config file */
   instance_map->lock();
-  error= correct_file(FALSE);
+
+  err_code= execute_impl(net, connection_id);
+
   instance_map->unlock();
 
-  return error;
+  return err_code;
 }
 
 
-int Set_option::execute(struct st_net *net, ulong connection_id)
+Instance_options_list *
+Abstract_option_cmd::get_instance_options_list(const LEX_STRING *instance_name)
 {
-  if (instance_name != NULL)
+  Instance_options_list *lst=
+    (Instance_options_list *) hash_search(&instance_options_map,
+                                        (byte *) instance_name->str,
+                                        instance_name->length);
+
+  if (!lst)
   {
-    int val;
+    lst= new Instance_options_list(instance_name);
 
-    val= do_command(net);
+    if (!lst)
+      return NULL;
+
+    if (lst->init() || my_hash_insert(&instance_options_map, (byte *) lst))
+    {
+      delete lst;
+      return NULL;
+    }
+  }
+
+  return lst;
+}
+
+
+int Abstract_option_cmd::execute_impl(st_net *net, ulong connection_id)
+{
+  int err_code;
 
-    if (val == 0)
-      net_send_ok(net, connection_id, NULL);
+  /* Check that all the specified instances exist and are offline. */
 
-    return val;
+  for (uint i= 0; i < instance_options_map.records; ++i)
+  {
+    Instance_options_list *lst=
+      (Instance_options_list *) hash_element(&instance_options_map, i);
+
+    lst->instance= instance_map->find(lst->get_instance_name());
+
+    if (!lst->instance)
+      return ER_BAD_INSTANCE_NAME;
+
+    if (instance_map->guardian->is_active(lst->instance))
+      return ER_INSTANCE_IS_ACTIVE;
+  }
+
+  /* Perform command-specific (SET/UNSET) actions. */
+
+  for (uint i= 0; i < instance_options_map.records; ++i)
+  {
+    Instance_options_list *lst=
+      (Instance_options_list *) hash_element(&instance_options_map, i);
+
+    for (int j= 0; j < lst->options.get_size(); ++j)
+    {
+      Named_value option= lst->options.get_element(j);
+      err_code= process_option(lst->instance, &option);
+
+      if (err_code)
+        break;
+    }
+
+    if (err_code)
+      break;
   }
 
-  return ER_BAD_INSTANCE_NAME;
+  if (err_code == 0)
+    net_send_ok(net, connection_id, NULL);
+
+  return err_code;
 }
 
 
-/* the only function from Unset_option we need to Implement */
+/**************************************************************************
+ Implementation of Set_option.
+**************************************************************************/
 
-int Unset_option::do_command(struct st_net *net)
+Set_option::Set_option(Instance_map *instance_map_arg)
+  :Abstract_option_cmd(instance_map_arg)
 {
-  return correct_file(TRUE);
 }
 
 
-/* Implementation for Stop_instance: */
+/*
+  This operation parses SET options.
 
-Stop_instance::Stop_instance(Instance_map *instance_map_arg,
-                               const char *name, uint len)
-  :Command(instance_map_arg)
+  SYNOPSYS
+    text            [IN/OUT] a pointer to the text containing options.
+
+  RETURN
+    FALSE           On success.
+    TRUE            On syntax error.
+*/
+
+bool Set_option::parse_args(const char **text)
 {
-  /* we make a search here, since we don't want to store the name */
-  if ((instance= instance_map->find(name, len)))
-    instance_name= instance->options.instance_name;
+  uint len;
+
+  /* Check if we have something (and trim leading spaces). */
+
+  get_word(text, &len, NONSPACE);
+
+  if (len == 0)
+    return TRUE; /* Syntax error: no option. */
+
+  /* Main parsing loop. */
+
+  while (TRUE)
+  {
+    LEX_STRING instance_name;
+    LEX_STRING option_name;
+    char *option_name_str;
+    char *option_value_str= NULL;
+
+    /* Looking for instance name. */
+
+    get_word(text, &instance_name.length, ALPHANUM);
+
+    if (instance_name.length == 0)
+      return TRUE; /* Syntax error: instance name expected. */
+
+    instance_name.str= (char *) *text;
+    *text+= instance_name.length;
+
+    skip_spaces(text);
+
+    /* Check the the delimiter is a dot. */
+
+    if (**text != '.')
+      return TRUE; /* Syntax error: dot expected. */
+
+    ++(*text);
+
+    /* Looking for option name. */
+
+    get_word(text, &option_name.length, OPTION_NAME);
+
+    if (option_name.length == 0)
+      return TRUE; /* Syntax error: option name expected. */
+
+    option_name.str= (char *) *text;
+    *text+= option_name.length;
+
+    /* Looking for equal sign. */
+
+    skip_spaces(text);
+
+    if (**text == '=')
+    {
+      ++(*text); /* Skip an equal sign. */
+
+      /* Looking for option value. */
+
+      skip_spaces(text);
+
+      if (!**text)
+        return TRUE; /* Syntax error: EOS when option value expected. */
+
+      if (**text != '\'' && **text != '"')
+      {
+        /* Option value is a simple token. */
+
+        LEX_STRING option_value;
+
+        get_word(text, &option_value.length, ALPHANUM);
+
+        if (option_value.length == 0)
+          return TRUE; /* internal parser error. */
+
+        option_value.str= (char *) *text;
+        *text+= option_value.length;
+
+        if (!(option_value_str= Named_value::alloc_str(&option_value)))
+          return TRUE; /* out of memory during parsing. */
+      }
+      else
+      {
+        /* Option value is a string. */
+
+        if (parse_option_value(*text, &len, &option_value_str))
+          return TRUE; /* Syntax error: invalid string specification. */
+
+        *text+= len;
+      }
+    }
+
+    if (!option_value_str)
+    {
+      LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+      if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+        return TRUE; /* out of memory during parsing. */
+    }
+
+    if (!(option_name_str= Named_value::alloc_str(&option_name)))
+    {
+      Named_value::free_str(&option_name_str);
+      return TRUE; /* out of memory during parsing. */
+    }
+
+    {
+      Named_value option(option_name_str, option_value_str);
+
+      if (add_option(&instance_name, &option))
+      {
+        option.free();
+        return TRUE; /* out of memory during parsing. */
+      }
+    }
+
+    skip_spaces(text);
+
+    if (!**text)
+      return FALSE; /* OK: end of options. */
+
+    if (**text != ',')
+      return TRUE; /* Syntax error: comma expected. */
+
+    ++(*text); /* Skip a comma. */
+  }
 }
 
 
-int Stop_instance::execute(struct st_net *net, ulong connection_id)
+int Set_option::process_option(Instance *instance, Named_value *option)
 {
-  uint err_code;
+  /* Check that the option is valid. */
 
-  if (instance == 0)
-    return ER_BAD_INSTANCE_NAME; /* haven't found an instance */
+  if (instance->is_mysqld_compatible() &&
+      Instance_options::is_option_im_specific(option->get_name()))
+  {
+      log_error("Error: IM-option (%s) can not be used "
+                "in the configuration of mysqld-compatible instance (%s).",
+                (const char *) option->get_name(),
+                (const char *) instance->get_name()->str);
+      return ER_INCOMPATIBLE_OPTION;
+  }
 
-  if (!(instance->options.nonguarded))
-    instance_map->guardian->stop_guard(instance);
+  /* Update the configuration file. */
 
-  if ((err_code= instance->stop()))
+  int err_code= correct_file(instance, option, FALSE);
+
+  if (err_code)
     return err_code;
 
-  net_send_ok(net, connection_id, NULL);
+  /* Update the internal cache. */
+
+  if (instance->options.set_option(option))
+    return ER_OUT_OF_RESOURCES;
+
   return 0;
 }
 
 
-int Syntax_error::execute(struct st_net *net, ulong connection_id)
+/**************************************************************************
+ Implementation of Unset_option.
+**************************************************************************/
+
+Unset_option::Unset_option(Instance_map *instance_map_arg)
+  :Abstract_option_cmd(instance_map_arg)
+{
+}
+
+
+/*
+  This operation parses UNSET options.
+
+  SYNOPSYS
+    text            [IN/OUT] a pointer to the text containing options.
+
+  RETURN
+    FALSE           On success.
+    TRUE            On syntax error.
+*/
+
+bool Unset_option::parse_args(const char **text)
+{
+  uint len;
+
+  /* Check if we have something (and trim leading spaces). */
+
+  get_word(text, &len, NONSPACE);
+
+  if (len == 0)
+    return TRUE; /* Syntax error: no option. */
+
+  /* Main parsing loop. */
+
+  while (TRUE)
+  {
+    LEX_STRING instance_name;
+    LEX_STRING option_name;
+    char *option_name_str;
+    char *option_value_str;
+
+    /* Looking for instance name. */
+
+    get_word(text, &instance_name.length, ALPHANUM);
+
+    if (instance_name.length == 0)
+      return TRUE; /* Syntax error: instance name expected. */
+
+    instance_name.str= (char *) *text;
+    *text+= instance_name.length;
+
+    skip_spaces(text);
+
+    /* Check the the delimiter is a dot. */
+
+    if (**text != '.')
+      return TRUE; /* Syntax error: dot expected. */
+
+    ++(*text); /* Skip a dot. */
+
+    /* Looking for option name. */
+
+    get_word(text, &option_name.length, OPTION_NAME);
+
+    if (option_name.length == 0)
+      return TRUE; /* Syntax error: option name expected. */
+
+    option_name.str= (char *) *text;
+    *text+= option_name.length;
+
+    if (!(option_name_str= Named_value::alloc_str(&option_name)))
+      return TRUE; /* out of memory during parsing. */
+
+    {
+      LEX_STRING empty_str= { C_STRING_WITH_SIZE("") };
+
+      if (!(option_value_str= Named_value::alloc_str(&empty_str)))
+      {
+        Named_value::free_str(&option_name_str);
+        return TRUE;
+      }
+    }
+
+    {
+      Named_value option(option_name_str, option_value_str);
+
+      if (add_option(&instance_name, &option))
+      {
+        option.free();
+        return TRUE; /* out of memory during parsing. */
+      }
+    }
+
+    skip_spaces(text);
+
+    if (!**text)
+      return FALSE; /* OK: end of options. */
+
+    if (**text != ',')
+      return TRUE; /* Syntax error: comma expected. */
+
+    ++(*text); /* Skip a comma. */
+  }
+}
+
+
+/*
+  Implementation of UNSET statement.
+
+  Possible error codes:
+    ER_BAD_INSTANCE_NAME        The instance name specified is not valid
+    ER_INSTANCE_IS_ACTIVE       The specified instance is active
+    ER_OUT_OF_RESOURCES         Not enough resources to complete the operation
+*/
+
+int Unset_option::process_option(Instance *instance, Named_value *option)
+{
+  /* Update the configuration file. */
+
+  int err_code= correct_file(instance, option, TRUE);
+
+  if (err_code)
+    return err_code;
+
+  /* Update the internal cache. */
+
+  instance->options.unset_option(option->get_name());
+
+  return 0;
+}
+
+
+/**************************************************************************
+ Implementation of Syntax_error.
+**************************************************************************/
+
+int Syntax_error::execute(st_net *net, ulong connection_id)
 {
   return ER_SYNTAX_ERROR;
 }
diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h
index bfd38d348890d38427e4bf6f6b6c713746716c1e..9a9911f2358deefc0ef7a79d264819a65b8a05d9 100644
--- a/server-tools/instance-manager/commands.h
+++ b/server-tools/instance-manager/commands.h
@@ -16,10 +16,20 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#include <my_global.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <hash.h>
+
 #include "command.h"
 #include "instance.h"
 #include "parse.h"
 
+#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
+#pragma interface
+#endif
+
+
 /*
   Print all instances of this instance manager.
   Grammar: SHOW ISTANCES
@@ -31,12 +41,16 @@ class Show_instances : public Command
   Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
   {}
 
-  int execute(struct st_net *net, ulong connection_id);
+  int execute(st_net *net, ulong connection_id);
+
+private:
+  int write_header(st_net *net);
+  int write_data(st_net *net);
 };
 
 
 /*
-  Reread configuration file and refresh instance map.
+  Reread configuration file and refresh internal cache.
   Grammar: FLUSH INSTANCES
 */
 
@@ -46,7 +60,43 @@ class Flush_instances : public Command
   Flush_instances(Instance_map *instance_map_arg): Command(instance_map_arg)
   {}
 
-  int execute(struct st_net *net, ulong connection_id);
+  int execute(st_net *net, ulong connection_id);
+};
+
+
+/*
+  Abstract class for Instance-specific commands.
+*/
+
+class Abstract_instance_cmd : public Command
+{
+public:
+  Abstract_instance_cmd(Instance_map *instance_map_arg,
+                        const LEX_STRING *instance_name_arg);
+
+public:
+  virtual int execute(st_net *net, ulong connection_id);
+
+protected:
+  /* MT-NOTE: this operation is called under acquired Instance_map's lock. */
+  virtual int execute_impl(st_net *net, Instance *instance) = 0;
+
+  /*
+    This operation is invoked on successful return of execute_impl() and is
+    intended to send closing data.
+
+    MT-NOTE: this operation is called under released Instance_map's lock.
+  */
+  virtual int send_ok_response(st_net *net, ulong connection_id) = 0;
+
+protected:
+  inline const LEX_STRING *get_instance_name() const
+  {
+    return instance_name.get_str();
+  }
+
+private:
+  Instance_name instance_name;
 };
 
 
@@ -55,31 +105,40 @@ class Flush_instances : public Command
   Grammar: SHOW ISTANCE STATUS <instance_name>
 */
 
-class Show_instance_status : public Command
+class Show_instance_status : public Abstract_instance_cmd
 {
 public:
-
   Show_instance_status(Instance_map *instance_map_arg,
-                       const char *name, uint len);
-  int execute(struct st_net *net, ulong connection_id);
-  const char *instance_name;
+                       const LEX_STRING *instance_name_arg);
+
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+  int write_header(st_net *net);
+  int write_data(st_net *net, Instance *instance);
 };
 
 
 /*
-  Print options if chosen instance.
+  Print options of chosen instance.
   Grammar: SHOW INSTANCE OPTIONS <instance_name>
 */
 
-class Show_instance_options : public Command
+class Show_instance_options : public Abstract_instance_cmd
 {
 public:
-
   Show_instance_options(Instance_map *instance_map_arg,
-                        const char *name, uint len);
+                        const LEX_STRING *instance_name_arg);
 
-  int execute(struct st_net *net, ulong connection_id);
-  const char *instance_name;
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+  int write_header(st_net *net);
+  int write_data(st_net *net, Instance *instance);
 };
 
 
@@ -88,14 +147,15 @@ class Show_instance_options : public Command
   Grammar: START INSTANCE <instance_name>
 */
 
-class Start_instance : public Command
+class Start_instance : public Abstract_instance_cmd
 {
 public:
-  Start_instance(Instance_map *instance_map_arg, const char *name, uint len);
+  Start_instance(Instance_map *instance_map_arg,
+                 const LEX_STRING *instance_name_arg);
 
-  int execute(struct st_net *net, ulong connection_id);
-  const char *instance_name;
-  Instance *instance;
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
 };
 
 
@@ -104,33 +164,95 @@ class Start_instance : public Command
   Grammar: STOP INSTANCE <instance_name>
 */
 
-class Stop_instance : public Command
+class Stop_instance : public Abstract_instance_cmd
 {
 public:
-  Stop_instance(Instance_map *instance_map_arg, const char *name, uint len);
+  Stop_instance(Instance_map *instance_map_arg,
+                const LEX_STRING *instance_name_arg);
 
-  Instance *instance;
-  int execute(struct st_net *net, ulong connection_id);
-  const char *instance_name;
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
 };
 
 
 /*
-  Print requested part of the log
+  Create an instance.
+  Grammar: CREATE INSTANCE <instance_name> [<options>]
+*/
+
+class Create_instance : public Command
+{
+public:
+  Create_instance(Instance_map *instance_map_arg,
+                  const LEX_STRING *instance_name_arg);
+
+public:
+  bool init(const char **text);
+
+protected:
+  virtual int execute(st_net *net, ulong connection_id);
+
+  inline const LEX_STRING *get_instance_name() const
+  {
+    return instance_name.get_str();
+  }
+
+private:
+  bool parse_args(const char **text);
+
+private:
+  Instance_name instance_name;
+
+  Named_value_arr options;
+};
+
+
+/*
+  Drop an instance.
+  Grammar: DROP INSTANCE <instance_name>
+
+  Operation is permitted only if the instance is stopped. On successful
+  completion the instance section is removed from config file and the instance
+  is removed from the instance map.
+*/
+
+class Drop_instance : public Abstract_instance_cmd
+{
+public:
+  Drop_instance(Instance_map *instance_map_arg,
+                const LEX_STRING *instance_name_arg);
+
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
+};
+
+
+/*
+  Print requested part of the log.
   Grammar:
-    SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end]
+    SHOW <instance_name> LOG {ERROR | SLOW | GENERAL} size[, offset_from_end]
 */
 
-class Show_instance_log : public Command
+class Show_instance_log : public Abstract_instance_cmd
 {
 public:
+  Show_instance_log(Instance_map *instance_map_arg,
+                    const LEX_STRING *instance_name_arg,
+                    Log_type log_type_arg, uint size_arg, uint offset_arg);
+
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+  int check_params(Instance *instance);
+  int write_header(st_net *net);
+  int write_data(st_net *net, Instance *instance);
 
-  Show_instance_log(Instance_map *instance_map_arg, const char *name,
-                    uint len, Log_type log_type_arg, const char *size_arg,
-                    const char *offset_arg);
-  int execute(struct st_net *net, ulong connection_id);
+private:
   Log_type log_type;
-  const char *instance_name;
   uint size;
   uint offset;
 };
@@ -141,75 +263,112 @@ class Show_instance_log : public Command
   Grammar: SHOW <instance_name> LOG FILES
 */
 
-class Show_instance_log_files : public Command
+class Show_instance_log_files : public Abstract_instance_cmd
 {
 public:
-
   Show_instance_log_files(Instance_map *instance_map_arg,
-                          const char *name, uint len);
-  int execute(struct st_net *net, ulong connection_id);
-  const char *instance_name;
-  const char *option;
+                          const LEX_STRING *instance_name_arg);
+
+protected:
+  virtual int execute_impl(st_net *net, Instance *instance);
+  virtual int send_ok_response(st_net *net, ulong connection_id);
+
+private:
+  int write_header(st_net *net);
+  int write_data(st_net *net, Instance *instance);
 };
 
 
 /*
-  Syntax error command. This command is issued if parser reported a syntax
-  error. We need it to distinguish the parse error and the situation when
-  parser internal error occured. E.g. parsing failed because we hadn't had
-  enought memory. In the latter case parse_command() should return an error.
+  Abstract class for option-management commands.
 */
 
-class Syntax_error : public Command
+class Instance_options_list;
+
+class Abstract_option_cmd : public Command
 {
 public:
-  int execute(struct st_net *net, ulong connection_id);
+  ~Abstract_option_cmd();
+
+public:
+  bool add_option(const LEX_STRING *instance_name, Named_value *option);
+
+public:
+  bool init(const char **text);
+
+  virtual int execute(st_net *net, ulong connection_id);
+
+protected:
+  Abstract_option_cmd(Instance_map *instance_map_arg);
+
+  int correct_file(Instance *instance, Named_value *option, bool skip);
+
+protected:
+  virtual bool parse_args(const char **text) = 0;
+  virtual int process_option(Instance *instance, Named_value *option) = 0;
+
+private:
+  Instance_options_list *
+  get_instance_options_list(const LEX_STRING *instance_name);
+
+  int execute_impl(st_net *net, ulong connection_id);
+
+private:
+  HASH instance_options_map;
+  bool initialized;
 };
 
+
 /*
   Set an option for the instance.
-  Grammar: SET instance_name.option=option_value
+  Grammar: SET instance_name.option[=option_value][, ...]
 */
 
-class Set_option : public Command
+class Set_option : public Abstract_option_cmd
 {
 public:
-  Set_option(Instance_map *instance_map_arg, const char *name, uint len,
-             const char *option_arg, uint option_len,
-             const char *option_value_arg, uint option_value_len);
-  /*
-    the following function is virtual to let Unset_option to use
-  */
-  virtual int do_command(struct st_net *net);
-  int execute(struct st_net *net, ulong connection_id);
+  Set_option(Instance_map *instance_map_arg);
+
 protected:
-  int correct_file(int skip);
-public:
-  const char *instance_name;
-  uint instance_name_len;
-  /* buffer for the option */
-  enum { MAX_OPTION_LEN= 1024 };
-  char option[MAX_OPTION_LEN];
-  char option_value[MAX_OPTION_LEN];
+  virtual bool parse_args(const char **text);
+  virtual int process_option(Instance *instance, Named_value *option);
 };
 
 
 /*
-  Remove option of the instance from config file
-  Grammar: UNSET instance_name.option
+  Remove option of the instance.
+  Grammar: UNSET instance_name.option[, ...]
 */
 
-class Unset_option: public Set_option
+class Unset_option: public Abstract_option_cmd
 {
 public:
-  Unset_option(Instance_map *instance_map_arg, const char *name, uint len,
-               const char *option_arg, uint option_len,
-               const char *option_value_arg, uint option_value_len):
-    Set_option(instance_map_arg, name, len, option_arg, option_len,
-               option_value_arg, option_value_len)
-    {}
-  int do_command(struct st_net *net);
+  Unset_option(Instance_map *instance_map_arg);
+
+protected:
+  virtual bool parse_args(const char **text);
+  virtual int process_option(Instance *instance, Named_value *option);
 };
 
 
+/*
+  Syntax error command.
+
+  This command is issued if parser reported a syntax error. We need it to
+  distinguish between syntax error and internal parser error.  E.g. parsing
+  failed because we hadn't had enought memory. In the latter case the parser
+  just returns NULL.
+*/
+
+class Syntax_error : public Command
+{
+public:
+  /* This is just to avoid compiler warning. */
+  Syntax_error() :Command(NULL)
+  {}
+
+public:
+  int execute(st_net *net, ulong connection_id);
+};
+
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
diff --git a/server-tools/instance-manager/exit_codes.h b/server-tools/instance-manager/exit_codes.h
new file mode 100644
index 0000000000000000000000000000000000000000..560ce30b7aa09e4cb09575b7650762e2efcecee4
--- /dev/null
+++ b/server-tools/instance-manager/exit_codes.h
@@ -0,0 +1,41 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
+
+/*
+   Copyright (C) 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
+*/
+
+/*
+  This file contains a list of exit codes, which are used when Instance
+  Manager is working in user-management mode.
+*/
+
+const int ERR_OK = 0;
+
+const int ERR_OUT_OF_MEMORY = 1;
+const int ERR_INVALID_USAGE = 2;
+const int ERR_INTERNAL_ERROR = 3;
+const int ERR_IO_ERROR = 4;
+const int ERR_PASSWORD_FILE_CORRUPTED = 5;
+const int ERR_PASSWORD_FILE_DOES_NOT_EXIST = 6;
+
+const int ERR_CAN_NOT_READ_USER_NAME = 10;
+const int ERR_CAN_NOT_READ_PASSWORD = 11;
+const int ERR_USER_ALREADY_EXISTS = 12;
+const int ERR_USER_NOT_FOUND = 13;
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_EXIT_CODES_H
diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc
index 3be672cd71c423ebe8fc8ea0b929ca1530961519..7a9ff3e8367d256f1cf84a1d2816d0f4e558ae83 100644
--- a/server-tools/instance-manager/guardian.cc
+++ b/server-tools/instance-manager/guardian.cc
@@ -21,16 +21,14 @@
 
 #include "guardian.h"
 
-#include "instance_map.h"
-#include "instance.h"
-#include "mysql_manager_error.h"
-#include "log.h"
-#include "portability.h"
-
 #include <string.h>
 #include <sys/types.h>
 #include <signal.h>
 
+#include "instance.h"
+#include "instance_map.h"
+#include "log.h"
+#include "mysql_manager_error.h"
 
 
 pthread_handler_t guardian(void *arg)
@@ -40,6 +38,37 @@ pthread_handler_t guardian(void *arg)
   return 0;
 }
 
+
+const char *
+Guardian_thread::get_instance_state_name(enum_instance_state state)
+{
+  switch (state) {
+  case NOT_STARTED:
+    return "offline";
+
+  case STARTING:
+    return "starting";
+
+  case STARTED:
+    return "online";
+
+  case JUST_CRASHED:
+    return "failed";
+
+  case CRASHED:
+    return "crashed";
+
+  case CRASHED_AND_ABANDONED:
+    return "abandoned";
+
+  case STOPPING:
+    return "stopping";
+  }
+
+  return NULL; /* just to ignore compiler warning. */
+}
+
+
 Guardian_thread::Guardian_thread(Thread_registry &thread_registry_arg,
                                  Instance_map *instance_map_arg,
                                  uint monitoring_interval_arg) :
@@ -89,10 +118,17 @@ void Guardian_thread::process_instance(Instance *instance,
   if (current_node->state == STOPPING)
   {
     /* this brach is executed during shutdown */
-    if (instance->options.shutdown_delay_val)
+    if (instance->options.shutdown_delay)
+    {
+      /*
+        NOTE: it is important to check shutdown_delay here, but use
+        shutdown_delay_val. The idea is that if the option is unset,
+        shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
+      */
       waitchild= instance->options.shutdown_delay_val;
+    }
 
-    /* this returns true if and only if an instance was stopped for sure */
+    /* this returns TRUE if and only if an instance was stopped for sure */
     if (instance->is_crashed())
       *guarded_instances= list_delete(*guarded_instances, node);
     else if ( (uint) (current_time - current_node->last_checked) > waitchild)
@@ -159,7 +195,11 @@ void Guardian_thread::process_instance(Instance *instance,
                    instance->options.instance_name);
         }
         else
+        {
+          log_info("guardian: cannot start instance %s. Abandoning attempts "
+                   "to (re)start it", instance->options.instance_name);
           current_node->state= CRASHED_AND_ABANDONED;
+        }
       }
       break;
     case CRASHED_AND_ABANDONED:
@@ -242,7 +282,9 @@ int Guardian_thread::is_stopped()
   SYNOPSYS
     Guardian_thread::init()
 
-  NOTE: One should always lock guardian before calling this routine.
+  NOTE: The operation should be invoked with the following locks acquired:
+    - Guardian_thread;
+    - Instance_map;
 
   RETURN
     0 - ok
@@ -261,12 +303,11 @@ int Guardian_thread::init()
 
   while ((instance= iterator.next()))
   {
-    if (!(instance->options.nonguarded))
-      if (guard(instance, TRUE))                /* do not lock guardian */
-      {
-        instance_map->unlock();
-        return 1;
-      }
+    if (instance->options.nonguarded)
+      continue;
+
+    if (guard(instance, TRUE))                /* do not lock guardian */
+      return 1;
   }
 
   return 0;
@@ -334,24 +375,14 @@ int Guardian_thread::stop_guard(Instance *instance)
   LIST *node;
 
   pthread_mutex_lock(&LOCK_guardian);
-  node= guarded_instances;
 
-  while (node != NULL)
-  {
-    /*
-      We compare only pointers, as we always use pointers from the
-      instance_map's MEM_ROOT.
-    */
-    if (((GUARD_NODE *) node->data)->instance == instance)
-    {
-      guarded_instances= list_delete(guarded_instances, node);
-      pthread_mutex_unlock(&LOCK_guardian);
-      return 0;
-    }
-    else
-      node= node->next;
-  }
+  node= find_instance_node(instance);
+
+  if (node != NULL)
+    guarded_instances= list_delete(guarded_instances, node);
+
   pthread_mutex_unlock(&LOCK_guardian);
+
   /* if there is nothing to delete it is also fine */
   return 0;
 }
@@ -420,7 +451,7 @@ int Guardian_thread::stop_instances(bool stop_instances_arg)
 
 void Guardian_thread::lock()
 {
-  pthread_mutex_lock(&LOCK_guardian); 
+  pthread_mutex_lock(&LOCK_guardian);
 }
 
 
@@ -428,3 +459,41 @@ void Guardian_thread::unlock()
 {
   pthread_mutex_unlock(&LOCK_guardian);
 }
+
+
+LIST *Guardian_thread::find_instance_node(Instance *instance)
+{
+  LIST *node= guarded_instances;
+
+  while (node != NULL)
+  {
+    /*
+      We compare only pointers, as we always use pointers from the
+      instance_map's MEM_ROOT.
+    */
+    if (((GUARD_NODE *) node->data)->instance == instance)
+      return node;
+
+    node= node->next;
+  }
+
+  return NULL;
+}
+
+
+bool Guardian_thread::is_active(Instance *instance)
+{
+  bool guarded;
+
+  lock();
+
+  guarded= find_instance_node(instance) != NULL;
+
+  /* is_running() can take a long time, so let's unlock mutex first. */
+  unlock();
+
+  if (guarded)
+    return true;
+
+  return instance->is_running();
+}
diff --git a/server-tools/instance-manager/guardian.h b/server-tools/instance-manager/guardian.h
index 16b4c373c91b7f5ee1d801482592054b30220f07..6d3a2b222d77ea08e1a3a3d2ee8a47f194971f27 100644
--- a/server-tools/instance-manager/guardian.h
+++ b/server-tools/instance-manager/guardian.h
@@ -17,11 +17,11 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <my_global.h>
-#include "thread_registry.h"
-
 #include <my_sys.h>
 #include <my_list.h>
 
+#include "thread_registry.h"
+
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
 #endif
@@ -79,6 +79,8 @@ class Guardian_thread: public Guardian_thread_args
     time_t last_checked;
   };
 
+  /* Return client state name. */
+  static const char *get_instance_state_name(enum_instance_state state);
 
   Guardian_thread(Thread_registry &thread_registry_arg,
                   Instance_map *instance_map_arg,
@@ -94,11 +96,28 @@ class Guardian_thread: public Guardian_thread_args
   int guard(Instance *instance, bool nolock= FALSE);
   /* Stop instance protection */
   int stop_guard(Instance *instance);
-  /* Returns true if guardian thread is stopped */
+  /* Returns TRUE if guardian thread is stopped */
   int is_stopped();
   void lock();
   void unlock();
 
+  /*
+    Return an internal list node for the given instance if the instance is
+    managed by Guardian. Otherwise, return NULL.
+
+    MT-NOTE: must be called under acquired lock.
+  */
+  LIST *find_instance_node(Instance *instance);
+
+  /* The operation is used to check if the instance is active or not. */
+  bool is_active(Instance *instance);
+
+  /*
+    Return state of the given instance list node. The pointer must specify
+    a valid list node.
+  */
+  inline enum_instance_state get_instance_state(LIST *instance_node);
+
 public:
   pthread_cond_t COND_guardian;
 
@@ -108,6 +127,7 @@ class Guardian_thread: public Guardian_thread_args
   /* check instance state and act accordingly */
   void process_instance(Instance *instance, GUARD_NODE *current_node,
                         LIST **guarded_instances, LIST *elem);
+
   int stopped;
 
 private:
@@ -115,9 +135,15 @@ class Guardian_thread: public Guardian_thread_args
   Thread_info thread_info;
   LIST *guarded_instances;
   MEM_ROOT alloc;
-  enum { MEM_ROOT_BLOCK_SIZE= 512 };
   /* this variable is set to TRUE when we want to stop Guardian thread */
   bool shutdown_requested;
 };
 
+
+inline Guardian_thread::enum_instance_state
+Guardian_thread::get_instance_state(LIST *instance_node)
+{
+  return ((GUARD_NODE *) instance_node->data)->state;
+}
+
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_GUARDIAN_H */
diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc
index 39381b457aba79d4d06a4bbafc2dcb84cd7aae85..456052bf7e56de5b5be54a6cfc6e6847c9e51172 100644
--- a/server-tools/instance-manager/instance.cc
+++ b/server-tools/instance-manager/instance.cc
@@ -20,18 +20,27 @@
 
 #include "instance.h"
 
-#include "mysql_manager_error.h"
-#include "log.h"
-#include "instance_map.h"
-#include "priv.h"
-#include "portability.h"
+#include <my_global.h>
+#include <mysql.h>
+
+#include <signal.h>
 #ifndef __WIN__
 #include <sys/wait.h>
 #endif
-#include <my_sys.h>
-#include <signal.h>
-#include <m_string.h>
-#include <mysql.h>
+
+#include "guardian.h"
+#include "instance_map.h"
+#include "log.h"
+#include "mysql_manager_error.h"
+#include "portability.h"
+#include "priv.h"
+
+
+const LEX_STRING
+Instance::DFLT_INSTANCE_NAME= { C_STRING_WITH_SIZE("mysqld") };
+
+static const char * const INSTANCE_NAME_PREFIX= Instance::DFLT_INSTANCE_NAME.str;
+static const int INSTANCE_NAME_PREFIX_LEN= Instance::DFLT_INSTANCE_NAME.length;
 
 
 static void start_and_monitor_instance(Instance_options *old_instance_options,
@@ -152,7 +161,7 @@ static int start_process(Instance_options *instance_options,
 
   switch (*pi) {
   case 0:                                       /* never happens on QNX */
-    execv(instance_options->mysqld_path, instance_options->argv);
+    execv(instance_options->mysqld_path.str, instance_options->argv);
     /* exec never returns */
     exit(1);
   case -1:
@@ -180,7 +189,7 @@ static int start_process(Instance_options *instance_options,
   char *cmdline= new char[cmdlen];
   if (cmdline == NULL)
     return 1;
-    
+
   cmdline[0]= 0;
   for (int i= 0; instance_options->argv[i] != 0; i++)
   {
@@ -232,9 +241,7 @@ static int start_process(Instance_options *instance_options,
 static void start_and_monitor_instance(Instance_options *old_instance_options,
                                        Instance_map *instance_map)
 {
-  enum { MAX_INSTANCE_NAME_LEN= 512 };
-  char instance_name_buff[MAX_INSTANCE_NAME_LEN];
-  uint instance_name_len;
+  Instance_name instance_name(&old_instance_options->instance_name);
   Instance *current_instance;
   My_process_info process_info;
 
@@ -248,11 +255,8 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
     Save the instance name in the case if Instance object we
     are using is destroyed. (E.g. by "FLUSH INSTANCES")
   */
-  strmake(instance_name_buff, old_instance_options->instance_name,
-          MAX_INSTANCE_NAME_LEN - 1);
-  instance_name_len= old_instance_options->instance_name_len;
 
-  log_info("starting instance %s", instance_name_buff);
+  log_info("starting instance %s", (const char *) instance_name.get_c_str());
 
   if (start_process(old_instance_options, &process_info))
   {
@@ -266,15 +270,36 @@ static void start_and_monitor_instance(Instance_options *old_instance_options,
   /* don't check for return value */
   wait_process(&process_info);
 
-  current_instance= instance_map->find(instance_name_buff, instance_name_len);
+  instance_map->lock();
+
+  current_instance= instance_map->find(instance_name.get_str());
 
   if (current_instance)
     current_instance->set_crash_flag_n_wake_all();
 
+  instance_map->unlock();
+
   return;
 }
 
 
+bool Instance::is_name_valid(const LEX_STRING *name)
+{
+  const char *name_suffix= name->str + INSTANCE_NAME_PREFIX_LEN;
+
+  if (strncmp(name->str, INSTANCE_NAME_PREFIX, INSTANCE_NAME_PREFIX_LEN) != 0)
+    return FALSE;
+
+  return *name_suffix == 0 || my_isdigit(default_charset_info, *name_suffix);
+}
+
+
+bool Instance::is_mysqld_compatible_name(const LEX_STRING *name)
+{
+  return strcmp(name->str, INSTANCE_NAME_PREFIX) == 0;
+}
+
+
 Instance_map *Instance::get_map()
 {
   return instance_map;
@@ -309,11 +334,11 @@ int Instance::start()
 {
   /* clear crash flag */
   pthread_mutex_lock(&LOCK_instance);
-  crashed= 0;
+  crashed= FALSE;
   pthread_mutex_unlock(&LOCK_instance);
 
 
-  if (!is_running())
+  if (configured && !is_running())
   {
     remove_pid();
 
@@ -339,8 +364,8 @@ int Instance::start()
     return 0;
   }
 
-  /* the instance is started already */
-  return ER_INSTANCE_ALREADY_STARTED;
+  /* The instance is started already or misconfigured. */
+  return configured ? ER_INSTANCE_ALREADY_STARTED : ER_INSTANCE_MISCONFIGURED;
 }
 
 /*
@@ -363,7 +388,7 @@ void Instance::set_crash_flag_n_wake_all()
 {
   /* set instance state to crashed */
   pthread_mutex_lock(&LOCK_instance);
-  crashed= 1;
+  crashed= TRUE;
   pthread_mutex_unlock(&LOCK_instance);
 
   /*
@@ -378,7 +403,7 @@ void Instance::set_crash_flag_n_wake_all()
 
 
 
-Instance::Instance(): crashed(0)
+Instance::Instance(): crashed(FALSE), configured(FALSE)
 {
   pthread_mutex_init(&LOCK_instance, 0);
   pthread_cond_init(&COND_instance_stopped, 0);
@@ -392,9 +417,9 @@ Instance::~Instance()
 }
 
 
-int Instance::is_crashed()
+bool Instance::is_crashed()
 {
-  int val;
+  bool val;
   pthread_mutex_lock(&LOCK_instance);
   val= crashed;
   pthread_mutex_unlock(&LOCK_instance);
@@ -413,10 +438,17 @@ bool Instance::is_running()
   bool return_val;
 
   if (options.mysqld_port)
+  {
+    /*
+      NOTE: it is important to check mysqld_port here, but use
+      mysqld_port_val. The idea is that if the option is unset, mysqld_port
+      will be NULL, but mysqld_port_val will not be reset.
+    */
     port= options.mysqld_port_val;
+  }
 
   if (options.mysqld_socket)
-    socket= strchr(options.mysqld_socket, '=') + 1;
+    socket= options.mysqld_socket;
 
   /* no port was specified => instance falled back to default value */
   if (!options.mysqld_port && !options.mysqld_socket)
@@ -469,8 +501,15 @@ int Instance::stop()
   struct timespec timeout;
   uint waitchild= (uint)  DEFAULT_SHUTDOWN_DELAY;
 
-  if (options.shutdown_delay_val)
+  if (options.shutdown_delay)
+  {
+    /*
+      NOTE: it is important to check shutdown_delay here, but use
+      shutdown_delay_val. The idea is that if the option is unset,
+      shutdown_delay will be NULL, but shutdown_delay_val will not be reset.
+    */
     waitchild= options.shutdown_delay_val;
+  }
 
   kill_instance(SIGTERM);
   /* sleep on condition to wait for SIGCHLD */
@@ -588,20 +627,33 @@ void Instance::kill_instance(int signum)
 }
 
 /*
-  We execute this function to initialize instance parameters.
-  Return value: 0 - ok. 1 - unable to init DYNAMIC_ARRAY.
+  Initialize instance parameters.
+
+  SYNOPSYS
+    Instance::init()
+    name_arg      name of the instance
+
+  RETURN:
+    0             ok
+    !0            error
 */
 
-int Instance::init(const char *name_arg)
+int Instance::init(const LEX_STRING *name_arg)
 {
+  mysqld_compatible= is_mysqld_compatible_name(name_arg);
+
   return options.init(name_arg);
 }
 
 
 int Instance::complete_initialization(Instance_map *instance_map_arg,
-                                      const char *mysqld_path,
-                                      uint instance_type)
+                                      const char *mysqld_path)
 {
   instance_map= instance_map_arg;
-  return options.complete_initialization(mysqld_path, instance_type);
+  configured= !options.complete_initialization(mysqld_path);
+  return 0;
+  /*
+    TODO: return actual status (from
+    Instance_options::complete_initialization()) here.
+  */
 }
diff --git a/server-tools/instance-manager/instance.h b/server-tools/instance-manager/instance.h
index adb669916853346e61c860902fd051e694b18a39..1f06cabebf72089ca9e456a0b138c6d5b4bd93f0 100644
--- a/server-tools/instance-manager/instance.h
+++ b/server-tools/instance-manager/instance.h
@@ -17,7 +17,10 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <my_global.h>
+#include <m_string.h>
+
 #include "instance_options.h"
+#include "priv.h"
 
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
@@ -25,31 +28,120 @@
 
 class Instance_map;
 
+
+/*
+  Instance_name -- the class represents instance name -- a string of length
+  less than MAX_INSTANCE_NAME_SIZE.
+
+  Generally, this is just a string with self-memory-management and should be
+  eliminated in the future.
+*/
+
+class Instance_name
+{
+public:
+  Instance_name(const LEX_STRING *name);
+
+public:
+  inline const LEX_STRING *get_str() const
+  {
+    return &str;
+  }
+
+  inline const char *get_c_str() const
+  {
+    return str.str;
+  }
+
+  inline uint get_length() const
+  {
+    return str.length;
+  }
+
+private:
+  LEX_STRING str;
+  char str_buffer[MAX_INSTANCE_NAME_SIZE];
+};
+
+
 class Instance
 {
+public:
+  /*
+    The following two constants defines name of the default mysqld-instance
+    ("mysqld").
+  */
+  static const LEX_STRING DFLT_INSTANCE_NAME;
+
+public:
+  /*
+    The operation is intended to check whether string is a well-formed
+    instance name or not.
+  */
+  static bool is_name_valid(const LEX_STRING *name);
+
+  /*
+    The operation is intended to check if the given instance name is
+    mysqld-compatible or not.
+  */
+  static bool is_mysqld_compatible_name(const LEX_STRING *name);
+
 public:
   Instance();
 
   ~Instance();
-  int init(const char *name);
+  int init(const LEX_STRING *name_arg);
   int complete_initialization(Instance_map *instance_map_arg,
-                              const char *mysqld_path, uint instance_type);
+                              const char *mysqld_path);
 
   bool is_running();
   int start();
   int stop();
   /* send a signal to the instance */
   void kill_instance(int signo);
-  int is_crashed();
+  bool is_crashed();
   void set_crash_flag_n_wake_all();
   Instance_map *get_map();
 
+  /*
+    The operation is intended to check if the instance is mysqld-compatible
+    or not.
+  */
+  inline bool is_mysqld_compatible() const;
+
+  /*
+    The operation is intended to check if the instance is configured properly
+    or not. Misconfigured instances are not managed.
+  */
+  inline bool is_configured() const;
+
+  inline const LEX_STRING *get_name() const;
+
 public:
   enum { DEFAULT_SHUTDOWN_DELAY= 35 };
   Instance_options options;
 
 private:
-  int crashed;
+  /* This attributes is a flag, specifies if the instance has been crashed. */
+  bool crashed;
+
+  /*
+    This attribute specifies if the instance is configured properly or not.
+    Misconfigured instances are not managed.
+  */
+  bool configured;
+
+  /*
+    This attribute specifies whether the instance is mysqld-compatible or not.
+    Mysqld-compatible instances can contain only mysqld-specific options.
+    At the moment an instance is mysqld-compatible if its name is "mysqld".
+
+    The idea is that [mysqld] section should contain only mysqld-specific
+    options (no Instance Manager-specific options) to be readable by mysqld
+    program.
+  */
+  bool mysqld_compatible;
+
   /*
     Mutex protecting the instance. Currently we use it to avoid the
     double start of the instance. This happens when the instance is starting
@@ -66,4 +158,22 @@ class Instance
   void  remove_pid();
 };
 
+
+inline bool Instance::is_mysqld_compatible() const
+{
+  return mysqld_compatible;
+}
+
+
+inline bool Instance::is_configured() const
+{
+  return configured;
+}
+
+
+inline const LEX_STRING *Instance::get_name() const
+{
+  return &options.instance_name;
+}
+
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_H */
diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc
index 543c9c31bfa2b2797f2c35def680623f24a7deea..c9608fa7c140ad1ba473ece0fbae48785e196576 100644
--- a/server-tools/instance-manager/instance_map.cc
+++ b/server-tools/instance-manager/instance_map.cc
@@ -20,14 +20,19 @@
 
 #include "instance_map.h"
 
+#include <my_global.h>
+#include <m_ctype.h>
+#include <mysql_com.h>
+
 #include "buffer.h"
+#include "guardian.h"
 #include "instance.h"
 #include "log.h"
+#include "manager.h"
+#include "mysqld_error.h"
+#include "mysql_manager_error.h"
 #include "options.h"
-
-#include <m_ctype.h>
-#include <mysql_com.h>
-#include <m_string.h>
+#include "priv.h"
 
 /*
   Note:  As we are going to suppost different types of connections,
@@ -45,8 +50,8 @@ static byte* get_instance_key(const byte* u, uint* len,
                           my_bool __attribute__((unused)) t)
 {
   const Instance *instance= (const Instance *) u;
-  *len= instance->options.instance_name_len;
-  return (byte *) instance->options.instance_name;
+  *len= instance->options.instance_name.length;
+  return (byte *) instance->options.instance_name.str;
 }
 
 static void delete_instance(void *u)
@@ -79,15 +84,59 @@ static void delete_instance(void *u)
 
 static int process_option(void *ctx, const char *group, const char *option)
 {
-  Instance_map *map= NULL;
+  Instance_map *map= (Instance_map*) ctx;
+  LEX_STRING group_str;
 
-  map = (Instance_map*) ctx;
-  return map->process_one_option(group, option);
+  group_str.str= (char *) group;
+  group_str.length= strlen(group);
+
+  return map->process_one_option(&group_str, option);
 }
 
 C_MODE_END
 
 
+/*
+   Parse option string.
+
+  SYNOPSIS
+    parse_option()
+      option_str        [IN] option string (e.g. "--name=value")
+      option_name_buf   [OUT] parsed name of the option.
+                        Must be of (MAX_OPTION_LEN + 1) size.
+      option_value_buf  [OUT] parsed value of the option.
+                        Must be of (MAX_OPTION_LEN + 1) size.
+
+  DESCRIPTION
+    This is an auxiliary function and should not be used externally. It is
+    intended to parse whole option string into option name and option value.
+*/
+
+static void parse_option(const char *option_str,
+                         char *option_name_buf,
+                         char *option_value_buf)
+{
+  const char *eq_pos;
+  const char *ptr= option_str;
+
+  while (*ptr == '-')
+    ++ptr;
+
+  strmake(option_name_buf, ptr, MAX_OPTION_LEN + 1);
+
+  eq_pos= strchr(ptr, '=');
+  if (eq_pos)
+  {
+    option_name_buf[eq_pos - ptr]= 0;
+    strmake(option_value_buf, eq_pos + 1, MAX_OPTION_LEN + 1);
+  }
+  else
+  {
+    option_value_buf[0]= 0;
+  }
+}
+
+
 /*
   Process one option from the configuration file.
 
@@ -103,34 +152,64 @@ C_MODE_END
     of the instance map object.
 */
 
-int Instance_map::process_one_option(const char *group, const char *option)
+int Instance_map::process_one_option(const LEX_STRING *group,
+                                     const char *option)
 {
   Instance *instance= NULL;
-  static const char prefix[]= { 'm', 'y', 's', 'q', 'l', 'd' };
 
-  if (strncmp(group, prefix, sizeof prefix) == 0 &&
-      ((my_isdigit(default_charset_info, group[sizeof prefix]))
-       || group[sizeof(prefix)] == '\0'))
+  if (!Instance::is_name_valid(group))
+  {
+    /*
+      Current section name is not a valid instance name.
+      We should skip it w/o error.
+    */
+    return 0;
+  }
+
+  if (!(instance= (Instance *) hash_search(&hash, (byte *) group->str,
+                                           group->length)))
+  {
+    if (!(instance= new Instance()))
+      return 1;
+
+    if (instance->init(group) || add_instance(instance))
     {
-      if (!(instance= (Instance *) hash_search(&hash, (byte *) group,
-                                               strlen(group))))
-      {
-        if (!(instance= new Instance))
-          goto err;
-        if (instance->init(group) || my_hash_insert(&hash, (byte *) instance))
-          goto err_instance;
-      }
-
-      if (instance->options.add_option(option))
-        goto err;   /* the instance'll be deleted when we destroy the map */
+      delete instance;
+      return 1;
     }
 
-  return 0;
+    if (instance->is_mysqld_compatible())
+      log_info("Warning: instance name '%s' is mysqld-compatible.",
+               (const char *) group->str);
 
-err_instance:
-  delete instance;
-err:
-  return 1;
+    log_info("mysqld instance '%s' has been added successfully.",
+             (const char *) group->str);
+  }
+
+  if (option)
+  {
+    char option_name[MAX_OPTION_LEN + 1];
+    char option_value[MAX_OPTION_LEN + 1];
+
+    parse_option(option, option_name, option_value);
+
+    if (instance->is_mysqld_compatible() &&
+        Instance_options::is_option_im_specific(option_name))
+    {
+      log_info("Warning: configuration of mysqld-compatible instance '%s' "
+               "contains IM-specific option '%s'. "
+               "This breaks backward compatibility for the configuration file.",
+               (const char *) group->str,
+               (const char *) option_name);
+    }
+
+    Named_value option(option_name, option_value);
+
+    if (instance->options.set_option(&option))
+      return 1;   /* the instance'll be deleted when we destroy the map */
+  }
+
+  return 0;
 }
 
 
@@ -181,7 +260,7 @@ void Instance_map::unlock()
      - pass on the new map to the guardian thread: it will start
        all instances that are marked `guarded' and not yet started.
     Note, as the check whether an instance is started is currently
-    very simple (returns true if there is a MySQL server running
+    very simple (returns TRUE if there is a MySQL server running
     at the given port), this function has some peculiar
     side-effects:
      * if the port number of a running instance was changed, the
@@ -194,9 +273,9 @@ void Instance_map::unlock()
     In order to avoid such side effects one should never call
     FLUSH INSTANCES without prior stop of all running instances.
 
-  TODO
-    FLUSH INSTANCES should return an error if it's called
-    while there is a running instance.
+  NOTE: The operation should be invoked with the following locks acquired:
+    - Guardian_thread;
+    - Instance_map;
 */
 
 int Instance_map::flush_instances()
@@ -209,67 +288,169 @@ int Instance_map::flush_instances()
     guardian (2) reload the instance map (3) reinitialize the guardian
     with new instances.
   */
-  guardian->lock();
-  pthread_mutex_lock(&LOCK_instance_map);
   hash_free(&hash);
   hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
             get_instance_key, delete_instance, 0);
+
   rc= load();
   guardian->init();
-  pthread_mutex_unlock(&LOCK_instance_map);
-  guardian->unlock();
   return rc;
 }
 
 
-Instance *
-Instance_map::find(const char *name, uint name_len)
+bool Instance_map::is_there_active_instance()
 {
   Instance *instance;
-  pthread_mutex_lock(&LOCK_instance_map);
-  instance= (Instance *) hash_search(&hash, (byte *) name, name_len);
-  pthread_mutex_unlock(&LOCK_instance_map);
-  return instance;
+  Iterator iterator(this);
+
+  while ((instance= iterator.next()))
+  {
+    if (guardian->find_instance_node(instance) != NULL ||
+        instance->is_running())
+    {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
 }
 
 
-int Instance_map::complete_initialization()
+int Instance_map::add_instance(Instance *instance)
 {
-  Instance *instance;
-  uint i= 0;
+  return my_hash_insert(&hash, (byte *) instance);
+}
 
 
-  if (hash.records == 0)                        /* no instances found */
-  {
-    if ((instance= new Instance) == 0)
-      goto err;
+int Instance_map::remove_instance(Instance *instance)
+{
+  return hash_delete(&hash, (byte *) instance);
+}
 
-    if (instance->init("mysqld") || my_hash_insert(&hash, (byte *) instance))
-      goto err_instance;
 
-    /*
-      After an instance have been added to the instance_map,
-      hash_free should handle it's deletion => goto err, not
-      err_instance.
-    */
-    if (instance->complete_initialization(this, mysqld_path,
-                                          DEFAULT_SINGLE_INSTANCE))
-      goto err;
+int Instance_map::create_instance(const LEX_STRING *instance_name,
+                                  const Named_value_arr *options)
+{
+  Instance *instance= new Instance();
+
+  if (!instance)
+  {
+    log_error("Error: can not initialize (name: '%s').",
+              (const char *) instance_name->str);
+    return ER_OUT_OF_RESOURCES;
   }
-  else
-    while (i < hash.records)
+
+  if (instance->init(instance_name))
+  {
+    log_error("Error: can not initialize (name: '%s').",
+              (const char *) instance_name->str);
+    delete instance;
+    return ER_OUT_OF_RESOURCES;
+  }
+
+  for (int i= 0; options && i < options->get_size(); ++i)
+  {
+    Named_value option= options->get_element(i);
+
+    if (instance->is_mysqld_compatible() &&
+        Instance_options::is_option_im_specific(option.get_name()))
     {
-      instance= (Instance *) hash_element(&hash, i);
-      if (instance->complete_initialization(this, mysqld_path, USUAL_INSTANCE))
-        goto err;
-      i++;
+      log_error("Error: IM-option (%s) can not be used "
+                "in configuration of mysqld-compatible instance (%s).",
+                (const char *) option.get_name(),
+                (const char *) instance_name->str);
+      delete instance;
+      return ER_INCOMPATIBLE_OPTION;
     }
 
+    instance->options.set_option(&option);
+  }
+
+  if (instance->is_mysqld_compatible())
+    log_info("Warning: instance name '%s' is mysqld-compatible.",
+             (const char *) instance_name->str);
+
+  if (instance->complete_initialization(this, mysqld_path))
+  {
+    log_error("Error: can not complete initialization of instance (name: '%s').",
+              (const char *) instance_name->str);
+    delete instance;
+    return ER_OUT_OF_RESOURCES;
+    /* TODO: return more appropriate error code in this case. */
+  }
+
+  if (add_instance(instance))
+  {
+    log_error("Error: can not register instance (name: '%s').",
+              (const char *) instance_name->str);
+    delete instance;
+    return ER_OUT_OF_RESOURCES;
+  }
+
   return 0;
-err_instance:
-  delete instance;
-err:
-  return 1;
+}
+
+
+Instance * Instance_map::find(const LEX_STRING *name)
+{
+  return (Instance *) hash_search(&hash, (byte *) name->str, name->length);
+}
+
+
+bool Instance_map::complete_initialization()
+{
+  bool mysqld_found;
+
+  /* Complete initialization of all registered instances. */
+
+  for (uint i= 0; i < hash.records; ++i)
+  {
+    Instance *instance= (Instance *) hash_element(&hash, i);
+
+    if (instance->complete_initialization(this, mysqld_path))
+      return TRUE;
+  }
+
+  /* That's all if we are runnning in an ordinary mode. */
+
+  if (!Options::Main::mysqld_safe_compatible)
+    return FALSE;
+
+  /* In mysqld-compatible mode we must ensure that there 'mysqld' instance. */
+
+  mysqld_found= find(&Instance::DFLT_INSTANCE_NAME) != NULL;
+
+  if (mysqld_found)
+    return FALSE;
+
+  if (create_instance(&Instance::DFLT_INSTANCE_NAME, NULL))
+  {
+    log_error("Error: could not create default instance.");
+    return TRUE;
+  }
+
+  switch (create_instance_in_file(&Instance::DFLT_INSTANCE_NAME, NULL))
+  {
+  case 0:
+  case ER_CONF_FILE_DOES_NOT_EXIST:
+    /*
+      Continue if the instance has been added to the config file
+      successfully, or the config file just does not exist.
+    */
+    break;
+
+  default:
+    log_error("Error: could not add default instance to the config file.");
+
+    Instance *instance= find(&Instance::DFLT_INSTANCE_NAME);
+
+    if (instance)
+      remove_instance(instance); /* instance is deleted here. */
+
+    return TRUE;
+  }
+
+  return FALSE;
 }
 
 
@@ -297,10 +478,10 @@ int Instance_map::load()
     name and start looking for files named "my.cnf.cnf" in all
     default dirs. Which is not what we want.
   */
-  if (Options::is_forced_default_file)
+  if (Options::Main::is_forced_default_file)
   {
     snprintf(defaults_file_arg, FN_REFLEN, "--defaults-file=%s",
-             Options::config_file);
+             Options::Main::config_file);
 
     argv_options[1]= defaults_file_arg;
     argv_options[2]= '\0';
@@ -314,15 +495,12 @@ int Instance_map::load()
     If the routine failed, we'll simply fallback to defaults in
     complete_initialization().
   */
-  if (my_search_option_files(Options::config_file, &argc,
+  if (my_search_option_files(Options::Main::config_file, &argc,
                              (char ***) &argv, &args_used,
                              process_option, (void*) this))
     log_info("Falling back to compiled-in defaults");
 
-  if (complete_initialization())
-    return 1;
-
-  return 0;
+  return complete_initialization();
 }
 
 
@@ -343,3 +521,105 @@ Instance *Instance_map::Iterator::next()
   return NULL;
 }
 
+
+const char *Instance_map::get_instance_state_name(Instance *instance)
+{
+  LIST *instance_node;
+
+  if (!instance->is_configured())
+    return "misconfigured";
+
+  if ((instance_node= guardian->find_instance_node(instance)) != NULL)
+  {
+    /* The instance is managed by Guardian: we can report precise state. */
+
+    return Guardian_thread::get_instance_state_name(
+      guardian->get_instance_state(instance_node));
+  }
+
+  /* The instance is not managed by Guardian: we can report status only.  */
+
+  return instance->is_running() ? "online" : "offline";
+}
+
+
+/*
+  Create a new configuration section for mysqld-instance in the config file.
+
+  SYNOPSYS
+    create_instance_in_file()
+    instance_name       mysqld-instance name
+    options             options for the new mysqld-instance
+
+  RETURN
+    0     On success
+    ER_CONF_FILE_DOES_NOT_EXIST     If config file does not exist
+    ER_ACCESS_OPTION_FILE           If config file is not writable or some I/O
+                                    error ocurred during writing configuration
+*/
+
+int create_instance_in_file(const LEX_STRING *instance_name,
+                            const Named_value_arr *options)
+{
+  File cnf_file;
+
+  if (my_access(Options::Main::config_file, W_OK))
+  {
+    log_error("Error: configuration file (%s) does not exist.",
+              (const char *) Options::Main::config_file);
+    return ER_CONF_FILE_DOES_NOT_EXIST;
+  }
+
+  cnf_file= my_open(Options::Main::config_file, O_WRONLY | O_APPEND, MYF(0));
+
+  if (cnf_file <= 0)
+  {
+    log_error("Error: can not open configuration file (%s): %s.",
+              (const char *) Options::Main::config_file,
+              (const char *) strerror(errno));
+    return ER_ACCESS_OPTION_FILE;
+  }
+
+  if (my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)) ||
+      my_write(cnf_file, (byte*)"[", 1, MYF(MY_NABP)) ||
+      my_write(cnf_file, (byte*)instance_name->str, instance_name->length,
+               MYF(MY_NABP)) ||
+      my_write(cnf_file, (byte*)"]", 1,   MYF(MY_NABP)) ||
+      my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
+  {
+    log_error("Error: can not write to configuration file (%s): %s.",
+              (const char *) Options::Main::config_file,
+              (const char *) strerror(errno));
+    my_close(cnf_file, MYF(0));
+    return ER_ACCESS_OPTION_FILE;
+  }
+
+  for (int i= 0; options && i < options->get_size(); ++i)
+  {
+    char option_str[MAX_OPTION_STR_LEN];
+    char *ptr;
+    int option_str_len;
+    Named_value option= options->get_element(i);
+
+    ptr= strxnmov(option_str, MAX_OPTION_LEN + 1, option.get_name(), NullS);
+
+    if (option.get_value()[0])
+      ptr= strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS);
+
+    option_str_len= ptr - option_str;
+
+    if (my_write(cnf_file, (byte*)option_str, option_str_len, MYF(MY_NABP)) ||
+        my_write(cnf_file, (byte*)NEWLINE, NEWLINE_LEN, MYF(MY_NABP)))
+    {
+      log_error("Error: can not write to configuration file (%s): %s.",
+                (const char *) Options::Main::config_file,
+                (const char *) strerror(errno));
+      my_close(cnf_file, MYF(0));
+      return ER_ACCESS_OPTION_FILE;
+    }
+  }
+
+  my_close(cnf_file, MYF(0));
+
+  return 0;
+}
diff --git a/server-tools/instance-manager/instance_map.h b/server-tools/instance-manager/instance_map.h
index d3de42f4d80a861acaf69d2132638a9721f880e7..8e6d2360652b5d4fcb6e91ba62242e987e583939 100644
--- a/server-tools/instance-manager/instance_map.h
+++ b/server-tools/instance-manager/instance_map.h
@@ -17,21 +17,24 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <my_global.h>
-
-#include "protocol.h"
-#include "guardian.h"
-
 #include <my_sys.h>
+#include <m_string.h>
 #include <hash.h>
 
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
 #endif
 
+class Guardian_thread;
 class Instance;
+class Named_value_arr;
+
 extern int load_all_groups(char ***groups, const char *filename);
 extern void free_groups(char **groups);
 
+extern int create_instance_in_file(const LEX_STRING *instance_name,
+                                   const Named_value_arr *options);
+
 
 /*
   Instance_map - stores all existing instances
@@ -56,22 +59,64 @@ class Instance_map
   };
   friend class Iterator;
 public:
-  /* returns a pointer to the instance or NULL, if there is no such instance */
-  Instance *find(const char *name, uint name_len);
+  /*
+    Return a pointer to the instance or NULL, if there is no such instance.
+    MT-NOTE: must be called under acquired lock.
+  */
+  Instance *find(const LEX_STRING *name);
 
+  /* Clear the configuration cache and reload the configuration file. */
   int flush_instances();
+
+  /* The operation is used to check if there is an active instance or not. */
+  bool is_there_active_instance();
+
   void lock();
   void unlock();
+
   int init();
+
   /*
     Process a given option and assign it to appropricate instance. This is
     required for the option handler, passed to my_search_option_files().
   */
-  int process_one_option(const char *group, const char *option);
+  int process_one_option(const LEX_STRING *group, const char *option);
+
+  /*
+    Add an instance into the internal hash.
+
+    MT-NOTE: the operation must be called under acquired lock.
+  */
+  int add_instance(Instance *instance);
+
+  /*
+    Remove instance from the internal hash.
+
+    MT-NOTE: the operation must be called under acquired lock.
+  */
+  int remove_instance(Instance *instance);
+
+  /*
+    Create a new instance and register it in the internal hash.
+
+    MT-NOTE: the operation must be called under acquired lock.
+  */
+  int create_instance(const LEX_STRING *instance_name,
+                      const Named_value_arr *options);
 
   Instance_map(const char *default_mysqld_path_arg);
   ~Instance_map();
 
+  /*
+    Retrieve client state name of the given instance.
+
+    MT-NOTE: the options must be called under acquired locks of the following
+    objects:
+      - Instance_map;
+      - Guardian_thread;
+  */
+  const char *get_instance_state_name(Instance *instance);
+
 public:
   const char *mysqld_path;
   Guardian_thread *guardian;
@@ -80,7 +125,7 @@ class Instance_map
   /* loads options from config files */
   int load();
   /* inits instances argv's after all options have been loaded */
-  int complete_initialization();
+  bool complete_initialization();
 private:
   enum { START_HASH_SIZE = 16 };
   pthread_mutex_t LOCK_instance_map;
diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc
index 8bbd362a15b9df527b2322ca97e2947ff60b6ce5..b05e40734b7bc527dd429cb9e85e49d1bec34eb0 100644
--- a/server-tools/instance-manager/instance_options.cc
+++ b/server-tools/instance-manager/instance_options.cc
@@ -20,28 +20,24 @@
 
 #include "instance_options.h"
 
-#include "parse_output.h"
-#include "buffer.h"
-#include "log.h"
-
+#include <my_global.h>
 #include <my_sys.h>
-#include <signal.h>
 #include <m_string.h>
 
-#ifdef __WIN__
-#define NEWLINE_LEN 2
-#else
-#define NEWLINE_LEN 1
-#endif
+#include <signal.h>
+
+#include "buffer.h"
+#include "instance.h"
+#include "log.h"
+#include "parse_output.h"
+#include "priv.h"
 
 
 /* Create "mysqld ..." command in the buffer */
 
 static inline int create_mysqld_command(Buffer *buf,
-                                        const char *mysqld_path_str,
-                                        uint mysqld_path_len,
-                                        const char *option,
-                                        uint option_len)
+                                        const LEX_STRING *mysqld_path,
+                                        const LEX_STRING *option)
 {
   int position= 0;
 
@@ -50,13 +46,13 @@ static inline int create_mysqld_command(Buffer *buf,
 #ifdef __WIN__
     buf->append(position++, "\"", 1);
 #endif
-    buf->append(position, mysqld_path_str, mysqld_path_len);
-    position+= mysqld_path_len;
+    buf->append(position, mysqld_path->str, mysqld_path->length);
+    position+= mysqld_path->length;
 #ifdef __WIN__
     buf->append(position++, "\"", 1);
 #endif
     /* here the '\0' character is copied from the option string */
-    buf->append(position, option, option_len);
+    buf->append(position, option->str, option->length + 1);
 
     return buf->is_error();
   }
@@ -64,6 +60,42 @@ static inline int create_mysqld_command(Buffer *buf,
 }
 
 
+bool Instance_options::is_option_im_specific(const char *option_name)
+{
+  static const char *IM_SPECIFIC_OPTIONS[] =
+  {
+    "nonguarded",
+    "mysqld-path",
+    "shutdown-delay",
+    NULL
+  };
+
+  for (int i= 0; IM_SPECIFIC_OPTIONS[i]; ++i)
+  {
+    if (!strcmp(option_name, IM_SPECIFIC_OPTIONS[i]))
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+Instance_options::Instance_options()
+  :mysqld_version(NULL), mysqld_socket(NULL), mysqld_datadir(NULL),
+  mysqld_pid_file(NULL), mysqld_port(NULL), mysqld_port_val(0),
+  nonguarded(NULL), shutdown_delay(NULL), shutdown_delay_val(0),
+  filled_default_options(0)
+{
+  mysqld_path.str= NULL;
+  mysqld_path.length= 0;
+
+  mysqld_real_path.str= NULL;
+  mysqld_real_path.length= 0;
+
+  memset(logs, 0, sizeof(logs));
+}
+
+
 /*
   Get compiled-in value of default_option
 
@@ -87,13 +119,13 @@ int Instance_options::get_default_option(char *result, size_t result_len,
                                          const char *option_name)
 {
   int rc= 1;
-  char verbose_option[]= " --no-defaults --verbose --help";
+  LEX_STRING verbose_option=
+    { C_STRING_WITH_SIZE(" --no-defaults --verbose --help") };
 
-  /* reserve space fot the path + option + final '\0' */
-  Buffer cmd(mysqld_path_len + sizeof(verbose_option));
+  /* reserve space for the path + option + final '\0' */
+  Buffer cmd(mysqld_path.length + verbose_option.length + 1);
 
-  if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
-                            verbose_option, sizeof(verbose_option)))
+  if (create_mysqld_command(&cmd, &mysqld_path, &verbose_option))
     goto err;
 
   /* +2 eats first "--" from the option string (E.g. "--datadir") */
@@ -121,21 +153,19 @@ int Instance_options::get_default_option(char *result, size_t result_len,
 
 int Instance_options::fill_instance_version()
 {
-  enum { MAX_VERSION_STRING_LENGTH= 160 };
-  char result[MAX_VERSION_STRING_LENGTH];
-  char version_option[]= " --no-defaults --version";
+  char result[MAX_VERSION_LENGTH];
+  LEX_STRING version_option=
+    { C_STRING_WITH_SIZE(" --no-defaults --version") };
   int rc= 1;
-  Buffer cmd(mysqld_path_len + sizeof(version_option));
+  Buffer cmd(mysqld_path.length + version_option.length + 1);
 
-  if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
-                            version_option, sizeof(version_option)))
+  if (create_mysqld_command(&cmd, &mysqld_path, &version_option))
     goto err;
 
-  bzero(result, MAX_VERSION_STRING_LENGTH);
+  bzero(result, MAX_VERSION_LENGTH);
 
-  rc= parse_output_and_get_value(cmd.buffer, "Ver",
-                                 result, MAX_VERSION_STRING_LENGTH,
-                                 GET_LINE);
+  rc= parse_output_and_get_value(cmd.buffer, "Ver", result,
+                                 MAX_VERSION_LENGTH, GET_LINE);
 
   if (*result != '\0')
   {
@@ -146,6 +176,7 @@ int Instance_options::fill_instance_version()
     start= result;
     while (my_isspace(default_charset_info, *start))
       ++start;
+
     mysqld_version= strdup_root(&alloc, start);
   }
 err:
@@ -178,12 +209,12 @@ int Instance_options::fill_instance_version()
 int Instance_options::fill_mysqld_real_path()
 {
   char result[FN_REFLEN];
-  char help_option[]= " --no-defaults --help";
+  LEX_STRING help_option=
+    { C_STRING_WITH_SIZE(" --no-defaults --help") };
   int rc= 1;
-  Buffer cmd(mysqld_path_len + sizeof(help_option));
+  Buffer cmd(mysqld_path.length + help_option.length);
 
-  if (create_mysqld_command(&cmd, mysqld_path, mysqld_path_len,
-                            help_option, sizeof(help_option)))
+  if (create_mysqld_command(&cmd, &mysqld_path, &help_option))
     goto err;
 
   bzero(result, FN_REFLEN);
@@ -198,7 +229,8 @@ int Instance_options::fill_mysqld_real_path()
     /* chop the path of at [OPTIONS] */
     if ((options_str= strstr(result, "[OPTIONS]")))
       *options_str= '\0';
-    mysqld_real_path= strdup_root(&alloc, result);
+    mysqld_real_path.str= strdup_root(&alloc, result);
+    mysqld_real_path.length= strlen(mysqld_real_path.str);
   }
 err:
   if (rc)
@@ -255,8 +287,7 @@ int Instance_options::fill_log_options()
   else
   {
     /* below is safe, as --datadir always has a value */
-    strmake(datadir,
-            strchr(mysqld_datadir, '=') + 1, MAX_LOG_OPTION_LENGTH - 1);
+    strmake(datadir, mysqld_datadir, MAX_LOG_OPTION_LENGTH - 1);
   }
 
   if (gethostname(hostname,sizeof(hostname)-1) < 0)
@@ -342,7 +373,6 @@ int Instance_options::fill_log_options()
 
 int Instance_options::get_pid_filename(char *result)
 {
-  const char *pid_file= mysqld_pid_file;
   char datadir[MAX_PATH_LEN];
 
   if (mysqld_datadir == NULL)
@@ -352,14 +382,10 @@ int Instance_options::get_pid_filename(char *result)
       return 1;
   }
   else
-    strxnmov(datadir, MAX_PATH_LEN - 1, strchr(mysqld_datadir, '=') + 1,
-             "/", NullS);
-
-  DBUG_ASSERT(mysqld_pid_file);
-  pid_file= strchr(pid_file, '=') + 1;
+    strxnmov(datadir, MAX_PATH_LEN - 1, mysqld_datadir, "/", NullS);
 
   /* get the full path to the pidfile */
-  my_load_path(result, pid_file, datadir);
+  my_load_path(result, mysqld_pid_file, datadir);
   return 0;
 }
 
@@ -388,23 +414,23 @@ pid_t Instance_options::get_pid()
 }
 
 
-int Instance_options::complete_initialization(const char *default_path,
-                                              uint instance_type)
+int Instance_options::complete_initialization(const char *default_path)
 {
+  int arg_idx;
   const char *tmp;
   char *end;
 
-  if (!mysqld_path && !(mysqld_path= strdup_root(&alloc, default_path)))
+  if (!mysqld_path.str && !(mysqld_path.str= strdup_root(&alloc, default_path)))
     goto err;
 
   // it's safe to cast this to char* since this is a buffer we are allocating
-  end= convert_dirname((char*)mysqld_path, mysqld_path, NullS);
+  end= convert_dirname((char*)mysqld_path.str, mysqld_path.str, NullS);
   end[-1]= 0;
 
-  mysqld_path_len= strlen(mysqld_path);
+  mysqld_path.length= strlen(mysqld_path.str);
 
   if (mysqld_port)
-    mysqld_port_val= atoi(strchr(mysqld_port, '=') + 1);
+    mysqld_port_val= atoi(mysqld_port);
 
   if (shutdown_delay)
     shutdown_delay_val= atoi(shutdown_delay);
@@ -412,7 +438,7 @@ int Instance_options::complete_initialization(const char *default_path,
   if (!(tmp= strdup_root(&alloc, "--no-defaults")))
     goto err;
 
-  if (!(mysqld_pid_file))
+  if (!mysqld_pid_file)
   {
     char pidfilename[MAX_PATH_LEN];
     char hostname[MAX_PATH_LEN];
@@ -421,26 +447,27 @@ int Instance_options::complete_initialization(const char *default_path,
       If we created only one istance [mysqld], because no config. files were
       found, we would like to model mysqld pid file values.
     */
+
     if (!gethostname(hostname, sizeof(hostname) - 1))
     {
-      if (instance_type & DEFAULT_SINGLE_INSTANCE)
-        strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", hostname,
-                 ".pid", NullS);
+      if (Instance::is_mysqld_compatible_name(&instance_name))
+        strxnmov(pidfilename, MAX_PATH_LEN - 1, hostname, ".pid", NullS);
       else
-        strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
-                 "-", hostname, ".pid", NullS);
+        strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, "-",
+                 hostname, ".pid", NullS);
     }
     else
     {
-      if (instance_type & DEFAULT_SINGLE_INSTANCE)
-        strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", "mysql",
-                 ".pid", NullS);
+      if (Instance::is_mysqld_compatible_name(&instance_name))
+        strxnmov(pidfilename, MAX_PATH_LEN - 1, "mysql", ".pid", NullS);
       else
-        strxnmov(pidfilename, MAX_PATH_LEN - 1, "--pid-file=", instance_name,
-                 ".pid", NullS);
+        strxnmov(pidfilename, MAX_PATH_LEN - 1, instance_name.str, ".pid",
+                 NullS);
     }
 
-    add_option(pidfilename);
+    Named_value option((char *) "pid-file", pidfilename);
+
+    set_option(&option);
   }
 
   if (get_pid_filename(pid_file_with_path))
@@ -448,20 +475,37 @@ int Instance_options::complete_initialization(const char *default_path,
 
   /* we need to reserve space for the final zero + possible default options */
   if (!(argv= (char**)
-        alloc_root(&alloc, (options_array.elements + 1
+        alloc_root(&alloc, (get_num_options() + 1
                             + MAX_NUMBER_OF_DEFAULT_OPTIONS) * sizeof(char*))))
     goto err;
+  filled_default_options= 0;
 
   /* the path must be first in the argv */
-  if (add_to_argv(mysqld_path))
+  if (add_to_argv(mysqld_path.str))
     goto err;
 
   if (add_to_argv(tmp))
     goto err;
 
-  memcpy((gptr) (argv + filled_default_options), options_array.buffer,
-         options_array.elements*sizeof(char*));
-  argv[filled_default_options + options_array.elements]= 0;
+  arg_idx= filled_default_options;
+  for (int opt_idx= 0; opt_idx < get_num_options(); ++opt_idx)
+  {
+    char option_str[MAX_OPTION_STR_LEN];
+    Named_value option= get_option(opt_idx);
+
+    if (is_option_im_specific(option.get_name()))
+      continue;
+
+    char *ptr= strxnmov(option_str, MAX_OPTION_LEN + 3, "--", option.get_name(),
+                        NullS);
+
+    if (option.get_value()[0])
+      strxnmov(ptr, MAX_OPTION_LEN + 2, "=", option.get_value(), NullS);
+
+    argv[arg_idx++]= strdup_root(&alloc, option_str);
+  }
+
+  argv[arg_idx]= 0;
 
   if (fill_log_options() || fill_mysqld_real_path() || fill_instance_version())
     goto err;
@@ -473,75 +517,91 @@ int Instance_options::complete_initialization(const char *default_path,
 }
 
 
-/*
-  Assigns given value to the appropriate option from the class.
+bool Instance_options::set_option(Named_value *option)
+{
+  bool err_status;
+  int idx= find_option(option->get_name());
+  char *option_name_str;
+  char *option_value_str;
 
-  SYNOPSYS
-    add_option()
-    option            string with the option prefixed by --
+  if (!(option_name_str= Named_value::alloc_str(option->get_name())))
+    return TRUE;
 
-  DESCRIPTION
+  if (!(option_value_str= Named_value::alloc_str(option->get_value())))
+  {
+    Named_value::free_str(&option_name_str);
+    return TRUE;
+  }
 
-    The method is called from the option handling routine.
+  Named_value option_copy(option_name_str, option_value_str);
 
-  RETURN
-    0 - ok
-    1 - error occured
-*/
+  if (idx < 0)
+    err_status= options.add_element(&option_copy);
+  else
+    err_status= options.replace_element(idx, &option_copy);
+
+  if (!err_status)
+    update_var(option_copy.get_name(), option_copy.get_value());
+  else
+    option_copy.free();
+
+  return err_status;
+}
 
-int Instance_options::add_option(const char* option)
+
+void Instance_options::unset_option(const char *option_name)
 {
-  char *tmp;
-  enum { SAVE_VALUE= 1, SAVE_WHOLE, SAVE_WHOLE_AND_ADD };
-  struct selected_options_st
+  int idx= find_option(option_name);
+
+  if (idx < 0)
+    return; /* the option has not been set. */
+
+  options.remove_element(idx);
+
+  update_var(option_name, NULL);
+}
+
+
+void Instance_options::update_var(const char *option_name,
+                                  const char *option_value)
+{
+  struct options_st
   {
     const char *name;
-    uint length;
-    const char **value;
-    uint type;
-  } options[]=
+    uint name_len;
+    const char **var;
+  } options_def[]=
   {
-    {"--socket=", 9, &mysqld_socket, SAVE_WHOLE_AND_ADD},
-    {"--port=", 7, &mysqld_port, SAVE_WHOLE_AND_ADD},
-    {"--datadir=", 10, &mysqld_datadir, SAVE_WHOLE_AND_ADD},
-    {"--bind-address=", 15, &mysqld_bind_address, SAVE_WHOLE_AND_ADD},
-    {"--pid-file=", 11, &mysqld_pid_file, SAVE_WHOLE_AND_ADD},
-    {"--mysqld-path=", 14, &mysqld_path, SAVE_VALUE},
-    {"--nonguarded", 9, &nonguarded, SAVE_WHOLE},
-    {"--shutdown_delay", 9, &shutdown_delay, SAVE_VALUE},
-    {NULL, 0, NULL, 0}
+    {"socket",          6,  &mysqld_socket},
+    {"port",            4,  &mysqld_port},
+    {"datadir",         7,  &mysqld_datadir},
+    {"pid-file",        8,  &mysqld_pid_file},
+    {"nonguarded",      10, &nonguarded},
+    {"mysqld-path",     11, (const char **) &mysqld_path.str},
+    {"shutdown-delay",  14, &shutdown_delay},
+    {NULL, 0, NULL}
   };
-  struct selected_options_st *selected_options;
 
-  if (!(tmp= strdup_root(&alloc, option)))
-    goto err;
+  for (options_st *opt= options_def; opt->name; ++opt)
+  {
+    if (!strncmp(opt->name, option_name, opt->name_len))
+    {
+      *(opt->var)= option_value;
+      break;
+    }
+  }
+}
 
-   for (selected_options= options; selected_options->name; selected_options++)
-   {
-     if (strncmp(tmp, selected_options->name, selected_options->length) == 0)
-       switch (selected_options->type) {
-       case SAVE_WHOLE_AND_ADD:
-         *(selected_options->value)= tmp;
-         insert_dynamic(&options_array,(gptr) &tmp);
-         return 0;
-       case SAVE_VALUE:
-         *(selected_options->value)= strchr(tmp, '=') + 1;
-         return 0;
-       case SAVE_WHOLE:
-         *(selected_options->value)= tmp;
-         return 0;
-       default:
-         break;
-       }
-   }
-
-  /* if we haven't returned earlier we should just save the option */
-  insert_dynamic(&options_array,(gptr) &tmp);
 
-  return 0;
+int Instance_options::find_option(const char *option_name)
+{
+  for (int i= 0; i < get_num_options(); i++)
+  {
+    if (!strcmp(get_option(i).get_name(), option_name))
+      return i;
+  }
 
-err:
-  return 1;
+  return -1;
 }
 
 
@@ -559,7 +619,10 @@ int Instance_options::add_to_argv(const char* option)
 void Instance_options::print_argv()
 {
   int i;
-  printf("printing out an instance %s argv:\n", instance_name);
+
+  printf("printing out an instance %s argv:\n",
+         (const char *) instance_name.str);
+
   for (i=0; argv[i] != NULL; i++)
     printf("argv: %s\n", argv[i]);
 }
@@ -570,17 +633,17 @@ void Instance_options::print_argv()
   Return value: 0 - ok. 1 - unable to allocate memory.
 */
 
-int Instance_options::init(const char *instance_name_arg)
+int Instance_options::init(const LEX_STRING *instance_name_arg)
 {
-  instance_name_len= strlen(instance_name_arg);
+  instance_name.length= instance_name_arg->length;
 
   init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0);
 
-  if (my_init_dynamic_array(&options_array, sizeof(char*), 0, 32))
+  if (options.init())
     goto err;
 
-  if (!(instance_name= strmake_root(&alloc, (char*) instance_name_arg,
-                                    instance_name_len)))
+  if (!(instance_name.str= strmake_root(&alloc, instance_name_arg->str,
+                                        instance_name_arg->length)))
     goto err;
 
   return 0;
@@ -593,6 +656,4 @@ int Instance_options::init(const char *instance_name_arg)
 Instance_options::~Instance_options()
 {
   free_root(&alloc, MYF(0));
-  delete_dynamic(&options_array);
 }
-
diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h
index b316dbf00fca765d468336df3b9f3c2c01eb66dd..c3b0a16a40dd27d79c5accaf77ce15db3c4c60a3 100644
--- a/server-tools/instance-manager/instance_options.h
+++ b/server-tools/instance-manager/instance_options.h
@@ -18,8 +18,9 @@
 
 #include <my_global.h>
 #include <my_sys.h>
+
 #include "parse.h"
-#include "portability.h"
+#include "portability.h" /* for pid_t on Win32 */
 
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
@@ -35,25 +36,26 @@
   don't have to synchronize between threads.
 */
 
-#define USUAL_INSTANCE 0
-#define DEFAULT_SINGLE_INSTANCE 1
-
 class Instance_options
 {
 public:
-  Instance_options() :
-    mysqld_version(0), mysqld_socket(0), mysqld_datadir(0),
-    mysqld_bind_address(0), mysqld_pid_file(0), mysqld_port(0),
-    mysqld_port_val(0), mysqld_path(0), mysqld_real_path(0),
-    nonguarded(0), shutdown_delay(0),
-    shutdown_delay_val(0), filled_default_options(0)
-  {}
+  /* The operation is used to check if the option is IM-specific or not. */
+   static bool is_option_im_specific(const char *option_name);
+
+public:
+  Instance_options();
   ~Instance_options();
   /* fills in argv */
-  int complete_initialization(const char *default_path, uint instance_type);
+  int complete_initialization(const char *default_path);
 
-  int add_option(const char* option);
-  int init(const char *instance_name_arg);
+  bool set_option(Named_value *option);
+  void unset_option(const char *option_name);
+
+  inline int get_num_options() const;
+  inline Named_value get_option(int idx) const;
+
+public:
+  int init(const LEX_STRING *instance_name_arg);
   pid_t get_pid();
   int get_pid_filename(char *result);
   int unlink_pidfile();
@@ -66,7 +68,6 @@ class Instance_options
   */
   enum { MAX_PATH_LEN= 512 };
   enum { MAX_NUMBER_OF_DEFAULT_OPTIONS= 2 };
-  enum { MEM_ROOT_BLOCK_SIZE= 512 };
   char pid_file_with_path[MAX_PATH_LEN];
   char **argv;
   /*
@@ -77,23 +78,18 @@ class Instance_options
   /* We need the some options, so we store them as a separate pointers */
   const char *mysqld_socket;
   const char *mysqld_datadir;
-  const char *mysqld_bind_address;
   const char *mysqld_pid_file;
   const char *mysqld_port;
   uint mysqld_port_val;
-  const char *instance_name;
-  uint instance_name_len;
-  const char *mysqld_path;
-  uint mysqld_path_len;
-  const char *mysqld_real_path;
+  LEX_STRING instance_name;
+  LEX_STRING mysqld_path;
+  LEX_STRING mysqld_real_path;
   const char *nonguarded;
   const char *shutdown_delay;
   uint shutdown_delay_val;
   /* log enums are defined in parse.h */
   char *logs[3];
 
-  /* this value is computed and cashed here */
-  DYNAMIC_ARRAY options_array;
 private:
   int fill_log_options();
   int fill_instance_version();
@@ -101,9 +97,27 @@ class Instance_options
   int add_to_argv(const char *option);
   int get_default_option(char *result, size_t result_len,
                          const char *option_name);
+
+  void update_var(const char *option_name, const char *option_value);
+  int find_option(const char *option_name);
+
 private:
   uint filled_default_options;
   MEM_ROOT alloc;
+
+  Named_value_arr options;
 };
 
+
+inline int Instance_options::get_num_options() const
+{
+  return options.get_size();
+}
+
+
+inline Named_value Instance_options::get_option(int idx) const
+{
+  return options.get_element(idx);
+}
+
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_INSTANCE_OPTIONS_H */
diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc
index 500b25bec033c7bef7763b0ea8408b18c2df47da..da9338e28c5d86bf84ab00a800abc4b0e92f9c98 100644
--- a/server-tools/instance-manager/listener.cc
+++ b/server-tools/instance-manager/listener.cc
@@ -19,21 +19,23 @@
 #endif
 
 #include "listener.h"
-#include "priv.h"
-#include <m_string.h>
+
+#include <my_global.h>
 #include <mysql.h>
 #include <violite.h>
+
+#include <sys/stat.h>
 #ifndef __WIN__
 #include <sys/un.h>
 #endif
-#include <sys/stat.h>
 
-#include "thread_registry.h"
-#include "options.h"
 #include "instance_map.h"
 #include "log.h"
 #include "mysql_connection.h"
+#include "options.h"
 #include "portability.h"
+#include "priv.h"
+#include "thread_registry.h"
 
 
 /*
@@ -62,8 +64,7 @@ class Listener_thread: public Listener_thread_args
 
 
 Listener_thread::Listener_thread(const Listener_thread_args &args) :
-  Listener_thread_args(args.thread_registry, args.options, args.user_map,
-                       args.instance_map)
+  Listener_thread_args(args.thread_registry, args.user_map, args.instance_map)
   ,total_connection_count(0)
   ,thread_info(pthread_self())
   ,num_sockets(0)
@@ -234,14 +235,16 @@ int Listener_thread::create_tcp_socket()
   bzero(&ip_socket_address, sizeof(ip_socket_address));
 
   ulong im_bind_addr;
-  if (options.bind_address != 0)
+  if (Options::Main::bind_address != 0)
   {
-    if ((im_bind_addr= (ulong) inet_addr(options.bind_address)) == INADDR_NONE)
+    im_bind_addr= (ulong) inet_addr(Options::Main::bind_address);
+
+    if (im_bind_addr == INADDR_NONE)
       im_bind_addr= htonl(INADDR_ANY);
   }
   else
     im_bind_addr= htonl(INADDR_ANY);
-  uint im_port= options.port_number;
+  uint im_port= Options::Main::port_number;
 
   ip_socket_address.sin_family= AF_INET;
   ip_socket_address.sin_addr.s_addr= im_bind_addr;
@@ -295,7 +298,7 @@ create_unix_socket(struct sockaddr_un &unix_socket_address)
   bzero(&unix_socket_address, sizeof(unix_socket_address));
 
   unix_socket_address.sun_family= AF_UNIX;
-  strmake(unix_socket_address.sun_path, options.socket_file_name,
+  strmake(unix_socket_address.sun_path, Options::Main::socket_file_name,
           sizeof(unix_socket_address.sun_path));
   unlink(unix_socket_address.sun_path); // in case we have stale socket file
 
diff --git a/server-tools/instance-manager/listener.h b/server-tools/instance-manager/listener.h
index 28ccbf91731025de1d9c0955f419579b7f5fd6a8..c28ab0649d746628e6a3dc3ad9ab2ed3041d465e 100644
--- a/server-tools/instance-manager/listener.h
+++ b/server-tools/instance-manager/listener.h
@@ -27,23 +27,19 @@
 pthread_handler_t listener(void *arg);
 
 class Thread_registry;
-struct Options;
 class User_map;
 class Instance_map;
 
 struct Listener_thread_args
 {
   Thread_registry &thread_registry;
-  const Options &options;
   const User_map &user_map;
   Instance_map &instance_map;
 
   Listener_thread_args(Thread_registry &thread_registry_arg,
-                       const Options &options_arg,
                        const User_map &user_map_arg,
                        Instance_map &instance_map_arg) :
     thread_registry(thread_registry_arg)
-    ,options(options_arg)
     ,user_map(user_map_arg)
     ,instance_map(instance_map_arg)
   {}
diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc
index 3f54bc0649a9132dff10543fd4e4d6702d999de2..a88344f0b9135a608a930ee1e349d129ec175dcc 100644
--- a/server-tools/instance-manager/log.cc
+++ b/server-tools/instance-manager/log.cc
@@ -14,14 +14,16 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-#include <my_global.h>
-
 #include "log.h"
-#include "portability.h"
-#include <stdarg.h>
+
+#include <my_global.h>
 #include <m_string.h>
 #include <my_sys.h>
 
+#include <stdarg.h>
+
+#include "portability.h" /* for vsnprintf() on Windows. */
+
 /*
   TODO:
   - add flexible header support
@@ -71,7 +73,7 @@ static inline void log(FILE *file,  const char *format, va_list args)
   {
     int size= sizeof(buff_stack) * 2;
     buff_msg= (char*) my_malloc(size, MYF(0));
-    while (true)
+    while (TRUE)
     {
       if (buff_msg == 0)
       {
diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc
index 90d9d04cd36014779d3009af979830cc83241cb9..e2bb09cb9fa2332131c6d7eacc3bbd2fc76592d6 100644
--- a/server-tools/instance-manager/manager.cc
+++ b/server-tools/instance-manager/manager.cc
@@ -14,39 +14,55 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-#include <my_global.h>
 #include "manager.h"
 
-#include "priv.h"
-#include "thread_registry.h"
-#include "listener.h"
-#include "instance_map.h"
-#include "options.h"
-#include "user_map.h"
-#include "log.h"
-#include "guardian.h"
-
-#include <my_sys.h>
+#include <my_global.h>
 #include <m_string.h>
-#include <signal.h>
+#include <my_sys.h>
 #include <thr_alarm.h>
+
+#include <signal.h>
 #ifndef __WIN__
 #include <sys/wait.h>
 #endif
 
+#include "exit_codes.h"
+#include "guardian.h"
+#include "instance_map.h"
+#include "listener.h"
+#include "log.h"
+#include "options.h"
+#include "priv.h"
+#include "thread_registry.h"
+#include "user_map.h"
+
 
 int create_pid_file(const char *pid_file_name, int pid)
 {
-  if (FILE *pid_file= my_fopen(pid_file_name,
-                               O_WRONLY | O_CREAT | O_BINARY, MYF(0)))
+  FILE *pid_file;
+
+  if (!(pid_file= my_fopen(pid_file_name, O_WRONLY | O_CREAT | O_BINARY,
+                           MYF(0))))
+  {
+    log_error("Error: can not create pid file '%s': %s (errno: %d)",
+              (const char *) pid_file_name,
+              (const char *) strerror(errno),
+              (int) errno);
+    return 1;
+  }
+
+  if (fprintf(pid_file, "%d\n", (int) pid) <= 0)
   {
-    fprintf(pid_file, "%d\n", (int) pid);
-    my_fclose(pid_file, MYF(0));
-    return 0;
+    log_error("Error: can not write to pid file '%s': %s (errno: %d)",
+              (const char *) pid_file_name,
+              (const char *) strerror(errno),
+              (int) errno);
+    return 1;
   }
-  log_error("can't create pid file %s: errno=%d, %s",
-            pid_file_name, errno, strerror(errno));
-  return 1;
+
+  my_fclose(pid_file, MYF(0));
+
+  return 0;
 }
 
 #ifndef __WIN__
@@ -82,14 +98,14 @@ bool have_signal;
 
 void onsignal(int signo)
 {
-  have_signal= true;
+  have_signal= TRUE;
 }
 
 void set_signals(sigset_t *set)
 {
   signal(SIGINT, onsignal);
   signal(SIGTERM, onsignal);
-  have_signal= false;
+  have_signal= FALSE;
 }
 
 int my_sigwait(const sigset_t *set, int *sig)
@@ -109,10 +125,16 @@ int my_sigwait(const sigset_t *set, int *sig)
   listener thread, write pid file and enter into signal handling.
   See also comments in mysqlmanager.cc to picture general Instance Manager
   architecture.
+
+  TODO: how about returning error status.
 */
 
-void manager(const Options &options)
+void manager()
 {
+  int err_code;
+  const char *err_msg;
+  bool shutdown_complete= FALSE;
+
   Thread_registry thread_registry;
   /*
     All objects created in the manager() function live as long as
@@ -121,31 +143,60 @@ void manager(const Options &options)
   */
 
   User_map user_map;
-  Instance_map instance_map(options.default_mysqld_path);
+  Instance_map instance_map(Options::Main::default_mysqld_path);
   Guardian_thread guardian_thread(thread_registry,
                                   &instance_map,
-                                  options.monitoring_interval);
+                                  Options::Main::monitoring_interval);
 
-  Listener_thread_args listener_args(thread_registry, options, user_map,
-                                     instance_map);
+  Listener_thread_args listener_args(thread_registry, user_map, instance_map);
 
   manager_pid= getpid();
   instance_map.guardian= &guardian_thread;
 
-  if (instance_map.init() || user_map.init())
+  /* Initialize instance map. */
+
+  if (instance_map.init())
+  {
+    log_error("Error: can not initialize instance list: out of memory.");
     return;
+  }
 
-  if (user_map.load(options.password_file_name))
+  /* Initialize user map and load password file. */
+
+  if (user_map.init())
+  {
+    log_error("Error: can not initialize user list: out of memory.");
     return;
+  }
+
+  if ((err_code= user_map.load(Options::Main::password_file_name, &err_msg)))
+  {
+    if (err_code == ERR_PASSWORD_FILE_DOES_NOT_EXIST &&
+        Options::Main::mysqld_safe_compatible)
+    {
+      /*
+        The password file does not exist, but we are running in
+        mysqld_safe-compatible mode. Continue, but complain in log.
+      */
+
+      log_error("Warning: password file does not exist, "
+                "nobody will be able to connect to Instance Manager.");
+    }
+    else
+    {
+      log_error("Error: %s.", (const char *) err_msg);
+      return;
+    }
+  }
 
   /* write Instance Manager pid file */
 
   log_info("IM pid file: '%s'; PID: %d.",
-           (const char *) options.pid_file_name,
+           (const char *) Options::Main::pid_file_name,
            (int) manager_pid);
 
-  if (create_pid_file(options.pid_file_name, manager_pid))
-    return;
+  if (create_pid_file(Options::Main::pid_file_name, manager_pid))
+    return; /* necessary logging has been already done. */
 
   sigset_t mask;
   set_signals(&mask);
@@ -198,17 +249,23 @@ void manager(const Options &options)
     To work nicely with LinuxThreads, the signal thread is the first thread
     in the process.
   */
-  int signo;
-  bool shutdown_complete;
-
-  shutdown_complete= FALSE;
 
-  if (instance_map.flush_instances())
   {
-    log_error("Cannot init instances repository. This might be caused by "
-               "the wrong config file options. For instance, missing mysqld "
-               "binary. Aborting.");
-    return;
+    instance_map.guardian->lock();
+    instance_map.lock();
+
+    int flush_instances_status= instance_map.flush_instances();
+
+    instance_map.unlock();
+    instance_map.guardian->unlock();
+
+    if (flush_instances_status)
+    {
+      log_error("Cannot init instances repository. This might be caused by "
+        "the wrong config file options. For instance, missing mysqld "
+        "binary. Aborting.");
+      return;
+    }
   }
 
   /*
@@ -219,6 +276,7 @@ void manager(const Options &options)
 
   while (!shutdown_complete)
   {
+    int signo;
     int status= 0;
 
     if ((status= my_sigwait(&mask, &signo)) != 0)
@@ -245,7 +303,7 @@ void manager(const Options &options)
     {
       if (!guardian_thread.is_stopped())
       {
-        bool stop_instances= true;
+        bool stop_instances= TRUE;
         guardian_thread.request_shutdown(stop_instances);
         pthread_cond_signal(&guardian_thread.COND_guardian);
       }
@@ -259,7 +317,7 @@ void manager(const Options &options)
 
 err:
   /* delete the pid file */
-  my_delete(options.pid_file_name, MYF(0));
+  my_delete(Options::Main::pid_file_name, MYF(0));
 
 #ifndef __WIN__
   /* free alarm structures */
@@ -267,4 +325,3 @@ void manager(const Options &options)
   /* don't pthread_exit to kill all threads who did not shut down in time */
 #endif
 }
-
diff --git a/server-tools/instance-manager/manager.h b/server-tools/instance-manager/manager.h
index 3ddf292132efad22f95b3ce02d01e538bfcb13a0..7aa4b3e1a962c0d3af71e9e75f1eccf273727567 100644
--- a/server-tools/instance-manager/manager.h
+++ b/server-tools/instance-manager/manager.h
@@ -16,9 +16,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-struct Options;
-
-void manager(const Options &options);
+void manager();
 
 int create_pid_file(const char *pid_file_name, int pid);
 
diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc
index a9b00b9e01f10ddac35adf0786440976c1678c7a..af35af1e7b0af156f5ad65b636a3994371c8f83a 100644
--- a/server-tools/instance-manager/messages.cc
+++ b/server-tools/instance-manager/messages.cc
@@ -14,15 +14,14 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-#include <my_global.h>
 #include "messages.h"
 
+#include <my_global.h>
+#include <mysql_com.h>
+
 #include "mysqld_error.h"
 #include "mysql_manager_error.h"
 
-#include <mysql_com.h>
-#include <assert.h>
-
 
 static const char *mysqld_error_message(unsigned sql_errno)
 {
@@ -70,6 +69,23 @@ static const char *mysqld_error_message(unsigned sql_errno)
            "in the instance options";
   case ER_ACCESS_OPTION_FILE:
     return "Cannot open the option file to edit. Check permissions";
+  case ER_DROP_ACTIVE_INSTANCE:
+    return "Cannot drop an active instance. You should stop it first";
+  case ER_CREATE_EXISTING_INSTANCE:
+    return "Instance already exists";
+  case ER_INSTANCE_MISCONFIGURED:
+    return "Instance is misconfigured. Cannot start it";
+  case ER_MALFORMED_INSTANCE_NAME:
+    return "Malformed instance name.";
+  case ER_INSTANCE_IS_ACTIVE:
+    return "The instance is active. Stop the instance first";
+  case ER_THERE_IS_ACTIVE_INSTACE:
+    return "At least one instance is active. Stop all instances first";
+  case ER_INCOMPATIBLE_OPTION:
+    return "Instance Manager-specific options are prohibited from being used "
+           "in the configuration of mysqld-compatible instances";
+  case ER_CONF_FILE_DOES_NOT_EXIST:
+    return "Configuration file does not exist";
   default:
     DBUG_ASSERT(0);
     return 0;
diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc
index dcd1807701fd9e71b157dbafd5f1b114a630bf26..17cda3af7043e508fb66aa98f87948a8761c6c20 100644
--- a/server-tools/instance-manager/mysql_connection.cc
+++ b/server-tools/instance-manager/mysql_connection.cc
@@ -20,22 +20,24 @@
 
 #include "mysql_connection.h"
 
-#include "priv.h"
-#include "mysql_manager_error.h"
-#include "mysqld_error.h"
-#include "thread_registry.h"
+#include <m_string.h>
+#include <m_string.h>
+#include <my_global.h>
+#include <mysql_com.h>
+#include <mysql.h>
+#include <my_sys.h>
+#include <violite.h>
+
+#include "command.h"
 #include "log.h"
-#include "user_map.h"
-#include "protocol.h"
 #include "messages.h"
-#include "command.h"
+#include "mysqld_error.h"
+#include "mysql_manager_error.h"
 #include "parse.h"
-
-#include <mysql.h>
-#include <violite.h>
-#include <mysql_com.h>
-#include <m_string.h>
-#include <my_sys.h>
+#include "priv.h"
+#include "protocol.h"
+#include "thread_registry.h"
+#include "user_map.h"
 
 
 Mysql_connection_thread_args::Mysql_connection_thread_args(
@@ -56,7 +58,7 @@ Mysql_connection_thread_args::Mysql_connection_thread_args(
   See also comments in mysqlmanager.cc to picture general Instance Manager
   architecture.
   We use conventional technique to work with classes without exceptions:
-  class acquires all vital resource in init(); Thus if init() succeed, 
+  class acquires all vital resource in init(); Thus if init() succeed,
   a user must call cleanup(). All other methods are valid only between
   init() and cleanup().
 */
@@ -190,8 +192,6 @@ void Mysql_connection_thread::run()
 int Mysql_connection_thread::check_connection()
 {
   ulong pkt_len=0;                              // to hold client reply length
-  /* maximum size of the version string */
-  enum { MAX_VERSION_LENGTH= 80 };
 
   /* buffer for the first packet */             /* packet contains: */
   char buff[MAX_VERSION_LENGTH + 1 +            // server version, 0-ended
@@ -202,8 +202,8 @@ int Mysql_connection_thread::check_connection()
   char *pos= buff;
   ulong server_flags;
 
-  memcpy(pos, mysqlmanager_version, mysqlmanager_version_length + 1);
-  pos+= mysqlmanager_version_length + 1;
+  memcpy(pos, mysqlmanager_version.str, mysqlmanager_version.length + 1);
+  pos+= mysqlmanager_version.length + 1;
 
   int4store((uchar*) pos, connection_id);
   pos+= 4;
@@ -271,12 +271,14 @@ int Mysql_connection_thread::check_connection()
   const char *user= pos;
   const char *password= strend(user)+1;
   ulong password_len= *password++;
+  LEX_STRING user_name= { (char *) user, password - user - 2 };
+
   if (password_len != SCRAMBLE_LENGTH)
   {
     net_send_error(&net, ER_ACCESS_DENIED_ERROR);
     return 1;
   }
-  if (user_map.authenticate(user, password-user-2, password, scramble))
+  if (user_map.authenticate(&user_name, password, scramble))
   {
     net_send_error(&net, ER_ACCESS_DENIED_ERROR);
     return 1;
@@ -312,7 +314,7 @@ int Mysql_connection_thread::do_command()
     packet= (char*) net.read_pos;
     enum enum_server_command command= (enum enum_server_command)
                                       (uchar) *packet;
-    log_info("connection %d: packet_length=%d, command=%d", 
+    log_info("connection %d: packet_length=%d, command=%d",
              connection_id, packet_length, command);
     return dispatch_command(command, packet + 1, packet_length - 1);
   }
@@ -336,7 +338,7 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command,
     if (Command *command= parse_command(&instance_map, packet))
     {
       int res= 0;
-      log_info("query for connection %d successefully parsed",connection_id);
+      log_info("query for connection %d successfully parsed",connection_id);
       res= command->execute(&net, connection_id);
       delete command;
       if (!res)
@@ -380,5 +382,5 @@ pthread_handler_t mysql_connection(void *arg)
 }
 
 /*
-  vim: fdm=marker 
+  vim: fdm=marker
 */
diff --git a/server-tools/instance-manager/mysql_manager_error.h b/server-tools/instance-manager/mysql_manager_error.h
index ff782923a8e04c37e71e6a1ba9fc0275eb950e5f..373c7d798a014c410de53b5ae213cc15aceb4dd3 100644
--- a/server-tools/instance-manager/mysql_manager_error.h
+++ b/server-tools/instance-manager/mysql_manager_error.h
@@ -29,5 +29,13 @@
 #define ER_ACCESS_OPTION_FILE       3008
 #define ER_OFFSET_ERROR             3009
 #define ER_READ_FILE                3010
+#define ER_DROP_ACTIVE_INSTANCE     3011
+#define ER_CREATE_EXISTING_INSTANCE 3012
+#define ER_INSTANCE_MISCONFIGURED   3013
+#define ER_MALFORMED_INSTANCE_NAME  3014
+#define ER_INSTANCE_IS_ACTIVE       3015
+#define ER_THERE_IS_ACTIVE_INSTACE  3016
+#define ER_INCOMPATIBLE_OPTION      3017
+#define ER_CONF_FILE_DOES_NOT_EXIST 3018
 
 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */
diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc
index ef714099de744b7bc7d6149eb8bc21fa38524d26..177b761b419cd8e9ff75beef41112ceeb4e9a070 100644
--- a/server-tools/instance-manager/mysqlmanager.cc
+++ b/server-tools/instance-manager/mysqlmanager.cc
@@ -15,25 +15,30 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <my_global.h>
-#include "manager.h"
-
-#include "options.h"
-#include "log.h"
-
 #include <my_sys.h>
+
 #include <string.h>
 #include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #ifndef __WIN__
 #include <pwd.h>
 #include <grp.h>
 #include <sys/wait.h>
 #endif
-#include <sys/types.h>
-#include <sys/stat.h>
+
+#include "log.h"
+#include "manager.h"
+#include "options.h"
+#include "user_management_commands.h"
+
 #ifdef __WIN__
-#include "windowsservice.h"
+#include "IMService.h"
+#include "WindowsService.h"
 #endif
 
+
 /*
   Few notes about Instance Manager architecture:
   Instance Manager consisits of two processes: the angel process, and the
@@ -59,13 +64,12 @@
 */
 
 static void init_environment(char *progname);
+
 #ifndef __WIN__
 static void daemonize(const char *log_file_name);
-static void angel(const Options &options);
+static void angel();
 static struct passwd *check_user(const char *user);
 static int set_user(const char *user, struct passwd *user_info);
-#else
-int HandleServiceOptions(Options options);
 #endif
 
 
@@ -81,41 +85,61 @@ int main(int argc, char *argv[])
 {
   int return_value= 1;
   init_environment(argv[0]);
-  Options options;
 
-  if (options.load(argc, argv))
-    goto err;
+  if ((return_value= Options::load(argc, argv)))
+    goto main_end;
+
+  if (Options::User_management::cmd)
+  {
+    return_value= Options::User_management::cmd->execute();
+
+    goto main_end;
+  }
 
 #ifndef __WIN__
+
   struct passwd *user_info;
 
-  if ((user_info= check_user(options.user)))
+  if ((user_info= check_user(Options::Daemon::user)))
   {
-      if (set_user(options.user, user_info))
-        goto err;
+      if (set_user(Options::Daemon::user, user_info))
+      {
+        return_value= 1;
+        goto main_end;
+      }
   }
 
-  if (options.run_as_service)
+  if (Options::Daemon::run_as_service)
   {
     /* forks, and returns only in child */
-    daemonize(options.log_file_name);
+    daemonize(Options::Daemon::log_file_name);
     /* forks again, and returns only in child: parent becomes angel */
-    angel(options);
+    angel();
   }
+
+  manager();
+
 #else
-  if (!options.stand_alone)
+
+  if (!Options::Service::stand_alone)
   {
-    if (HandleServiceOptions(options))
-      goto err;
+    if (HandleServiceOptions())
+    {
+      return_value= 1;
+      goto main_end;
+    }
   }
   else
+  {
+    manager();
+  }
+
 #endif
 
-  manager(options);
   return_value= 0;
 
-err:
-  options.cleanup();
+main_end:
+  Options::cleanup();
   my_end(0);
   return return_value;
 }
@@ -200,7 +224,7 @@ static void init_environment(char *progname)
   MY_INIT(progname);
   log_init();
   umask(0117);
-  srand(time(0));
+  srand((unsigned int) time(0));
 }
 
 
@@ -298,7 +322,7 @@ void terminate(int signo)
   Angel process will exit silently if mysqlmanager exits normally.
 */
 
-static void angel(const Options &options)
+static void angel()
 {
   /* install signal handlers */
   sigset_t zeromask;                            // to sigsuspend in parent
@@ -341,10 +365,10 @@ static void angel(const Options &options)
     pid= getpid(); /* Get our pid. */
 
     log_info("Angel pid file: '%s'; PID: %d.",
-             (const char *) options.angel_pid_file_name,
+             (const char *) Options::Daemon::angel_pid_file_name,
              (int) pid);
 
-    create_pid_file(Options::angel_pid_file_name, pid);
+    create_pid_file(Options::Daemon::angel_pid_file_name, pid);
 
     while (child_status == CHILD_OK && is_terminated == 0)
       sigsuspend(&zeromask);
diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc
index 8de592f59b6b35b6b703f37c4dca8345737a93b5..31ce5b001901f5ea5cac76a42809ad93a67b4994 100644
--- a/server-tools/instance-manager/options.cc
+++ b/server-tools/instance-manager/options.cc
@@ -20,46 +20,89 @@
 
 #include "options.h"
 
-#include "priv.h"
-#include "portability.h"
+#include <my_global.h>
 #include <my_sys.h>
 #include <my_getopt.h>
-#include <m_string.h>
 #include <mysql_com.h>
 
+#include "exit_codes.h"
+#include "log.h"
+#include "portability.h"
+#include "priv.h"
+#include "user_management_commands.h"
+
 #define QUOTE2(x) #x
 #define QUOTE(x) QUOTE2(x)
 
 #ifdef __WIN__
-char Options::install_as_service;
-char Options::remove_service;
-char Options::stand_alone;
-char windows_config_file[FN_REFLEN];
-char default_password_file_name[FN_REFLEN];
-char default_log_file_name[FN_REFLEN];
-const char *Options::config_file= windows_config_file;
-#else
-char Options::run_as_service;
-const char *Options::user= 0;                   /* No default value */
-const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
-const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
-const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE);
-const char *Options::angel_pid_file_name= NULL;
+
+/* Define holders for default values. */
+
+static char win_dflt_config_file_name[FN_REFLEN];
+static char win_dflt_password_file_name[FN_REFLEN];
+static char win_dflt_pid_file_name[FN_REFLEN];
+static char win_dflt_socket_file_name[FN_REFLEN];
+
+static char win_dflt_mysqld_path[FN_REFLEN];
+
+/* Define and initialize Windows-specific options. */
+
+my_bool Options::Service::install_as_service;
+my_bool Options::Service::remove_service;
+my_bool Options::Service::stand_alone;
+
+const char *Options::Main::config_file= win_dflt_config_file_name;
+const char *Options::Main::password_file_name= win_dflt_password_file_name;
+const char *Options::Main::pid_file_name= win_dflt_pid_file_name;
+const char *Options::Main::socket_file_name= win_dflt_socket_file_name;
+
+const char *Options::Main::default_mysqld_path= win_dflt_mysqld_path;
+
+static int setup_windows_defaults();
+
+#else /* UNIX */
+
+/* Define and initialize UNIX-specific options. */
+
+my_bool Options::Daemon::run_as_service= FALSE;
+const char *Options::Daemon::log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
+const char *Options::Daemon::user= NULL; /* No default value */
+const char *Options::Daemon::angel_pid_file_name= NULL;
+
+const char *Options::Main::config_file= QUOTE(DEFAULT_CONFIG_FILE);
+const char *
+Options::Main::password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
+const char *Options::Main::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
+const char *Options::Main::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
+
+const char *Options::Main::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
+
 #endif
-const char *Options::log_file_name= default_log_file_name;
-const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
-const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
-const char *Options::password_file_name= default_password_file_name;
-const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
-const char *Options::bind_address= 0;           /* No default value */
-uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
-uint Options::port_number= DEFAULT_PORT;
-/* just to declare */
+
+/* Remember if the config file was forced. */
+
+bool Options::Main::is_forced_default_file= FALSE;
+
+/* Define and initialize common options. */
+
+const char *Options::Main::bind_address= NULL; /* No default value */
+uint Options::Main::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
+uint Options::Main::port_number= DEFAULT_PORT;
+my_bool Options::Main::mysqld_safe_compatible= FALSE;
+
+/* Options::User_management */
+
+char *Options::User_management::user_name= NULL;
+char *Options::User_management::password= NULL;
+
+User_management_cmd *Options::User_management::cmd= NULL;
+
+/* Private members. */
+
 char **Options::saved_argv= NULL;
-/* Remember if the config file was forced */
-bool Options::is_forced_default_file= 0;
+
 #ifndef DBUG_OFF
-const char *Options::default_dbug_option= "d:t:i:O,im.trace";
+const char *Options::Debug::config_str= "d:t:i:O,im.trace";
 #endif
 
 static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid";
@@ -71,24 +114,34 @@ static const int ANGEL_PID_FILE_SUFFIX_LEN= strlen(ANGEL_PID_FILE_SUFFIX);
 */
 
 enum options {
+  OPT_PASSWD= 'P',
+  OPT_USERNAME= 'u',
+  OPT_PASSWORD= 'p',
   OPT_LOG= 256,
   OPT_PID_FILE,
   OPT_SOCKET,
   OPT_PASSWORD_FILE,
   OPT_MYSQLD_PATH,
-#ifndef __WIN__
-  OPT_RUN_AS_SERVICE,
-  OPT_USER,
-  OPT_ANGEL_PID_FILE,
-#else
+#ifdef __WIN__
   OPT_INSTALL_SERVICE,
   OPT_REMOVE_SERVICE,
   OPT_STAND_ALONE,
+#else
+  OPT_RUN_AS_SERVICE,
+  OPT_USER,
+  OPT_ANGEL_PID_FILE,
 #endif
   OPT_MONITORING_INTERVAL,
   OPT_PORT,
   OPT_WAIT_TIMEOUT,
-  OPT_BIND_ADDRESS
+  OPT_BIND_ADDRESS,
+  OPT_ADD_USER,
+  OPT_DROP_USER,
+  OPT_EDIT_USER,
+  OPT_CLEAN_PASSWORD_FILE,
+  OPT_CHECK_PASSWORD_FILE,
+  OPT_LIST_USERS,
+  OPT_MYSQLD_SAFE_COMPATIBLE
 };
 
 static struct my_option my_long_options[] =
@@ -96,101 +149,158 @@ static struct my_option my_long_options[] =
   { "help", '?', "Display this help and exit.",
    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
 
+  { "add-user", OPT_ADD_USER,
+    "Add a user to the password file",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
 #ifndef __WIN__
   { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.",
-    (gptr *) &Options::angel_pid_file_name,
-    (gptr *) &Options::angel_pid_file_name,
+    (gptr *) &Options::Daemon::angel_pid_file_name,
+    (gptr *) &Options::Daemon::angel_pid_file_name,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 #endif
 
   { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
-    (gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
+    (gptr *) &Options::Main::bind_address,
+    (gptr *) &Options::Main::bind_address,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 
+  { "check-password-file", OPT_CHECK_PASSWORD_FILE,
+    "Check the password file for consistency",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+  { "clean-password-file", OPT_CLEAN_PASSWORD_FILE,
+    "Clean the password file",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
 #ifndef DBUG_OFF
   {"debug", '#', "Debug log.",
-   (gptr*) &Options::default_dbug_option, (gptr*) &Options::default_dbug_option,
+   (gptr *) &Options::Debug::config_str,
+   (gptr *) &Options::Debug::config_str,
    0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 #endif
 
   { "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL"
     " Server binary.",
-    (gptr *) &Options::default_mysqld_path,
-    (gptr *) &Options::default_mysqld_path,
+    (gptr *) &Options::Main::default_mysqld_path,
+    (gptr *) &Options::Main::default_mysqld_path,
     0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 },
+
+  { "drop-user", OPT_DROP_USER,
+    "Drop existing user from the password file",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+  { "edit-user", OPT_EDIT_USER,
+    "Edit existing user in the password file",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
 #ifdef __WIN__
   { "install", OPT_INSTALL_SERVICE, "Install as system service.",
-    (gptr *) &Options::install_as_service, (gptr*) &Options::install_as_service,
+    (gptr *) &Options::Service::install_as_service,
+    (gptr *) &Options::Service::install_as_service,
     0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
 #endif
 
+  { "list-users", OPT_LIST_USERS,
+    "Print out a list of registered users",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+#ifndef __WIN__
   { "log", OPT_LOG, "Path to log file. Used only with --run-as-service.",
-    (gptr *) &Options::log_file_name, (gptr *) &Options::log_file_name,
+    (gptr *) &Options::Daemon::log_file_name,
+    (gptr *) &Options::Daemon::log_file_name,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+#endif
 
   { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor"
     " instances in seconds.",
-    (gptr *) &Options::monitoring_interval,
-    (gptr *) &Options::monitoring_interval,
+    (gptr *) &Options::Main::monitoring_interval,
+    (gptr *) &Options::Main::monitoring_interval,
     0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL,
     0, 0, 0, 0, 0 },
 
-  { "passwd", 'P', "Prepare entry for passwd file and exit.", 0, 0, 0,
-    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+  { "mysqld-safe-compatible", OPT_MYSQLD_SAFE_COMPATIBLE,
+    "Start Instance Manager in mysqld_safe compatible manner",
+    (gptr *) &Options::Main::mysqld_safe_compatible,
+    (gptr *) &Options::Main::mysqld_safe_compatible,
+    0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
+
+  { "passwd", OPT_PASSWD,
+    "Prepare an entry for the password file and exit.",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
+
+  { "password", OPT_PASSWORD, "Password to update the password file",
+    (gptr *) &Options::User_management::password,
+    (gptr *) &Options::User_management::password,
+    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 
-  { "password-file", OPT_PASSWORD_FILE, "Look for Instance Manager users"
-                                        " and passwords here.",
-    (gptr *) &Options::password_file_name,
-    (gptr *) &Options::password_file_name,
+  { "password-file", OPT_PASSWORD_FILE,
+    "Look for Instance Manager users and passwords here.",
+    (gptr *) &Options::Main::password_file_name,
+    (gptr *) &Options::Main::password_file_name,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 
   { "pid-file", OPT_PID_FILE, "Pid file to use.",
-    (gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name,
+    (gptr *) &Options::Main::pid_file_name,
+    (gptr *) &Options::Main::pid_file_name,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 
   { "port", OPT_PORT, "Port number to use for connections",
-    (gptr *) &Options::port_number, (gptr *) &Options::port_number,
+    (gptr *) &Options::Main::port_number,
+    (gptr *) &Options::Main::port_number,
     0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 },
 
 #ifdef __WIN__
   { "remove", OPT_REMOVE_SERVICE, "Remove system service.",
-    (gptr *)&Options::remove_service, (gptr*) &Options::remove_service,
+    (gptr *) &Options::Service::remove_service,
+    (gptr *) &Options::Service::remove_service,
     0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
 #else
   { "run-as-service", OPT_RUN_AS_SERVICE,
-    "Daemonize and start angel process.", (gptr *) &Options::run_as_service,
+    "Daemonize and start angel process.",
+    (gptr *) &Options::Daemon::run_as_service,
     0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
 #endif
 
   { "socket", OPT_SOCKET, "Socket file to use for connection.",
-    (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
+    (gptr *) &Options::Main::socket_file_name,
+    (gptr *) &Options::Main::socket_file_name,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 
 #ifdef __WIN__
   { "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.",
-    (gptr *)&Options::stand_alone, (gptr*) &Options::stand_alone,
+    (gptr *) &Options::Service::stand_alone,
+    (gptr *) &Options::Service::stand_alone,
     0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
 #else
   { "user", OPT_USER, "Username to start mysqlmanager",
-    (gptr *) &Options::user,
-    (gptr *) &Options::user,
+    (gptr *) &Options::Daemon::user,
+    (gptr *) &Options::Daemon::user,
     0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
 #endif
 
+  { "username", OPT_USERNAME,
+    "Username to update the password file",
+    (gptr *) &Options::User_management::user_name,
+    (gptr *) &Options::User_management::user_name,
+    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+
   { "version", 'V', "Output version information and exit.", 0, 0, 0,
     GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
 
   { "wait-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits "
     "for activity on a connection before closing it.",
-    (gptr *) &net_read_timeout, (gptr *) &net_read_timeout, 0, GET_ULONG,
-    REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },
+    (gptr *) &net_read_timeout,
+    (gptr *) &net_read_timeout,
+    0, GET_ULONG, REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },
 
   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
 };
 
 static void version()
 {
-  printf("%s Ver %s for %s on %s\n", my_progname, mysqlmanager_version,
+  printf("%s Ver %s for %s on %s\n", my_progname,
+         (const char *) mysqlmanager_version.str,
          SYSTEM_TYPE, MACHINE_TYPE);
 }
 
@@ -218,37 +328,6 @@ static void usage()
 }
 
 
-static void passwd()
-{
-  char user[1024], *p;
-  const char *pw1, *pw2;
-  char pw1msg[]= "Enter password: ";
-  char pw2msg[]= "Re-type password: ";
-  char crypted_pw[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
-
-  fprintf(stderr, "Creating record for new user.\n");
-  fprintf(stderr, "Enter user name: ");
-  if (!fgets(user, sizeof(user), stdin))
-  {
-    fprintf(stderr, "Unable to read user.\n");
-    return;
-  }
-  if ((p= strchr(user, '\n'))) *p= 0;
-
-  pw1= get_tty_password(pw1msg);
-  pw2= get_tty_password(pw2msg);
-
-  if (strcmp(pw1, pw2))
-  {
-    fprintf(stderr, "Sorry, passwords do not match.\n");
-    return;
-  }
-
-  make_scrambled_password(crypted_pw, pw1);
-  printf("%s:%s\n", user, crypted_pw);
-}
-
-
 C_MODE_START
 
 static my_bool
@@ -260,16 +339,52 @@ get_one_option(int optid,
   case 'V':
     version();
     exit(0);
-  case 'P':
-    passwd();
-    exit(0);
+  case OPT_PASSWD:
+  case OPT_ADD_USER:
+  case OPT_DROP_USER:
+  case OPT_EDIT_USER:
+  case OPT_CLEAN_PASSWORD_FILE:
+  case OPT_CHECK_PASSWORD_FILE:
+  case OPT_LIST_USERS:
+    if (Options::User_management::cmd)
+    {
+      fprintf(stderr, "Error: only one password-management command "
+              "can be specified at a time.\n");
+      exit(ERR_INVALID_USAGE);
+    }
+
+    switch (optid) {
+    case OPT_PASSWD:
+      Options::User_management::cmd= new Passwd_cmd();
+      break;
+    case OPT_ADD_USER:
+      Options::User_management::cmd= new Add_user_cmd();
+      break;
+    case OPT_DROP_USER:
+      Options::User_management::cmd= new Drop_user_cmd();
+      break;
+    case OPT_EDIT_USER:
+      Options::User_management::cmd= new Edit_user_cmd();
+      break;
+    case OPT_CLEAN_PASSWORD_FILE:
+      Options::User_management::cmd= new Clean_db_cmd();
+      break;
+    case OPT_CHECK_PASSWORD_FILE:
+      Options::User_management::cmd= new Check_db_cmd();
+      break;
+    case OPT_LIST_USERS:
+      Options::User_management::cmd= new List_users_cmd();
+      break;
+    }
+
+    break;
   case '?':
     usage();
     exit(0);
   case '#':
 #ifndef DBUG_OFF
-    DBUG_SET(argument ? argument : Options::default_dbug_option);
-    DBUG_SET_INITIAL(argument ? argument : Options::default_dbug_option);
+    DBUG_SET(argument ? argument : Options::Debug::config_str);
+    DBUG_SET_INITIAL(argument ? argument : Options::Debug::config_str);
 #endif
     break;
   }
@@ -295,8 +410,8 @@ int Options::load(int argc, char **argv)
   {
     if (is_prefix(argv[1], "--defaults-file="))
     {
-      Options::config_file= strchr(argv[1], '=') + 1;
-      Options::is_forced_default_file= 1;
+      Main::config_file= strchr(argv[1], '=') + 1;
+      Main::is_forced_default_file= TRUE;
     }
     if (is_prefix(argv[1], "--defaults-extra-file=") ||
         is_prefix(argv[1], "--no-defaults"))
@@ -305,29 +420,44 @@ int Options::load(int argc, char **argv)
       fprintf(stderr, "The --defaults-extra-file and --no-defaults options"
               " are not supported by\n"
               "Instance Manager. Program aborted.\n");
-      goto err;
+      return ERR_INVALID_USAGE;
     }
   }
 
 #ifdef __WIN__
   if (setup_windows_defaults())
-    goto err;
+  {
+    fprintf(stderr, "Internal error: could not setup default values.\n");
+    return ERR_OUT_OF_MEMORY;
+  }
 #endif
+
   /* load_defaults will reset saved_argv with a new allocated list */
   saved_argv= argv;
 
   /* config-file options are prepended to command-line ones */
-  load_defaults(config_file, default_groups, &argc,
-                &saved_argv);
 
-  if ((handle_options(&argc, &saved_argv, my_long_options,
-                      get_one_option)) != 0)
-    goto err;
+  log_info("Loading config file '%s'...",
+           (const char *) Main::config_file);
+
+  load_defaults(Main::config_file, default_groups, &argc, &saved_argv);
+
+  if ((handle_options(&argc, &saved_argv, my_long_options, get_one_option)))
+    return ERR_INVALID_USAGE;
+
+  if (!User_management::cmd &&
+      (User_management::user_name || User_management::password))
+  {
+    fprintf(stderr,
+            "--username and/or --password options have been specified, "
+            "but no password-management command has been given.\n");
+    return ERR_INVALID_USAGE;
+  }
 
 #ifndef __WIN__
-  if (Options::run_as_service)
+  if (Options::Daemon::run_as_service)
   {
-    if (Options::angel_pid_file_name == NULL)
+    if (Options::Daemon::angel_pid_file_name == NULL)
     {
       /*
         Calculate angel pid file on the IM pid file basis: replace the
@@ -339,10 +469,11 @@ int Options::load(int argc, char **argv)
       char *base_name_ptr;
       char *ext_ptr;
 
-      angel_pid_file_name= (char *) malloc(strlen(Options::pid_file_name) +
-                                           ANGEL_PID_FILE_SUFFIX_LEN);
+      angel_pid_file_name=
+        (char *) malloc(strlen(Options::Main::pid_file_name) +
+                        ANGEL_PID_FILE_SUFFIX_LEN);
 
-      strcpy(angel_pid_file_name, Options::pid_file_name);
+      strcpy(angel_pid_file_name, Options::Main::pid_file_name);
 
       base_name_ptr= strrchr(angel_pid_file_name, '/');
 
@@ -355,54 +486,73 @@ int Options::load(int argc, char **argv)
 
       strcat(angel_pid_file_name, ANGEL_PID_FILE_SUFFIX);
 
-      Options::angel_pid_file_name= angel_pid_file_name;
+      Options::Daemon::angel_pid_file_name= angel_pid_file_name;
     }
     else
     {
-      Options::angel_pid_file_name= strdup(Options::angel_pid_file_name);
+      Options::Daemon::angel_pid_file_name=
+        strdup(Options::Daemon::angel_pid_file_name);
     }
   }
 #endif
 
   return 0;
-
-err:
-  return 1;
 }
 
 void Options::cleanup()
 {
-  /* free_defaults returns nothing */
-  if (Options::saved_argv != NULL)
-    free_defaults(Options::saved_argv);
+  if (saved_argv)
+    free_defaults(saved_argv);
+
+  delete User_management::cmd;
 
 #ifndef __WIN__
-  if (Options::run_as_service)
-    free((void *) Options::angel_pid_file_name);
+  if (Options::Daemon::run_as_service)
+    free((void *) Options::Daemon::angel_pid_file_name);
 #endif
 }
 
 #ifdef __WIN__
 
-int Options::setup_windows_defaults()
+static int setup_windows_defaults()
 {
-  if (!GetModuleFileName(NULL, default_password_file_name,
-                         sizeof(default_password_file_name)))
-    return 1;
-  char *filename= strstr(default_password_file_name, ".exe");
-  strcpy(filename, ".passwd");
- 
-  if (!GetModuleFileName(NULL, default_log_file_name,
-                         sizeof(default_log_file_name)))
+  char module_full_name[FN_REFLEN];
+  char dir_name[FN_REFLEN];
+  char base_name[FN_REFLEN];
+  char im_name[FN_REFLEN];
+  char *base_name_ptr;
+  char *ptr;
+
+  /* Determine dirname and basename. */
+
+  if (!GetModuleFileName(NULL, module_full_name, sizeof (module_full_name)) ||
+      !GetFullPathName(module_full_name, sizeof (dir_name), dir_name,
+                       &base_name_ptr))
+  {
     return 1;
-  filename= strstr(default_log_file_name, ".exe");
-  strcpy(filename, ".log");
+  }
+
+  strmake(base_name, base_name_ptr, FN_REFLEN);
+  *base_name_ptr= 0;
+
+  strmake(im_name, base_name, FN_REFLEN);
+  ptr= strrchr(im_name, '.');
+
+  if (!ptr)
+     return 1;
+
+  *ptr= 0;
+
+  /* Initialize the defaults. */
+
+  strxmov(win_dflt_config_file_name, dir_name, DFLT_CONFIG_FILE_NAME, NullS);
+  strxmov(win_dflt_mysqld_path, dir_name, DFLT_MYSQLD_PATH, NullS);
+  strxmov(win_dflt_password_file_name, dir_name, im_name, DFLT_PASSWD_FILE_EXT,
+          NullS);
+  strxmov(win_dflt_pid_file_name, dir_name, im_name, DFLT_PID_FILE_EXT, NullS);
+  strxmov(win_dflt_socket_file_name, dir_name, im_name, DFLT_SOCKET_FILE_EXT,
+          NullS);
 
-  if (!GetModuleFileName(NULL, windows_config_file,
-                         sizeof(windows_config_file)))
-    return 1;
-  char *slash= strrchr(windows_config_file, '\\');
-  strcpy(slash, "\\my.ini");
   return 0;
 }
 
diff --git a/server-tools/instance-manager/options.h b/server-tools/instance-manager/options.h
index 00a50a2acdb95a3db80a6edd0484a49381bb246c..5c54ff201b293774e94fe8ba579a6b649ef4c982 100644
--- a/server-tools/instance-manager/options.h
+++ b/server-tools/instance-manager/options.h
@@ -17,50 +17,87 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 /*
-  Options - all possible options for the instance manager grouped in one
-  struct.
+  Options - all possible command-line options for the Instance Manager grouped
+  in one struct.
 */
+
 #include <my_global.h>
 
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
 #endif
 
+class User_management_cmd;
+
 struct Options
 {
-#ifdef __WIN__
-  static char install_as_service;
-  static char remove_service;
-  static char stand_alone;
-#else
-  static char run_as_service;        /* handle_options doesn't support bool */
-  static const char *user;
-  static const char *angel_pid_file_name;
-#endif
-  static bool is_forced_default_file;
-  static const char *log_file_name;
-  static const char *pid_file_name;
-  static const char *socket_file_name;
-  static const char *password_file_name;
-  static const char *default_mysqld_path;
-  /* the option which should be passed to process_default_option_files */
-  static uint monitoring_interval;
-  static uint port_number;
-  static const char *bind_address;
-  static const char *config_file;
+  /*
+    NOTE: handle_options() expects value of my_bool type for GET_BOOL
+    accessor (i.e. bool must not be used).
+  */
 
-  /* argv pointer returned by load_defaults() to be used by free_defaults() */
-  static char **saved_argv;
+  struct User_management
+  {
+    static User_management_cmd *cmd;
+
+    static char *user_name;
+    static char *password;
+  };
+
+  struct Main
+  {
+    /* this is not an option parsed by handle_options(). */
+    static bool is_forced_default_file;
+
+    static const char *pid_file_name;
+    static const char *socket_file_name;
+    static const char *password_file_name;
+    static const char *default_mysqld_path;
+    static uint monitoring_interval;
+    static uint port_number;
+    static const char *bind_address;
+    static const char *config_file;
+    static my_bool mysqld_safe_compatible;
+  };
 
 #ifndef DBUG_OFF
-  static const char *default_dbug_option;
+  struct Debug
+  {
+    static const char *config_str;
+  };
 #endif
 
-  int load(int argc, char **argv);
-  void cleanup();
-#ifdef __WIN__
-  int setup_windows_defaults();
+#ifndef __WIN__
+
+  struct Daemon
+  {
+    static my_bool run_as_service;
+    static const char *log_file_name;
+    static const char *user;
+    static const char *angel_pid_file_name;
+  };
+
+#else
+
+  struct Service
+  {
+    static my_bool install_as_service;
+    static my_bool remove_service;
+    static my_bool stand_alone;
+  };
+
 #endif
+
+public:
+  static int load(int argc, char **argv);
+  static void cleanup();
+
+private:
+  Options(); /* Deny instantiation of this class. */
+
+private:
+  /* argv pointer returned by load_defaults() to be used by free_defaults() */
+  static char **saved_argv;
 };
 
 #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_OPTIONS_H
diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc
index 14b3db16b45b1d252b8312c0bd98d17b7f5f339c..4e931488fcecc5160c3049033654c587abbf0d20 100644
--- a/server-tools/instance-manager/parse.cc
+++ b/server-tools/instance-manager/parse.cc
@@ -17,12 +17,12 @@
 #include "parse.h"
 #include "commands.h"
 
-#include <string.h>
-
 
 enum Token
 {
-  TOK_ERROR= 0, /* Encodes the "ERROR" word, it doesn't indicate error. */
+  TOK_CREATE= 0,
+  TOK_DROP,
+  TOK_ERROR, /* Encodes the "ERROR" word, it doesn't indicate error. */
   TOK_FILES,
   TOK_FLUSH,
   TOK_GENERAL,
@@ -50,6 +50,8 @@ struct tokens_st
 
 
 static struct tokens_st tokens[]= {
+  {6, "CREATE"},
+  {4, "DROP"},
   {5, "ERROR"},
   {5, "FILES"},
   {5, "FLUSH"},
@@ -67,6 +69,37 @@ static struct tokens_st tokens[]= {
   {5, "UNSET"}
 };
 
+/************************************************************************/
+
+Named_value_arr::Named_value_arr() :
+  initialized(FALSE)
+{
+}
+
+
+bool Named_value_arr::init()
+{
+  if (my_init_dynamic_array(&arr, sizeof(Named_value), 0, 32))
+    return TRUE;
+
+  initialized= TRUE;
+
+  return FALSE;
+}
+
+
+Named_value_arr::~Named_value_arr()
+{
+  if (!initialized)
+    return;
+
+  for (int i= 0; i < get_size(); ++i)
+    get_element(i).free();
+
+  delete_dynamic(&arr);
+}
+
+/************************************************************************/
 
 /*
   Returns token no if word corresponds to some token, otherwise returns
@@ -104,53 +137,200 @@ Token shift_token(const char **text, uint *word_len)
 }
 
 
-int get_text_id(const char **text, uint *word_len, const char **id)
+int get_text_id(const char **text, LEX_STRING *token)
 {
-  get_word(text, word_len);
-  if (*word_len == 0)
+  get_word(text, &token->length);
+  if (token->length == 0)
     return 1;
-  *id= *text;
+  token->str= (char *) *text;
   return 0;
 }
 
 
+static bool parse_long(const LEX_STRING *token, long *value)
+{
+  int err_code;
+  char *end_ptr= token->str + token->length;
+
+  *value= my_strtoll10(token->str, &end_ptr, &err_code);
+
+  return err_code != 0;
+}
+
+
+bool parse_option_value(const char *text, uint *text_len, char **value)
+{
+  char beginning_quote;
+  const char *text_start_ptr;
+  char *v;
+  bool escape_mode= FALSE;
+
+  if (!*text || (*text != '\'' && *text != '"'))
+    return TRUE; /* syntax error: string expected. */
+
+  beginning_quote= *text;
+
+  ++text; /* skip the beginning quote. */
+
+  text_start_ptr= text;
+
+  if (!(v= Named_value::alloc_str(text)))
+    return TRUE;
+
+  *value= v;
+
+  while (TRUE)
+  {
+    if (!*text)
+    {
+      Named_value::free_str(value);
+      return TRUE; /* syntax error: missing terminating ' character. */
+    }
+
+    if (*text == '\n' || *text == '\r')
+    {
+      Named_value::free_str(value);
+      return TRUE; /* syntax error: option value should be a single line. */
+    }
+
+    if (!escape_mode && *text == beginning_quote)
+      break;
+
+    if (escape_mode)
+    {
+      switch (*text)
+      {
+        case 'b': /* \b -- backspace */
+          if (v > *value)
+            --v;
+          break;
+
+        case 't': /* \t -- tab */
+          *v= '\t';
+          ++v;
+          break;
+
+        case 'n': /* \n -- newline */
+          *v= '\n';
+          ++v;
+          break;
+
+        case 'r': /* \r -- carriage return */
+          *v= '\r';
+          ++v;
+          break;
+
+        case '\\': /* \\ -- back slash */
+          *v= '\\';
+          ++v;
+          break;
+
+        case 's': /* \s -- space */
+          *v= ' ';
+          ++v;
+          break;
+
+        default: /* Unknown escape sequence. Treat as error. */
+          Named_value::free_str(value);
+          return TRUE;
+      }
+
+      escape_mode= FALSE;
+    }
+    else
+    {
+      if (*text == '\\')
+      {
+        escape_mode= TRUE;
+      }
+      else
+      {
+        *v= *text;
+        ++v;
+      }
+    }
+
+    ++text;
+  }
+
+  *v= 0;
+
+  /* "2" below stands for beginning and ending quotes. */
+  *text_len= text - text_start_ptr + 2;
+
+  return FALSE;
+}
+
+
+void skip_spaces(const char **text)
+{
+  while (**text && my_isspace(default_charset_info, **text))
+    ++(*text);
+}
+
+
 Command *parse_command(Instance_map *map, const char *text)
 {
   uint word_len;
-  const char *instance_name;
-  uint instance_name_len;
-  const char *option;
-  uint option_len;
-  const char *option_value;
-  uint option_value_len;
-  const char *log_size;
+  LEX_STRING instance_name;
   Command *command;
   const char *saved_text= text;
-  bool skip= false;
-  const char *tmp;
 
   Token tok1= shift_token(&text, &word_len);
 
   switch (tok1) {
   case TOK_START:                               // fallthrough
   case TOK_STOP:
+  case TOK_CREATE:
+  case TOK_DROP:
     if (shift_token(&text, &word_len) != TOK_INSTANCE)
       goto syntax_error;
     get_word(&text, &word_len);
     if (word_len == 0)
       goto syntax_error;
-    instance_name= text;
-    instance_name_len= word_len;
+    instance_name.str= (char *) text;
+    instance_name.length= word_len;
     text+= word_len;
-    /* it should be the end of command */
-    get_word(&text, &word_len, NONSPACE);
-    if (word_len)
-      goto syntax_error;
 
-    if (tok1 == TOK_START)
-      command= new Start_instance(map, instance_name, instance_name_len);
+    if (tok1 == TOK_CREATE)
+    {
+      Create_instance *cmd= new Create_instance(map, &instance_name);
+
+      if (!cmd)
+        return NULL; /* Report ER_OUT_OF_RESOURCES. */
+
+      if (cmd->init(&text))
+      {
+        delete cmd;
+        goto syntax_error;
+      }
+
+      command= cmd;
+    }
     else
-      command= new Stop_instance(map, instance_name, instance_name_len);
+    {
+      /* it should be the end of command */
+      get_word(&text, &word_len, NONSPACE);
+      if (word_len)
+        goto syntax_error;
+    }
+
+    switch (tok1) {
+    case TOK_START:
+      command= new Start_instance(map, &instance_name);
+      break;
+    case TOK_STOP:
+      command= new Stop_instance(map, &instance_name);
+      break;
+    case TOK_CREATE:
+      ; /* command already initialized. */
+      break;
+    case TOK_DROP:
+      command= new Drop_instance(map, &instance_name);
+      break;
+    default: /* this is impossible, but nevertheless... */
+      DBUG_ASSERT(0);
+    }
     break;
   case TOK_FLUSH:
     if (shift_token(&text, &word_len) != TOK_INSTANCES)
@@ -163,53 +343,28 @@ Command *parse_command(Instance_map *map, const char *text)
     command= new Flush_instances(map);
     break;
   case TOK_UNSET:
-    skip= true;
   case TOK_SET:
+    {
+      Abstract_option_cmd *cmd;
 
-    if (get_text_id(&text, &instance_name_len, &instance_name))
-      goto syntax_error;
-    text+= instance_name_len;
-
-   /* the next token should be a dot */
-    get_word(&text, &word_len);
-    if (*text != '.')
-      goto syntax_error;
-    text++;
+      if (tok1 == TOK_SET)
+        cmd= new Set_option(map);
+      else
+        cmd= new Unset_option(map);
 
-    get_word(&text, &option_len, NONSPACE);
-    option= text;
-    if ((tmp= strchr(text, '=')) != NULL)
-      option_len= tmp - text;
-    text+= option_len;
+      if (!cmd)
+        return NULL; /* Report ER_OUT_OF_RESOURCES. */
 
-    get_word(&text, &word_len);
-    if (*text == '=')
-    {
-      text++;                                   /* skip '=' */
-      get_word(&text, &option_value_len, NONSPACE);
-      option_value= text;
-      text+= option_value_len;
-    }
-    else
-    {
-      option_value= "";
-      option_value_len= 0;
-    }
+      if (cmd->init(&text))
+      {
+        delete cmd;
+        goto syntax_error;
+      }
 
-    /* should be empty */
-    get_word(&text, &word_len, NONSPACE);
-    if (word_len)
-      goto syntax_error;
+      command= cmd;
 
-    if (skip)
-      command= new  Unset_option(map, instance_name, instance_name_len,
-                                 option, option_len, option_value,
-                                 option_value_len);
-    else
-      command= new Set_option(map, instance_name, instance_name_len,
-                              option, option_len, option_value,
-                              option_value_len);
-    break;
+      break;
+    }
   case TOK_SHOW:
     switch (shift_token(&text, &word_len)) {
     case TOK_INSTANCES:
@@ -222,30 +377,35 @@ Command *parse_command(Instance_map *map, const char *text)
       switch (Token tok2= shift_token(&text, &word_len)) {
       case TOK_OPTIONS:
       case TOK_STATUS:
-        if (get_text_id(&text, &instance_name_len, &instance_name))
+        if (get_text_id(&text, &instance_name))
           goto syntax_error;
-        text+= instance_name_len;
+        text+= instance_name.length;
         /* check that this is the end of the command */
         get_word(&text, &word_len, NONSPACE);
         if (word_len)
           goto syntax_error;
         if (tok2 == TOK_STATUS)
-          command= new Show_instance_status(map, instance_name,
-                                            instance_name_len);
+          command= new Show_instance_status(map, &instance_name);
         else
-          command= new Show_instance_options(map, instance_name,
-                                            instance_name_len);
+          command= new Show_instance_options(map, &instance_name);
         break;
       default:
         goto syntax_error;
       }
       break;
     default:
-      instance_name= text - word_len;
-      instance_name_len= word_len;
-      if (instance_name_len)
+      instance_name.str= (char *) text - word_len;
+      instance_name.length= word_len;
+      if (instance_name.length)
       {
         Log_type log_type;
+
+        long log_size;
+        LEX_STRING log_size_str;
+
+        long log_offset= 0;
+        LEX_STRING log_offset_str= { NULL, 0 };
+
         switch (shift_token(&text, &word_len)) {
         case TOK_LOG:
           switch (Token tok3= shift_token(&text, &word_len)) {
@@ -254,8 +414,7 @@ Command *parse_command(Instance_map *map, const char *text)
             /* check that this is the end of the command */
             if (word_len)
               goto syntax_error;
-            command= new Show_instance_log_files(map, instance_name,
-                                                 instance_name_len);
+            command= new Show_instance_log_files(map, &instance_name);
             break;
           case TOK_ERROR:
           case TOK_GENERAL:
@@ -275,12 +434,14 @@ Command *parse_command(Instance_map *map, const char *text)
               goto syntax_error;
             }
             /* get the size of the log we want to retrieve */
-            if (get_text_id(&text, &word_len, &log_size))
+            if (get_text_id(&text, &log_size_str))
               goto syntax_error;
-            text+= word_len;
+            text+= log_size_str.length;
+
             /* this parameter is required */
-            if (!word_len)
+            if (!log_size_str.length)
               goto syntax_error;
+
             /* the next token should be comma, or nothing */
             get_word(&text, &word_len);
             switch (*text) {
@@ -290,23 +451,41 @@ Command *parse_command(Instance_map *map, const char *text)
                 get_word(&text, &word_len);
                 if (!word_len)
                   goto syntax_error;
+                log_offset_str.str= (char *) text;
+                log_offset_str.length= word_len;
                 text+= word_len;
-                command= new Show_instance_log(map, instance_name,
-                                               instance_name_len, log_type,
-                                               log_size, text);
                 get_word(&text, &word_len, NONSPACE);
                 /* check that this is the end of the command */
                 if (word_len)
                   goto syntax_error;
                 break;
               case '\0':
-                command= new Show_instance_log(map, instance_name,
-                                               instance_name_len, log_type,
-                                               log_size, NULL);
                 break; /* this is ok */
               default:
+                goto syntax_error;
+            }
+
+            /* Parse size parameter. */
+
+            if (parse_long(&log_size_str, &log_size))
+              goto syntax_error;
+
+            if (log_size <= 0)
               goto syntax_error;
+
+            /* Parse offset parameter (if specified). */
+
+            if (log_offset_str.length)
+            {
+              if (parse_long(&log_offset_str, &log_offset))
+                goto syntax_error;
+
+              if (log_offset <= 0)
+                goto syntax_error;
             }
+
+            command= new Show_instance_log(map, &instance_name,
+                                           log_type, log_size, log_offset);
           break;
           default:
             goto syntax_error;
diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h
index 3da53e3a61e15d9ab118cf6360cb07f1d40a66f6..ae29c7eb64abcabffd8867335a4043790f6d9b26 100644
--- a/server-tools/instance-manager/parse.h
+++ b/server-tools/instance-manager/parse.h
@@ -18,6 +18,7 @@
 
 #include <my_global.h>
 #include <my_sys.h>
+#include <m_string.h>
 
 class Command;
 class Instance_map;
@@ -29,10 +30,148 @@ enum Log_type
   IM_LOG_SLOW
 };
 
-Command *parse_command(Instance_map *instance_map, const char *text);
+Command *parse_command(Instance_map *map, const char *text);
+
+bool parse_option_value(const char *text, uint *text_len, char **value);
+
+void skip_spaces(const char **text);
 
 /* define kinds of the word seek method */
-enum { ALPHANUM= 1, NONSPACE };
+enum enum_seek_method { ALPHANUM= 1, NONSPACE, OPTION_NAME };
+
+/************************************************************************/
+
+class Named_value
+{
+public:
+  /*
+    The purpose of these methods is just to have one method for
+    allocating/deallocating memory for strings for Named_value.
+  */
+
+  static inline char *alloc_str(const LEX_STRING *str);
+  static inline char *alloc_str(const char *str);
+  static inline void free_str(char **str);
+
+public:
+  inline Named_value();
+  inline Named_value(char *name_arg, char *value_arg);
+
+  inline char *get_name();
+  inline char *get_value();
+
+  inline void free();
+
+private:
+  char *name;
+  char *value;
+};
+
+inline char *Named_value::alloc_str(const LEX_STRING *str)
+{
+  return my_strndup((const byte *) str->str, str->length, MYF(0));
+}
+
+inline char *Named_value::alloc_str(const char *str)
+{
+  return my_strdup(str, MYF(0));
+}
+
+inline void Named_value::free_str(char **str)
+{
+  my_free(*str, MYF(MY_ALLOW_ZERO_PTR));
+  *str= NULL;
+}
+
+inline Named_value::Named_value()
+  :name(NULL), value(NULL)
+{ }
+
+inline Named_value::Named_value(char *name_arg, char *value_arg)
+  :name(name_arg), value(value_arg)
+{ }
+
+inline char *Named_value::get_name()
+{
+  return name;
+}
+
+inline char *Named_value::get_value()
+{
+  return value;
+}
+
+void Named_value::free()
+{
+  free_str(&name);
+  free_str(&value);
+}
+
+/************************************************************************/
+
+class Named_value_arr
+{
+public:
+  Named_value_arr();
+  ~Named_value_arr();
+
+  bool init();
+
+  inline int get_size() const;
+  inline Named_value get_element(int idx) const;
+  inline void remove_element(int idx);
+  inline bool add_element(Named_value *option);
+  inline bool replace_element(int idx, Named_value *option);
+
+private:
+  bool initialized;
+  DYNAMIC_ARRAY arr;
+};
+
+
+inline int Named_value_arr::get_size() const
+{
+  return arr.elements;
+}
+
+
+inline Named_value Named_value_arr::get_element(int idx) const
+{
+  DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
+
+  Named_value option;
+  get_dynamic((DYNAMIC_ARRAY *) &arr, (gptr) &option, idx);
+
+  return option;
+}
+
+
+inline void Named_value_arr::remove_element(int idx)
+{
+  DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
+
+  get_element(idx).free();
+
+  delete_dynamic_element(&arr, idx);
+}
+
+
+inline bool Named_value_arr::add_element(Named_value *option)
+{
+  return insert_dynamic(&arr, (gptr) option);
+}
+
+
+inline bool Named_value_arr::replace_element(int idx, Named_value *option)
+{
+  DBUG_ASSERT(0 <= idx && (uint) idx < arr.elements);
+
+  get_element(idx).free();
+
+  return set_dynamic(&arr, (gptr) option, idx);
+}
+
+/************************************************************************/
 
 /*
   tries to find next word in the text
@@ -41,7 +180,7 @@ enum { ALPHANUM= 1, NONSPACE };
 */
 
 inline void get_word(const char **text, uint *word_len,
-                     int seek_method= ALPHANUM)
+                     enum_seek_method seek_method= ALPHANUM)
 {
   const char *word_end;
 
@@ -51,13 +190,23 @@ inline void get_word(const char **text, uint *word_len,
 
   word_end= *text;
 
-  if (seek_method == ALPHANUM)
+  switch (seek_method) {
+  case ALPHANUM:
     while (my_isalnum(default_charset_info, *word_end))
       ++word_end;
-  else
+    break;
+  case NONSPACE:
     while (!my_isspace(default_charset_info, *word_end) &&
            (*word_end != '\0'))
       ++word_end;
+    break;
+  case OPTION_NAME:
+    while (my_isalnum(default_charset_info, *word_end) ||
+           *word_end == '-' ||
+           *word_end == '_')
+      ++word_end;
+    break;
+  }
 
   *word_len= word_end - *text;
 }
diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc
index 64bb6a6485f7b9f59ba8b4ea9ecd108158131c18..643a50625a1ed4e39897af7fbf403bb403b81448 100644
--- a/server-tools/instance-manager/parse_output.cc
+++ b/server-tools/instance-manager/parse_output.cc
@@ -14,13 +14,15 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-#include <my_global.h>
-#include "parse.h"
 #include "parse_output.h"
 
-#include <stdio.h>
+#include <my_global.h>
 #include <my_sys.h>
 #include <m_string.h>
+
+#include <stdio.h>
+
+#include "parse.h"
 #include "portability.h"
 
 
diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h
index 6a84fabbf17830debf87aba43e834e1bcc4f04a1..b86363a4452e2298af820322c9e8631cfffa3854 100644
--- a/server-tools/instance-manager/parse_output.h
+++ b/server-tools/instance-manager/parse_output.h
@@ -16,6 +16,8 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#include <my_global.h>
+
 #define GET_VALUE 1
 #define GET_LINE  2
 
diff --git a/server-tools/instance-manager/portability.h b/server-tools/instance-manager/portability.h
index 1a3be5705e35bb937154089fd8c0747d32c2d5e4..a76cff588935318375bde7b02fa9715b4db2f5d1 100644
--- a/server-tools/instance-manager/portability.h
+++ b/server-tools/instance-manager/portability.h
@@ -16,11 +16,25 @@
 /*TODO:  fix this */
 #define PROTOCOL_VERSION 10
 
+#define DFLT_CONFIG_FILE_NAME "my.ini"
+#define DFLT_MYSQLD_PATH      "mysqld"
+#define DFLT_PASSWD_FILE_EXT  ".passwd"
+#define DFLT_PID_FILE_EXT     ".pid"
+#define DFLT_SOCKET_FILE_EXT  ".sock"
+
 typedef int pid_t;
 
 #undef popen
 #define popen(A,B) _popen(A,B)
 
+#define NEWLINE "\r\n"
+#define NEWLINE_LEN 2
+
+#else /* ! __WIN__ */
+
+#define NEWLINE "\n"
+#define NEWLINE_LEN 1
+
 #endif /* __WIN__ */
 
 #endif  /* INCLUDES_MYSQL_INSTANCE_MANAGER_PORTABILITY_H */
diff --git a/server-tools/instance-manager/priv.cc b/server-tools/instance-manager/priv.cc
index d2d6a3f636c2ed015c10b6235d761fb4881f5bf2..d3cc52ec6386793fb44d45bf9eee5f3c001438db 100644
--- a/server-tools/instance-manager/priv.cc
+++ b/server-tools/instance-manager/priv.cc
@@ -14,10 +14,10 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#include "priv.h"
+
 #include <my_global.h>
 #include <mysql_com.h>
-#include "priv.h"
-#include "portability.h"
 
 #if defined(__ia64__) || defined(__ia64)
 /*
@@ -43,9 +43,7 @@ bool linuxthreads;
   The following string must be less then 80 characters, as
   mysql_connection.cc relies on it
 */
-const char mysqlmanager_version[] = "0.2-alpha";
-
-const int mysqlmanager_version_length= sizeof(mysqlmanager_version) - 1;
+const LEX_STRING mysqlmanager_version= { C_STRING_WITH_SIZE("1.0-beta") };
 
 const unsigned char protocol_version= PROTOCOL_VERSION;
 
diff --git a/server-tools/instance-manager/priv.h b/server-tools/instance-manager/priv.h
index 52d7aa1d23d2db754952a344c17d9a0725b599fc..0b393c17ac2f8d419ce97576159c30e529c5294d 100644
--- a/server-tools/instance-manager/priv.h
+++ b/server-tools/instance-manager/priv.h
@@ -16,13 +16,17 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
+#include <my_global.h>
+#include <m_string.h>
+#include <my_pthread.h>
+
 #include <sys/types.h>
-#ifdef __WIN__
-#include "portability.h"
-#else
+
+#ifndef __WIN__
 #include <unistd.h>
 #endif
-#include "my_pthread.h"
+
+#include "portability.h"
 
 /* IM-wide platform-independent defines */
 #define SERVER_DEFAULT_PORT 3306
@@ -31,6 +35,21 @@
 /* three-week timeout should be enough */
 #define LONG_TIMEOUT ((ulong) 3600L*24L*21L)
 
+const int MEM_ROOT_BLOCK_SIZE= 512;
+
+/* The maximal length of option name and option value. */
+const int MAX_OPTION_LEN= 1024;
+
+/*
+  The maximal length of whole option string:
+    --<option name>=<option value>
+*/
+const int MAX_OPTION_STR_LEN= 2 + MAX_OPTION_LEN + 1 + MAX_OPTION_LEN + 1;
+
+const int MAX_VERSION_LENGTH= 160;
+
+const int MAX_INSTANCE_NAME_SIZE= FN_REFLEN;
+
 /* the pid of the manager process (of the signal thread on the LinuxThreads) */
 extern pid_t manager_pid;
 
@@ -42,8 +61,7 @@ extern pid_t manager_pid;
 extern bool linuxthreads;
 #endif
 
-extern const char mysqlmanager_version[];
-extern const int mysqlmanager_version_length;
+extern const LEX_STRING mysqlmanager_version;
 
 /* MySQL client-server protocol version: substituted from configure */
 extern const unsigned char protocol_version;
diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc
index 73e07f993ae26513e354806fe6f9f6d338877a8c..4a8c4d0b88d6013e9f69b3e67f0a6b0cb88c2d78 100644
--- a/server-tools/instance-manager/protocol.cc
+++ b/server-tools/instance-manager/protocol.cc
@@ -163,7 +163,7 @@ int send_fields(struct st_net *net, LIST *fields)
   Buffer send_buff;
   char small_buff[4];
   uint position= 0;
-  NAME_WITH_LENGTH *field;
+  LEX_STRING *field;
 
   /* send the number of fileds */
   net_store_length(small_buff, (uint) list_length(fields));
@@ -173,7 +173,7 @@ int send_fields(struct st_net *net, LIST *fields)
   while (tmp)
   {
     position= 0;
-    field= (NAME_WITH_LENGTH *) tmp->data;
+    field= (LEX_STRING *) tmp->data;
 
     store_to_protocol_packet(&send_buff,
                              (char*) "", &position);    /* catalog name */
@@ -184,9 +184,9 @@ int send_fields(struct st_net *net, LIST *fields)
     store_to_protocol_packet(&send_buff,
                              (char*) "", &position);    /* table name alias */
     store_to_protocol_packet(&send_buff,
-                             field->name, &position);   /* column name */
+                             field->str, &position);    /* column name */
     store_to_protocol_packet(&send_buff,
-                             field->name, &position);   /* column name alias */
+                             field->str, &position);    /* column name alias */
     send_buff.reserve(position, 12);
     if (send_buff.is_error())
       goto err;
diff --git a/server-tools/instance-manager/protocol.h b/server-tools/instance-manager/protocol.h
index f38eac6b079b4840f4a80607c732a2dc3c8b3c14..2c84ad394b4fe7467b26c862ca550eabff5d0c95 100644
--- a/server-tools/instance-manager/protocol.h
+++ b/server-tools/instance-manager/protocol.h
@@ -20,11 +20,6 @@
 
 #include <my_list.h>
 
-typedef struct field {
-  char *name;
-  uint length;
-} NAME_WITH_LENGTH;
-
 /* default field length to be used in various field-realted functions */
 enum { DEFAULT_FIELD_LENGTH= 20 };
 
diff --git a/server-tools/instance-manager/thread_registry.cc b/server-tools/instance-manager/thread_registry.cc
index 0091d713a9101605fcbf217c86ac7b2d376bd46e..a424860548d66c2a7bc2c3889cab8270c891ec6d 100644
--- a/server-tools/instance-manager/thread_registry.cc
+++ b/server-tools/instance-manager/thread_registry.cc
@@ -20,11 +20,12 @@
 
 #include "thread_registry.h"
 
-#include "log.h"
+#include <my_global.h>
+#include <thr_alarm.h>
 
-#include <assert.h>
 #include <signal.h>
-#include <thr_alarm.h>
+
+#include "log.h"
 
 
 #ifndef __WIN__
@@ -52,7 +53,7 @@ Thread_info::Thread_info(pthread_t thread_id_arg) :
 */
 
 Thread_registry::Thread_registry() :
-   shutdown_in_progress(false)
+   shutdown_in_progress(FALSE)
   ,sigwait_thread_pid(pthread_self())
 {
   pthread_mutex_init(&LOCK_thread_registry, 0);
@@ -186,7 +187,7 @@ void Thread_registry::deliver_shutdown()
   set_timespec(shutdown_time, 1);
 
   pthread_mutex_lock(&LOCK_thread_registry);
-  shutdown_in_progress= true;
+  shutdown_in_progress= TRUE;
 
 #ifndef __WIN__
   /* to stop reading from the network we need to flush alarm queue */
diff --git a/server-tools/instance-manager/user_management_commands.cc b/server-tools/instance-manager/user_management_commands.cc
new file mode 100644
index 0000000000000000000000000000000000000000..03a3f9814e3fbdd242c427a2189f15aad28f2bb9
--- /dev/null
+++ b/server-tools/instance-manager/user_management_commands.cc
@@ -0,0 +1,406 @@
+#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
+#pragma implementation
+#endif
+
+#include "user_management_commands.h"
+
+#include "exit_codes.h"
+#include "options.h"
+#include "user_map.h"
+
+/*************************************************************************
+  Module-specific (internal) functions.
+*************************************************************************/
+
+/*
+  The function returns user name. The user name is retrieved from command-line
+  options (if specified) or from console.
+
+  NOTE
+    This function must not be used in user-management command implementations.
+    Use get_user_name() instead.
+
+  SYNOPSYS
+    get_user_name_impl()
+
+  RETURN
+    NULL            on error
+    valid pointer   on success
+*/
+
+static char *get_user_name_impl()
+{
+  static char user_name_buf[1024];
+  char *ptr;
+
+  if (Options::User_management::user_name)
+    return Options::User_management::user_name;
+
+  printf("Enter user name: ");
+  fflush(stdout);
+
+  if (!fgets(user_name_buf, sizeof (user_name_buf), stdin))
+    return NULL;
+
+  if ((ptr= strchr(user_name_buf, '\n')))
+    *ptr= 0;
+
+  if ((ptr= strchr(user_name_buf, '\r')))
+    *ptr= 0;
+
+  return user_name_buf;
+}
+
+
+/*
+  The function is intended to provide user name for user-management
+  operations. It also checks that length of the specified user name is correct
+  (not empty, not exceeds USERNAME_LENGTH). Report to stderr if something is
+  wrong.
+
+  SYNOPSYS
+    get_user_name()
+    user_name     [OUT] on success contains user name
+
+  RETURN
+    TRUE    on error
+    FALSE   on success
+*/
+
+static bool get_user_name(LEX_STRING *user_name)
+{
+  char *user_name_str= get_user_name_impl();
+
+  if (!user_name_str)
+  {
+    fprintf(stderr, "Error: unable to read user name from stdin.\n");
+    return TRUE;
+  }
+
+  user_name->str= user_name_str;
+  user_name->length= strlen(user_name->str);
+
+  if (user_name->length == 0)
+  {
+    fprintf(stderr, "Error: user name can not be empty.\n");
+    return TRUE;
+  }
+
+  if (user_name->length > USERNAME_LENGTH)
+  {
+    fprintf(stderr, "Error: user name must not exceed %d characters.\n",
+            (int) USERNAME_LENGTH);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+/*
+  The function is intended to provide password for user-management operations.
+  The password is retrieved from command-line options (if specified) or from
+  console.
+
+  SYNOPSYS
+    get_password()
+
+  RETURN
+    NULL            on error
+    valid pointer   on success
+*/
+
+static const char *get_password()
+{
+  if (Options::User_management::password)
+    return Options::User_management::password;
+
+  const char *passwd1= get_tty_password("Enter password: ");
+  const char *passwd2= get_tty_password("Re-type password: ");
+
+  if (strcmp(passwd1, passwd2))
+  {
+    fprintf(stderr, "Error: passwords do not match.\n");
+    return 0;
+  }
+
+  return passwd1;
+}
+
+
+/*
+  Load password file into user map.
+
+  SYNOPSYS
+    load_password_file()
+    user_map            target user map
+
+  RETURN
+    See exit_codes.h for possible values.
+*/
+
+static int load_password_file(User_map *user_map)
+{
+  int err_code;
+  const char *err_msg;
+
+  if (user_map->init())
+  {
+    fprintf(stderr, "Error: can not initialize user map.\n");
+    return ERR_OUT_OF_MEMORY;
+  }
+
+  if ((err_code= user_map->load(Options::Main::password_file_name, &err_msg)))
+    fprintf(stderr, "Error: %s.\n", (const char *) err_msg);
+
+  return err_code;
+}
+
+
+/*
+  Save user map into password file.
+
+  SYNOPSYS
+    save_password_file()
+    user_map            user map
+
+  RETURN
+    See exit_codes.h for possible values.
+*/
+
+static int save_password_file(User_map *user_map)
+{
+  int err_code;
+  const char *err_msg;
+
+  if ((err_code= user_map->save(Options::Main::password_file_name, &err_msg)))
+    fprintf(stderr, "Error: %s.\n", (const char *) err_msg);
+
+  return err_code;
+}
+
+/*************************************************************************
+  Passwd_cmd
+*************************************************************************/
+
+int Passwd_cmd::execute()
+{
+  LEX_STRING user_name;
+  const char *password;
+
+  printf("Creating record for new user.\n");
+
+  if (get_user_name(&user_name))
+    return ERR_CAN_NOT_READ_USER_NAME;
+
+  if (!(password= get_password()))
+    return ERR_CAN_NOT_READ_PASSWORD;
+
+  {
+    User user(&user_name, password);
+
+    printf("%s:%s\n",
+           (const char *) user.user,
+           (const char *) user.scrambled_password);
+  }
+
+  return ERR_OK;
+}
+
+
+/*************************************************************************
+  Add_user_cmd
+*************************************************************************/
+
+int Add_user_cmd::execute()
+{
+  LEX_STRING user_name;
+  const char *password;
+
+  User_map user_map;
+  User *new_user;
+
+  int err_code;
+
+  if (get_user_name(&user_name))
+    return ERR_CAN_NOT_READ_USER_NAME;
+
+  /* Load the password file. */
+
+  if ((err_code= load_password_file(&user_map)) != ERR_OK)
+    return err_code;
+
+  /* Check that the user does not exist. */
+
+  if (user_map.find_user(&user_name))
+  {
+    fprintf(stderr, "Error: user '%s' already exists.\n",
+            (const char *) user_name.str);
+    return ERR_USER_ALREADY_EXISTS;
+  }
+
+  /* Add the user. */
+
+  if (!(password= get_password()))
+    return ERR_CAN_NOT_READ_PASSWORD;
+
+  if (!(new_user= new User(&user_name, password)))
+    return ERR_OUT_OF_MEMORY;
+
+  if (user_map.add_user(new_user))
+  {
+    delete new_user;
+    return ERR_OUT_OF_MEMORY;
+  }
+
+  /* Save the password file. */
+
+  return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+  Drop_user_cmd
+*************************************************************************/
+
+int Drop_user_cmd::execute()
+{
+  LEX_STRING user_name;
+
+  User_map user_map;
+  User *user;
+
+  int err_code;
+
+  if (get_user_name(&user_name))
+    return ERR_CAN_NOT_READ_USER_NAME;
+
+  /* Load the password file. */
+
+  if ((err_code= load_password_file(&user_map)) != ERR_OK)
+    return err_code;
+
+  /* Find the user. */
+
+  user= user_map.find_user(&user_name);
+
+  if (!user)
+  {
+    fprintf(stderr, "Error: user '%s' does not exist.\n",
+            (const char *) user_name.str);
+    return ERR_USER_NOT_FOUND;
+  }
+
+  /* Remove the user (ignore possible errors). */
+
+  user_map.remove_user(user);
+
+  /* Save the password file. */
+
+  return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+  Edit_user_cmd
+*************************************************************************/
+
+int Edit_user_cmd::execute()
+{
+  LEX_STRING user_name;
+  const char *password;
+
+  User_map user_map;
+  User *user;
+
+  int err_code;
+
+  if (get_user_name(&user_name))
+    return ERR_CAN_NOT_READ_USER_NAME;
+
+  /* Load the password file. */
+
+  if ((err_code= load_password_file(&user_map)) != ERR_OK)
+    return err_code;
+
+  /* Find the user. */
+
+  user= user_map.find_user(&user_name);
+
+  if (!user)
+  {
+    fprintf(stderr, "Error: user '%s' does not exist.\n",
+            (const char *) user_name.str);
+    return ERR_USER_NOT_FOUND;
+  }
+
+  /* Modify user's password. */
+
+  if (!(password= get_password()))
+    return ERR_CAN_NOT_READ_PASSWORD;
+
+  user->set_password(password);
+
+  /* Save the password file. */
+
+  return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+  Clean_db_cmd
+*************************************************************************/
+
+int Clean_db_cmd::execute()
+{
+  User_map user_map;
+
+  if (user_map.init())
+  {
+    fprintf(stderr, "Error: can not initialize user map.\n");
+    return ERR_OUT_OF_MEMORY;
+  }
+
+  return save_password_file(&user_map);
+}
+
+
+/*************************************************************************
+  Check_db_cmd
+*************************************************************************/
+
+int Check_db_cmd::execute()
+{
+  User_map user_map;
+
+  return load_password_file(&user_map);
+}
+
+
+/*************************************************************************
+  List_users_cmd
+*************************************************************************/
+
+int List_users_cmd::execute()
+{
+  User_map user_map;
+
+  int err_code;
+
+  /* Load the password file. */
+
+  if ((err_code= load_password_file(&user_map)))
+    return err_code;
+
+  /* Print out registered users. */
+
+  {
+    User_map::Iterator it(&user_map);
+    User *user;
+
+    while ((user= it.next()))
+      fprintf(stderr, "%s\n", (const char *) user->user);
+  }
+
+  return ERR_OK;
+}
diff --git a/server-tools/instance-manager/user_management_commands.h b/server-tools/instance-manager/user_management_commands.h
new file mode 100644
index 0000000000000000000000000000000000000000..4bf3546f0a6749ef445ff600409b8da0731396fe
--- /dev/null
+++ b/server-tools/instance-manager/user_management_commands.h
@@ -0,0 +1,167 @@
+#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
+#define INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
+
+/*
+   Copyright (C) 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
+*/
+
+/*
+  This header contains declarations of classes inteded to support
+  user-management commands (such as add user, get list of users, etc).
+
+  The general idea is to have one interface (pure abstract class) for such a
+  command. Each concrete user-management command is implemented in concrete
+  class, derived from the common interface.
+*/
+
+#if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
+#pragma interface
+#endif
+
+/*************************************************************************
+  User_management_cmd -- base class for User-management commands.
+*************************************************************************/
+
+class User_management_cmd
+{
+public:
+  User_management_cmd()
+  { }
+
+  virtual ~User_management_cmd()
+  { }
+
+public:
+  /*
+    Executes user-management command.
+
+    SYNOPSYS
+      execute()
+
+    RETURN
+      See exit_codes.h for possible values.
+  */
+
+  virtual int execute() = 0;
+};
+
+
+/*************************************************************************
+  Passwd_cmd: support for --passwd command-line option.
+*************************************************************************/
+
+class Passwd_cmd : public User_management_cmd
+{
+public:
+  Passwd_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+
+/*************************************************************************
+  Add_user_cmd: support for --add-user command-line option.
+*************************************************************************/
+
+class Add_user_cmd : public User_management_cmd
+{
+public:
+  Add_user_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+
+/*************************************************************************
+  Drop_user_cmd: support for --drop-user command-line option.
+*************************************************************************/
+
+class Drop_user_cmd : public User_management_cmd
+{
+public:
+  Drop_user_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+
+/*************************************************************************
+  Edit_user_cmd: support for --edit-user command-line option.
+*************************************************************************/
+
+class Edit_user_cmd : public User_management_cmd
+{
+public:
+  Edit_user_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+
+/*************************************************************************
+  Clean_db_cmd: support for --clean-db command-line option.
+*************************************************************************/
+
+class Clean_db_cmd : public User_management_cmd
+{
+public:
+  Clean_db_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+
+/*************************************************************************
+  Check_db_cmd: support for --check-db command-line option.
+*************************************************************************/
+
+class Check_db_cmd : public User_management_cmd
+{
+public:
+  Check_db_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+
+/*************************************************************************
+  List_users_cmd: support for --list-users command-line option.
+*************************************************************************/
+
+class List_users_cmd : public User_management_cmd
+{
+public:
+  List_users_cmd()
+  { }
+
+public:
+  virtual int execute();
+};
+
+#endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MANAGEMENT_CMD_H
diff --git a/server-tools/instance-manager/user_map.cc b/server-tools/instance-manager/user_map.cc
index 9cb153071311805ebc654d433bc1969d5208c71e..e8128cf015be105d5b729b386d46d614da9151f0 100644
--- a/server-tools/instance-manager/user_map.cc
+++ b/server-tools/instance-manager/user_map.cc
@@ -19,32 +19,32 @@
 #endif
 
 #include "user_map.h"
-
-#include <mysql_com.h>
-#include <m_string.h>
-
+#include "exit_codes.h"
 #include "log.h"
+#include "portability.h"
 
-struct User
+User::User(const LEX_STRING *user_name_arg, const char *password)
 {
-  char user[USERNAME_LENGTH + 1];
-  uint8 user_length;
-  uint8 salt[SCRAMBLE_LENGTH];
-  int init(const char *line);
-};
+  user_length= strmake(user, user_name_arg->str, USERNAME_LENGTH + 1) - user;
 
+  set_password(password);
+}
 
 int User::init(const char *line)
 {
   const char *name_begin, *name_end, *password;
-  int line_ending_len= 1;
+  int password_length;
 
   if (line[0] == '\'' || line[0] == '"')
   {
     name_begin= line + 1;
     name_end= strchr(name_begin, line[0]);
     if (name_end == 0 || name_end[1] != ':')
-      goto err;
+    {
+      log_info("Error: invalid format (unmatched quote) of user line (%s).",
+                (const char *) line);
+      return 1;
+    }
     password= name_end + 2;
   }
   else
@@ -52,33 +52,47 @@ int User::init(const char *line)
     name_begin= line;
     name_end= strchr(name_begin, ':');
     if (name_end == 0)
-      goto err;
+    {
+      log_info("Error: invalid format (no delimiter) of user line (%s).",
+                (const char *) line);
+      return 1;
+    }
     password= name_end + 1;
   }
+
   user_length= name_end - name_begin;
   if (user_length > USERNAME_LENGTH)
-    goto err;
-
-  /*
-    assume that newline characater is present
-    we support reading password files that end in \n or \r\n on
-    either platform.
-  */
-  if (password[strlen(password)-2] == '\r')
-    line_ending_len= 2;
-  if (strlen(password) != (uint) (SCRAMBLED_PASSWORD_CHAR_LENGTH +
-                                  line_ending_len))
-    goto err;
+  {
+    log_info("Error: user name is too long (%d). Max length: %d. "
+              "User line: '%s'.",
+              (int) user_length,
+              (int) USERNAME_LENGTH,
+              (const char *) line);
+    return 1;
+  }
+
+  password_length= strlen(password);
+  if (password_length > SCRAMBLED_PASSWORD_CHAR_LENGTH)
+  {
+    log_info("Error: password is too long (%d). Max length: %d. ",
+              "User line: '%s'.",
+              (int) password_length,
+              (int) SCRAMBLED_PASSWORD_CHAR_LENGTH,
+              (const char *) line);
+    return 1;
+  }
 
   memcpy(user, name_begin, user_length);
   user[user_length]= 0;
+
+  memcpy(scrambled_password, password, password_length);
+  scrambled_password[password_length]= 0;
+
   get_salt_from_password(salt, password);
-  log_info("loaded user %s", user);
+
+  log_info("loaded user '%s'.", user);
 
   return 0;
-err:
-  log_error("error parsing user and password at line %s", line);
-  return 1;
 }
 
 
@@ -101,30 +115,70 @@ static void delete_user(void *u)
 C_MODE_END
 
 
+void User_map::Iterator::reset()
+{
+  cur_idx= 0;
+}
+
+
+User *User_map::Iterator::next()
+{
+  if (cur_idx < user_map->hash.records)
+    return (User *) hash_element(&user_map->hash, cur_idx++);
+
+  return NULL;
+}
+
+
 int User_map::init()
 {
   enum { START_HASH_SIZE= 16 };
   if (hash_init(&hash, default_charset_info, START_HASH_SIZE, 0, 0,
       get_user_key, delete_user, 0))
     return 1;
+
+  initialized= TRUE;
+
   return 0;
 }
 
 
+User_map::User_map()
+  :initialized(FALSE)
+{
+}
+
+
 User_map::~User_map()
 {
-  hash_free(&hash);
+  if (initialized)
+    hash_free(&hash);
 }
 
 
 /*
-  Load all users from the password file. Must be called once right after
-  construction.
-  In case of failure, puts error message to the log file and returns 1
+  Load password database.
+
+  SYNOPSYS
+    load()
+    password_file_name  [IN] password file path
+    err_msg             [OUT] error message
+
+  DESCRIPTION
+    Load all users from the password file. Must be called once right after
+    construction. In case of failure, puts error message to the log file and
+    returns specific error code.
+
+  RETURN
+    0   on success
+    !0  on error
 */
 
-int User_map::load(const char *password_file_name)
+int User_map::load(const char *password_file_name, const char **err_msg)
 {
+  static const int ERR_MSG_BUF_SIZE = 255;
+  static char err_msg_buf[ERR_MSG_BUF_SIZE];
+
   FILE *file;
   char line[USERNAME_LENGTH + SCRAMBLED_PASSWORD_CHAR_LENGTH +
             2 +                               /* for possible quotes */
@@ -134,33 +188,172 @@ int User_map::load(const char *password_file_name)
   User *user;
   int rc= 1;
 
+  if (my_access(password_file_name, F_OK) != 0)
+  {
+    if (err_msg)
+    {
+      snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+               "password file (%s) does not exist",
+               (const char *) password_file_name);
+      *err_msg= err_msg_buf;
+    }
+
+    return ERR_PASSWORD_FILE_DOES_NOT_EXIST;
+  }
+
   if ((file= my_fopen(password_file_name, O_RDONLY | O_BINARY, MYF(0))) == 0)
   {
-    /* Probably the password file wasn't specified. Try to leave without it */
-    log_info("[WARNING] can't open password file %s: errno=%d, %s", password_file_name,
-              errno, strerror(errno));
-    return 0;
+    if (err_msg)
+    {
+      snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+               "can not open password file (%s): %s",
+               (const char *) password_file_name,
+               (const char *) strerror(errno));
+      *err_msg= err_msg_buf;
+    }
+
+    return ERR_IO_ERROR;
   }
 
+  log_info("loading the password database...");
+
   while (fgets(line, sizeof(line), file))
   {
+    char *user_line= line;
+
+    /*
+      We need to skip EOL-symbols also from the beginning of the line, because
+      if the previous line was ended by \n\r sequence, we get \r in our line.
+    */
+
+    while (user_line[0] == '\r' || user_line[0] == '\n')
+      ++user_line;
+
+    /* Skip EOL-symbols in the end of the line. */
+
+    {
+      char *ptr;
+
+      if ((ptr= strchr(user_line, '\n')))
+        *ptr= 0;
+
+      if ((ptr= strchr(user_line, '\r')))
+        *ptr= 0;
+    }
+
     /* skip comments and empty lines */
-    if (line[0] == '#' || line[0] == '\n' &&
-        (line[1] == '\0' || line[1] == '\r'))
+    if (!user_line[0] || user_line[0] == '#')
       continue;
+
     if ((user= new User) == 0)
-      goto done;
-    if (user->init(line) || my_hash_insert(&hash, (byte *) user))
-      goto err_init_user;
+    {
+      my_fclose(file, MYF(0));
+
+      if (err_msg)
+      {
+        snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+                 "out of memory while parsing password file (%s)",
+                 (const char *) password_file_name);
+        *err_msg= err_msg_buf;
+      }
+
+      return ERR_OUT_OF_MEMORY;
+    }
+
+    if (user->init(user_line))
+    {
+      delete user;
+      my_fclose(file, MYF(0));
+
+      if (err_msg)
+      {
+        snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+                 "password file (%s) corrupted",
+                 (const char *) password_file_name);
+        *err_msg= err_msg_buf;
+      }
+
+      return ERR_PASSWORD_FILE_CORRUPTED;
+    }
+
+    if (my_hash_insert(&hash, (byte *) user))
+    {
+      delete user;
+      my_fclose(file, MYF(0));
+
+      if (err_msg)
+      {
+        snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+                 "out of memory while parsing password file (%s)",
+                 (const char *) password_file_name);
+        *err_msg= err_msg_buf;
+      }
+
+      return ERR_OUT_OF_MEMORY;
+    }
   }
-  if (feof(file))
-    rc= 0;
-  goto done;
-err_init_user:
-  delete user;
-done:
+
+  log_info("the password database loaded successfully.");
+
   my_fclose(file, MYF(0));
-  return rc;
+
+  if (err_msg)
+    *err_msg= NULL;
+
+  return ERR_OK;
+}
+
+
+int User_map::save(const char *password_file_name, const char **err_msg)
+{
+  static const int ERR_MSG_BUF_SIZE = 255;
+  static char err_msg_buf[ERR_MSG_BUF_SIZE];
+
+  FILE *file;
+
+  if ((file= my_fopen(password_file_name, O_WRONLY | O_TRUNC | O_BINARY,
+                      MYF(0))) == 0)
+  {
+    if (err_msg)
+    {
+      snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+               "can not open password file (%s) for writing: %s",
+               (const char *) password_file_name,
+               (const char *) strerror(errno));
+      *err_msg= err_msg_buf;
+    }
+
+    return ERR_IO_ERROR;
+  }
+
+  {
+    User_map::Iterator it(this);
+    User *user;
+
+    while ((user= it.next()))
+    {
+      if (fprintf(file, "%s:%s\n", (const char *) user->user,
+                  (const char *) user->scrambled_password) < 0)
+      {
+        if (err_msg)
+        {
+          snprintf(err_msg_buf, ERR_MSG_BUF_SIZE,
+                   "can not write to password file (%s): %s",
+                   (const char *) password_file_name,
+                   (const char *) strerror(errno));
+          *err_msg= err_msg_buf;
+        }
+
+        my_fclose(file, MYF(0));
+
+        return ERR_IO_ERROR;
+      }
+    }
+  }
+
+  my_fclose(file, MYF(0));
+
+  return ERR_OK;
 }
 
 
@@ -172,13 +365,33 @@ int User_map::load(const char *password_file_name)
     2 - user not found
 */
 
-int User_map::authenticate(const char *user_name, uint length,
+int User_map::authenticate(const LEX_STRING *user_name,
                            const char *scrambled_password,
                            const char *scramble) const
 {
-  const User *user= (const User *) hash_search((HASH *) &hash,
-                                               (byte *) user_name, length);
-  if (user)
-    return check_scramble(scrambled_password, scramble, user->salt);
-  return 2;
+  const User *user= find_user(user_name);
+  return user ? check_scramble(scrambled_password, scramble, user->salt) : 2;
+}
+
+
+User *User_map::find_user(const LEX_STRING *user_name)
+{
+  return (User*) hash_search(&hash, (byte*) user_name->str, user_name->length);
+}
+
+const User *User_map::find_user(const LEX_STRING *user_name) const
+{
+  return const_cast<User_map *> (this)->find_user(user_name);
+}
+
+
+bool User_map::add_user(User *user)
+{
+  return my_hash_insert(&hash, (byte*) user) == 0 ? FALSE : TRUE;
+}
+
+
+bool User_map::remove_user(User *user)
+{
+  return hash_delete(&hash, (byte*) user) == 0 ? FALSE : TRUE;
 }
diff --git a/server-tools/instance-manager/user_map.h b/server-tools/instance-manager/user_map.h
index 4134017dd9b44845ec90c41c38ffa0cf07ca99f3..de207c11e658793fb87f2bea598c22cd80fca2d5 100644
--- a/server-tools/instance-manager/user_map.h
+++ b/server-tools/instance-manager/user_map.h
@@ -18,14 +18,35 @@
 
 
 #include <my_global.h>
-
 #include <my_sys.h>
+#include <mysql_com.h>
+#include <m_string.h>
 #include <hash.h>
 
 #if defined(__GNUC__) && defined(USE_PRAGMA_INTERFACE)
 #pragma interface
 #endif
 
+struct User
+{
+  User()
+  {}
+
+  User(const LEX_STRING *user_name_arg, const char *password);
+
+  int init(const char *line);
+
+  inline void set_password(const char *password)
+  {
+    make_scrambled_password(scrambled_password, password);
+  }
+
+  char user[USERNAME_LENGTH + 1];
+  char scrambled_password[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];
+  uint8 user_length;
+  uint8 salt[SCRAMBLE_LENGTH];
+};
+
 /*
   User_map -- all users and passwords
 */
@@ -33,15 +54,51 @@
 class User_map
 {
 public:
+  /* User_map iterator */
+
+  class Iterator
+  {
+  public:
+    Iterator(User_map *user_map_arg) :
+      cur_idx(0), user_map(user_map_arg)
+    { }
+
+  public:
+    void reset();
+
+    User *next();
+
+  private:
+    User_map *user_map;
+    uint cur_idx;
+  };
+
+public:
+  User_map();
   ~User_map();
 
   int init();
-  int load(const char *password_file_name);
-  int authenticate(const char *user_name, uint length,
+  int load(const char *password_file_name, const char **err_msg);
+  int save(const char *password_file_name, const char **err_msg);
+  int authenticate(const LEX_STRING *user_name,
                    const char *scrambled_password,
                    const char *scramble) const;
+
+  const User *find_user(const LEX_STRING *user_name) const;
+  User *find_user(const LEX_STRING *user_name);
+
+  bool add_user(User *user);
+  bool remove_user(User *user);
+
+private:
+  User_map(const User_map &);
+  User_map &operator =(const User_map &);
+
 private:
   HASH hash;
+  bool initialized;
+
+  friend class Iterator;
 };
 
 #endif // INCLUDES_MYSQL_INSTANCE_MANAGER_USER_MAP_H
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 05b1efdbe5193f0aa21971f5c63f8d201578deaa..2b44fbdcc793175f87bebe481748a598c3807ac5 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -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
diff --git a/sql/Makefile.am b/sql/Makefile.am
index deaf2427aebe85d4b3171e071a66de9534f436c9..eec7209bf508ef018cd9bd5b8a8a7d36c0d8cc74 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -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
 
diff --git a/sql/event.cc b/sql/event.cc
index 4a3c6aad30c16ec524d3d47866e8b13806dae480..7c3f17304aaeaef1ba9c482d3d286478875dc739 100644
--- a/sql/event.cc
+++ b/sql/event.cc
@@ -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
@@ -16,13 +16,12 @@
 
 #include "event_priv.h"
 #include "event.h"
+#include "event_scheduler.h"
 #include "sp.h"
+#include "sp_head.h"
 
 /*
  TODO list :
- - The default value of created/modified should not be 0000-00-00 because of
-   STRICT mode restricions.
-
  - CREATE EVENT should not go into binary log! Does it now? The SQL statements
    issued by the EVENT are replicated.
    I have an idea how to solve the problem at failover. So the status field
@@ -38,23 +37,8 @@
    ENABLED to DISABLED status change and this is safe for replicating. As well
    an event may be deleted which is also safe for RBR.
 
- - Maybe move all allocations during parsing to evex_mem_root thus saving
-    double parsing in evex_create_event!
-
- - If the server is killed (stopping) try to kill executing events?
- 
- - What happens if one renames an event in the DB while it is in memory?
-   Or even deleting it?
-  
- - Consider using conditional variable when doing shutdown instead of
-   waiting till all worker threads end.
- 
- - Make Event_timed::get_show_create_event() work
-
  - Add logging to file
 
- - Move comparison code to class Event_timed
-
 Warning:
  - For now parallel execution is not possible because the same sp_head cannot be
    executed few times!!! There is still no lock attached to particular event.
@@ -62,12 +46,26 @@
 */
 
 
-QUEUE EVEX_EQ_NAME;
 MEM_ROOT evex_mem_root;
 time_t mysql_event_last_create_time= 0L;
 
 
-static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
+const char *event_scheduler_state_names[]=
+    { "OFF", "0", "ON", "1", "SUSPEND", "2", NullS };
+
+TYPELIB Events::opt_typelib=
+{
+  array_elements(event_scheduler_state_names)-1,
+  "",
+  event_scheduler_state_names,
+  NULL
+};
+
+
+ulong Events::opt_event_scheduler= 2;
+
+static
+TABLE_FIELD_W_TYPE event_table_fields[Events::FIELD_COUNT] = {
   {
     {(char *) STRING_WITH_LEN("db")},
     {(char *) STRING_WITH_LEN("char(64)")},
@@ -186,41 +184,17 @@ LEX_STRING interval_type_to_name[] = {
 }; 
 
 
-
-/*
-  Inits the scheduler queue - prioritized queue from mysys/queue.c
-
-  Synopsis
-    evex_queue_init()
-
-      queue - pointer the the memory to be initialized as queue. has to be
-              allocated from the caller
-
-  Notes
-    During initialization the queue is sized for 30 events, and when is full
-    will auto extent with 30.
-*/
-
-void
-evex_queue_init(EVEX_QUEUE_TYPE *queue)
-{
-  if (init_queue_ex(queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
-                    event_timed_compare_q, NULL, 30 /*auto_extent*/))
-    sql_print_error("Insufficient memory to initialize executing queue.");
-}
-
-
 /*
   Compares 2 LEX strings regarding case.
 
-  Synopsis
+  SYNOPSIS
     my_time_compare()
 
       s - first LEX_STRING
       t - second LEX_STRING
       cs - charset
 
-  RETURNS:
+  RETURN VALUE
    -1   - s < t
     0   - s == t
     1   - s > t
@@ -239,32 +213,26 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
 /*
   Compares 2 TIME structures
 
-  Synopsis
+  SYNOPSIS
     my_time_compare()
 
       a - first TIME
       b - second time
 
-  RETURNS:
+  RETURN VALUE
    -1   - a < b
     0   - a == b
     1   - a > b
 
-  Notes
+  NOTES
     TIME.second_part is not considered during comparison
 */
 
 int
 my_time_compare(TIME *a, TIME *b)
 {
-
-#ifdef ENABLE_WHEN_WE_HAVE_MILLISECOND_IN_TIMESTAMPS
-  my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
-  my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
-#else
   my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
   my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
-#endif
 
   if (a_t > b_t)
     return 1;
@@ -275,37 +243,12 @@ my_time_compare(TIME *a, TIME *b)
 }
 
 
-/*
-  Compares the execute_at members of 2 Event_timed instances
-
-  Synopsis
-    event_timed_compare()
-
-      a - first Event_timed object
-      b - second Event_timed object
-
-  RETURNS:
-   -1   - a->execute_at < b->execute_at
-    0   - a->execute_at == b->execute_at
-    1   - a->execute_at > b->execute_at
-
-  Notes
-    execute_at.second_part is not considered during comparison
-*/
-
-int
-event_timed_compare(Event_timed *a, Event_timed *b)
-{
-  return my_time_compare(&a->execute_at, &b->execute_at);
-}
-
-
 /*
   Compares the execute_at members of 2 Event_timed instances.
   Used as callback for the prioritized queue when shifting
   elements inside.
 
-  Synopsis
+  SYNOPSIS
     event_timed_compare()
   
       vptr - not used (set it to NULL)
@@ -324,7 +267,8 @@ event_timed_compare(Event_timed *a, Event_timed *b)
 int 
 event_timed_compare_q(void *vptr, byte* a, byte *b)
 {
-  return event_timed_compare((Event_timed *)a, (Event_timed *)b);
+  return my_time_compare(&((Event_timed *)a)->execute_at,
+                         &((Event_timed *)b)->execute_at);
 }
 
 
@@ -335,8 +279,8 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
     YEAR_MONTH - expression is in months
     DAY_MINUTE - expression is in minutes
 
-  Synopsis
-    event_reconstruct_interval_expression()
+  SYNOPSIS
+    Events::reconstruct_interval_expression()
       buf - preallocated String buffer to add the value to
       interval - the interval type (for instance YEAR_MONTH)
       expression - the value in the lowest entity
@@ -347,9 +291,9 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
 */
 
 int
-event_reconstruct_interval_expression(String *buf,
-                                      interval_type interval,
-                                      longlong expression)
+Events::reconstruct_interval_expression(String *buf,
+                                                  interval_type interval,
+                                                  longlong expression)
 {
   ulonglong expr= expression;
   char tmp_buff[128], *end;
@@ -466,19 +410,20 @@ event_reconstruct_interval_expression(String *buf,
   Open mysql.event table for read
 
   SYNOPSIS
-    evex_open_event_table_for_read()
+    Events::open_event_table()
       thd         Thread context
       lock_type   How to lock the table
       table       The table pointer
 
-  RETURN
+  RETURN VALUE
     1   Cannot lock table
     2   The table is corrupted - different number of fields
     0   OK
 */
 
 int
-evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
+Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
+                                   TABLE **table)
 {
   TABLE_LIST tables;
   DBUG_ENTER("open_proc_table");
@@ -491,7 +436,8 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table)
   if (simple_open_n_lock_tables(thd, &tables))
     DBUG_RETURN(1);
   
-  if (table_check_intact(tables.table, EVEX_FIELD_COUNT, event_table_fields,
+  if (table_check_intact(tables.table, Events::FIELD_COUNT,
+                         event_table_fields,
                          &mysql_event_last_create_time,
                          ER_CANNOT_LOAD_FROM_TABLE))
   {
@@ -558,50 +504,56 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
     'db' and 'name' and the first key is the primary key over the
     same fields.
   */
-  if (dbname.length > table->field[EVEX_FIELD_DB]->field_length ||
-      ev_name.length > table->field[EVEX_FIELD_NAME]->field_length ||
-      user_name.length > table->field[EVEX_FIELD_DEFINER]->field_length)
+  if (dbname.length > table->field[Events::FIELD_DB]->field_length ||
+      ev_name.length > table->field[Events::FIELD_NAME]->field_length ||
+      user_name.length > table->field[Events::FIELD_DEFINER]->field_length)
       
     DBUG_RETURN(EVEX_KEY_NOT_FOUND);
 
-  table->field[EVEX_FIELD_DB]->store(dbname.str, dbname.length, &my_charset_bin);
-  table->field[EVEX_FIELD_NAME]->store(ev_name.str, ev_name.length,
-                                       &my_charset_bin);
-  table->field[EVEX_FIELD_DEFINER]->store(user_name.str, user_name.length,
-                                          &my_charset_bin);
+  table->field[Events::FIELD_DB]->store(dbname.str, dbname.length,
+                                                  &my_charset_bin);
+  table->field[Events::FIELD_NAME]->store(ev_name.str, ev_name.length,
+                                                    &my_charset_bin);
+  table->field[Events::FIELD_DEFINER]->store(user_name.str,
+                                                       user_name.length,
+                                                       &my_charset_bin);
 
   key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
 
   if (table->file->index_read_idx(table->record[0], 0, key,
                                  table->key_info->key_length,HA_READ_KEY_EXACT))
+  {
+    DBUG_PRINT("info", ("Row not fonud"));
     DBUG_RETURN(EVEX_KEY_NOT_FOUND);
+  }
 
+  DBUG_PRINT("info", ("Row found!"));
   DBUG_RETURN(0);
 }
 
 
 /*
-   Puts some data common to CREATE and ALTER EVENT into a row.
+  Puts some data common to CREATE and ALTER EVENT into a row.
 
-   SYNOPSIS
-     evex_fill_row()
-       thd    THD
-       table  the row to fill out
-       et     Event's data
+  SYNOPSIS
+    evex_fill_row()
+      thd    THD
+      table  the row to fill out
+      et     Event's data
 
-   Returns
-     0 - ok
-     EVEX_GENERAL_ERROR    - bad data
-     EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
+  RETURN VALUE
+    0 - OK
+    EVEX_GENERAL_ERROR    - bad data
+    EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
 
-   DESCRIPTION 
-     Used both when an event is created and when it is altered.
+  DESCRIPTION 
+    Used both when an event is created and when it is altered.
 */
 
 static int
 evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
 {
-  enum evex_table_field field_num;
+  enum Events::enum_table_field field_num;
 
   DBUG_ENTER("evex_fill_row");
 
@@ -609,19 +561,20 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
   DBUG_PRINT("info", ("name  =[%s]", et->name.str));
   DBUG_PRINT("info", ("body  =[%s]", et->body.str));
 
-  if (table->field[field_num= EVEX_FIELD_DB]->
+  if (table->field[field_num= Events::FIELD_DB]->
                   store(et->dbname.str, et->dbname.length, system_charset_info))
     goto trunc_err;
 
-  if (table->field[field_num= EVEX_FIELD_NAME]->
+  if (table->field[field_num= Events::FIELD_NAME]->
                   store(et->name.str, et->name.length, system_charset_info))
     goto trunc_err;
 
-  /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() */
-  table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion,
-                                                true);
+  /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
+  table->field[Events::FIELD_ON_COMPLETION]->
+                                       store((longlong)et->on_completion, true);
 
-  table->field[EVEX_FIELD_STATUS]->store((longlong)et->status, true);
+  table->field[Events::FIELD_STATUS]->
+                                       store((longlong)et->status, true);
 
   /*
     Change the SQL_MODE only if body was present in an ALTER EVENT and of course
@@ -629,53 +582,54 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
   */ 
   if (et->body.str)
   {
-    table->field[EVEX_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode,
-                                             true);
+    table->field[Events::FIELD_SQL_MODE]->
+                               store((longlong)thd->variables.sql_mode, true);
 
-    if (table->field[field_num= EVEX_FIELD_BODY]->
+    if (table->field[field_num= Events::FIELD_BODY]->
                      store(et->body.str, et->body.length, system_charset_info))
       goto trunc_err;
   }
 
   if (et->expression)
   {
-    table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull();
-    table->field[EVEX_FIELD_INTERVAL_EXPR]->store((longlong)et->expression,true);
+    table->field[Events::FIELD_INTERVAL_EXPR]->set_notnull();
+    table->field[Events::FIELD_INTERVAL_EXPR]->
+                                          store((longlong)et->expression, true);
 
-    table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_notnull();
+    table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_notnull();
     /*
       In the enum (C) intervals start from 0 but in mysql enum valid values start
       from 1. Thus +1 offset is needed!
     */
-    table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1,
-                                                       true);
+    table->field[Events::FIELD_TRANSIENT_INTERVAL]->
+                                         store((longlong)et->interval+1, true);
 
-    table->field[EVEX_FIELD_EXECUTE_AT]->set_null();
+    table->field[Events::FIELD_EXECUTE_AT]->set_null();
 
     if (!et->starts_null)
     {
-      table->field[EVEX_FIELD_STARTS]->set_notnull();
-      table->field[EVEX_FIELD_STARTS]->
+      table->field[Events::FIELD_STARTS]->set_notnull();
+      table->field[Events::FIELD_STARTS]->
                             store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
     }	   
 
     if (!et->ends_null)
     {
-      table->field[EVEX_FIELD_ENDS]->set_notnull();
-      table->field[EVEX_FIELD_ENDS]->
+      table->field[Events::FIELD_ENDS]->set_notnull();
+      table->field[Events::FIELD_ENDS]->
                             store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
     }
   }
   else if (et->execute_at.year)
   {
-    table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null();
-    table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
-    table->field[EVEX_FIELD_STARTS]->set_null();
-    table->field[EVEX_FIELD_ENDS]->set_null();
+    table->field[Events::FIELD_INTERVAL_EXPR]->set_null();
+    table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_null();
+    table->field[Events::FIELD_STARTS]->set_null();
+    table->field[Events::FIELD_ENDS]->set_null();
     
-    table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull();
-    table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at,
-                                                    MYSQL_TIMESTAMP_DATETIME);
+    table->field[Events::FIELD_EXECUTE_AT]->set_notnull();
+    table->field[Events::FIELD_EXECUTE_AT]->
+                        store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
   }
   else
   {
@@ -686,13 +640,12 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
     */
   }
     
-  ((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time();
+  ((Field_timestamp *)table->field[Events::FIELD_MODIFIED])->set_time();
 
   if (et->comment.str)
   {
-    if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str,
-                                                           et->comment.length,
-                                                           system_charset_info))
+    if (table->field[field_num= Events::FIELD_COMMENT]->
+                 store(et->comment.str, et->comment.length, system_charset_info))
       goto trunc_err;
   }
 
@@ -704,28 +657,30 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
 
 
 /*
-   Creates an event in mysql.event
-
-   SYNOPSIS
-     db_create_event()
-       thd             THD
-       et              Event_timed object containing information for the event
-       create_if_not - if an warning should be generated in case event exists
-       rows_affected - how many rows were affected
-
-     Return value
-                        0 - OK
-       EVEX_GENERAL_ERROR - Failure
-   DESCRIPTION 
-     Creates an event. Relies on evex_fill_row which is shared with
-     db_update_event. The name of the event is inside "et".
+  Creates an event in mysql.event
+
+  SYNOPSIS
+    db_create_event()
+      thd             THD
+      et              Event_timed object containing information for the event
+      create_if_not   If an warning should be generated in case event exists
+      rows_affected   How many rows were affected
+
+  RETURN VALUE
+                     0 - OK
+    EVEX_GENERAL_ERROR - Failure
+
+  DESCRIPTION 
+    Creates an event. Relies on evex_fill_row which is shared with
+    db_update_event. The name of the event is inside "et".
 */
 
-static int
+int
 db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
                 uint *rows_affected)
 {
   int ret= 0;
+  CHARSET_INFO *scs= system_charset_info;
   TABLE *table;
   char olddb[128];
   bool dbchanged= false;
@@ -734,7 +689,7 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
 
   *rows_affected= 0;
   DBUG_PRINT("info", ("open mysql.event for update"));
-  if (evex_open_event_table(thd, TL_WRITE, &table))
+  if (Events::open_event_table(thd, TL_WRITE, &table))
   {
     my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
     goto err;
@@ -778,7 +733,7 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
     goto err;
   }
 
-  if (et->body.length > table->field[EVEX_FIELD_BODY]->field_length)
+  if (et->body.length > table->field[Events::FIELD_BODY]->field_length)
   {
     my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
     goto err;
@@ -791,15 +746,14 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
     goto err;
   }
 
-  if ((ret=table->field[EVEX_FIELD_DEFINER]->store(et->definer.str,
-                                                   et->definer.length,
-                                                   system_charset_info)))
+  if ((ret=table->field[Events::FIELD_DEFINER]->
+                               store(et->definer.str, et->definer.length, scs)))
   {
     my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
     goto err;
   }
 
-  ((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
+  ((Field_timestamp *)table->field[Events::FIELD_CREATED])->set_time();
 
   /*
     evex_fill_row() calls my_error() in case of error so no need to
@@ -819,8 +773,8 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
   {
     thd->clear_error();
     /* Such a statement can always go directly to binlog, no trans cache */
-    thd->binlog_query(THD::MYSQL_QUERY_TYPE,
-                      thd->query, thd->query_length, FALSE, FALSE);
+    thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
+                      FALSE, FALSE);
   }
 #endif
 
@@ -842,17 +796,21 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
 
 
 /*
-   Used to execute ALTER EVENT. Pendant to evex_update_event().
+  Used to execute ALTER EVENT. Pendant to Events::update_event().
 
-   SYNOPSIS
-     db_update_event()
-       thd      THD
-       sp_name  the name of the event to alter
-       et       event's data
+  SYNOPSIS
+    db_update_event()
+      thd      THD
+      sp_name  the name of the event to alter
+      et       event's data
+
+  RETURN VALUE
+    0  OK
+    EVEX_GENERAL_ERROR  Error occured (my_error() called)
 
-   NOTES
-     sp_name is passed since this is the name of the event to
-     alter in case of RENAME TO.
+  NOTES
+    sp_name is passed since this is the name of the event to
+    alter in case of RENAME TO.
 */
 
 static int
@@ -863,12 +821,12 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
   DBUG_ENTER("db_update_event");
   DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
   DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
-  DBUG_PRINT("enter", ("user: %.*s", et->name.length, et->name.str));
+  DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
   if (new_name)
     DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
                                             new_name->m_name.str));
 
-  if (evex_open_event_table(thd, TL_WRITE, &table))
+  if (Events::open_event_table(thd, TL_WRITE, &table))
   {
     my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
     goto err;
@@ -914,9 +872,9 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
 
   if (new_name)
   {    
-    table->field[EVEX_FIELD_DB]->
+    table->field[Events::FIELD_DB]->
       store(new_name->m_db.str, new_name->m_db.length, system_charset_info);
-    table->field[EVEX_FIELD_NAME]->
+    table->field[Events::FIELD_NAME]->
       store(new_name->m_name.str, new_name->m_name.length, system_charset_info);
   }
 
@@ -938,33 +896,33 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
 
 
 /*
-   Looks for a named event in mysql.event and in case of success returns
-   an object will data loaded from the table.
-
-   SYNOPSIS
-     db_find_event()
-       thd      THD
-       name     the name of the event to find
-       definer  who owns the event
-       ett      event's data if event is found
-       tbl      TABLE object to use when not NULL
-
-   NOTES
-     1) Use sp_name for look up, return in **ett if found
-     2) tbl is not closed at exit
-
-   RETURN
-     0  ok     In this case *ett is set to the event
-     #  error  *ett == 0
+  Looks for a named event in mysql.event and in case of success returns
+  an object will data loaded from the table.
+
+  SYNOPSIS
+    db_find_event()
+      thd      THD
+      name     the name of the event to find
+      definer  who owns the event
+      ett      event's data if event is found
+      tbl      TABLE object to use when not NULL
+
+  NOTES
+    1) Use sp_name for look up, return in **ett if found
+    2) tbl is not closed at exit
+
+  RETURN VALUE
+    0  ok     In this case *ett is set to the event
+    #  error  *ett == 0
 */
 
-static int
+int
 db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
               TABLE *tbl, MEM_ROOT *root)
 {
   TABLE *table;
   int ret;
-  Event_timed *et= 0;
+  Event_timed *et=NULL;
   DBUG_ENTER("db_find_event");
   DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
 
@@ -973,7 +931,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
 
   if (tbl)
     table= tbl;
-  else if (evex_open_event_table(thd, TL_READ, &table))
+  else if (Events::open_event_table(thd, TL_READ, &table))
   {
     my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
     ret= EVEX_GENERAL_ERROR;
@@ -1001,7 +959,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
   }
 
 done:
-  if (ret)
+  if (ret && et)
   {
     delete et;
     et= 0;
@@ -1015,179 +973,43 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
 
 
 /*
-   Looks for a named event in mysql.event and then loads it from 
-   the table, compiles it and insert it into the cache.
-
-   SYNOPSIS
-     evex_load_and_compile_event()
-       thd       THD
-       spn       the name of the event to alter
-       definer   who is the owner
-       use_lock  whether to obtain a lock on LOCK_event_arrays or not
-
-   RETURN VALUE
-       0   - OK
-       < 0 - error (in this case underlying functions call my_error()).
-*/
-
-static int
-evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
-                            bool use_lock)
-{
-  int ret= 0;
-  MEM_ROOT *tmp_mem_root;
-  Event_timed *ett;
-  Open_tables_state backup;
-
-  DBUG_ENTER("db_load_and_compile_event");
-  DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
-
-  tmp_mem_root= thd->mem_root;
-  thd->mem_root= &evex_mem_root;
-
-  thd->reset_n_backup_open_tables_state(&backup);
-  /* no need to use my_error() here because db_find_event() has done it */
-  ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
-  thd->restore_backup_open_tables_state(&backup);
-  if (ret)
-    goto done;
-  
-  ett->compute_next_execution_time();
-  if (use_lock)
-    VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
-  evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) ett);
-
-  /*
-    There is a copy in the array which we don't need. sphead won't be
-    destroyed.
-  */
-
-  if (use_lock)
-    VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
-done:
-  if (thd->mem_root != tmp_mem_root)
-    thd->mem_root= tmp_mem_root;  
-
-  DBUG_RETURN(ret);
-}
-
-
-/*
-  Removes from queue in memory the event which is identified by the tupple
-  (db, name).
-
-   SYNOPSIS
-     evex_remove_from_cache()
-  
-       db       - db name
-       name     - event name
-       use_lock - whether to lock the mutex LOCK_event_arrays or not in case it
-                  has been already locked outside
-       is_drop  - if an event is currently being executed then we can also delete
-                  the Event_timed instance, so we alarm the event that it should
-                  drop itself if this parameter is set to TRUE. It's false on
-                  ALTER EVENT.
-
-   RETURNS
-     0  OK (always)
-*/
-
-static int
-evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
-                       bool is_drop)
-{
-  //ToDo : Add definer to the tuple (db, name) to become triple
-  uint i;
-  int ret= 0;
-
-  DBUG_ENTER("evex_remove_from_cache");
-  /*
-    It is possible that 2 (or 1) pass(es) won't find the event in memory.
-    The reason is that DISABLED events are not cached.
-  */
-
-  if (use_lock)
-    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*);
-    DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str,
-                        et->name.str));
-    if (!sortcmp_lex_string(*name, et->name, system_charset_info) &&
-        !sortcmp_lex_string(*db, et->dbname, system_charset_info))
-    {
-      if (et->can_spawn_now())
-      {
-        DBUG_PRINT("evex_remove_from_cache", ("not running - free and delete"));
-        et->free_sp();
-        delete et;
-      }
-      else
-      {
-        DBUG_PRINT("evex_remove_from_cache",
-               ("running.defer mem free. is_drop=%d", is_drop));
-        et->flags|= EVENT_EXEC_NO_MORE;
-        et->dropped= is_drop;
-      }
-      DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
-      evex_queue_delete_element(&EVEX_EQ_NAME, i);
-      /* ok, we have cleaned */
-      ret= 0;
-      goto done;
-    }
-  }
-
-done:
-  if (use_lock)
-    VOID(pthread_mutex_unlock(&LOCK_event_arrays));
+  The function exported to the world for creating of events.
 
-  DBUG_RETURN(ret);
-}
+  SYNOPSIS
+    Events::create_event()
+      thd            THD
+      et             event's data
+      create_options Options specified when in the query. We are
+                     interested whether there is IF NOT EXISTS
+      rows_affected  How many rows were affected
 
+  RETURN VALUE
+    0   OK
+    !0  Error
 
-/*
-   The function exported to the world for creating of events.
-
-   SYNOPSIS
-     evex_create_event()
-       thd            THD
-       et             event's data
-       create_options Options specified when in the query. We are
-                      interested whether there is IF NOT EXISTS
-       rows_affected  How many rows were affected
-
-   NOTES
-     - in case there is an event with the same name (db) and 
-       IF NOT EXISTS is specified, an warning is put into the W stack.
+  NOTES
+    - in case there is an event with the same name (db) and 
+      IF NOT EXISTS is specified, an warning is put into the W stack.
 */
 
 int
-evex_create_event(THD *thd, Event_timed *et, uint create_options,
-                  uint *rows_affected)
+Events::create_event(THD *thd, Event_timed *et, uint create_options,
+                               uint *rows_affected)
 {
-  int ret = 0;
+  int ret;
 
-  DBUG_ENTER("evex_create_event");
+  DBUG_ENTER("Events::create_event");
   DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
                 et->name.str, create_options));
 
-  if ((ret = db_create_event(thd, et,
+  if (!(ret = db_create_event(thd, et,
                              create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
                              rows_affected)))
-    goto done;
-
-  VOID(pthread_mutex_lock(&LOCK_evex_running));
-  if (evex_is_running && et->status == MYSQL_EVENT_ENABLED)
   {
-    sp_name spn(et->dbname, et->name);
-    ret= evex_load_and_compile_event(thd, &spn, et->definer, true);
+    Event_scheduler *scheduler= Event_scheduler::get_instance();
+    if (scheduler->initialized() && (ret= scheduler->add_event(thd, et, true)))
+      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
   }
-  VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
   /* No need to close the table, it will be closed in sql_parse::do_command */
 
   DBUG_RETURN(ret);
@@ -1195,73 +1017,63 @@ evex_create_event(THD *thd, Event_timed *et, uint create_options,
 
 
 /*
-   The function exported to the world for alteration of events.
-
-   SYNOPSIS
-     evex_update_event()
-       thd        THD
-       et         event's data
-       new_name   set in case of RENAME TO.    
-
-   NOTES
-     et contains data about dbname and event name. 
-     new_name is the new name of the event, if not null (this means
-     that RENAME TO was specified in the query)
+  The function exported to the world for alteration of events.
+
+  SYNOPSIS
+    Events::update_event()
+      thd        THD
+      et         event's data
+      new_name   set in case of RENAME TO.    
+
+  RETURN VALUE
+    0   OK
+    !0  Error
+
+  NOTES
+    et contains data about dbname and event name. 
+    new_name is the new name of the event, if not null (this means
+    that RENAME TO was specified in the query)
 */
 
 int
-evex_update_event(THD *thd, Event_timed *et, sp_name *new_name,
-                  uint *rows_affected)
+Events::update_event(THD *thd, Event_timed *et, sp_name *new_name,
+                               uint *rows_affected)
 {
   int ret;
-  bool need_second_pass= true;
 
-  DBUG_ENTER("evex_update_event");
+  DBUG_ENTER("Events::update_event");
   DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
-
   /*
     db_update_event() opens & closes the table to prevent
     crash later in the code when loading and compiling the new definition.
     Also on error conditions my_error() is called so no need to handle here
   */
-  if ((ret= db_update_event(thd, et, new_name)))
-    goto done;
-
-  VOID(pthread_mutex_lock(&LOCK_evex_running));
-  if (!evex_is_running)
-    UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_evex_running, done);
-
-  VOID(pthread_mutex_lock(&LOCK_event_arrays));
-  evex_remove_from_cache(&et->dbname, &et->name, false, false);
-  if (et->status == MYSQL_EVENT_ENABLED)
+  if (!(ret= db_update_event(thd, et, new_name)))
   {
-    if (new_name)
-      ret= evex_load_and_compile_event(thd, new_name, et->definer, false);
-    else
-    {
-      sp_name spn(et->dbname, et->name);
-      ret= evex_load_and_compile_event(thd, &spn, et->definer, false);
-    }
-    if (ret == EVEX_COMPILE_ERROR)
-      my_error(ER_EVENT_COMPILE_ERROR, MYF(0));
+    Event_scheduler *scheduler= Event_scheduler::get_instance();
+    if (scheduler->initialized() &&
+        (ret= scheduler->replace_event(thd, et,
+                                       new_name? &new_name->m_db: NULL,
+                                       new_name? &new_name->m_name: NULL)))
+      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
   }
-  VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-  VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
   DBUG_RETURN(ret);
 }
 
 
 /*
- Drops an event
-
- SYNOPSIS
-   db_drop_event()
-     thd             THD
-     et              event's name
-     drop_if_exists  if set and the event not existing => warning onto the stack
-     rows_affected   affected number of rows is returned heres
+  Drops an event
+
+  SYNOPSIS
+    db_drop_event()
+      thd             THD
+      et              event's name
+      drop_if_exists  if set and the event not existing => warning onto the stack
+      rows_affected   affected number of rows is returned heres
+
+  RETURN VALUE
+    0   OK
+    !0  Error (my_error() called)
 */
 
 int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
@@ -1275,7 +1087,7 @@ int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
   ret= EVEX_OPEN_TABLE_FAILED;
 
   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))
   {
     my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
     goto done;
@@ -1315,58 +1127,54 @@ int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
 
 
 /*
- Drops an event
-
- SYNOPSIS
-   evex_drop_event()
-     thd             THD
-     et              event's name
-     drop_if_exists  if set and the event not existing => warning onto the stack
-     rows_affected   affected number of rows is returned heres
-          
+  Drops an event
+
+  SYNOPSIS
+    Events::drop_event()
+      thd             THD
+      et              event's name
+      drop_if_exists  if set and the event not existing => warning onto the stack
+      rows_affected   affected number of rows is returned heres
+
+  RETURN VALUE
+     0  OK
+    !0  Error (reported)
 */
 
 int
-evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
-                uint *rows_affected)
+Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
+                             uint *rows_affected)
 {
-  int ret= 0;
-
-  DBUG_ENTER("evex_drop_event");
-
-
-  VOID(pthread_mutex_lock(&LOCK_evex_running));
-  if (evex_is_running)
-    ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
-  VOID(pthread_mutex_unlock(&LOCK_evex_running));
+  int ret;
 
-  if (ret == 1)
-    ret= 0;
-  else if (ret == 0)   
-    ret= db_drop_event(thd, et, drop_if_exists, rows_affected);
-  else
-    my_error(ER_UNKNOWN_ERROR, MYF(0));
+  DBUG_ENTER("Events::drop_event");
+  if (!(ret= db_drop_event(thd, et, drop_if_exists, rows_affected)))
+  {
+    Event_scheduler *scheduler= Event_scheduler::get_instance();
+    if (scheduler->initialized() && (ret= scheduler->drop_event(thd, et)))
+      my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+  }
 
   DBUG_RETURN(ret);
 }
 
 
 /*
-   SHOW CREATE EVENT
+  SHOW CREATE EVENT
 
-   SYNOPSIS
-     evex_show_create_event()
-       thd        THD
-       spn        the name of the event (db, name)
-       definer    the definer of the event
+  SYNOPSIS
+    Events::show_create_event()
+      thd        THD
+      spn        the name of the event (db, name)
+      definer    the definer of the event
 
-   RETURNS
-     0  -  OK
-     1  - Error during writing to the wire
+  RETURN VALUE
+    0  OK
+    1  Error during writing to the wire
 */
 
 int
-evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
+Events::show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
 {
   int ret;
   Event_timed *et= NULL;
@@ -1379,7 +1187,7 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
   ret= db_find_event(thd, spn, &definer, &et, NULL, thd->mem_root);
   thd->restore_backup_open_tables_state(&backup);
 
-  if (et)
+  if (!ret)
   {
     Protocol *protocol= thd->protocol;
     char show_str_buf[768];
@@ -1389,12 +1197,10 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
     ulong sql_mode_len=0;
 
     show_str.length(0);
+    show_str.set_charset(system_charset_info);
 
     if (et->get_create_event(thd, &show_str))
-    {
-      delete et;
-      DBUG_RETURN(1);
-    }
+      goto err;
 
     field_list.push_back(new Item_empty_string("Event", NAME_LEN));
 
@@ -1408,201 +1214,216 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
                                                show_str.length()));
     if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
                                            Protocol::SEND_EOF))
-    {
-      delete et;
-      DBUG_RETURN(1);
-    }
+      goto err;
+
     protocol->prepare_for_resend();
     protocol->store(et->name.str, et->name.length, system_charset_info);
 
     protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
 
-    protocol->store(show_str.ptr(), show_str.length(), system_charset_info);
+    protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
     ret= protocol->write();
     send_eof(thd);
-    delete et;
   }
-
+  delete et;
   DBUG_RETURN(ret);
+err:
+  delete et;
+  DBUG_RETURN(1);  
 }
 
 
 /*
-  evex_drop_db_events - Drops all events in the selected database
+  Drops all events from a schema
 
-  thd  - Thread
-  db   - ASCIIZ the name of the database
-  
-  Returns:
-    0  - OK
-    1  - Failed to delete a specific row
-    2  - Got NULL while reading db name from a row
-
-  Note:
-    The algo is the following
-    1. Go through the in-memory cache, if the scheduler is working
-       and for every event whose dbname matches the database we drop
-       check whether is currently in execution:
-       - Event_timed::can_spawn() returns true -> the event is not
-         being executed in a child thread. The reason not to use
-         Event_timed::is_running() is that the latter shows only if
-         it is being executed, which is 99% of the time in the thread
-         but there are some initiliazations before and after the
-         anonymous SP is being called. So if we delete in this moment
-         -=> *boom*, so we have to check whether the thread has been
-         spawned and can_spawn() is the right method.
-       - Event_timed::can_spawn() returns false -> being runned ATM
-         just set the flags so it should drop itself.
+  SYNOPSIS
+    Events::drop_schema_events()
+      thd  Thread
+      db   ASCIIZ schema name
+
+  RETURN VALUE
+    0   OK
+    !0  Error
 */
 
 int
-evex_drop_db_events(THD *thd, char *db)
+Events::drop_schema_events(THD *thd, char *db)
 {
-  TABLE *table;
-  READ_RECORD read_record_info;
   int ret= 0;
-  uint i;
   LEX_STRING db_lex= {db, strlen(db)};
   
   DBUG_ENTER("evex_drop_db_events");  
-  DBUG_PRINT("info",("dropping events from %s", db));
+  DBUG_PRINT("enter", ("dropping events from %s", db));
 
-  VOID(pthread_mutex_lock(&LOCK_event_arrays));
+  Event_scheduler *scheduler= Event_scheduler::get_instance();
+  if (scheduler->initialized())
+    ret= scheduler->drop_schema_events(thd, &db_lex);
+  else
+    ret= db_drop_events_from_table(thd, &db_lex);
 
-  if ((ret= evex_open_event_table(thd, TL_WRITE, &table)))
-  {
-    sql_print_error("Table mysql.event is damaged.");
-    VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-    DBUG_RETURN(SP_OPEN_TABLE_FAILED);
-  }
+  DBUG_RETURN(ret);
+}
 
-  DBUG_PRINT("info",("%d elements in the queue",
-             evex_queue_num_elements(EVEX_EQ_NAME)));
-  VOID(pthread_mutex_lock(&LOCK_evex_running));
-  if (!evex_is_running)
-    goto skip_memory;
 
-  for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
-  {
-    Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
-    if (sortcmp_lex_string(et->dbname, db_lex, system_charset_info))
-      continue;
+/*
+  Drops all events in the selected database, from mysql.event.
 
-    if (et->can_spawn_now_n_lock(thd))
-    {
-      DBUG_PRINT("info",("event %s not running - direct delete", et->name.str));
-      if (!(ret= evex_db_find_event_aux(thd, et, table)))
-      {
-        DBUG_PRINT("info",("event %s found on disk", et->name.str));
-        if ((ret= table->file->ha_delete_row(table->record[0])))
-        {
-          sql_print_error("Error while deleting a row - dropping "
-                          "a database. Skipping the rest.");
-          my_error(ER_EVENT_DROP_FAILED, MYF(0), et->name.str);
-          goto end;
-        }
-        DBUG_PRINT("info",("deleted event [%s] num [%d]. Time to free mem",
-                   et->name.str, i));
-      }
-      else if (ret == EVEX_KEY_NOT_FOUND)
-      {
-        sql_print_error("Expected to find event %s.%s of %s on disk-not there.",
-                        et->dbname.str, et->name.str, et->definer.str);
-      }
-      et->free_sp();
-      delete et;
-      et= 0;
-      /* no need to call et->spawn_unlock because we already cleaned et */
-    }
-    else
-    {
-      DBUG_PRINT("info",("event %s is running. setting exec_no_more and dropped",
-                  et->name.str));
-      et->flags|= EVENT_EXEC_NO_MORE;
-      et->dropped= TRUE;
-    }
-    DBUG_PRINT("info",("%d elements in the queue",
-               evex_queue_num_elements(EVEX_EQ_NAME)));
-    evex_queue_delete_element(&EVEX_EQ_NAME, i);// 0 is top
-    DBUG_PRINT("info",("%d elements in the queue",
-               evex_queue_num_elements(EVEX_EQ_NAME)));
-    /*
-      decrease so we start at the same position, there will be
-      less elements in the queue, it will still be ordered so on
-      next iteration it will be again i the current element or if
-      no more we finish.
-    */
-    --i;
-  }
+  SYNOPSIS
+    evex_drop_db_events_from_table()
+      thd  Thread
+      db   Schema name
 
-skip_memory:
-  /*
-   The reasoning behind having two loops is the following:
-   If there was only one loop, the table-scan, then for every element which
-   matches, the queue in memory has to be searched to remove the element.
-   While if we go first over the queue and remove what's in there we have only
-   one pass over it and after finishing it, moving to table-scan for the disabled
-   events. This needs quite less time and means quite less locking on
-   LOCK_event_arrays.
-  */
-  DBUG_PRINT("info",("Mem-cache checked, now going to db for disabled events"));
+  RETURN VALUE
+     0  OK
+    !0  Error from ha_delete_row
+*/
+
+int
+db_drop_events_from_table(THD *thd, LEX_STRING *db)
+{
+  int ret;
+  TABLE *table;
+  READ_RECORD read_record_info;
+  DBUG_ENTER("db_drop_events_from_table");  
+  DBUG_PRINT("info", ("dropping events from %s", db->str));
+
+  if ((ret= Events::open_event_table(thd, TL_WRITE, &table)))
+  {
+    sql_print_error("Table mysql.event is damaged.");
+    DBUG_RETURN(ret);
+  }
   /* only enabled events are in memory, so we go now and delete the rest */
-  init_read_record(&read_record_info, thd, table ,NULL,1,0);
+  init_read_record(&read_record_info, thd, table, NULL, 1, 0);
   while (!(read_record_info.read_record(&read_record_info)) && !ret)
   {
-    char *et_db;
+    char *et_db= get_field(thd->mem_root,
+                           table->field[Events::FIELD_DB]);
 
-    if ((et_db= get_field(thd->mem_root, table->field[EVEX_FIELD_DB])) == NULL)
-    {
-      ret= 2;
-      break;
-    }
-    
     LEX_STRING et_db_lex= {et_db, strlen(et_db)};
-    if (!sortcmp_lex_string(et_db_lex, db_lex, system_charset_info))
+    DBUG_PRINT("info", ("Current event %s.%s", et_db,
+               get_field(thd->mem_root,
+               table->field[Events::FIELD_NAME])));
+
+    if (!sortcmp_lex_string(et_db_lex, *db, system_charset_info))
     {
-      Event_timed ett;
-      char *ptr;
-      
-      if ((ptr= get_field(thd->mem_root, table->field[EVEX_FIELD_STATUS]))
-           == NullS)
-      {
-        sql_print_error("Error while loading from mysql.event. "
-                        "Table probably corrupted");
-        goto end;
-      }
-      /*
-        When not running nothing is in memory so we have to clean
-        everything.
-        We don't delete EVENT_ENABLED events when the scheduler is running
-        because maybe this is an event which we asked to drop itself when
-        it is finished and it hasn't finished yet, so we don't touch it.
-        It will drop itself. The not running ENABLED events has been already
-        deleted from ha_delete_row() above in the loop over the QUEUE
-        (in case the executor is running).
-        'D' stands for DISABLED, 'E' for ENABLED - it's an enum
-      */
-      if ((evex_is_running && ptr[0] == 'D') || !evex_is_running)
-      {
-        DBUG_PRINT("info", ("Dropping %s.%s", et_db, ett.name.str));
-        if ((ret= table->file->ha_delete_row(table->record[0])))
-        {
-          my_error(ER_EVENT_DROP_FAILED, MYF(0), ett.name.str);
-          goto end;
-        }
-      }
+      DBUG_PRINT("info", ("Dropping"));
+      if ((ret= table->file->ha_delete_row(table->record[0])))
+        my_error(ER_EVENT_DROP_FAILED, MYF(0),
+                 get_field(thd->mem_root,
+                           table->field[Events::FIELD_NAME]));
     }
   }
-  DBUG_PRINT("info",("Disk checked for disabled events. Finishing."));
-
-end:
-  VOID(pthread_mutex_unlock(&LOCK_evex_running));
-  VOID(pthread_mutex_unlock(&LOCK_event_arrays));
   end_read_record(&read_record_info);
-
   thd->version--;   /* Force close to free memory */
 
   close_thread_tables(thd);
 
   DBUG_RETURN(ret);
 }
+
+
+
+/*
+  Inits the scheduler's structures.
+
+  SYNOPSIS
+    Events::init()
+
+  NOTES
+    This function is not synchronized.
+
+  RETURN VALUE
+    0  OK
+    1  Error
+*/
+
+int
+Events::init()
+{
+  int ret= 0;
+  DBUG_ENTER("Events::init");
+
+  /* it should be an assignment! */
+  if (opt_event_scheduler)
+  {
+    Event_scheduler *scheduler= Event_scheduler::get_instance();
+    DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
+    DBUG_RETURN(scheduler->init() || 
+                (opt_event_scheduler == 1? scheduler->start():
+                                           scheduler->start_suspended()));
+  }
+  DBUG_RETURN(0);
+}
+
+
+/*
+  Cleans up scheduler's resources. Called at server shutdown.
+
+  SYNOPSIS
+    Events::shutdown()
+
+  NOTES
+    This function is not synchronized.
+*/
+
+void
+Events::shutdown()
+{
+  DBUG_ENTER("Events::shutdown");
+  Event_scheduler *scheduler= Event_scheduler::get_instance();
+  if (scheduler->initialized())
+  {
+    scheduler->stop();
+    scheduler->destroy();
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Proxy for Event_scheduler::dump_internal_status
+
+  SYNOPSIS
+    Events::dump_internal_status()
+      thd  Thread
+  
+  RETURN VALUE
+    0  OK
+    !0 Error
+*/
+
+int
+Events::dump_internal_status(THD *thd)
+{
+  return Event_scheduler::dump_internal_status(thd);
+}
+
+
+/*
+  Inits Events mutexes
+
+  SYNOPSIS
+    Events::init_mutexes()
+      thd  Thread
+*/
+
+void
+Events::init_mutexes()
+{
+  Event_scheduler::init_mutexes();
+}
+
+
+/*
+  Destroys Events mutexes
+
+  SYNOPSIS
+    Events::destroy_mutexes()
+*/
+
+void
+Events::destroy_mutexes()
+{
+  Event_scheduler::destroy_mutexes();
+}
diff --git a/sql/event.h b/sql/event.h
index 27de8b46e32a7793e023d10d3ba5e597a266271d..40ede7b0c5f0cf0294c5e8018516ed249aae0c97 100644
--- a/sql/event.h
+++ b/sql/event.h
@@ -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_event_status
-{
-  MYSQL_EVENT_ENABLED = 1,
-  MYSQL_EVENT_DISABLED
+  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 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 @@ class Event_timed
 
   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 @@ class Event_timed
     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 @@ class Event_timed
   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 @@ class Event_timed
   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);
-
-  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;  
-  }
+  compile(THD *thd, MEM_ROOT *mem_root);
 
-  /*
-    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);
-
-  int
-  spawn_unlock(THD *thd);
+  bool
+  is_running();
 
   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_ */
diff --git a/sql/event_executor.cc b/sql/event_executor.cc
index 21464dd777bfc9359d7d7b3237af8db183e4f8e1..f236fb47771ae037babf981b1c72c792f82a14e4 100644
--- a/sql/event_executor.cc
+++ b/sql/event_executor.cc
@@ -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);
-}
diff --git a/sql/event_priv.h b/sql/event_priv.h
index 6b23136847e9dd837238f6e252c1055a45d2e087..b0a18377aceaf60dd3c21cba9a9ed94ed0a2bfef 100644
--- a/sql/event_priv.h
+++ b/sql/event_priv.h
@@ -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,
-                uint *rows_affected);
-
+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);
 
-#define EXEC_QUEUE_QUEUE_NAME executing_queue
-#define EXEC_QUEUE_DARR_NAME evex_executing_queue
+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 EVEX_QUEUE_TYPE QUEUE
-#define EVEX_PTOQEL byte *
+int
+sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
 
-#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);
+/* 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);
 
-void
-evex_queue_init(EVEX_QUEUE_TYPE *queue);
+/* Compares the whole identifier*/
+bool
+event_timed_identifier_equal(Event_timed *a, Event_timed *b);
 
-#define evex_queue_num_elements(queue) queue.elements
 
+bool
+change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
+                        LEX_STRING db, Security_context *s_ctx,
+                        Security_context **backup);
 
-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;
+void
+restore_security_context(THD *thd, Security_context *backup);
 
 #endif /* _EVENT_PRIV_H_ */
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..784c87c0e8ef2e26cb819720b3f639011e781256
--- /dev/null
+++ b/sql/event_scheduler.cc
@@ -0,0 +1,2411 @@
+/* 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 */
+
+#include "event_priv.h"
+#include "event.h"
+#include "event_scheduler.h"
+#include "sp_head.h"
+
+/*
+  ToDo:
+  1. Talk to Alik to get a check for configure.in for my_time_t and time_t
+  2. Look at guardian.h|cc to see its life cycle, has similarities.
+*/
+
+
+/*
+  The scheduler is implemented as class Event_scheduler. Only one instance is
+  kept during the runtime of the server, by implementing the Singleton DP.
+  Object instance is always there because the memory is allocated statically
+  and initialized when the OS loader loads mysqld. This initialization is
+  bare. Extended initialization is done during the call to
+  Event_scheduler::init() in Events::init(). The reason for that late initialization
+  is that some subsystems needed to boot the Scheduler are not available at
+  earlier stages of the mysqld boot procedure. Events::init() is called in
+  mysqld.cc . If the mysqld is started with --event-scheduler=0 then
+  no initialization takes place and the scheduler is unavailable during this
+  server run. The server should be started with --event-scheduler=1 to have
+  the scheduler initialized and able to execute jobs. This starting alwa
+  s implies that the jobs execution will start immediately. If the server
+  is started with --event-scheduler=2 then the scheduler is started in suspended
+  state. Default state, if --event-scheduler is not specified is 2.
+
+  The scheduler only manages execution of the events. Their creation,
+  alteration and deletion is delegated to other routines found in event.cc .
+  These routines interact with the scheduler :
+  - CREATE EVENT -> Event_scheduler::add_event()
+  - ALTER EVENT  -> Event_scheduler::replace_event()
+  - DROP EVENT   -> Event_scheduler::drop_event()
+
+  There is one mutex in the single Event_scheduler object which controls
+  the simultaneous access to the objects invariants. Using one lock makes
+  it easy to follow the workflow. This mutex is LOCK_scheduler_data. It is
+  initialized in Event_scheduler::init(). Which in turn is called by the
+  Facade class Events in event.cc, coming from init_thread_environment() from
+  mysqld.cc -> no concurrency at this point. It's destroyed in
+  Events::destroy_mutexes() called from clean_up_mutexes() in mysqld.cc .
+
+  The full initialization is done in Event_scheduler::init() called from 
+  Events::init(). It's done before any requests coming in, so this is a
+  guarantee for not having concurrency.
+
+  The scheduler is started with Event_scheduler::start() and stopped with
+  Event_scheduler::stop(). When the scheduler starts it loads all events
+  from mysql.event table. Unfortunately, there is a race condition between
+  the event disk management functions and the scheduler ones
+  (add/replace/drop_event & load_events_from_db()), because the operations
+  do not happen under one global lock but the disk operations are guarded
+  by the MYISAM lock on mysql.event. In the same time, the queue operations
+  are guarded by  LOCK_scheduler_data. If the scheduler is start()-ed during
+  server startup and stopped()-ed during server shutdown (in Events::shutdown()
+  called by kill_server() in mysqld.cc) these races does not exist.
+
+  Since the user may want to temporarily inhibit execution of events the
+  scheduler can be suspended and then it can be forced to resume its
+  operations. The API call to perform these is
+  Event_scheduler::suspend_or_resume(enum enum_suspend_or_resume) .
+  When the scheduler is suspended the main scheduler thread, which ATM
+  happens to have thread_id 1, locks on a condition COND_suspend_or_resume.
+  When this is signal is sent for the reverse operation the main scheduler
+  loops continues to roll and execute events.
+
+  When the scheduler is suspended all add/replace/drop_event() operations
+  work as expected and the modify the queue but no events execution takes
+  place.
+
+  In contrast to the previous scheduler implementation, found in
+  event_executor.cc, the start, shutdown, suspend and resume are synchronous
+  operations. As a whole all operations are synchronized and no busy waits
+  are used except in stop_all_running_events(), which waits until all
+  running event worker threads have finished. It would have been nice to
+  use a conditional on which this method will wait and the last thread to
+  finish would signal it but this implies subclassing THD.
+
+  The scheduler does not keep a counter of how many event worker threads are
+  running, at any specific moment, because this will copy functionality
+  already existing in the server. Namely, all THDs are registered in the
+  global `threads` array. THD has member variable system_thread which
+  identifies the type of thread. Connection threads being NON_SYSTEM_THREAD,
+  all other have their enum value. Important for the scheduler are 
+  SYSTEM_THREAD_EVENT_SCHEDULER and SYSTEM_THREAD_EVENT_WORKER.
+
+  Class THD subclasses class ilink, which is the linked list of all threads.
+  When a THD instance is destroyed it's being removed from threads, thus
+  no manual intervention is needed. On the contrary registering is manual
+  with threads.append() . Traversing the threads array every time a subclass
+  of THD, for instance if we would have had THD_scheduler_worker to see
+  how many events we have and whether the scheduler is shutting down will
+  take much time and lead to a deadlock. stop_all_running_events() is called
+  under LOCK_scheduler_data. If the THD_scheduler_worker was aware of
+  the single Event_scheduler instance it will try to check
+  Event_scheduler::state but for this it would need to acquire 
+  LOCK_scheduler_data => deadlock. Thus stop_all_running_events() uses a
+  busy wait.
+
+  DROP DATABASE DDL should drop all events defined in a specific schema.
+  DROP USER also should drop all events who has as definer the user being
+  dropped (this one is not addressed at the moment but a hook exists). For
+  this specific needs Event_scheduler::drop_matching_events() is
+  implemented. Which expects a callback to be applied on every object in
+  the queue. Thus events that match specific schema or user, will be
+  removed from the queue. The exposed interface is :
+  - Event_scheduler::drop_schema_events()
+  - Event_scheduler::drop_user_events()
+
+  This bulk dropping happens under LOCK_scheduler_data, thus no two or
+  more threads can execute it in parallel. However, DROP DATABASE is also
+  synchronized, currently, in the server thus this does not impact the 
+  overall performance. In addition, DROP DATABASE is not that often
+  executed DDL.
+
+  Though the interface to the scheduler is only through the public methods
+  of class Event_scheduler, there are currently few functions which are
+  used during its operations. Namely :
+  - static evex_print_warnings()
+    After every event execution all errors/warnings are dumped, so the user
+    can see in case of a problem what the problem was.
+
+  - static init_event_thread()
+    This function is both used by event_scheduler_thread() and
+    event_worker_thread(). It initializes the THD structure. The
+    initialization looks pretty similar to the one in slave.cc done for the
+    replication threads. However, though the similarities it cannot be
+    factored out to have one routine.
+
+  - static event_scheduler_thread()
+    Because our way to register functions to be used by the threading library
+    does not allow usage of static methods this function is used to start the
+    scheduler in it. It does THD initialization and then calls
+    Event_scheduler::run(). 
+
+  - static event_worker_thread()
+    With already stated the reason for not being able to use methods, this
+    function executes the worker threads.
+
+  The execution of events is, to some extent, synchronized to inhibit race
+  conditions when Event_timed::thread_id is being updated with the thread_id of
+  the THD in which the event is being executed. The thread_id is in the
+  Event_timed object because we need to be able to kill quickly a specific
+  event during ALTER/DROP EVENT without traversing the global `threads` array.
+  However, this makes the scheduler's code more complicated. The event worker
+  thread is started by Event_timed::spawn_now(), which in turn calls
+  pthread_create(). The thread_id which will be associated in init_event_thread
+  is not known in advance thus the registering takes place in
+  event_worker_thread(). This registering has to be synchronized under
+  LOCK_scheduler_data, so no kill_event() on a object in
+  replace_event/drop_event/drop_matching_events() could take place.
+  
+  This synchronization is done through class Worker_thread_param that is
+  local to this file. Event_scheduler::execute_top() is called under
+  LOCK_scheduler_data. This method :
+  1. Creates an instance of Worker_thread_param on the stack
+  2. Locks Worker_thread_param::LOCK_started
+  3. Calls Event_timed::spawn_now() which in turn creates a new thread.
+  4. Locks on Worker_thread_param::COND_started_or_stopped and waits till the
+     worker thread send signal. The code is spurious wake-up safe because
+     Worker_thread_param::started is checked.
+  5. The worker thread initializes its THD, then sets Event_timed::thread_id,
+     sets Worker_thread_param::started to TRUE and sends back
+     Worker_thread_param::COND_started. From this moment on, the event
+     is being executed and could be killed by using Event_timed::thread_id.
+     When Event_timed::spawn_thread_finish() is called in the worker thread,
+     it sets thread_id to 0. From this moment on, the worker thread should not
+     touch the Event_timed instance.
+
+
+  The life-cycle of the server is a FSA.
+  enum enum_state Event_scheduler::state keeps the state of the scheduler.
+
+  The states are:
+
+  |---UNINITIALIZED
+  |                                         
+  |                                      |------------------> IN_SHUTDOWN   
+  --> INITIALIZED -> COMMENCING ---> RUNNING ----------|
+       ^ ^               |            | ^              |
+       | |- CANTSTART <--|            | |- SUSPENDED <-|
+       |______________________________|
+
+    - UNINITIALIZED :The object is created and only the mutex is initialized
+    - INITIALIZED   :All member variables are initialized
+    - COMMENCING    :The scheduler is starting, no other attempt to start 
+                     should succeed before the state is back to INITIALIZED.
+    - CANTSTART     :Set by the ::run() method in case it can't start for some
+                     reason. In this case the connection thread that tries to
+                     start the scheduler sees that some error has occurred and
+                     returns an error to the user. Finally, the connection
+                     thread sets the state to INITIALIZED, so further attempts
+                     to start the scheduler could be made.
+    - RUNNING       :The scheduler is running. New events could be added,
+                     dropped, altered. The scheduler could be stopped.
+    - SUSPENDED     :Like RUNNING but execution of events does not take place.
+                     Operations on the memory queue are possible.
+    - IN_SHUTDOWN   :The scheduler is shutting down, due to request by setting
+                     the global event_scheduler to 0/FALSE, or because of a
+                     KILL command sent by a user to the master thread.
+
+  In every method the macros LOCK_SCHEDULER_DATA() and UNLOCK_SCHEDULER_DATA()
+  are used for (un)locking purposes.  They are used to save the programmer
+  from typing everytime
+  lock_data(__FUNCTION__, __LINE__); 
+  All locking goes through Event_scheduler::lock_data() and ::unlock_data().
+  These two functions then record in variables where for last time
+  LOCK_scheduler_data was locked and unlocked (two different variables). In
+  multithreaded environment, in some cases they make no sense but are useful for
+  inspecting deadlocks without having the server debug log turned on and the
+  server is still running.
+
+  The same strategy is used for conditional variables.
+  Event_scheduler::cond_wait() is invoked from all places with parameter
+  an enum enum_cond_vars. In this manner, it's possible to inspect the last
+  on which condition the last call to cond_wait() was waiting. If the server
+  was started with debug trace switched on, the trace file also holds information
+  about conditional variables used.
+*/
+
+
+#define LOCK_SCHEDULER_DATA()   lock_data(__FUNCTION__,__LINE__)
+#define UNLOCK_SCHEDULER_DATA() unlock_data(__FUNCTION__,__LINE__)
+
+
+#ifndef DBUG_OFF
+static
+LEX_STRING states_names[] =
+{
+  {(char*) STRING_WITH_LEN("UNINITIALIZED")},
+  {(char*) STRING_WITH_LEN("INITIALIZED")},
+  {(char*) STRING_WITH_LEN("COMMENCING")},
+  {(char*) STRING_WITH_LEN("CANTSTART")},
+  {(char*) STRING_WITH_LEN("RUNNING")},
+  {(char*) STRING_WITH_LEN("SUSPENDED")},
+  {(char*) STRING_WITH_LEN("IN_SHUTDOWN")}
+};
+#endif
+
+
+Event_scheduler
+Event_scheduler::singleton;
+
+
+const char * const
+Event_scheduler::cond_vars_names[Event_scheduler::COND_LAST] =
+{
+  "new work",
+  "started or stopped",
+  "suspend or resume"
+};
+
+
+class Worker_thread_param
+{
+public:
+  Event_timed *et;
+  pthread_mutex_t LOCK_started;
+  pthread_cond_t COND_started;
+  bool started;
+
+  Worker_thread_param(Event_timed *etn):et(etn), started(FALSE)
+  {
+    pthread_mutex_init(&LOCK_started, MY_MUTEX_INIT_FAST);
+    pthread_cond_init(&COND_started, NULL);  
+  }
+
+  ~Worker_thread_param()
+  {
+    pthread_mutex_destroy(&LOCK_started);
+    pthread_cond_destroy(&COND_started);
+  }
+};
+
+
+/*
+  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
+*/
+
+static void
+evex_print_warnings(THD *thd, Event_timed *et)
+{
+  MYSQL_ERROR *err;
+  DBUG_ENTER("evex_print_warnings");
+  if (!thd->warn_list.elements)
+    DBUG_VOID_RETURN;
+
+  char msg_buf[10 * STRING_BUFFER_USUAL_SIZE];
+  char prefix_buf[5 * STRING_BUFFER_USUAL_SIZE];
+  String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
+  prefix.length(0);
+  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);
+
+  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);
+    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_message_handlers[err->level])("%*s", err_msg.length(),
+                                              err_msg.c_ptr());
+  }
+  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.
+
+  RETURN VALUE
+    0  OK
+   -1  Error
+*/
+
+static int
+init_event_thread(THD** t, enum enum_thread_type thread_type)
+{
+  THD *thd= *t;
+  thd->thread_stack= (char*)t;                  // remember where our stack is
+  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_MULTI_RESULTS;
+  thd->real_id=pthread_self();
+  VOID(pthread_mutex_lock(&LOCK_thread_count));
+  thd->thread_id= thread_id++;
+  threads.append(thd);
+  thread_count++;
+  thread_running++;
+  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+  if (init_thr_lock() || thd->store_globals())
+  {
+    thd->cleanup();
+    DBUG_RETURN(-1);
+  }
+
+#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
+  sigset_t set;
+  VOID(sigemptyset(&set));			// Get mask in use
+  VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
+#endif
+
+  /*
+    Guarantees that we will see the thread in SHOW PROCESSLIST though its
+    vio is NULL.
+  */
+  thd->system_thread= thread_type;
+
+  thd->proc_info= "Initialized";
+  thd->version= refresh_version;
+  thd->set_time();
+
+  DBUG_RETURN(0);
+}
+
+
+/*
+  Inits the main scheduler thread and then calls Event_scheduler::run()
+  of arg. 
+
+  SYNOPSIS
+    event_scheduler_thread()
+      arg  void* ptr to Event_scheduler
+
+  NOTES
+    1. The host of the thead is my_localhost
+    2. thd->net is initted with NULL - no communication.
+    3. The reason to have a proxy function is that it's not possible to
+       use a method as function to be executed in a spawned thread:
+       - our pthread_hander_t macro uses extern "C"
+       - separating thread setup from the real execution loop is also to be
+         considered good.
+
+  RETURN VALUE
+    0  OK
+*/
+
+pthread_handler_t
+event_scheduler_thread(void *arg)
+{
+  /* needs to be first for thread_stack */
+  THD *thd= NULL;                               
+  Event_scheduler *scheduler= (Event_scheduler *) arg;
+
+  DBUG_ENTER("event_scheduler_thread");
+
+  my_thread_init();
+  pthread_detach_this_thread();
+
+  /* note that constructor of THD uses DBUG_ ! */
+  if (!(thd= new THD) || init_event_thread(&thd, SYSTEM_THREAD_EVENT_SCHEDULER))
+  {
+    sql_print_error("SCHEDULER: Cannot init manager event thread.");
+    scheduler->report_error_during_start();
+  }
+  else
+  {
+    thd->security_ctx->set_user((char*)"event_scheduler");
+
+    sql_print_information("SCHEDULER: Manager thread booting");
+    if (Event_scheduler::check_system_tables(thd))
+      scheduler->report_error_during_start();
+    else
+      scheduler->run(thd);
+
+    /*
+      NOTE: Don't touch `scheduler` after this point because we have notified
+            the
+            thread which shuts us down that we have finished cleaning. In this
+            very moment a new scheduler thread could be started and a crash is
+            not welcome.
+    */
+  }
+
+  /*
+    If we cannot create THD then don't decrease because we haven't touched
+    thread_count and thread_running in init_event_thread() which was never
+    called. In init_event_thread() thread_count and thread_running are
+    always increased even in the case the method returns an error.
+  */
+  if (thd)
+  {
+    thd->proc_info= "Clearing";
+    DBUG_ASSERT(thd->net.buff != 0);
+    net_end(&thd->net);
+    pthread_mutex_lock(&LOCK_thread_count);
+    thread_count--;
+    thread_running--;
+    delete thd;
+    pthread_mutex_unlock(&LOCK_thread_count);
+  }
+  my_thread_end();
+  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_worker_thread()
+      arg  The Event_timed object to be processed
+
+  RETURN VALUE
+    0  OK
+*/
+
+pthread_handler_t
+event_worker_thread(void *arg)
+{
+  THD *thd; /* needs to be first for thread_stack */
+  Worker_thread_param *param= (Worker_thread_param *) arg;
+  Event_timed *event= param->et;
+  int ret;
+  bool startup_error= FALSE;
+  Security_context *save_ctx;
+  /* this one is local and not needed after exec */
+  Security_context security_ctx;
+
+  DBUG_ENTER("event_worker_thread");
+  DBUG_PRINT("enter", ("event=[%s.%s]", event->dbname.str, event->name.str));
+
+  my_thread_init();
+  pthread_detach_this_thread();
+
+  if (!(thd= new THD) || init_event_thread(&thd, SYSTEM_THREAD_EVENT_WORKER))
+  {
+    sql_print_error("SCHEDULER: Startup failure.");
+    startup_error= TRUE;
+    event->spawn_thread_finish(thd);
+  }
+  else
+    event->set_thread_id(thd->thread_id);
+
+  DBUG_PRINT("info", ("master_access=%d db_access=%d",
+             thd->security_ctx->master_access, thd->security_ctx->db_access));
+  /*
+    If we don't change it before we send the signal back, then an intermittent
+    DROP EVENT will take LOCK_scheduler_data and try to kill this thread, because
+    event->thread_id is already real. However, because thd->security_ctx->user
+    is not initialized then a crash occurs in kill_one_thread(). Thus, we have
+    to change the context before sending the signal. We are under
+    LOCK_scheduler_data being held by Event_scheduler::run() -> ::execute_top().
+  */
+  change_security_context(thd, event->definer_user, event->definer_host,
+                          event->dbname, &security_ctx, &save_ctx);
+  DBUG_PRINT("info", ("master_access=%d db_access=%d",
+             thd->security_ctx->master_access, thd->security_ctx->db_access));
+
+  /* Signal the scheduler thread that we have started successfully */
+  pthread_mutex_lock(&param->LOCK_started);
+  param->started= TRUE;
+  pthread_cond_signal(&param->COND_started);
+  pthread_mutex_unlock(&param->LOCK_started);
+
+  if (!startup_error)
+  {
+    thd->init_for_queries();
+    thd->enable_slow_log= TRUE;
+
+    event->set_thread_id(thd->thread_id);
+    sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu",
+                          event->dbname.str, event->name.str,
+                          event->definer.str, thd->thread_id);
+
+    ret= event->execute(thd, thd->mem_root);
+    evex_print_warnings(thd, event);
+    sql_print_information("SCHEDULER: [%s.%s of %s] executed. RetCode=%d",
+                          event->dbname.str, event->name.str,
+                          event->definer.str, ret);
+    if (ret == EVEX_COMPILE_ERROR)
+      sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
+                            event->dbname.str, event->name.str,
+                            event->definer.str);
+    else if (ret == EVEX_MICROSECOND_UNSUP)
+      sql_print_information("SCHEDULER: MICROSECOND is not supported");
+    
+    DBUG_PRINT("info", ("master_access=%d db_access=%d",
+               thd->security_ctx->master_access, thd->security_ctx->db_access));
+
+    /* If true is returned, we are expected to free it */
+    if (event->spawn_thread_finish(thd))
+    {
+      DBUG_PRINT("info", ("Freeing object pointer"));
+      delete event;
+    }
+  }
+
+  if (thd)
+  {
+    thd->proc_info= "Clearing";
+    DBUG_ASSERT(thd->net.buff != 0);
+    /*
+      Free it here because net.vio is NULL for us => THD::~THD will check it
+      and won't call net_end(&net); See also replication code.
+    */
+    net_end(&thd->net);
+    DBUG_PRINT("info", ("Worker thread %lu exiting", thd->thread_id));
+    VOID(pthread_mutex_lock(&LOCK_thread_count));
+    thread_count--;
+    thread_running--;
+    delete thd;
+    VOID(pthread_mutex_unlock(&LOCK_thread_count));
+  }
+
+  my_thread_end();
+  DBUG_RETURN(0);                               // Can't return anything here
+}
+
+
+/*
+  Constructor of class Event_scheduler.
+
+  SYNOPSIS
+    Event_scheduler::Event_scheduler()
+*/
+
+Event_scheduler::Event_scheduler()
+  :state(UNINITIALIZED), start_scheduler_suspended(FALSE),
+  thread_id(0), mutex_last_locked_at_line(0),
+  mutex_last_unlocked_at_line(0), mutex_last_locked_in_func(""),
+  mutex_last_unlocked_in_func(""), cond_waiting_on(COND_NONE),
+  mutex_scheduler_data_locked(FALSE)
+{
+}
+
+
+/*
+  Returns the singleton instance of the class.
+
+  SYNOPSIS
+    Event_scheduler::get_instance()
+
+  RETURN VALUE
+    address
+*/
+
+Event_scheduler*
+Event_scheduler::get_instance()
+{
+  DBUG_ENTER("Event_scheduler::get_instance");
+  DBUG_RETURN(&singleton);
+}
+
+
+/*
+  The implementation of full-fledged initialization.
+
+  SYNOPSIS
+    Event_scheduler::init()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
+bool
+Event_scheduler::init()
+{
+  int i= 0;
+  bool ret= FALSE;
+  DBUG_ENTER("Event_scheduler::init");
+  DBUG_PRINT("enter", ("this=%p", this));
+
+  LOCK_SCHEDULER_DATA();
+  for (;i < COND_LAST; i++)
+    if (pthread_cond_init(&cond_vars[i], NULL))
+    {
+      sql_print_error("SCHEDULER: Unable to initalize conditions");
+      ret= TRUE;
+      goto end;
+    }
+
+  /* init memory root */
+  init_alloc_root(&scheduler_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+
+  if (init_queue_ex(&queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
+                    event_timed_compare_q, NULL, 30 /*auto_extent*/))
+  {
+    sql_print_error("SCHEDULER: Can't initialize the execution queue");
+    ret= TRUE;
+    goto end;
+  }
+
+  if (sizeof(my_time_t) != sizeof(time_t))
+  {
+    sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
+                    "The scheduler may not work correctly. Stopping.");
+    DBUG_ASSERT(0);
+    ret= TRUE;
+    goto end;
+  }
+
+  state= INITIALIZED;
+end:
+  UNLOCK_SCHEDULER_DATA();
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Frees all memory allocated by the scheduler object.
+
+  SYNOPSIS
+    Event_scheduler::destroy()
+  
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
+void
+Event_scheduler::destroy()
+{
+  DBUG_ENTER("Event_scheduler");
+
+  LOCK_SCHEDULER_DATA();
+  switch (state) {
+  case UNINITIALIZED:
+    break;
+  case INITIALIZED:
+    delete_queue(&queue);
+    free_root(&scheduler_root, MYF(0));
+    int i;
+    for (i= 0; i < COND_LAST; i++)
+      pthread_cond_destroy(&cond_vars[i]);
+    state= UNINITIALIZED;
+    break;
+  default:
+    sql_print_error("SCHEDULER: Destroying while state is %d", state);
+    /* I trust my code but ::safe() > ::sorry() */
+    DBUG_ASSERT(0);
+    break;
+  }
+  UNLOCK_SCHEDULER_DATA();
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Adds an event to the scheduler queue
+
+  SYNOPSIS
+    Event_scheduler::add_event()
+      et              The event to add
+      check_existence Whether to check if already loaded.
+
+  RETURN VALUE
+    OP_OK             OK or scheduler not working
+    OP_LOAD_ERROR     Error during loading from disk
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::add_event(THD *thd, Event_timed *et, bool check_existence)
+{
+  enum enum_error_code res;
+  Event_timed *et_new;
+  DBUG_ENTER("Event_scheduler::add_event");
+  DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
+
+  LOCK_SCHEDULER_DATA();
+  if (!is_running_or_suspended())
+  {
+    DBUG_PRINT("info", ("scheduler not running but %d. doing nothing", state));
+    UNLOCK_SCHEDULER_DATA();
+    DBUG_RETURN(OP_OK);
+  }
+  if (check_existence && find_event(et, FALSE))
+  {
+    res= OP_ALREADY_EXISTS;
+    goto end;
+  }
+
+  /* We need to load the event on scheduler_root */
+  if (!(res= load_event(thd, et, &et_new)))
+  {
+    queue_insert_safe(&queue, (byte *) et_new);
+    DBUG_PRINT("info", ("Sending COND_new_work"));
+    pthread_cond_signal(&cond_vars[COND_new_work]);
+  }
+  else if (res == OP_DISABLED_EVENT)
+    res= OP_OK;
+end:
+  UNLOCK_SCHEDULER_DATA();
+  DBUG_RETURN(res);
+}
+
+
+/*
+  Drops an event from the scheduler queue
+
+  SYNOPSIS
+    Event_scheduler::drop_event()
+      etn    The event to drop
+      state  Wait the event or kill&drop
+
+  RETURN VALUE
+    FALSE OK (replaced or scheduler not working)
+    TRUE  Failure
+*/
+
+bool
+Event_scheduler::drop_event(THD *thd, Event_timed *et)
+{
+  int res;
+  Event_timed *et_old;
+  DBUG_ENTER("Event_scheduler::drop_event");
+  DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
+
+  LOCK_SCHEDULER_DATA();
+  if (!is_running_or_suspended())
+  {
+    DBUG_PRINT("info", ("scheduler not running but %d. doing nothing", state));
+    UNLOCK_SCHEDULER_DATA();
+    DBUG_RETURN(OP_OK);
+  }
+
+  if (!(et_old= find_event(et, TRUE)))
+    DBUG_PRINT("info", ("No such event found, probably DISABLED"));
+
+  UNLOCK_SCHEDULER_DATA();
+
+  /* See comments in ::replace_event() why this is split in two parts. */
+  if (et_old)
+  {
+    switch ((res= et_old->kill_thread(thd))) {
+    case EVEX_CANT_KILL:
+      /* Don't delete but continue */
+      et_old->flags |= EVENT_FREE_WHEN_FINISHED;
+      break;
+    case 0:
+      /* 
+        kill_thread() waits till the spawned thread finishes after it's
+        killed. Hence, we delete here memory which is no more referenced from
+        a running thread.
+      */
+      delete et_old;
+      /*
+        We don't signal COND_new_work here because:
+        1. Even if the dropped event is on top of the queue this will not
+          move another one to be executed before the time the one on the
+          top (but could be at the same second as the dropped one)
+        2. If this was the last event on the queue, then pthread_cond_timedwait
+          in ::run() will finish and then see that the queue is empty and
+          call cond_wait(). Hence, no need to interrupt the blocked
+          ::run() thread.
+      */
+      break;
+    default:
+      sql_print_error("SCHEDULER: Got unexpected error %d", res);
+      DBUG_ASSERT(0);
+    }
+  }
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/*
+  Replaces an event in the scheduler queue
+
+  SYNOPSIS
+    Event_scheduler::replace_event()
+      et    The event to replace(add) into the queue
+      state  Async or sync stopping
+
+  RETURN VALUE
+    OP_OK             OK or scheduler not working
+    OP_LOAD_ERROR     Error during loading from disk
+    OP_ALREADY_EXISTS Event already in the queue    
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::replace_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
+                               LEX_STRING *new_name)
+{
+  enum enum_error_code res;
+  Event_timed *et_old, *et_new= NULL;
+  LEX_STRING old_schema, old_name;
+
+  DBUG_ENTER("Event_scheduler::replace_event");
+  DBUG_PRINT("enter", ("thd=%p et=%p et=[%s.%s] lock=%p",
+             thd, et, et->dbname.str, et->name.str, &LOCK_scheduler_data));
+
+  LOCK_SCHEDULER_DATA();
+  if (!is_running_or_suspended())
+  {
+    DBUG_PRINT("info", ("scheduler not running but %d. doing nothing", state));
+    UNLOCK_SCHEDULER_DATA();
+    DBUG_RETURN(OP_OK);
+  }
+
+  if (!(et_old= find_event(et, TRUE)))
+    DBUG_PRINT("info", ("%s.%s not found cached, probably was DISABLED",
+                        et->dbname.str, et->name.str));
+
+  if (new_schema && new_name)
+  {
+    old_schema= et->dbname;
+    old_name= et->name;
+    et->dbname= *new_schema;
+    et->name= *new_name;
+  }
+  /*
+    We need to load the event (it's strings but on the object itself)
+    on scheduler_root. et_new could be NULL :
+    1. Error occured
+    2. If the replace is DISABLED, we don't load it into the queue.
+  */
+  if (!(res= load_event(thd, et, &et_new)))
+  {
+    queue_insert_safe(&queue, (byte *) et_new);
+    DBUG_PRINT("info", ("Sending COND_new_work"));
+    pthread_cond_signal(&cond_vars[COND_new_work]);
+  }
+  else if (res == OP_DISABLED_EVENT)
+    res= OP_OK;
+
+  if (new_schema && new_name)
+  {
+    et->dbname= old_schema;
+    et->name= old_name;
+  }
+
+  UNLOCK_SCHEDULER_DATA();
+  /*
+    Andrey: Is this comment still truthful ???
+
+    We don't move this code above because a potential kill_thread will call
+    THD::awake(). Which in turn will try to acqure mysys_var->current_mutex,
+    which is LOCK_scheduler_data on which the COND_new_work in ::run() locks.
+    Hence, we try to acquire a lock which we have already acquired and we run
+    into an assert. Holding LOCK_scheduler_data however is not needed because
+    we don't touch any invariant of the scheduler anymore. ::drop_event() does
+    the same.
+  */
+  if (et_old)
+  {
+    switch (et_old->kill_thread(thd)) {
+    case EVEX_CANT_KILL:
+      /* Don't delete but continue */
+      et_old->flags |= EVENT_FREE_WHEN_FINISHED;
+      break;
+    case 0:
+      /* 
+        kill_thread() waits till the spawned thread finishes after it's
+        killed. Hence, we delete here memory which is no more referenced from
+        a running thread.
+      */
+      delete et_old;
+      /*
+        We don't signal COND_new_work here because:
+        1. Even if the dropped event is on top of the queue this will not
+          move another one to be executed before the time the one on the
+          top (but could be at the same second as the dropped one)
+        2. If this was the last event on the queue, then pthread_cond_timedwait
+          in ::run() will finish and then see that the queue is empty and
+          call cond_wait(). Hence, no need to interrupt the blocked
+          ::run() thread.
+      */
+      break;
+    default:
+      DBUG_ASSERT(0);
+    }
+  }
+
+  DBUG_RETURN(res);
+}
+
+
+/*
+  Searches for an event in the scheduler queue
+
+  SYNOPSIS
+    Event_scheduler::find_event()
+      etn            The event to find
+      comparator     The function to use for comparing
+      remove_from_q  If found whether to remove from the Q
+
+  RETURN VALUE
+    NULL       Not found
+    otherwise  Address
+
+  NOTE
+    The caller should do the locking also the caller is responsible for
+    actual signalling in case an event is removed from the queue 
+    (signalling COND_new_work for instance).
+*/
+
+Event_timed *
+Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
+{
+  uint i;
+  DBUG_ENTER("Event_scheduler::find_event");
+
+  for (i= 0; i < queue.elements; ++i)
+  {
+    Event_timed *et= (Event_timed *) queue_element(&queue, i);
+    DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", etn->dbname.str, etn->name.str,
+                        et->dbname.str, et->name.str));
+    if (event_timed_identifier_equal(etn, et))
+    {
+      if (remove_from_q)
+        queue_remove(&queue, i);
+      DBUG_RETURN(et);
+    }
+  }
+
+  DBUG_RETURN(NULL);
+}
+
+
+/*
+  Drops all events from the in-memory queue and disk that match
+  certain pattern evaluated by a comparator function
+
+  SYNOPSIS
+    Event_scheduler::drop_matching_events()
+      thd            THD
+      pattern        A pattern string
+      comparator     The function to use for comparing
+
+  RETURN VALUE
+     -1  Scheduler not working
+    >=0  Number of dropped events
+    
+  NOTE
+    Expected is the caller to acquire lock on LOCK_scheduler_data
+*/
+
+void
+Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
+                           bool (*comparator)(Event_timed *,LEX_STRING *))
+{
+  DBUG_ENTER("Event_scheduler::drop_matching_events");
+  DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern->length, pattern->str,
+             state));
+  if (is_running_or_suspended())
+  {
+    uint i= 0, dropped= 0;   
+    while (i < queue.elements)
+    {
+      Event_timed *et= (Event_timed *) queue_element(&queue, i);
+      DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
+      if (comparator(et, pattern))
+      {
+        /*
+          The queue is ordered. If we remove an element, then all elements after
+          it will shift one position to the left, if we imagine it as an array
+          from left to the right. In this case we should not increment the 
+          counter and the (i < queue.elements) condition is ok.
+        */
+        queue_remove(&queue, i);
+
+        /* See replace_event() */
+        switch (et->kill_thread(thd)) {
+        case EVEX_CANT_KILL:
+          /* Don't delete but continue */
+          et->flags |= EVENT_FREE_WHEN_FINISHED;
+          ++dropped;
+          break;
+        case 0:
+          delete et;
+          ++dropped;
+          break;
+        default:
+          DBUG_ASSERT(0);
+        }
+      }
+      else
+        i++;
+    }
+    DBUG_PRINT("info", ("Dropped %lu", dropped));
+  }
+  /*
+    Don't send COND_new_work because no need to wake up the scheduler thread.
+    When it wakes next time up it will recalculate how much more it should
+    sleep if the top of the queue has been changed by this method.
+  */
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Drops all events from the in-memory queue and disk that are from
+  certain schema.
+
+  SYNOPSIS
+    Event_scheduler::drop_schema_events()
+      thd        THD
+      db         The schema name
+
+  RETURN VALUE
+     -1  Scheduler not working
+    >=0  Number of dropped events
+*/
+
+int
+Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
+{
+  int ret;
+  DBUG_ENTER("Event_scheduler::drop_schema_events");
+  LOCK_SCHEDULER_DATA();
+  if (is_running_or_suspended())
+    drop_matching_events(thd, schema, event_timed_db_equal);
+
+  ret= db_drop_events_from_table(thd, schema);
+  UNLOCK_SCHEDULER_DATA();
+
+  DBUG_RETURN(ret);
+}
+
+
+extern pthread_attr_t connection_attrib;
+
+
+/*
+  Starts the event scheduler
+
+  SYNOPSIS
+    Event_scheduler::start()
+
+  RETURN VALUE
+    FALSE  OK
+    TRUE   Error
+*/
+
+bool
+Event_scheduler::start()
+{
+  bool ret= FALSE;
+  pthread_t th;
+  DBUG_ENTER("Event_scheduler::start");
+
+  LOCK_SCHEDULER_DATA();
+  /* If already working or starting don't make another attempt */
+  DBUG_ASSERT(state == INITIALIZED);
+  if (state > INITIALIZED)
+  {
+    DBUG_PRINT("info", ("scheduler is already running or starting"));
+    ret= TRUE;
+    goto end;
+  }
+
+  /*
+    Now if another thread calls start it will bail-out because the branch
+    above will be executed. Thus no two or more child threads will be forked.
+    If the child thread cannot start for some reason then `state` is set
+    to CANTSTART and COND_started is also signaled. In this case we
+    set `state` back to INITIALIZED so another attempt to start the scheduler
+    can be made.
+  */
+  state= COMMENCING;
+  /* Fork */
+  if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
+                    (void*)this))
+  {
+    DBUG_PRINT("error", ("cannot create a new thread"));
+    state= INITIALIZED;
+    ret= TRUE;
+    goto end;
+  }
+
+  /*  Wait till the child thread has booted (w/ or wo success) */
+  while (!is_running_or_suspended() && state != CANTSTART)
+    cond_wait(COND_started_or_stopped, &LOCK_scheduler_data);
+
+  /*
+    If we cannot start for some reason then don't prohibit further attempts.
+    Set back to INITIALIZED.
+  */
+  if (state == CANTSTART)
+  {
+    state= INITIALIZED;
+    ret= TRUE;
+    goto end;
+  }
+
+end:
+  UNLOCK_SCHEDULER_DATA();
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Starts the event scheduler in suspended mode.
+
+  SYNOPSIS
+    Event_scheduler::start_suspended()
+
+  RETURN VALUE
+    TRUE   OK
+    FALSE  Error
+*/
+
+bool
+Event_scheduler::start_suspended()
+{
+  DBUG_ENTER("Event_scheduler::start_suspended");
+  start_scheduler_suspended= TRUE;
+  DBUG_RETURN(start());
+}
+
+
+
+/*
+  Report back that we cannot start. Used for ocasions where
+  we can't go into ::run() and have to report externally.
+
+  SYNOPSIS
+    Event_scheduler::report_error_during_start()
+*/
+
+inline void
+Event_scheduler::report_error_during_start()
+{
+  DBUG_ENTER("Event_scheduler::report_error_during_start");
+
+  LOCK_SCHEDULER_DATA();
+  state= CANTSTART;
+  DBUG_PRINT("info", ("Sending back COND_started_or_stopped"));
+  pthread_cond_signal(&cond_vars[COND_started_or_stopped]);
+  UNLOCK_SCHEDULER_DATA();
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  The internal loop of the event scheduler
+
+  SYNOPSIS
+    Event_scheduler::run()
+      thd  Thread
+
+  RETURN VALUE
+    FALSE OK
+    TRUE  Failure
+*/
+
+bool
+Event_scheduler::run(THD *thd)
+{
+  int ret;
+  struct timespec abstime;
+  DBUG_ENTER("Event_scheduler::run");
+  DBUG_PRINT("enter", ("thd=%p", thd));
+
+  LOCK_SCHEDULER_DATA();
+  ret= load_events_from_db(thd);
+
+  if (!ret)
+  {
+    thread_id= thd->thread_id;
+    state= start_scheduler_suspended? SUSPENDED:RUNNING;
+    start_scheduler_suspended= FALSE;
+  }
+  else 
+    state= CANTSTART;
+
+  DBUG_PRINT("info", ("Sending back COND_started_or_stopped"));
+  pthread_cond_signal(&cond_vars[COND_started_or_stopped]);
+  if (ret)
+  {
+    UNLOCK_SCHEDULER_DATA();
+    DBUG_RETURN(TRUE);
+  }
+  if (!check_n_suspend_if_needed(thd))
+    UNLOCK_SCHEDULER_DATA();
+
+  sql_print_information("SCHEDULER: Manager thread started with id %lu",
+                        thd->thread_id);
+  abstime.tv_nsec= 0;
+  while (is_running_or_suspended())
+  {
+    Event_timed *et;
+
+    LOCK_SCHEDULER_DATA();
+    if (check_n_wait_for_non_empty_queue(thd))
+      continue;
+
+    /* On TRUE data is unlocked, go back to the beginning */
+    if (check_n_suspend_if_needed(thd))
+      continue;
+
+    /* Guaranteed locked here */
+    if (state == IN_SHUTDOWN || shutdown_in_progress)
+    {
+      UNLOCK_SCHEDULER_DATA();
+      break;
+    }
+    DBUG_ASSERT(state == RUNNING);
+
+    et= (Event_timed *)queue_top(&queue);
+    
+    /* Skip disabled events */
+    if (et->status != Event_timed::ENABLED)
+    {
+      sql_print_error("SCHEDULER: Found a disabled event %*s.%*s in the queue",
+                      et->dbname.length, et->dbname.str, et->name.length,
+                      et->name.str);
+      queue_remove(&queue, 0);
+      /* ToDo: check this again */
+      delete et;
+      UNLOCK_SCHEDULER_DATA();
+      continue;
+    }
+    thd->proc_info= (char *)"Computing";
+    DBUG_PRINT("evex manager",("computing time to sleep till next exec"));
+    /* Timestamp is in UTC */
+    abstime.tv_sec= sec_since_epoch_TIME(&et->execute_at);
+
+    thd->end_time();
+    if (abstime.tv_sec > thd->query_start())
+    {
+      /* Event trigger time is in the future */
+      thd->proc_info= (char *)"Sleep";
+      DBUG_PRINT("info", ("Going to sleep. Should wakeup after approx %d secs",
+                         abstime.tv_sec - thd->query_start()));
+      DBUG_PRINT("info", ("Entering condition because waiting for activation"));
+      /*
+        Use THD::enter_cond()/exit_cond() or we won't be able to kill a
+        sleeping thread. Though ::stop() can do it by sending COND_new_work
+        an user can't by just issuing 'KILL x'; . In the latter case
+        pthread_cond_timedwait() will wait till `abstime`.
+        "Sleeping until next time"
+      */
+      thd->enter_cond(&cond_vars[COND_new_work],&LOCK_scheduler_data,"Sleeping");
+
+      pthread_cond_timedwait(&cond_vars[COND_new_work], &LOCK_scheduler_data,
+                             &abstime);
+
+      DBUG_PRINT("info", ("Manager woke up. state is %d", state));
+      /*
+        If we get signal we should recalculate the whether it's the right time
+        because there could be :
+        1. Spurious wake-up
+        2. The top of the queue was changed (new one becase of add/drop/replace)
+      */
+      /* This will do implicit UNLOCK_SCHEDULER_DATA() */
+      thd->exit_cond("");
+    }
+    else
+    {
+      thd->proc_info= (char *)"Executing";
+      /*
+        Execute the event. An error may occur if a thread cannot be forked.
+        In this case stop  the manager.
+        We should enter ::execute_top() with locked LOCK_scheduler_data.
+      */
+      int ret= execute_top(thd);
+      UNLOCK_SCHEDULER_DATA();
+      if (ret)
+        break;
+    }
+  }
+
+  thd->proc_info= (char *)"Cleaning";
+
+  LOCK_SCHEDULER_DATA();
+  /*
+    It's possible that a user has used (SQL)COM_KILL. Hence set the appropriate
+    state because it is only set by ::stop().
+  */
+  if (state != IN_SHUTDOWN)
+  {
+    DBUG_PRINT("info", ("We got KILL but the but not from ::stop()"));
+    state= IN_SHUTDOWN;
+  }
+  UNLOCK_SCHEDULER_DATA();
+
+  sql_print_information("SCHEDULER: Shutting down");
+
+  thd->proc_info= (char *)"Cleaning queue";
+  clean_queue(thd);
+  THD_CHECK_SENTRY(thd);
+
+  /* free mamager_root memory but don't destroy the root */
+  thd->proc_info= (char *)"Cleaning memory root";
+  free_root(&scheduler_root, MYF(0));
+  THD_CHECK_SENTRY(thd);
+
+  /*
+    We notify the waiting thread which shutdowns us that we have cleaned.
+    There are few more instructions to be executed in this pthread but
+    they don't affect manager structures thus it's safe to signal already
+    at this point.
+  */
+  LOCK_SCHEDULER_DATA();
+  thd->proc_info= (char *)"Sending shutdown signal";
+  DBUG_PRINT("info", ("Sending COND_started_or_stopped"));
+  if (state == IN_SHUTDOWN)
+    pthread_cond_signal(&cond_vars[COND_started_or_stopped]);
+
+  state= INITIALIZED;
+  /*
+    We set it here because ::run() can stop not only because of ::stop()
+    call but also because of `KILL x`
+  */
+  thread_id= 0;
+  sql_print_information("SCHEDULER: Stopped");
+  UNLOCK_SCHEDULER_DATA();
+
+  /* We have modified, we set back */
+  thd->query= NULL;
+  thd->query_length= 0;
+
+  DBUG_RETURN(FALSE);
+}
+
+
+/*
+  Executes the top element of the queue. Auxiliary method for ::run().
+
+  SYNOPSIS
+    Event_scheduler::execute_top()
+
+  RETURN VALUE
+    FALSE OK
+    TRUE  Failure
+
+  NOTE
+    NO locking is done. EXPECTED is that the caller should have locked
+    the queue (w/ LOCK_scheduler_data).
+*/
+
+bool
+Event_scheduler::execute_top(THD *thd)
+{
+  int spawn_ret_code;
+  bool ret= FALSE;
+  DBUG_ENTER("Event_scheduler::execute_top");
+  DBUG_PRINT("enter", ("thd=%p", thd));
+
+  Event_timed *et= (Event_timed *)queue_top(&queue);
+
+  /* Is it good idea to pass a stack address ?*/
+  Worker_thread_param param(et);
+
+  pthread_mutex_lock(&param.LOCK_started);
+  /* 
+    We don't lock LOCK_scheduler_data fpr workers_increment() because it's a
+    pre-requisite for calling the current_method.
+  */
+  switch ((spawn_ret_code= et->spawn_now(event_worker_thread, &param))) {
+  case EVENT_EXEC_CANT_FORK:
+    /* 
+      We don't lock LOCK_scheduler_data here because it's a pre-requisite
+      for calling the current_method.
+    */
+    sql_print_error("SCHEDULER: Problem while trying to create a thread");
+    ret= TRUE;
+    break;
+  case EVENT_EXEC_ALREADY_EXEC:
+    /* 
+      We don't lock LOCK_scheduler_data here because it's a pre-requisite
+      for calling the current_method.
+    */
+    sql_print_information("SCHEDULER: %s.%s in execution. Skip this time.",
+                          et->dbname.str, et->name.str);
+    if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == Event_timed::DISABLED)
+      queue_remove(&queue, 0);// 0 is top, internally 1
+    else
+      queue_replaced(&queue);
+    break;
+  default:
+    DBUG_ASSERT(!spawn_ret_code);
+    if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == Event_timed::DISABLED)
+      queue_remove(&queue, 0);// 0 is top, internally 1
+    else
+      queue_replaced(&queue);
+    /* 
+      We don't lock LOCK_scheduler_data here because it's a pre-requisite
+      for calling the current_method.
+    */
+    if (likely(!spawn_ret_code))
+    {
+      /* Wait the forked thread to start */
+      do {
+        pthread_cond_wait(&param.COND_started, &param.LOCK_started);
+      } while (!param.started);
+    }
+    /*
+      param was allocated on the stack so no explicit delete as well as
+      in this moment it's no more used in the spawned thread so it's safe
+      to be deleted.
+    */
+    break;
+  }
+  pthread_mutex_unlock(&param.LOCK_started);
+  /* `param` is on the stack and will be destructed by the compiler */
+
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Cleans the scheduler's queue. Auxiliary method for ::run().
+
+  SYNOPSIS
+    Event_scheduler::clean_queue()
+      thd  Thread
+*/
+
+void
+Event_scheduler::clean_queue(THD *thd)
+{
+  CHARSET_INFO *scs= system_charset_info;
+  uint i;
+  DBUG_ENTER("Event_scheduler::clean_queue");
+  DBUG_PRINT("enter", ("thd=%p", thd));
+
+  LOCK_SCHEDULER_DATA();
+  stop_all_running_events(thd);
+  UNLOCK_SCHEDULER_DATA();
+
+  sql_print_information("SCHEDULER: Emptying the queue");
+
+  /* empty the queue */
+  for (i= 0; i < queue.elements; ++i)
+  {
+    Event_timed *et= (Event_timed *) queue_element(&queue, i);
+    et->free_sp();
+    delete et;
+  }
+  resize_queue(&queue, 0);
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Stops all running events
+
+  SYNOPSIS
+    Event_scheduler::stop_all_running_events()
+      thd  Thread
+  
+  NOTE
+    LOCK_scheduler data must be acquired prior to call to this method
+*/
+
+void
+Event_scheduler::stop_all_running_events(THD *thd)
+{
+  CHARSET_INFO *scs= system_charset_info;
+  uint i;
+  DYNAMIC_ARRAY running_threads;
+  THD *tmp;
+  DBUG_ENTER("Event_scheduler::stop_all_running_events");
+  DBUG_PRINT("enter", ("workers_count=%d", workers_count()));
+
+  my_init_dynamic_array(&running_threads, sizeof(ulong), 10, 10);
+
+  bool had_super= FALSE;
+  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+  I_List_iterator<THD> it(threads);
+  while ((tmp=it++))
+  {
+    if (tmp->command == COM_DAEMON)
+      continue;
+    if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
+      push_dynamic(&running_threads, (gptr) &tmp->thread_id);
+  }
+  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+  /* We need temporarily SUPER_ACL to be able to kill our offsprings */
+  if (!(thd->security_ctx->master_access & SUPER_ACL))
+    thd->security_ctx->master_access|= SUPER_ACL;
+  else
+    had_super= TRUE;
+
+  char tmp_buff[10*STRING_BUFFER_USUAL_SIZE];
+  char int_buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
+  String int_string(int_buff, sizeof(int_buff), scs);
+  tmp_string.length(0);
+
+  for (i= 0; i < running_threads.elements; ++i)
+  {
+    int ret;
+    ulong thd_id= *dynamic_element(&running_threads, i, ulong*);
+
+    int_string.set((longlong) thd_id,scs);
+    tmp_string.append(int_string);
+    if (i < running_threads.elements - 1)
+      tmp_string.append(' ');
+
+    if ((ret= kill_one_thread(thd, thd_id, FALSE)))
+    {
+      sql_print_error("SCHEDULER: Error killing %lu code=%d", thd_id, ret);
+      break;
+    }
+  }
+  if (running_threads.elements)
+    sql_print_information("SCHEDULER: Killing workers :%s", tmp_string.c_ptr());
+
+  if (!had_super)
+    thd->security_ctx->master_access &= ~SUPER_ACL;
+
+  delete_dynamic(&running_threads);
+
+  sql_print_information("SCHEDULER: Waiting for worker threads to finish");
+
+  while (workers_count())
+    my_sleep(100000);
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Stops the event scheduler
+
+  SYNOPSIS
+    Event_scheduler::stop()
+
+  RETURN VALUE
+    OP_OK           OK
+    OP_CANT_KILL    Error during stopping of manager thread
+    OP_NOT_RUNNING  Manager not working
+
+  NOTE
+    The caller must have acquited LOCK_scheduler_data.
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::stop()
+{
+  THD *thd= current_thd;
+  DBUG_ENTER("Event_scheduler::stop");
+  DBUG_PRINT("enter", ("thd=%p", current_thd));
+
+  LOCK_SCHEDULER_DATA();
+  if (!is_running_or_suspended())
+  {
+    /*
+      One situation to be here is if there was a start that forked a new
+      thread but the new thread did not acquire yet LOCK_scheduler_data.
+      Hence, in this case return an error.    
+    */
+    DBUG_PRINT("info", ("manager not running but %d. doing nothing", state));
+    UNLOCK_SCHEDULER_DATA();
+    DBUG_RETURN(OP_NOT_RUNNING);
+  }
+  state= IN_SHUTDOWN;
+
+  DBUG_PRINT("info", ("Manager thread has id %d", thread_id));
+  sql_print_information("SCHEDULER: Killing manager thread %lu", thread_id);
+  
+  /* 
+    Sending the COND_new_work to ::run() is a way to get this working without
+    race conditions. If we use kill_one_thread() it will call THD::awake() and
+    because in ::run() both THD::enter_cond()/::exit_cond() are used,
+    THD::awake() will try to lock LOCK_scheduler_data. If we UNLOCK it before,
+    then the pthread_cond_signal(COND_started_or_stopped) could be signaled in
+    ::run() and we can miss the signal before we relock. A way is to use
+    another mutex for this shutdown procedure but better not.
+  */
+  pthread_cond_signal(&cond_vars[COND_new_work]);
+  /* Or we are suspended - then we should wake up */
+  pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+
+  /* Guarantee we don't catch spurious signals */
+  sql_print_information("SCHEDULER: Waiting the manager thread to reply");
+  while (state != INITIALIZED)
+  {
+    DBUG_PRINT("info", ("Waiting for COND_started_or_stopped from the manager "
+                        "thread.  Current value of state is %d . "
+                        "workers count=%d", state, workers_count()));
+    cond_wait(COND_started_or_stopped, &LOCK_scheduler_data);
+  }
+  DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
+  UNLOCK_SCHEDULER_DATA();
+
+  DBUG_RETURN(OP_OK);
+}
+
+
+/*
+  Suspends or resumes the scheduler.
+  SUSPEND - it won't execute any event till resumed.
+  RESUME - it will resume if suspended.
+
+  SYNOPSIS
+    Event_scheduler::suspend_or_resume()
+
+  RETURN VALUE
+    OP_OK  OK
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::suspend_or_resume(
+              enum Event_scheduler::enum_suspend_or_resume action)
+{
+  DBUG_ENTER("Event_scheduler::suspend_or_resume");
+  DBUG_PRINT("enter", ("action=%d", action));
+
+  LOCK_SCHEDULER_DATA();
+
+  if ((action == SUSPEND && state == SUSPENDED) ||
+      (action == RESUME  && state == RUNNING))
+  {
+    DBUG_PRINT("info", ("Either trying to suspend suspended or resume "
+               "running scheduler. Doing nothing."));
+  }
+  else
+  {
+    /* Wake the main thread up if he is asleep */
+    DBUG_PRINT("info", ("Sending signal"));
+    if (action==SUSPEND)
+    {
+      state= SUSPENDED;
+      pthread_cond_signal(&cond_vars[COND_new_work]);
+    }
+    else
+    {
+      state= RUNNING;
+      pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+    }
+    DBUG_PRINT("info", ("Waiting on COND_suspend_or_resume"));
+    cond_wait(COND_suspend_or_resume, &LOCK_scheduler_data);
+    DBUG_PRINT("info", ("Got response"));
+  }
+  UNLOCK_SCHEDULER_DATA();
+  DBUG_RETURN(OP_OK);
+}
+
+
+/*
+  Returns the number of executing events.
+
+  SYNOPSIS
+    Event_scheduler::workers_count()
+*/
+
+uint
+Event_scheduler::workers_count()
+{
+  THD *tmp;
+  uint count= 0;
+  
+  DBUG_ENTER("Event_scheduler::workers_count");
+  VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+  I_List_iterator<THD> it(threads);
+  while ((tmp=it++))
+  {
+    if (tmp->command == COM_DAEMON)
+      continue;
+    if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
+      ++count;
+  }
+  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+  DBUG_PRINT("exit", ("%d", count));
+  DBUG_RETURN(count);  
+}
+
+
+/*
+  Checks and suspends if needed
+
+  SYNOPSIS
+    Event_scheduler::check_n_suspend_if_needed()
+      thd  Thread
+  
+  RETURN VALUE
+    FALSE  Not suspended, we haven't slept
+    TRUE   We were suspended. LOCK_scheduler_data is unlocked.
+
+  NOTE
+    The caller should have locked LOCK_scheduler_data!
+    The mutex will be unlocked in case this function returns TRUE
+*/
+
+bool
+Event_scheduler::check_n_suspend_if_needed(THD *thd)
+{
+  bool was_suspended= FALSE;
+  DBUG_ENTER("Event_scheduler::check_n_suspend_if_needed");
+  if (thd->killed && !shutdown_in_progress)
+  {
+    state= SUSPENDED;
+    thd->killed= THD::NOT_KILLED;
+  }
+  if (state == SUSPENDED)
+  {
+    thd->enter_cond(&cond_vars[COND_suspend_or_resume], &LOCK_scheduler_data,
+                    "Suspended");
+    /* Send back signal to the thread that asked us to suspend operations */
+    pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+    sql_print_information("SCHEDULER: Suspending operations");
+    was_suspended= TRUE;
+  }
+  while (state == SUSPENDED)
+  {
+    cond_wait(COND_suspend_or_resume, &LOCK_scheduler_data);
+    DBUG_PRINT("info", ("Woke up after waiting on COND_suspend_or_resume"));
+    if (state != SUSPENDED)
+    {
+      pthread_cond_signal(&cond_vars[COND_suspend_or_resume]);
+      sql_print_information("SCHEDULER: Resuming operations");
+    }
+  }
+  if (was_suspended)
+  {
+    if (queue.elements)
+    {
+      uint i;
+      DBUG_PRINT("info", ("We have to recompute the execution times"));
+
+      for (i= 0; i < queue.elements; i++)
+        ((Event_timed*)queue_element(&queue, i))->compute_next_execution_time();
+      queue_fix(&queue);
+    }
+    /* This will implicitly unlock LOCK_scheduler_data */
+    thd->exit_cond("");
+  }
+  DBUG_RETURN(was_suspended);
+}
+
+
+/*
+  Checks for empty queue and waits till new element gets in
+
+  SYNOPSIS
+    Event_scheduler::check_n_wait_for_non_empty_queue()
+      thd  Thread
+
+  RETURN VALUE
+    FALSE  Did not wait - LOCK_scheduler_data still locked.
+    TRUE   Waited - LOCK_scheduler_data unlocked.
+
+  NOTE
+    The caller should have locked LOCK_scheduler_data!
+*/
+
+bool
+Event_scheduler::check_n_wait_for_non_empty_queue(THD *thd)
+{
+  bool slept= FALSE;
+  DBUG_ENTER("Event_scheduler::check_n_wait_for_non_empty_queue");
+  DBUG_PRINT("enter", ("q.elements=%lu state=%s",
+             queue.elements, states_names[state]));
+  
+  if (!queue.elements)
+    thd->enter_cond(&cond_vars[COND_new_work], &LOCK_scheduler_data,
+                    "Empty queue, sleeping");  
+
+  /* Wait in a loop protecting against catching spurious signals */
+  while (!queue.elements && state == RUNNING)
+  {
+    slept= TRUE;
+    DBUG_PRINT("info", ("Entering condition because of empty queue"));
+    cond_wait(COND_new_work, &LOCK_scheduler_data);
+    DBUG_PRINT("info", ("Manager woke up. Hope we have events now. state=%d",
+               state));
+    /*
+      exit_cond does implicit mutex_UNLOCK, we needed it locked if
+      1. we loop again
+      2. end the current loop and start doing calculations
+    */
+  }
+  if (slept)
+    thd->exit_cond("");
+
+  DBUG_PRINT("exit", ("q.elements=%lu state=%s thd->killed=%d",
+             queue.elements, states_names[state], thd->killed));
+
+  DBUG_RETURN(slept);
+}
+
+
+/*
+  Wrapper for pthread_mutex_lock
+
+  SYNOPSIS
+    Event_scheduler::lock_data()
+      mutex Mutex to lock
+      line  The line number on which the lock is done
+
+  RETURN VALUE
+    Error code of pthread_mutex_lock()
+*/
+
+inline void
+Event_scheduler::lock_data(const char *func, uint line)
+{
+  DBUG_ENTER("Event_scheduler::lock_mutex");
+  DBUG_PRINT("enter", ("mutex_lock=%p func=%s line=%u",
+             &LOCK_scheduler_data, func, line));
+  pthread_mutex_lock(&LOCK_scheduler_data);
+  mutex_last_locked_in_func= func;
+  mutex_last_locked_at_line= line;
+  mutex_scheduler_data_locked= TRUE;
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Wrapper for pthread_mutex_unlock
+
+  SYNOPSIS
+    Event_scheduler::unlock_data()
+      mutex Mutex to unlock
+      line  The line number on which the unlock is done
+*/
+
+inline void
+Event_scheduler::unlock_data(const char *func, uint line)
+{
+  DBUG_ENTER("Event_scheduler::UNLOCK_mutex");
+  DBUG_PRINT("enter", ("mutex_unlock=%p func=%s line=%u",
+             &LOCK_scheduler_data, func, line));
+  mutex_last_unlocked_at_line= line;
+  mutex_scheduler_data_locked= FALSE;
+  mutex_last_unlocked_in_func= func;
+  pthread_mutex_unlock(&LOCK_scheduler_data);
+  DBUG_VOID_RETURN;
+}
+
+
+/*
+  Wrapper for pthread_cond_wait
+
+  SYNOPSIS
+    Event_scheduler::cond_wait()
+      cond   Conditional to wait for
+      mutex  Mutex of the conditional
+
+  RETURN VALUE
+    Error code of pthread_cond_wait()
+*/
+
+inline int
+Event_scheduler::cond_wait(enum Event_scheduler::enum_cond_vars cond,
+                           pthread_mutex_t *mutex)
+{
+  int ret;
+  DBUG_ENTER("Event_scheduler::cond_wait");
+  DBUG_PRINT("enter", ("cond=%s mutex=%p", cond_vars_names[cond], mutex));
+  ret= pthread_cond_wait(&cond_vars[cond_waiting_on=cond], mutex);
+  cond_waiting_on= COND_NONE;
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Checks whether the scheduler is in a running or suspended state.
+
+  SYNOPSIS
+    Event_scheduler::is_running_or_suspended()
+
+  RETURN VALUE
+    TRUE   Either running or suspended
+    FALSE  IN_SHUTDOWN, not started, etc.
+*/
+
+inline bool
+Event_scheduler::is_running_or_suspended()
+{
+  return (state == SUSPENDED || state == RUNNING);
+}
+
+
+/*
+  Returns the current state of the scheduler
+
+  SYNOPSIS
+    Event_scheduler::get_state()
+*/
+
+enum Event_scheduler::enum_state
+Event_scheduler::get_state()
+{
+  enum Event_scheduler::enum_state ret;
+  DBUG_ENTER("Event_scheduler::get_state");
+  /* lock_data & unlock_data are not static */
+  pthread_mutex_lock(&singleton.LOCK_scheduler_data);
+  ret= singleton.state;
+  pthread_mutex_unlock(&singleton.LOCK_scheduler_data);
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Returns whether the scheduler was initialized.
+
+  SYNOPSIS
+    Event_scheduler::initialized()
+  
+  RETURN VALUE
+    FALSE  Was not initialized so far
+    TRUE   Was initialized
+*/
+
+bool
+Event_scheduler::initialized()
+{
+  DBUG_ENTER("Event_scheduler::initialized");
+  DBUG_RETURN(Event_scheduler::get_state() != UNINITIALIZED);
+}
+
+
+/*
+  Returns the number of elements in the queue
+
+  SYNOPSIS
+    Event_scheduler::events_count()
+
+  RETURN VALUE
+    0  Number of Event_timed objects in the queue
+*/
+
+uint
+Event_scheduler::events_count()
+{
+  uint n;
+  DBUG_ENTER("Event_scheduler::events_count");
+  LOCK_SCHEDULER_DATA();
+  n= queue.elements;
+  UNLOCK_SCHEDULER_DATA();
+
+  DBUG_RETURN(n);
+}
+
+
+/*
+  Looks for a named event in mysql.event and then loads it from
+  the table, compiles and inserts it into the cache.
+
+  SYNOPSIS
+    Event_scheduler::load_event()
+      thd      THD
+      etn      The name of the event to load and compile on scheduler's root
+      etn_new  The loaded event
+
+  RETURN VALUE
+    NULL       Error during compile or the event is non-enabled.
+    otherwise  Address
+*/
+
+enum Event_scheduler::enum_error_code
+Event_scheduler::load_event(THD *thd, Event_timed *etn, Event_timed **etn_new)
+{
+  int ret= 0;
+  MEM_ROOT *tmp_mem_root;
+  Event_timed *et_loaded= NULL;
+  Open_tables_state backup;
+
+  DBUG_ENTER("Event_scheduler::load_and_compile_event");
+  DBUG_PRINT("enter",("thd=%p name:%*s",thd, etn->name.length, etn->name.str));
+
+  thd->reset_n_backup_open_tables_state(&backup);
+  /* No need to use my_error() here because db_find_event() has done it */
+  {
+    sp_name spn(etn->dbname, etn->name);
+    ret= db_find_event(thd, &spn, &etn->definer, &et_loaded, NULL,
+                       &scheduler_root);
+  }
+  thd->restore_backup_open_tables_state(&backup);
+  /* In this case no memory was allocated so we don't need to clean */
+  if (ret)
+    DBUG_RETURN(OP_LOAD_ERROR);
+
+  if (et_loaded->status != Event_timed::ENABLED)
+  {
+    /*
+      We don't load non-enabled events.
+      In db_find_event() `et_new` was allocated on the heap and not on
+      scheduler_root therefore we delete it here.
+    */
+    delete et_loaded;
+    DBUG_RETURN(OP_DISABLED_EVENT);
+  }
+
+  et_loaded->compute_next_execution_time();
+  *etn_new= et_loaded;
+
+  DBUG_RETURN(OP_OK);
+}
+
+
+/*
+   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
+     Event_scheduler::load_events_from_db()
+       thd - Thread context. Used for memory allocation in some cases.
+     
+   RETURN VALUE
+     0  OK
+    !0  Error (EVEX_OPEN_TABLE_FAILED, EVEX_MICROSECOND_UNSUP, 
+               EVEX_COMPILE_ERROR) - in all these cases mysql.event was
+               tampered.
+
+   NOTES
+     Reports the error to the console
+*/
+
+int
+Event_scheduler::load_events_from_db(THD *thd)
+{
+  TABLE *table;
+  READ_RECORD read_record_info;
+  int ret= -1;
+  uint count= 0;
+  bool clean_the_queue= FALSE;
+  /* Compile the events on this root but only for syntax check, then discard */
+  MEM_ROOT boot_root;
+
+  DBUG_ENTER("Event_scheduler::load_events_from_db");
+  DBUG_PRINT("enter", ("thd=%p", thd));
+
+  if (state > COMMENCING)
+  {
+    DBUG_ASSERT(0);
+    sql_print_error("SCHEDULER: Trying to load events while already running.");
+    DBUG_RETURN(EVEX_GENERAL_ERROR);
+  }
+
+  if ((ret= Events::open_event_table(thd, TL_READ, &table)))
+  {
+    sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
+    DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
+  }
+
+  init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+  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("info", ("Out of memory"));
+      clean_the_queue= TRUE;
+      break;
+    }
+    DBUG_PRINT("info", ("Loading event from row."));
+
+    if ((ret= et->load_from_row(&scheduler_root, table)))
+    {
+      clean_the_queue= TRUE;
+      sql_print_error("SCHEDULER: Error while loading from mysql.event. "
+                      "Table probably corrupted");
+      break;
+    }
+    if (et->status != Event_timed::ENABLED)
+    {
+      DBUG_PRINT("info",("%s is disabled",et->name.str));
+      delete et;
+      continue;
+    }
+
+    DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
+
+    /* We load only on scheduler root just to check whether the body compiles */
+    switch (ret= et->compile(thd, &boot_root)) {
+    case EVEX_MICROSECOND_UNSUP:
+      et->free_sp();
+      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:
+      /* Free it, it will be compiled again on the worker thread */
+      et->free_sp();
+      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("load_events_from_db", ("Adding %p to the exec list."));
+    queue_insert_safe(&queue,  (byte *) et);
+    count++;
+  }
+end:
+  end_read_record(&read_record_info);
+  free_root(&boot_root, MYF(0));
+
+  if (clean_the_queue)
+  {
+    for (count= 0; count < queue.elements; ++count)
+      queue_remove(&queue, 0);
+    ret= -1;
+  }
+  else
+  {
+    ret= 0;
+    sql_print_information("SCHEDULER: Loaded %d event%s", count, (count == 1)?"":"s");
+  }
+
+  /* Force close to free memory */
+  thd->version--;  
+
+  close_thread_tables(thd);
+
+  DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  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
+    Event_scheduler::check_system_tables()
+*/
+
+bool
+Event_scheduler::check_system_tables(THD *thd)
+{
+  TABLE_LIST tables;
+  bool not_used;
+  Open_tables_state backup;
+  bool ret;
+
+  DBUG_ENTER("Event_scheduler::check_system_tables");
+  DBUG_PRINT("enter", ("thd=%p", thd));
+
+  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 ((ret= simple_open_n_lock_tables(thd, &tables)))
+    sql_print_error("Cannot open mysql.db");
+  else
+  {
+    ret= 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);
+  }
+  if (ret)
+    DBUG_RETURN(TRUE);
+
+  bzero((char*) &tables, sizeof(tables));
+  tables.db= (char*) "mysql";
+  tables.table_name= tables.alias= (char*) "user";
+  tables.lock_type= TL_READ;
+
+  if ((ret= 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");
+      ret= TRUE;
+    }
+    close_thread_tables(thd);
+  }
+
+  thd->restore_backup_open_tables_state(&backup);
+
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  Inits mutexes.
+
+  SYNOPSIS
+    Event_scheduler::init_mutexes()
+*/
+
+void
+Event_scheduler::init_mutexes()
+{
+  pthread_mutex_init(&singleton.LOCK_scheduler_data, MY_MUTEX_INIT_FAST);
+}
+
+
+/*
+  Destroys mutexes.
+
+  SYNOPSIS
+    Event_scheduler::destroy_mutexes()
+*/
+
+void
+Event_scheduler::destroy_mutexes()
+{
+  pthread_mutex_destroy(&singleton.LOCK_scheduler_data);
+}
+
+
+/*
+  Dumps some data about the internal status of the scheduler.
+
+  SYNOPSIS
+    Event_scheduler::dump_internal_status()
+      thd      THD
+
+  RETURN VALUE
+    0  OK
+    1  Error
+*/
+
+int
+Event_scheduler::dump_internal_status(THD *thd)
+{
+  DBUG_ENTER("dump_internal_status");
+#ifndef DBUG_OFF
+  CHARSET_INFO *scs= system_charset_info;
+  Protocol *protocol= thd->protocol;
+  List<Item> field_list;
+  int ret;
+  char tmp_buff[5*STRING_BUFFER_USUAL_SIZE];
+  char int_buff[STRING_BUFFER_USUAL_SIZE];
+  String tmp_string(tmp_buff, sizeof(tmp_buff), scs);
+  String int_string(int_buff, sizeof(int_buff), scs);
+  tmp_string.length(0);
+  int_string.length(0);
+
+  field_list.push_back(new Item_empty_string("Name", 20));
+  field_list.push_back(new Item_empty_string("Value",20));
+  if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
+                                         Protocol::SEND_EOF))
+    DBUG_RETURN(1);
+
+  protocol->prepare_for_resend();
+  protocol->store(STRING_WITH_LEN("state"), scs);
+  protocol->store(states_names[singleton.state].str,
+                  states_names[singleton.state].length,
+                  scs);
+
+  ret= protocol->write();
+  /*
+    If not initialized - don't show anything else. get_instance()
+    will otherwise implicitly initialize it. We don't want that.
+  */
+  if (singleton.state >= INITIALIZED)
+  {
+    /* last locked at*/
+    /* 
+      The first thing to do, or get_instance() will overwrite the values.
+      mutex_last_locked_at_line / mutex_last_unlocked_at_line
+    */
+    protocol->prepare_for_resend();
+    protocol->store(STRING_WITH_LEN("last locked at"), scs);
+    tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+                                       tmp_string.alloced_length(), "%s::%d",
+                                       singleton.mutex_last_locked_in_func,
+                                       singleton.mutex_last_locked_at_line));
+    protocol->store(&tmp_string);
+    ret= protocol->write();
+
+    /* last unlocked at*/
+    protocol->prepare_for_resend();
+    protocol->store(STRING_WITH_LEN("last unlocked at"), scs);
+    tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+                                       tmp_string.alloced_length(), "%s::%d",
+                                       singleton.mutex_last_unlocked_in_func,
+                                       singleton.mutex_last_unlocked_at_line));
+    protocol->store(&tmp_string);
+    ret= protocol->write();
+
+    /* waiting on */
+    protocol->prepare_for_resend();
+    protocol->store(STRING_WITH_LEN("waiting on condition"), scs);
+    tmp_string.length(scs->cset->
+                    snprintf(scs, (char*) tmp_string.ptr(),
+                             tmp_string.alloced_length(), "%s",
+                             (singleton.cond_waiting_on != COND_NONE) ?
+                               cond_vars_names[singleton.cond_waiting_on]:
+                               "NONE"));
+    protocol->store(&tmp_string);
+    ret= protocol->write();
+
+    Event_scheduler *scheduler= get_instance();
+
+    /* workers_count */
+    protocol->prepare_for_resend();
+    protocol->store(STRING_WITH_LEN("workers_count"), scs);
+    int_string.set((longlong) scheduler->workers_count(), scs);
+    protocol->store(&int_string);
+    ret= protocol->write();
+
+    /* queue.elements */
+    protocol->prepare_for_resend();
+    protocol->store(STRING_WITH_LEN("queue.elements"), scs);
+    int_string.set((longlong) scheduler->queue.elements, scs);
+    protocol->store(&int_string);
+    ret= protocol->write();
+
+    /* scheduler_data_locked */
+    protocol->prepare_for_resend();
+    protocol->store(STRING_WITH_LEN("scheduler data locked"), scs);
+    int_string.set((longlong) scheduler->mutex_scheduler_data_locked, scs);
+    protocol->store(&int_string);
+    ret= protocol->write();
+  }
+  send_eof(thd);
+#endif
+  DBUG_RETURN(0);
+}
diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h
new file mode 100644
index 0000000000000000000000000000000000000000..247b4481c9f4b5b2933be59c7ec9b5c198fd1a69
--- /dev/null
+++ b/sql/event_scheduler.h
@@ -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_ */
diff --git a/sql/event_timed.cc b/sql/event_timed.cc
index 879f4d6a3c912abf683f2e919d684cf71995a0a9..fd85f5ebecc94c17e1f4dd6ebbe0a9512ad5e746 100644
--- a/sql/event_timed.cc
+++ b/sql/event_timed.cc
@@ -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 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
       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 @@ bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
   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 @@ Event_timed::execute(THD *thd, MEM_ROOT *mem_root)
 
 
 /*
-  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 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
   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 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
 }
 
 
-/*
-  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", ("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);
+}
+
+
+/*
+  Kills a running event
+  SYNOPSIS
+    Event_timed::kill_thread()
+    
+  RETURN VALUE 
+     0    OK
+    -1    EVEX_CANT_KILL
+    !0   Error 
+*/
+
+int
+Event_timed::kill_thread(THD *thd)
+{
+  int ret= 0;
+  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)
   {
-    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;
+    /*
+      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));
-  DBUG_VOID_RETURN;
+  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);
 }
 
 
 /*
-  Unlocks the object after it has been locked with ::can_spawn_now_n_lock()
+  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
-    0 - ok
-    1 - not locked by this thread
+    TRUE  definers are equal
+    FALSE definers are not equal
 */
 
-int
-Event_timed::spawn_unlock(THD *thd)
+bool
+event_timed_definer_equal(Event_timed *et, LEX_STRING *definer)
 {
-  int ret= 0;
-  VOID(pthread_mutex_lock(&this->LOCK_running));
-  if (!in_spawned_thread)
+  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))
   {
-    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;
-    }
+    my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
+    DBUG_RETURN(TRUE);
   }
-  VOID(pthread_mutex_unlock(&this->LOCK_running));
-  return ret;
+  *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;
 }
diff --git a/sql/lex.h b/sql/lex.h
index 555a68dc38836f516d8cc681b612ed825d2adc18..d541a3fb228c5da392d66990b09c0dc84dbd7b49 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -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)},
diff --git a/sql/log.cc b/sql/log.cc
index fa86064682d971f6c7e0c8598f1b7595d0c9de4e..31133a71757fe24a8b6c1fb8899423eda71814ab 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -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!
 
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 650d2a52b53e57e4268559785304c593037158bf..e4fd4c0da059e011ace8e9056755e2d179503b0a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 11c7e12f84f81ca2bbf9ac57144355b611485d6a..ccf52113c23db9ca7ad4adefea67815e04837375 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -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 */
 
@@ -3623,6 +3625,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
   mysqld_server_started= 1;
   pthread_cond_signal(&COND_server_started);
 
+  if (!opt_noacl)
+  {
+    Events::init();
+  }
 #if defined(__NT__) || defined(HAVE_SMEM)
   handle_connections_methods();
 #else
@@ -3674,7 +3680,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 +4670,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 +5003,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 +7332,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;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 9cabe1a3df0001938a44bbf4838b787ebe77595d..66e2aa1c31ca84a7fa1c0818c2e3e9ba285a3817 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -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;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index ae9e415174494a8aea42e7438bc1181db866fa22..242fe0f60680e87ab6341b6a85030457a23cdc77 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -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
 ****************************************************************************/
diff --git a/sql/set_var.h b/sql/set_var.h
index e374ac4e9406a3c4e8b08d3d27ca5b0c7b0553fd..1049b154d47034bc827af35bc4c060b484558d17 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -871,13 +871,14 @@ class sys_var_trust_routine_creators :public sys_var_bool_ptr
 };
 
 
-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);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index afce112814716f46ecad32b4c7d39cfcd63880fd..7c465678e17d0683689f34123ada53981da05bf2 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -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"
@@ -5844,4 +5844,7 @@ ER_CANT_CHANGE_TX_ISOLATION 25001
 	eng "Transaction isolation level can't be changed while a transaction is in progress"
 ER_DUP_ENTRY_AUTOINCREMENT_CASE
         eng "ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '%-.64s' for key '%-.64s'"
-
+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"
diff --git a/sql/sp.cc b/sql/sp.cc
index 6f074fd7dceb0fba8e78ed37659b0c2495b5bd16..0e81e627f71ceefc92623c371b7ab914413314be 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -408,15 +408,13 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
   ulong old_sql_mode= thd->variables.sql_mode;
   ha_rows old_select_limit= thd->variables.select_limit;
   sp_rcontext *old_spcont= thd->spcont;
-  
+
   char definer_user_name_holder[USERNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder,
-                                         USERNAME_LENGTH);
+  LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH };
 
   char definer_host_name_holder[HOSTNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder,
-                                         HOSTNAME_LENGTH);
-  
+  LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
+
   int ret;
 
   thd->variables.sql_mode= sql_mode;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index de56e261bd3e489b9f2a031036eae6fcd0c93c36..093ac3a3109de703e4e92158f6609882892ef434 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1823,10 +1823,10 @@ void
 sp_head::set_definer(const char *definer, uint definerlen)
 {
   char user_name_holder[USERNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT user_name(user_name_holder, USERNAME_LENGTH);
+  LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
 
   char host_name_holder[HOSTNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT host_name(host_name_holder, HOSTNAME_LENGTH);
+  LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
 
   parse_user(definer, definerlen, user_name.str, &user_name.length,
              host_name.str, &host_name.length);
diff --git a/sql/spatial.cc b/sql/spatial.cc
index e91653f79d59b193ae4a87084d615c5537843540..9f1f05aa18f931e631ad221777637b25d0d362ee 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -34,8 +34,11 @@ static Geometry::Class_info **ci_collection_end=
 
 Geometry::Class_info::Class_info(const char *name, int type_id,
 					 void(*create_func)(void *)):
-  m_name(name, strlen(name)), m_type_id(type_id), m_create_func(create_func)
+  m_type_id(type_id), m_create_func(create_func)
 {
+  m_name.str= (char *) name;
+  m_name.length= strlen(name);
+
   ci_collection[type_id]= this;
 }
 
diff --git a/sql/spatial.h b/sql/spatial.h
index a6f74a1ada0c5a4910b22eb0e6ea354a3592dc2a..36949ff501496e57d9e4f920679332576de8fe28 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -200,7 +200,7 @@ class Geometry
   class Class_info
   {
   public:
-    LEX_STRING_WITH_INIT m_name;
+    LEX_STRING m_name;
     int m_type_id;
     void (*m_create_func)(void *);
     Class_info(const char *name, int type_id, void(*create_func)(void *));
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 4bc89bfe9163098e5e82751abde7e6938e6db1c1..9b2ad209e84f37cf33c04d74b5e6f617fa960b02 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -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.
 
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 04095ff9acdde99ec8521228921930945fc1c725..a0971b22d3da4a7e86b2617ba1c5f0bedfe9fcc2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -629,6 +629,8 @@ class Security_context {
   {
     return (*priv_host ? priv_host : (char *)"%");
   }
+  
+  bool set_user(char *user_arg);
 };
 
 
@@ -770,6 +772,19 @@ class Sub_statement_state
 };
 
 
+/* 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 @@ class THD :public Statement,
   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 @@ class THD :public Statement,
 
 #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 
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 3d035359b6f46a0e959e5472fac0fbb9920461a6..6d5362c2554a29d9f585313245452ae8ea2037bf 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -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
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 223b50be74497e43f10868a8f93254ddc40563f4..b5cac24d89485142da88968a4a31dfa7827f6c2f 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -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[];
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f0bd85367d0a899003702a22240edcfe0a3484b8..3342165a97a3041f86d0b4dda293acac24a27044 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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 !!! */
 
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 33b3118de1aa2fd4853917af5670551dc9863aba..af6ac7d862acedd0ecd75df0cf362ed2ea9002ee 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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 @@ mysql_execute_command(THD *thd)
 
       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 @@ mysql_execute_command(THD *thd)
       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 @@ mysql_execute_command(THD *thd)
 		 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);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 28bedf62ea5261eb7a53e18ce6a0801b4b10fefc..f94ddc57c8064db4a2be2dca55f2498b063ae43b 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -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;
     }
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 0659f684afe41bcdb0156ed588a341e923198b0a..ddae6368228021e7181d731f09e2f08198b1e69e 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -24,8 +24,6 @@
 #define NOT_FIXED_DEC			31
 #endif
 
-#define STRING_WITH_LEN(X)  ((const char*) X), ((uint) (sizeof(X) - 1))
-
 class String;
 int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
 String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index b2b6b115f7d146d034af26e4caf0507c9a89cf8a..0ea87f3dfe438d95a9777b9f50e453caf0d18d7e 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1412,8 +1412,8 @@ bool Table_triggers_list::change_table_name(THD *thd, const char *db,
   }
   if (table.triggers)
   {
-    LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
-    LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
+    LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
+    LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
     /*
       Since triggers should be in the same schema as their subject tables
       moving table with them between two schemas raises too many questions.
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index fb84d5e4459c8d97f95084df51740514eee6d2bc..4398e0039e81771931de4e308c5deb6b40134dd3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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	{}
diff --git a/sql/structs.h b/sql/structs.h
index 722378875149898c1f6d28964829f3aeee48915c..78f00f72df17237a1fb18e107beed44c576561b0 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -20,22 +20,6 @@
 struct st_table;
 class Field;
 
-typedef struct st_lex_string
-{
-  char *str;
-  uint length;
-} LEX_STRING;
-
-typedef struct st_lex_string_with_init :public st_lex_string
-{
-  st_lex_string_with_init(const char *str_arg, uint length_arg)
-  {
-    str= (char*) str_arg;
-    length= length_arg;
-  }
-} LEX_STRING_WITH_INIT;
-
-
 typedef struct st_date_time_format {
   uchar positions[8];
   char  time_separator;			/* Separator between hour and minute */
diff --git a/sql/table.cc b/sql/table.cc
index 52f41f03d0db61827a5eb9884bb24fec73c98d5d..d0caba7fe9e05cd9c0deb314ede9d9e0201f3232 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -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 "
diff --git a/storage/ndb/include/mgmapi/mgmapi.h b/storage/ndb/include/mgmapi/mgmapi.h
index 4585e78029a3dec748fae552a072ed5fc8be502c..5a0ffcfe2c699147e9043dc5e5d8d579e4ef61ce 100644
--- a/storage/ndb/include/mgmapi/mgmapi.h
+++ b/storage/ndb/include/mgmapi/mgmapi.h
@@ -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
 
   /**
diff --git a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
index 8772e00f02792a44bb3f57c8bdf7d631ebfef244..4d5ac377a5a9fb6e0bc46bfaf6d2c78b76d59637 100644
--- a/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
+++ b/storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp
@@ -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;
diff --git a/storage/ndb/src/kernel/vm/Configuration.cpp b/storage/ndb/src/kernel/vm/Configuration.cpp
index e0e414e566983b1fe408ee320c1f26a14e744f17..12badffe0e06ce7a28a747f2f6e34d246cffaed0 100644
--- a/storage/ndb/src/kernel/vm/Configuration.cpp
+++ b/storage/ndb/src/kernel/vm/Configuration.cpp
@@ -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 },
diff --git a/storage/ndb/src/mgmapi/mgmapi.cpp b/storage/ndb/src/mgmapi/mgmapi.cpp
index b3d2d403dcc679074684af34d73253a43af11119..6dfb48667aa63f076f684615f5cabe3d4e123324 100644
--- a/storage/ndb/src/mgmapi/mgmapi.cpp
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp
@@ -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,
diff --git a/storage/ndb/src/mgmsrv/Services.cpp b/storage/ndb/src/mgmsrv/Services.cpp
index d7f58d124aad95b402a6254e9b116f1428c5fa57..2731bfd422bcc8b8d59c95df3b70e5cfdb7f0f31 100644
--- a/storage/ndb/src/mgmsrv/Services.cpp
+++ b/storage/ndb/src/mgmsrv/Services.cpp
@@ -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) {
diff --git a/storage/ndb/src/mgmsrv/Services.hpp b/storage/ndb/src/mgmsrv/Services.hpp
index 975202b96df0ae28c166044e8fca28474d985ab2..abe0233cb332fdcee6584560f5f7c57e73fab8de 100644
--- a/storage/ndb/src/mgmsrv/Services.hpp
+++ b/storage/ndb/src/mgmsrv/Services.hpp
@@ -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);
diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh
index bf17375c0ebaea5df3fdeb03dfae5a20ae229f29..bd16297f8e77ce7ca8974bbe4a2aaba34f583fce 100644
--- a/support-files/mysql.server.sh
+++ b/support-files/mysql.server.sh
@@ -265,7 +265,10 @@ case "$mode" in
     then
       # Give extra arguments to mysqld with the my.cnf file. This script may
       # be overwritten at next upgrade.
-      $manager --user=$user --pid-file=$pid_file >/dev/null 2>&1 &
+      "$manager" \
+        --mysqld-safe-compatible \
+        --user="$user" \
+        --pid-file="$pid_file" >/dev/null 2>&1 &
       wait_for_pid created
 
       # Make lock for RedHat / SuSE