diff options
77 files changed, 1852 insertions, 526 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c index ee6d7b9d12b..c0a3c55746e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2785,14 +2785,13 @@ static my_bool dump_all_views_in_db(char *database) different case (e.g. T1 vs t1) RETURN - int - 0 if a tablename was retrieved. 1 if not + pointer to the table name + 0 if error */ -static int get_actual_table_name(const char *old_table_name, - char *new_table_name, - int buf_size) +static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root) { - int retval; + char *name= 0; MYSQL_RES *table_res; MYSQL_ROW row; char query[50 + 2*NAME_LEN]; @@ -2809,66 +2808,55 @@ static int get_actual_table_name(const char *old_table_name, safe_exit(EX_MYSQLERR); } - retval = 1; - if ((table_res= mysql_store_result(sock))) { my_ulonglong num_rows= mysql_num_rows(table_res); if (num_rows > 0) { + ulong *lengths; /* Return first row TODO: Return all matching rows */ row= mysql_fetch_row(table_res); - strmake(new_table_name, row[0], buf_size-1); - retval= 0; + lengths= mysql_fetch_lengths(table_res); + name= strmake_root(root, row[0], lengths[0]); } mysql_free_result(table_res); } - return retval; + DBUG_PRINT("exit", ("new_table_name: %s", name)); + DBUG_RETURN(name); } static int dump_selected_tables(char *db, char **table_names, int tables) { - uint i; char table_buff[NAME_LEN*+3]; - char new_table_name[NAME_LEN]; DYNAMIC_STRING lock_tables_query; - HASH dump_tables; - char *table_name; + MEM_ROOT root; + char **dump_tables, **pos, **end; DBUG_ENTER("dump_selected_tables"); if (init_dumping(db)) return 1; - /* Init hash table for storing the actual name of tables to dump */ - if (hash_init(&dump_tables, charset_info, 16, 0, 0, - (hash_get_key) get_table_key, (hash_free_key) free_table_ent, - 0)) - exit(EX_EOM); + init_alloc_root(&root, 8192, 0); + if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *)))) + exit(EX_EOM); init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024); for (; tables > 0 ; tables-- , table_names++) { /* the table name passed on commandline may be wrong case */ - if (!get_actual_table_name(*table_names, - new_table_name, sizeof(new_table_name))) + if ((*pos= get_actual_table_name(*table_names, &root))) { /* Add found table name to lock_tables_query */ if (lock_tables) { - dynstr_append(&lock_tables_query, - quote_name(new_table_name, table_buff, 1)); + dynstr_append(&lock_tables_query, quote_name(*pos, table_buff, 1)); dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,"); } - - /* Add found table name to dump_tables list */ - if (my_hash_insert(&dump_tables, - (byte*)my_strdup(new_table_name, MYF(0)))) - exit(EX_EOM); - + pos++; } else { @@ -2878,6 +2866,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) /* We shall countinue here, if --force was given */ } } + end= pos; if (lock_tables) { @@ -2897,24 +2886,20 @@ static int dump_selected_tables(char *db, char **table_names, int tables) print_xml_tag1(md_result_file, "", "database name=", db, "\n"); /* Dump each selected table */ - for (i= 0; i < dump_tables.records; i++) + for (pos= dump_tables; pos < end; pos++) { - table_name= hash_element(&dump_tables, i); - DBUG_PRINT("info",("Dumping table %s", table_name)); - dump_table(table_name,db); + DBUG_PRINT("info",("Dumping table %s", *pos)); + dump_table(*pos, db); if (opt_dump_triggers && mysql_get_server_version(sock) >= 50009) - dump_triggers_for_table(table_name, db); + dump_triggers_for_table(*pos, db); } /* Dump each selected view */ if (was_views) { - for(i=0; i < dump_tables.records; i++) - { - table_name= hash_element(&dump_tables, i); - get_view_structure(table_name, db); - } + for (pos= dump_tables; pos < end; pos++) + get_view_structure(*pos, db); } /* obtain dump of routines (procs/functions) */ if (opt_routines && !opt_xml && @@ -2923,7 +2908,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) DBUG_PRINT("info", ("Dumping routines for database %s", db)); dump_routines_for_db(db); } - hash_free(&dump_tables); + free_root(&root, MYF(0)); my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); order_by= 0; if (opt_xml) diff --git a/extra/yassl/examples/echoserver/echoserver.cpp b/extra/yassl/examples/echoserver/echoserver.cpp index 3243cc21a7c..8e23ead20ab 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 a7eca9138a2..23e48d2011f 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 d2258a93723..16db142b3a2 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/include/yassl_error.hpp b/extra/yassl/include/yassl_error.hpp index 9c12b06e34a..2f35fecb59b 100644 --- a/extra/yassl/include/yassl_error.hpp +++ b/extra/yassl/include/yassl_error.hpp @@ -26,7 +26,6 @@ #ifndef yaSSL_ERROR_HPP #define yaSSL_ERROR_HPP -#include "stdexcept.hpp" namespace yaSSL { @@ -63,7 +62,7 @@ enum { MAX_ERROR_SZ = 80 }; void SetErrorString(YasslError, char*); - +/* remove for now, if go back to exceptions use this wrapper // Base class for all yaSSL exceptions class Error : public mySTL::runtime_error { YasslError error_; @@ -75,6 +74,7 @@ public: YasslError get_number() const; Library get_lib() const; }; +*/ } // naemspace diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp index 2603365e41a..2b099af930c 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 c6611803421..803f4b01249 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 66196514a87..747305730df 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 43b80d59a4d..134deb00c75 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 4fe0d3aa4f9..8b7d2d17a84 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 59113d7438c..72b8e459241 100644 --- a/extra/yassl/src/yassl_error.cpp +++ b/extra/yassl/src/yassl_error.cpp @@ -26,10 +26,13 @@ #include "runtime.hpp" #include "yassl_error.hpp" #include "error.hpp" // TaoCrypt error numbers +#include "openssl/ssl.h" // SSL_ERROR_WANT_READ +#include <string.h> // strncpy namespace yaSSL { +/* may bring back in future Error::Error(const char* s, YasslError e, Library l) : mySTL::runtime_error(s), error_(e), lib_(l) { @@ -47,6 +50,7 @@ Library Error::get_lib() const return lib_; } +*/ void SetErrorString(YasslError error, char* buffer) @@ -117,6 +121,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 f7fb1abfa3f..842bcd5fb5d 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,23 @@ ASN1_STRING* StringHolder::GetString() } - } // namespace + +extern "C" void yaSSL_CleanUp() +{ + TaoCrypt::CleanUp(); + yaSSL::ysDelete(yaSSL::cryptProviderInstance); + yaSSL::ysDelete(yaSSL::sslFactoryInstance); + yaSSL::ysDelete(yaSSL::sessionsInstance); + + // In case user calls more than once, prevent seg fault + yaSSL::cryptProviderInstance = 0; + yaSSL::sslFactoryInstance = 0; + yaSSL::sessionsInstance = 0; +} + + #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/include/block.hpp b/extra/yassl/taocrypt/include/block.hpp index 4c262e1a540..76836615ce6 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 00000000000..aac930d7498 --- /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 09ca7524ef3..3a5cf62865a 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 d3e72346110..1110ed335b8 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/integer.cpp b/extra/yassl/taocrypt/src/integer.cpp index 885ddfbf630..a296e122985 100644 --- a/extra/yassl/taocrypt/src/integer.cpp +++ b/extra/yassl/taocrypt/src/integer.cpp @@ -2735,8 +2735,11 @@ void CleanUp() { tcDelete(one); tcDelete(zero); -} + // In case user calls more than once, prevent seg fault + one = 0; + zero = 0; +} Integer::Integer(RandomNumberGenerator& rng, const Integer& min, const Integer& max) diff --git a/extra/yassl/taocrypt/src/md4.cpp b/extra/yassl/taocrypt/src/md4.cpp new file mode 100644 index 00000000000..dfc2b079141 --- /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/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp index 4ef163a7f5d..2869df71c8a 100644 --- a/extra/yassl/taocrypt/src/misc.cpp +++ b/extra/yassl/taocrypt/src/misc.cpp @@ -81,6 +81,19 @@ extern "C" { } +#if defined(__ICC) || defined(__INTEL_COMPILER) + +extern "C" { + + int __cxa_pure_virtual() { + assert("Pure virtual method called." == "Aborted"); + return 0; + } + +} // extern "C" + +#endif + #endif // YASSL_PURE_C diff --git a/extra/yassl/taocrypt/src/template_instnt.cpp b/extra/yassl/taocrypt/src/template_instnt.cpp index 5efd2d32a10..12bcd8238f2 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 b741cef0096..19edf7b2f22 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/taocrypt.vcproj b/extra/yassl/taocrypt/taocrypt.vcproj index 603fafd4090..7eef7b82db7 100755 --- a/extra/yassl/taocrypt/taocrypt.vcproj +++ b/extra/yassl/taocrypt/taocrypt.vcproj @@ -397,6 +397,27 @@ </FileConfiguration> </File> <File + RelativePath="src\md4.cpp"> + <FileConfiguration + Name="Debug|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="" + PreprocessorDefinitions="" + BasicRuntimeChecks="3" + BrowseInformation="1"/> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32"> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + AdditionalIncludeDirectories="" + PreprocessorDefinitions=""/> + </FileConfiguration> + </File> + <File RelativePath="src\md5.cpp"> <FileConfiguration Name="Debug|Win32"> @@ -572,6 +593,9 @@ RelativePath="include\md2.hpp"> </File> <File + RelativePath="include\md4.hpp"> + </File> + <File RelativePath="include\md5.hpp"> </File> <File diff --git a/extra/yassl/taocrypt/test/test.cpp b/extra/yassl/taocrypt/test/test.cpp index b8618b18d47..28ef73dfac8 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 259975fba0b..c80e3ad23da 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/heap/hp_write.c b/heap/hp_write.c index a60d32eecb6..bc94e3bfae4 100644 --- a/heap/hp_write.c +++ b/heap/hp_write.c @@ -105,7 +105,7 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *record, custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos); if (keyinfo->flag & HA_NOSAME) { - custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME | SEARCH_UPDATE; + custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE; keyinfo->rb_tree.flag= TREE_NO_DUPS; } else diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index 16c308e3450..a7f5e5e8fec 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -48,3 +48,10 @@ lock table t1 read, t2 read, t3 read; flush tables with read lock; unlock tables; drop table t1, t2, t3; +create table t1 (c1 int); +create table t2 (c1 int); +lock table t1 write; + flush tables with read lock; + insert into t2 values(1); +unlock tables; +drop table t1, t2; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 3432de5179a..07fc120da93 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -357,12 +357,12 @@ show grants for grant_user@localhost; Grants for grant_user@localhost GRANT USAGE ON *.* TO 'grant_user'@'localhost' GRANT INSERT (a, d, c, b) ON `test`.`t1` TO 'grant_user'@'localhost' -select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; Host Db User Table_name Column_name Column_priv -localhost test grant_user t1 b Insert -localhost test grant_user t1 d Insert localhost test grant_user t1 a Insert +localhost test grant_user t1 b Insert localhost test grant_user t1 c Insert +localhost test grant_user t1 d Insert revoke ALL PRIVILEGES on t1 from grant_user@localhost; show grants for grant_user@localhost; Grants for grant_user@localhost @@ -381,13 +381,27 @@ grant update (a) on mysqltest_1.t1 to mysqltest_3@localhost; grant select (b) on mysqltest_1.t2 to mysqltest_3@localhost; grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost; grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost; -show grants for mysqltest_3@localhost; -Grants for mysqltest_3@localhost -GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost' -GRANT SELECT (b) ON `mysqltest_1`.`t2` TO 'mysqltest_3'@'localhost' -GRANT UPDATE (a) ON `mysqltest_1`.`t1` TO 'mysqltest_3'@'localhost' -GRANT UPDATE (d) ON `mysqltest_2`.`t2` TO 'mysqltest_3'@'localhost' -GRANT SELECT (c) ON `mysqltest_2`.`t1` TO 'mysqltest_3'@'localhost' +SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' +ORDER BY TABLE_NAME,COLUMN_NAME,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_3'@'localhost' NULL mysqltest_1 t1 a UPDATE NO +'mysqltest_3'@'localhost' NULL mysqltest_2 t1 c SELECT NO +'mysqltest_3'@'localhost' NULL mysqltest_1 t2 b SELECT NO +'mysqltest_3'@'localhost' NULL mysqltest_2 t2 d UPDATE NO +SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' +ORDER BY TABLE_NAME,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE +SELECT * from INFORMATION_SCHEMA.SCHEMA_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' +ORDER BY TABLE_SCHEMA,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE +SELECT * from INFORMATION_SCHEMA.USER_PRIVILEGES +WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_CATALOG,PRIVILEGE_TYPE; +GRANTEE TABLE_CATALOG PRIVILEGE_TYPE IS_GRANTABLE +'mysqltest_3'@'localhost' NULL USAGE NO update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1; ERROR 42000: UPDATE command denied to user 'mysqltest_3'@'localhost' for column 'q' in table 't1' update mysqltest_1.t2, mysqltest_2.t2 set d=20 where d=1; diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index f9b55cc6a7b..d62586dba85 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1981,46 +1981,7 @@ a b c d -create table t4 ( -pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' -) engine=innodb; -insert into t4 (a1, a2, b, c, d, dummy) select * from t1; -create index idx12672_0 on t4 (a1); -create index idx12672_1 on t4 (a1,a2,b,c); -create index idx12672_2 on t4 (a1,a2,b); -analyze table t1; -Table Op Msg_type Msg_text -test.t1 analyze status Table is already up to date -select distinct a1 from t4 where pk_col not in (1,2,3,4); -a1 -a -b -c -d -drop table t1,t2,t3,t4; -create table t1 ( -a varchar(30), b varchar(30), primary key(a), key(b) -) engine=innodb; -select distinct a from t1; -a -drop table t1; -create table t1(a int, key(a)) engine=innodb; -insert into t1 values(1); -select a, count(a) from t1 group by a with rollup; -a count(a) -1 1 -NULL 1 -drop table t1; -create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb; -insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d"); -alter table t1 drop primary key, add primary key (f2, f1); -explain select distinct f1 a, f1 b from t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 5 NULL 4 Using index; Using temporary -explain select distinct f1, f2 from t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range NULL PRIMARY 5 NULL 3 Using index for group-by; Using temporary -drop table t1; +drop table t1,t2,t3; create table t1 (c1 int not null,c2 int not null, primary key(c1,c2)); insert into t1 (c1,c2) values (10,1),(10,2),(10,3),(20,4),(20,5),(20,6),(30,7),(30,8),(30,9); diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result index b63eaf7e48c..4b05e8f44e1 100644 --- a/mysql-test/r/heap_btree.result +++ b/mysql-test/r/heap_btree.result @@ -256,3 +256,6 @@ SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() INDEX_LENGTH 21 DROP TABLE t1; +CREATE TABLE t1 (a INT, UNIQUE USING BTREE(a)) ENGINE=MEMORY; +INSERT INTO t1 VALUES(NULL),(NULL); +DROP TABLE t1; diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 6295bac34a0..61a10c5f72c 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -1,3 +1,7 @@ +drop table if exists t1,t2; +drop view if exists v1,v2; +drop function if exists f1; +drop function if exists f2; use INFORMATION_SCHEMA; show tables; Tables_in_information_schema @@ -24,10 +28,12 @@ TABLE_CONSTRAINTS TABLE_PRIVILEGES TRIGGERS create database `inf%`; +create database mbase; use `inf%`; show tables; Tables_in_inf% grant all privileges on `inf%`.* to 'mysqltest_1'@'localhost'; +grant all privileges on `mbase`.* to 'mysqltest_1'@'localhost'; create table t1 (f1 int); create function func1(curr_int int) returns int begin @@ -36,9 +42,58 @@ select max(f1) from t1 into ret_val; return ret_val; end| create view v1 as select f1 from t1 where f1 = func1(f1); +create function func2() returns int return 1; +use mbase; +create procedure p1 () +begin +select table_name from information_schema.key_column_usage +order by table_name; +end| +create table t1 +(f1 int(10) unsigned not null, +f2 varchar(100) not null, +primary key (f1), unique key (f2)); select * from information_schema.tables; +call mbase.p1(); +call mbase.p1(); +call mbase.p1(); +use `inf%`; drop user mysqltest_1@localhost; +drop table t1; +select table_name, table_type, table_comment from information_schema.tables +where table_schema='inf%' and func2(); +table_name table_type table_comment +v1 VIEW View 'inf%.v1' references invalid table(s) or column(s) or function(s) or define +select table_name, table_type, table_comment from information_schema.tables +where table_schema='inf%' and func2(); +table_name table_type table_comment +v1 VIEW View 'inf%.v1' references invalid table(s) or column(s) or function(s) or define drop view v1; drop function func1; -drop table t1; +drop function func2; drop database `inf%`; +drop procedure mbase.p1; +drop database mbase; +use test; +create table t1 (i int); +create function f1 () returns int return (select max(i) from t1); +create view v1 as select f1(); +create table t2 (id int); +create function f2 () returns int return (select max(i) from t2); +create view v2 as select f2(); +drop table t2; +select table_name, table_type, table_comment from information_schema.tables +where table_schema='test'; +table_name table_type table_comment +t1 BASE TABLE +v1 VIEW VIEW +v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define +drop table t1; +select table_name, table_type, table_comment from information_schema.tables +where table_schema='test'; +table_name table_type table_comment +v1 VIEW View 'test.v1' references invalid table(s) or column(s) or function(s) or define +v2 VIEW View 'test.v2' references invalid table(s) or column(s) or function(s) or define +drop function f1; +drop function f2; +drop view v1, v2; diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index bbd9550196f..8dbfa906fe1 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -192,3 +192,79 @@ select count(*), min(7), max(7) from t2m, t1i; count(*) min(7) max(7) 0 NULL NULL drop table t1m, t1i, t2m, t2i; +create table t1 ( +a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +); +insert into t1 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'), +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'); +create table t4 ( +pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=innodb; +insert into t4 (a1, a2, b, c, d, dummy) select * from t1; +create index idx12672_0 on t4 (a1); +create index idx12672_1 on t4 (a1,a2,b,c); +create index idx12672_2 on t4 (a1,a2,b); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select distinct a1 from t4 where pk_col not in (1,2,3,4); +a1 +a +b +c +d +drop table t1,t4; +create table t1 ( +a varchar(30), b varchar(30), primary key(a), key(b) +) engine=innodb; +select distinct a from t1; +a +drop table t1; +create table t1(a int, key(a)) engine=innodb; +insert into t1 values(1); +select a, count(a) from t1 group by a with rollup; +a count(a) +1 1 +NULL 1 +drop table t1; +create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb; +insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d"); +alter table t1 drop primary key, add primary key (f2, f1); +explain select distinct f1 a, f1 b from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 5 NULL 4 Using index; Using temporary +explain select distinct f1, f2 from t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL PRIMARY 5 NULL 3 Using index for group-by; Using temporary +drop table t1; diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index 73e3a9d32e3..89428ed6a9b 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -43,3 +43,19 @@ Field Type Null Key Default Extra a int(11) YES NULL unlock tables; drop table t1; +use mysql; +LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; +FLUSH TABLES; +use mysql; + SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; +OPTIMIZE TABLES columns_priv, db, host, user; +Table Op Msg_type Msg_text +mysql.columns_priv optimize status OK +mysql.db optimize status OK +mysql.host optimize status OK +mysql.user optimize status OK +UNLOCK TABLES; +Select_priv +N +use test; +use test; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 467e0818646..eff46ecc2d6 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; +DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa, t3; drop database if exists mysqldump_test_db; drop database if exists db1; drop database if exists db2; @@ -1508,6 +1508,7 @@ a b 12 meg drop table t1, t2; drop database db1; +--fields-optionally-enclosed-by=" CREATE DATABASE mysqldump_test_db; USE mysqldump_test_db; CREATE TABLE t1 ( a INT ); @@ -2669,6 +2670,44 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; drop table t1; +create table t1(a int); +create table t2(a int); +create table t3(a int); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t3`; +CREATE TABLE `t3` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +drop table t1, t2, t3; +End of 4.1 tests create table t1 (a int); insert into t1 values (289), (298), (234), (456), (789); create definer = CURRENT_USER view v1 as select * from t1; diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index acb67250c26..89999eca051 100644 --- a/mysql-test/r/ndb_alter_table.result +++ b/mysql-test/r/ndb_alter_table.result @@ -1,4 +1,4 @@ -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; drop database if exists mysqltest; CREATE TABLE t1 ( a INT NOT NULL, @@ -315,3 +315,24 @@ unique key tx1 (c002, c003, c004, c005)) engine=ndb; create index tx2 on t1 (c010, c011, c012, c013); drop table t1; +create table t1 (a int primary key auto_increment, b int) engine=ndb; +insert into t1 (b) values (101),(102),(103); +select * from t1 where a = 3; +a b +3 103 +alter table t1 rename t2; +insert into t2 (b) values (201),(202),(203); +select * from t2 where a = 6; +a b +6 203 +alter table t2 add c int; +insert into t2 (b) values (301),(302),(303); +select * from t2 where a = 9; +a b c +9 303 NULL +alter table t2 rename t1; +insert into t1 (b) values (401),(402),(403); +select * from t1 where a = 12; +a b c +12 403 NULL +drop table t1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 056457a4786..e4bc59e4d19 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -3183,3 +3183,24 @@ select * from (select min(i) from t1 where j=(select * from (select min(j) from min(i) 1 drop table t1; +CREATE TABLE t1 (i BIGINT UNSIGNED); +INSERT INTO t1 VALUES (10000000000000000000); +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (i BIGINT UNSIGNED); +INSERT INTO t2 VALUES (10000000000000000000); +INSERT INTO t2 VALUES (1); +/* simple test */ +SELECT t1.i FROM t1 JOIN t2 ON t1.i = t2.i; +i +10000000000000000000 +1 +/* subquery test */ +SELECT t1.i FROM t1 WHERE t1.i = (SELECT MAX(i) FROM t2); +i +10000000000000000000 +/* subquery test with cast*/ +SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED); +i +10000000000000000000 +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 3feffb4a510..f6559e6f838 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -533,3 +533,88 @@ View Create View v2 CREATE ALGORITHM=UNDEFINED DEFINER=`some_user`@`localhost` SQL SECURITY INVOKER VIEW `v2` AS select 1 AS `1` drop view v1; drop view v2; +CREATE DATABASE mysqltest1; +CREATE USER readonly@localhost; +CREATE TABLE mysqltest1.t1 (x INT); +INSERT INTO mysqltest1.t1 VALUES (1), (2); +CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1; +GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly; +GRANT SELECT ON mysqltest1.v_ts TO readonly; +GRANT INSERT ON mysqltest1.v_ti TO readonly; +GRANT UPDATE ON mysqltest1.v_tu TO readonly; +GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly; +GRANT DELETE ON mysqltest1.v_td TO readonly; +GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly; +SELECT * FROM mysqltest1.v_t1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +INSERT INTO mysqltest1.v_t1 VALUES(4); +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DELETE FROM mysqltest1.v_t1 WHERE x = 1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +UPDATE mysqltest1.v_t1 SET x = 3; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DELETE FROM mysqltest1.v_t1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SELECT 1 FROM mysqltest1.v_t1; +ERROR HY000: View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SELECT * FROM mysqltest1.t1; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1' +SELECT * FROM mysqltest1.v_ts; +x +1 +2 +SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 't1' +SELECT * FROM mysqltest1.v_ti; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for table 'v_ti' +INSERT INTO mysqltest1.v_ts VALUES (100); +ERROR 42000: INSERT command denied to user 'readonly'@'localhost' for table 'v_ts' +INSERT INTO mysqltest1.v_ti VALUES (100); +UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100; +ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts' +UPDATE mysqltest1.v_ts SET x= 200; +ERROR 42000: UPDATE command denied to user 'readonly'@'localhost' for table 'v_ts' +UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tu SET x= 200; +DELETE FROM mysqltest1.v_ts WHERE x= 200; +ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts' +DELETE FROM mysqltest1.v_ts; +ERROR 42000: DELETE command denied to user 'readonly'@'localhost' for table 'v_ts' +DELETE FROM mysqltest1.v_td WHERE x= 200; +ERROR 42000: SELECT command denied to user 'readonly'@'localhost' for column 'x' in table 'v_td' +DELETE FROM mysqltest1.v_tds WHERE x= 200; +DELETE FROM mysqltest1.v_td; +DROP VIEW mysqltest1.v_tds; +DROP VIEW mysqltest1.v_td; +DROP VIEW mysqltest1.v_tus; +DROP VIEW mysqltest1.v_tu; +DROP VIEW mysqltest1.v_ti; +DROP VIEW mysqltest1.v_ts; +DROP VIEW mysqltest1.v_t1; +DROP TABLE mysqltest1.t1; +DROP USER readonly@localhost; +DROP DATABASE mysqltest1; +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2), (3); +CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; +Warnings: +Note 1449 There is no 'no-such-user'@'localhost' registered +SHOW CREATE VIEW v; +View Create View +v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `t1`.`a` AS `a` from `t1` +Warnings: +Note 1449 There is no 'no-such-user'@'localhost' registered +SELECT * FROM v; +ERROR HY000: There is no 'no-such-user'@'localhost' registered +DROP VIEW v; +DROP TABLE t1; +USE test; diff --git a/mysql-test/std_data/bug15328.cnf b/mysql-test/std_data/bug15328.cnf new file mode 100644 index 00000000000..e23d33bfa54 --- /dev/null +++ b/mysql-test/std_data/bug15328.cnf @@ -0,0 +1,2 @@ +[mysqldump] +fields-optionally-enclosed-by=" diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index f5fd9fcadf2..95ba633fefd 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -102,3 +102,43 @@ unlock tables; drop table t1, t2, t3; # End of 4.1 tests + +# +# Test of deadlock problem when doing FLUSH TABLE with read lock +# (Bug was in NTPL threads in Linux when using different mutex while +# waiting for a condtion variable) + +create table t1 (c1 int); +create table t2 (c1 int); + +connect (con1,localhost,root,,); +connect (con3,localhost,root,,); + +connection con1; +lock table t1 write; + +connection con2; +send flush tables with read lock; +--sleep 1 + +connection con3; +send insert into t2 values(1); +--sleep 1 + +connection con1; +unlock tables; +disconnect con1; + +connection con2; +reap; +disconnect con2; + +connection con3; +# It hangs here (insert into t2 does not end). +reap; +disconnect con3; + +connection default; +drop table t1, t2; + +# End of 5.0 tests diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 97f13381557..3db38d93ee1 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -302,7 +302,7 @@ DROP DATABASE testdb10; create table t1(a int, b int, c int, d int); grant insert(b), insert(c), insert(d), insert(a) on t1 to grant_user@localhost; show grants for grant_user@localhost; -select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; +select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv order by Column_name; revoke ALL PRIVILEGES on t1 from grant_user@localhost; show grants for grant_user@localhost; select Host,Db,User,Table_name,Column_name,Column_priv from mysql.columns_priv; @@ -326,7 +326,18 @@ grant select (c) on mysqltest_2.t1 to mysqltest_3@localhost; grant update (d) on mysqltest_2.t2 to mysqltest_3@localhost; connect (conn1,localhost,mysqltest_3,,); connection conn1; -show grants for mysqltest_3@localhost; +SELECT * FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_NAME,COLUMN_NAME,PRIVILEGE_TYPE; +SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_NAME,PRIVILEGE_TYPE; +SELECT * from INFORMATION_SCHEMA.SCHEMA_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_SCHEMA,PRIVILEGE_TYPE; +SELECT * from INFORMATION_SCHEMA.USER_PRIVILEGES + WHERE GRANTEE = '''mysqltest_3''@''localhost''' + ORDER BY TABLE_CATALOG,PRIVILEGE_TYPE; --error 1143 update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1; --error 1143 diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index d9836ccc8df..874f3cd1a80 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -659,59 +659,7 @@ select a1 from t1 where a2 = 'b' group by a1; explain select distinct a1 from t1 where a2 = 'b'; select distinct a1 from t1 where a2 = 'b'; -# -# Bug #12672: primary key implcitly included in every innodb index -# - ---disable_warnings -create table t4 ( - pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' -) engine=innodb; ---enable_warnings -insert into t4 (a1, a2, b, c, d, dummy) select * from t1; - -create index idx12672_0 on t4 (a1); -create index idx12672_1 on t4 (a1,a2,b,c); -create index idx12672_2 on t4 (a1,a2,b); -analyze table t1; - -select distinct a1 from t4 where pk_col not in (1,2,3,4); - -drop table t1,t2,t3,t4; - -# -# Bug #6142: a problem with the empty innodb table -# - ---disable_warnings -create table t1 ( - a varchar(30), b varchar(30), primary key(a), key(b) -) engine=innodb; ---enable_warnings -select distinct a from t1; -drop table t1; - -# -# Bug #9798: group by with rollup -# - ---disable_warnings -create table t1(a int, key(a)) engine=innodb; ---enable_warnings -insert into t1 values(1); -select a, count(a) from t1 group by a with rollup; -drop table t1; - -# -# Bug #13293 Wrongly used index results in endless loop. -# -create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb; -insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d"); -alter table t1 drop primary key, add primary key (f2, f1); -explain select distinct f1 a, f1 b from t1; -explain select distinct f1, f2 from t1; -drop table t1; - +drop table t1,t2,t3; # # Bug #14920 Ordering aggregated result sets with composite primary keys # corrupts resultset diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test index f1b9d290885..fb715fccefe 100644 --- a/mysql-test/t/heap_btree.test +++ b/mysql-test/t/heap_btree.test @@ -176,4 +176,12 @@ UPDATE t1 SET val=1; SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='t1'; DROP TABLE t1; +# +# BUG#12873 - BTREE index on MEMORY table with multiple NULL values doesn't +# work properly +# +CREATE TABLE t1 (a INT, UNIQUE USING BTREE(a)) ENGINE=MEMORY; +INSERT INTO t1 VALUES(NULL),(NULL); +DROP TABLE t1; + # End of 4.1 tests diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test index b65135a621d..2cfa766d799 100644 --- a/mysql-test/t/information_schema_db.test +++ b/mysql-test/t/information_schema_db.test @@ -1,16 +1,25 @@ -- source include/testdb_only.inc +--disable_warnings +drop table if exists t1,t2; +drop view if exists v1,v2; +drop function if exists f1; +drop function if exists f2; +--enable_warnings + use INFORMATION_SCHEMA; --replace_result Tables_in_INFORMATION_SCHEMA Tables_in_information_schema show tables; --replace_result 'Tables_in_INFORMATION_SCHEMA (T%)' 'Tables_in_information_schema (T%)' show tables from INFORMATION_SCHEMA like 'T%'; create database `inf%`; +create database mbase; use `inf%`; show tables; # # Bug#18113 SELECT * FROM information_schema.xxx crashes server +# Bug#17204 second CALL to procedure crashes Server # Crash happened when one selected data from one of INFORMATION_SCHEMA # tables and in order to build its contents server had to open view which # used stored function and table or view on which one had not global or @@ -18,6 +27,7 @@ show tables; # privileges at all). # grant all privileges on `inf%`.* to 'mysqltest_1'@'localhost'; +grant all privileges on `mbase`.* to 'mysqltest_1'@'localhost'; create table t1 (f1 int); delimiter |; create function func1(curr_int int) returns int @@ -28,15 +38,63 @@ begin end| delimiter ;| create view v1 as select f1 from t1 where f1 = func1(f1); +create function func2() returns int return 1; + +use mbase; +delimiter |; +create procedure p1 () +begin +select table_name from information_schema.key_column_usage +order by table_name; +end| +delimiter ;| + +create table t1 +(f1 int(10) unsigned not null, + f2 varchar(100) not null, + primary key (f1), unique key (f2)); + connect (user1,localhost,mysqltest_1,,); connection user1; --disable_result_log select * from information_schema.tables; +call mbase.p1(); +call mbase.p1(); +call mbase.p1(); --enable_result_log + connection default; +use `inf%`; drop user mysqltest_1@localhost; +drop table t1; +select table_name, table_type, table_comment from information_schema.tables +where table_schema='inf%' and func2(); +select table_name, table_type, table_comment from information_schema.tables +where table_schema='inf%' and func2(); drop view v1; drop function func1; -drop table t1; +drop function func2; drop database `inf%`; +drop procedure mbase.p1; +drop database mbase; + +# +# Bug#18282 INFORMATION_SCHEMA.TABLES provides inconsistent info about invalid views +# +use test; +create table t1 (i int); +create function f1 () returns int return (select max(i) from t1); +create view v1 as select f1(); +create table t2 (id int); +create function f2 () returns int return (select max(i) from t2); +create view v2 as select f2(); +drop table t2; +select table_name, table_type, table_comment from information_schema.tables +where table_schema='test'; +drop table t1; +select table_name, table_type, table_comment from information_schema.tables +where table_schema='test'; +drop function f1; +drop function f2; +drop view v1, v2; diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index 3de55e1c403..c7d2e2c0acd 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -129,3 +129,97 @@ select count(*), min(7), max(7) from t2m, t1i; drop table t1m, t1i, t2m, t2i; +# +# Bug #12672: primary key implcitly included in every innodb index +# (was part of group_min_max.test) +# + +create table t1 ( + a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +); + +insert into t1 (a1, a2, b, c, d) values +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'), +('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'), +('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'), +('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'), +('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'), +('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'), +('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'), +('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'), +('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'), +('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'), +('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'), +('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'), +('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'), +('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'), +('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'), +('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'), +('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'); +--disable_warnings +create table t4 ( + pk_col int auto_increment primary key, a1 char(64), a2 char(64), b char(16), c char(16) not null, d char(16), dummy char(64) default ' ' +) engine=innodb; +--enable_warnings +insert into t4 (a1, a2, b, c, d, dummy) select * from t1; + +create index idx12672_0 on t4 (a1); +create index idx12672_1 on t4 (a1,a2,b,c); +create index idx12672_2 on t4 (a1,a2,b); +analyze table t1; + +select distinct a1 from t4 where pk_col not in (1,2,3,4); + +drop table t1,t4; + +# +# Bug #6142: a problem with the empty innodb table +# (was part of group_min_max.test) +# + +--disable_warnings +create table t1 ( + a varchar(30), b varchar(30), primary key(a), key(b) +) engine=innodb; +--enable_warnings +select distinct a from t1; +drop table t1; + +# +# Bug #9798: group by with rollup +# (was part of group_min_max.test) +# + +--disable_warnings +create table t1(a int, key(a)) engine=innodb; +--enable_warnings +insert into t1 values(1); +select a, count(a) from t1 group by a with rollup; +drop table t1; + +# +# Bug #13293 Wrongly used index results in endless loop. +# (was part of group_min_max.test) +# +create table t1 (f1 int, f2 char(1), primary key(f1,f2)) engine=innodb; +insert into t1 values ( 1,"e"),(2,"a"),( 3,"c"),(4,"d"); +alter table t1 drop primary key, add primary key (f2, f1); +explain select distinct f1 a, f1 b from t1; +explain select distinct f1, f2 from t1; +drop table t1; + diff --git a/mysql-test/t/lock_multi.test b/mysql-test/t/lock_multi.test index 0d2266fc2ae..3c829848bf3 100644 --- a/mysql-test/t/lock_multi.test +++ b/mysql-test/t/lock_multi.test @@ -107,3 +107,35 @@ show columns from t1; connection locker; unlock tables; drop table t1; + +# +# Bug#16986 - Deadlock condition with MyISAM tables +# +connection locker; +use mysql; +LOCK TABLES columns_priv WRITE, db WRITE, host WRITE, user WRITE; +FLUSH TABLES; +--sleep 1 +# +connection reader; +use mysql; +#NOTE: This must be a multi-table select, otherwise the deadlock will not occur +send SELECT user.Select_priv FROM user, db WHERE user.user = db.user LIMIT 1; +--sleep 1 +# +connection locker; +# Make test case independent from earlier grants. +--replace_result "Table is already up to date" "OK" +OPTIMIZE TABLES columns_priv, db, host, user; +UNLOCK TABLES; +# +connection reader; +reap; +use test; +# +connection locker; +use test; +# +connection default; + +# End of 5.0 tests diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 4076fd258e9..d53022665a0 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -2,7 +2,7 @@ --source include/not_embedded.inc --disable_warnings -DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; +DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa, t3; drop database if exists mysqldump_test_db; drop database if exists db1; drop database if exists db2; @@ -607,6 +607,13 @@ drop table t1, t2; drop database db1; # +# BUG#15328 Segmentation fault occured if my.cnf is invalid for escape sequence +# + +--exec $MYSQL_MY_PRINT_DEFAULTS --defaults-extra-file=$MYSQL_TEST_DIR/std_data/bug15328.cnf mysqldump + + +# # Bug #9558 mysqldump --no-data db t1 t2 format still dumps data # @@ -1065,7 +1072,18 @@ insert into t1 values ('',''); --exec $MYSQL_DUMP --skip-comments --hex-blob test t1 drop table t1; -# End of 4.1 tests +# +# Bug #18536: wrong table order +# + +create table t1(a int); +create table t2(a int); +create table t3(a int); +--error 6 +--exec $MYSQL_DUMP --skip-comments --force --no-data test t3 t1 non_existing t2 +drop table t1, t2, t3; + +--echo End of 4.1 tests # # Bug 14871 Invalid view dump output diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 0a0211c8c83..957b95c6fd9 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -3,7 +3,7 @@ -- source include/not_embedded.inc --disable_warnings -DROP TABLE IF EXISTS t1; +DROP TABLE IF EXISTS t1, t2; drop database if exists mysqltest; --enable_warnings @@ -326,5 +326,20 @@ on t1 (c010, c011, c012, c013); drop table t1; +# simple test that auto incr is not lost at rename or alter +create table t1 (a int primary key auto_increment, b int) engine=ndb; +insert into t1 (b) values (101),(102),(103); +select * from t1 where a = 3; +alter table t1 rename t2; +insert into t2 (b) values (201),(202),(203); +select * from t2 where a = 6; +alter table t2 add c int; +insert into t2 (b) values (301),(302),(303); +select * from t2 where a = 9; +alter table t2 rename t1; +insert into t1 (b) values (401),(402),(403); +select * from t1 where a = 12; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 3f48b648f40..8916a5cec6d 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2109,3 +2109,25 @@ insert into t1 values (1, 2), (2, 2), (3, 2); select * from (select min(i) from t1 where j=(select * from (select min(j) from t1) t2)) t3; drop table t1; +# +# Bug#19700: subselect returning BIGINT always returned it as SIGNED +# +CREATE TABLE t1 (i BIGINT UNSIGNED); +INSERT INTO t1 VALUES (10000000000000000000); -- > MAX SIGNED BIGINT 9323372036854775807 +INSERT INTO t1 VALUES (1); + +CREATE TABLE t2 (i BIGINT UNSIGNED); +INSERT INTO t2 VALUES (10000000000000000000); -- same as first table +INSERT INTO t2 VALUES (1); + +/* simple test */ +SELECT t1.i FROM t1 JOIN t2 ON t1.i = t2.i; + +/* subquery test */ +SELECT t1.i FROM t1 WHERE t1.i = (SELECT MAX(i) FROM t2); + +/* subquery test with cast*/ +SELECT t1.i FROM t1 WHERE t1.i = CAST((SELECT MAX(i) FROM t2) AS UNSIGNED); + +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index e80e1770ba2..4663a667d25 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -712,3 +712,98 @@ show create view v1; show create view v2; drop view v1; drop view v2; + +# +# Bug#18681: View privileges are broken +# +CREATE DATABASE mysqltest1; +CREATE USER readonly@localhost; +CREATE TABLE mysqltest1.t1 (x INT); +INSERT INTO mysqltest1.t1 VALUES (1), (2); +CREATE SQL SECURITY INVOKER VIEW mysqltest1.v_t1 AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ts AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_ti AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tu AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tus AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_td AS SELECT * FROM mysqltest1.t1; +CREATE SQL SECURITY DEFINER VIEW mysqltest1.v_tds AS SELECT * FROM mysqltest1.t1; +GRANT SELECT, INSERT, UPDATE, DELETE ON mysqltest1.v_t1 TO readonly; +GRANT SELECT ON mysqltest1.v_ts TO readonly; +GRANT INSERT ON mysqltest1.v_ti TO readonly; +GRANT UPDATE ON mysqltest1.v_tu TO readonly; +GRANT UPDATE,SELECT ON mysqltest1.v_tus TO readonly; +GRANT DELETE ON mysqltest1.v_td TO readonly; +GRANT DELETE,SELECT ON mysqltest1.v_tds TO readonly; + +CONNECT (n1,localhost,readonly,,); +CONNECTION n1; + +--error 1356 +SELECT * FROM mysqltest1.v_t1; +--error 1356 +INSERT INTO mysqltest1.v_t1 VALUES(4); +--error 1356 +DELETE FROM mysqltest1.v_t1 WHERE x = 1; +--error 1356 +UPDATE mysqltest1.v_t1 SET x = 3 WHERE x = 2; +--error 1356 +UPDATE mysqltest1.v_t1 SET x = 3; +--error 1356 +DELETE FROM mysqltest1.v_t1; +--error 1356 +SELECT 1 FROM mysqltest1.v_t1; +--error 1142 +SELECT * FROM mysqltest1.t1; + +SELECT * FROM mysqltest1.v_ts; +--error 1142 +SELECT * FROM mysqltest1.v_ts, mysqltest1.t1 WHERE mysqltest1.t1.x = mysqltest1.v_ts.x; +--error 1142 +SELECT * FROM mysqltest1.v_ti; + +--error 1142 +INSERT INTO mysqltest1.v_ts VALUES (100); +INSERT INTO mysqltest1.v_ti VALUES (100); + +--error 1142 +UPDATE mysqltest1.v_ts SET x= 200 WHERE x = 100; +--error 1142 +UPDATE mysqltest1.v_ts SET x= 200; +UPDATE mysqltest1.v_tu SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tus SET x= 200 WHERE x = 100; +UPDATE mysqltest1.v_tu SET x= 200; + +--error 1142 +DELETE FROM mysqltest1.v_ts WHERE x= 200; +--error 1142 +DELETE FROM mysqltest1.v_ts; +--error 1143 +DELETE FROM mysqltest1.v_td WHERE x= 200; +DELETE FROM mysqltest1.v_tds WHERE x= 200; +DELETE FROM mysqltest1.v_td; + +CONNECTION default; +DROP VIEW mysqltest1.v_tds; +DROP VIEW mysqltest1.v_td; +DROP VIEW mysqltest1.v_tus; +DROP VIEW mysqltest1.v_tu; +DROP VIEW mysqltest1.v_ti; +DROP VIEW mysqltest1.v_ts; +DROP VIEW mysqltest1.v_t1; +DROP TABLE mysqltest1.t1; +DROP USER readonly@localhost; +DROP DATABASE mysqltest1; + +# +# BUG#14875: Bad view DEFINER makes SHOW CREATE VIEW fail +# +CREATE TABLE t1 (a INT PRIMARY KEY); +INSERT INTO t1 VALUES (1), (2), (3); +CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; +--warning 1448 +SHOW CREATE VIEW v; +--error 1449 +SELECT * FROM v; +DROP VIEW v; +DROP TABLE t1; +USE test; diff --git a/mysys/default.c b/mysys/default.c index 90f8dc5f689..540968d4ba0 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -755,7 +755,9 @@ static int search_default_file_with_ext(Process_option_func opt_handler, value_end=value; /* remove quotes around argument */ - if ((*value == '\"' || *value == '\'') && *value == value_end[-1]) + if ((*value == '\"' || *value == '\'') && /* First char is quote */ + (value + 1 < value_end ) && /* String is longer than 1 */ + *value == value_end[-1] ) /* First char is equal to last char */ { value++; value_end--; diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index 7e2e9037a34..f128a45f5bf 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -984,6 +984,7 @@ class BaseString; class NdbEventOperation; class NdbBlob; class NdbReceiver; +class Ndb_local_table_info; template <class T> struct Ndb_free_list_t; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); @@ -1431,27 +1432,29 @@ public: * * @param cacheSize number of values to cache in this Ndb object * - * @return tuple id or 0 on error + * @return 0 or -1 on error, and tupleId in out parameter */ - Uint64 getAutoIncrementValue(const char* aTableName, - Uint32 cacheSize = 1); - Uint64 getAutoIncrementValue(const NdbDictionary::Table * aTable, - Uint32 cacheSize = 1); - Uint64 readAutoIncrementValue(const char* aTableName); - Uint64 readAutoIncrementValue(const NdbDictionary::Table * aTable); - bool setAutoIncrementValue(const char* aTableName, Uint64 val, - bool increase = false); - bool setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, - bool increase = false); - Uint64 getTupleIdFromNdb(const char* aTableName, - Uint32 cacheSize = 1000); - Uint64 getTupleIdFromNdb(Uint32 aTableId, - Uint32 cacheSize = 1000); - Uint64 readTupleIdFromNdb(Uint32 aTableId); - bool setTupleIdInNdb(const char* aTableName, Uint64 val, - bool increase); - bool setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase); - Uint64 opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op); + int getAutoIncrementValue(const char* aTableName, + Uint64 & tupleId, Uint32 cacheSize); + int getAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId, Uint32 cacheSize); + int readAutoIncrementValue(const char* aTableName, + Uint64 & tupleId); + int readAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId); + int setAutoIncrementValue(const char* aTableName, + Uint64 tupleId, bool increase); + int setAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 tupleId, bool increase); +private: + int getTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId, Uint32 cacheSize); + int readTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId); + int setTupleIdInNdb(Ndb_local_table_info* info, + Uint64 tupleId, bool increase); + int opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op); +public: /** */ @@ -1650,11 +1653,6 @@ private: Uint64 the_last_check_time; Uint64 theFirstTransId; - - // The tupleId is retreived from DB the - // tupleId is unique for each tableid. - Uint64 theFirstTupleId[2048]; - Uint64 theLastTupleId[2048]; Uint32 theRestartGCI; // the Restart GCI used by DIHNDBTAMPER diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index c403aad5516..176bab0d4bf 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -1607,10 +1607,9 @@ void Ndbcntr::systemErrorLab(Signal* signal, int line) /* |-2048| # 1 00000001 | */ /* | : | : | */ /* | -1 | # 1 00000001 | */ -/* | 0 | 0 | */ -/* | 1 | 0 | */ -/* | : | : | */ -/* | 2047| 0 | */ +/* | 1 | 0 | tupleid sequence now created on first use */ +/* | : | : | v */ +/* | 2048| 0 | v */ /*---------------------------------------------------------------------------*/ void Ndbcntr::createSystableLab(Signal* signal, unsigned index) { @@ -1819,8 +1818,7 @@ void Ndbcntr::crSystab8Lab(Signal* signal) jam(); ckey = 1; ctransidPhase = ZFALSE; - crSystab7Lab(signal); - return; + // skip 2nd loop - tupleid sequence now created on first use }//if signal->theData[0] = ctcConnectionP; signal->theData[1] = reference(); diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index 740f67da2df..a6a90fe3039 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -45,6 +45,8 @@ void Ndb_local_table_info::destroy(Ndb_local_table_info *info) Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl) { m_table_impl= table_impl; + m_first_tuple_id = ~(Uint64)0; + m_last_tuple_id = ~(Uint64)0; } Ndb_local_table_info::~Ndb_local_table_info() diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp index 6afa7946a8e..19198e88824 100644 --- a/ndb/src/ndbapi/DictCache.hpp +++ b/ndb/src/ndbapi/DictCache.hpp @@ -33,6 +33,11 @@ public: static Ndb_local_table_info *create(NdbTableImpl *table_impl, Uint32 sz=0); static void destroy(Ndb_local_table_info *); NdbTableImpl *m_table_impl; + + // range of cached tuple ids per thread + Uint64 m_first_tuple_id; + Uint64 m_last_tuple_id; + Uint64 m_local_data[1]; // Must be last member. Used to access extra space. private: Ndb_local_table_info(NdbTableImpl *table_impl); diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index 7893aaae15c..56d68503825 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -760,172 +760,226 @@ Remark: Returns a new TupleId to the application. The TupleId comes from SYSTAB_0 where SYSKEY_0 = TableId. It is initialized to (TableId << 48) + 1 in NdbcntrMain.cpp. ****************************************************************************/ -Uint64 -Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize) +int +Ndb::getAutoIncrementValue(const char* aTableName, + Uint64 & tupleId, Uint32 cacheSize) { - DBUG_ENTER("getAutoIncrementValue"); + DBUG_ENTER("Ndb::getAutoIncrementValue"); BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); - if (info == 0) - DBUG_RETURN(~(Uint64)0); - const NdbTableImpl *table= info->m_table_impl; - Uint64 tupleId = getTupleIdFromNdb(table->m_tableId, cacheSize); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); - DBUG_RETURN(tupleId); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(-1); + } + if (getTupleIdFromNdb(info, tupleId, cacheSize) == -1) + DBUG_RETURN(-1); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); + DBUG_RETURN(0); } -Uint64 -Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, Uint32 cacheSize) +int +Ndb::getAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId, Uint32 cacheSize) { - DBUG_ENTER("getAutoIncrementValue"); - if (aTable == 0) - DBUG_RETURN(~(Uint64)0); + DBUG_ENTER("Ndb::getAutoIncrementValue"); + assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - Uint64 tupleId = getTupleIdFromNdb(table->m_tableId, cacheSize); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); - DBUG_RETURN(tupleId); -} + const BaseString& internal_tabname = table->m_internalName; -Uint64 -Ndb::getTupleIdFromNdb(const char* aTableName, Uint32 cacheSize) -{ - const NdbTableImpl* table = theDictionary->getTable(aTableName); - if (table == 0) - return ~(Uint64)0; - return getTupleIdFromNdb(table->m_tableId, cacheSize); + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(-1); + } + if (getTupleIdFromNdb(info, tupleId, cacheSize) == -1) + DBUG_RETURN(-1); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); + DBUG_RETURN(0); } -Uint64 -Ndb::getTupleIdFromNdb(Uint32 aTableId, Uint32 cacheSize) +int +Ndb::getTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId, Uint32 cacheSize) { - DBUG_ENTER("getTupleIdFromNdb"); - if ( theFirstTupleId[aTableId] != theLastTupleId[aTableId] ) + DBUG_ENTER("Ndb::getTupleIdFromNdb"); + if (info->m_first_tuple_id != info->m_last_tuple_id) { - theFirstTupleId[aTableId]++; - DBUG_PRINT("info", ("next cached value %ul", - (ulong) theFirstTupleId[aTableId])); - DBUG_RETURN(theFirstTupleId[aTableId]); + assert(info->m_first_tuple_id < info->m_last_tuple_id); + tupleId = ++info->m_first_tuple_id; + DBUG_PRINT("info", ("next cached value %llu", (ulonglong)tupleId)); } - else // theFirstTupleId == theLastTupleId + else { - DBUG_PRINT("info",("reading %u values from database", - (cacheSize == 0) ? 1 : cacheSize)); - DBUG_RETURN(opTupleIdOnNdb(aTableId, (cacheSize == 0) ? 1 : cacheSize, 0)); + if (cacheSize == 0) + cacheSize = 1; + DBUG_PRINT("info", ("reading %u values from database", (uint)cacheSize)); + /* + * reserve next cacheSize entries in db. adds cacheSize to NEXTID + * and returns first tupleId in the new range. + */ + Uint64 opValue = cacheSize; + if (opTupleIdOnNdb(info, opValue, 0) == -1) + DBUG_RETURN(-1); + tupleId = opValue; } + DBUG_RETURN(0); } -Uint64 -Ndb::readAutoIncrementValue(const char* aTableName) +int +Ndb::readAutoIncrementValue(const char* aTableName, + Uint64 & tupleId) { - DBUG_ENTER("readAutoIncrementValue"); - const NdbTableImpl* table = theDictionary->getTable(aTableName); - if (table == 0) { - theError= theDictionary->getNdbError(); - DBUG_RETURN(~(Uint64)0); + DBUG_ENTER("Ndb::readAutoIncrementValue"); + BaseString internal_tabname(internalize_table_name(aTableName)); + + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(-1); } - Uint64 tupleId = readTupleIdFromNdb(table->m_tableId); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); - DBUG_RETURN(tupleId); + if (readTupleIdFromNdb(info, tupleId) == -1) + DBUG_RETURN(-1); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); + DBUG_RETURN(0); } -Uint64 -Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable) +int +Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 & tupleId) { - DBUG_ENTER("readAutoIncrementValue"); - if (aTable == 0) - DBUG_RETURN(~(Uint64)0); + DBUG_ENTER("Ndb::readAutoIncrementValue"); + assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - Uint64 tupleId = readTupleIdFromNdb(table->m_tableId); - DBUG_PRINT("info", ("value %ul", (ulong) tupleId)); - DBUG_RETURN(tupleId); + const BaseString& internal_tabname = table->m_internalName; + + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(-1); + } + if (readTupleIdFromNdb(info, tupleId) == -1) + DBUG_RETURN(-1); + DBUG_PRINT("info", ("value %llu", (ulonglong)tupleId)); + DBUG_RETURN(0); } -Uint64 -Ndb::readTupleIdFromNdb(Uint32 aTableId) +int +Ndb::readTupleIdFromNdb(Ndb_local_table_info* info, + Uint64 & tupleId) { - if ( theFirstTupleId[aTableId] == theLastTupleId[aTableId] ) - // Cache is empty, check next in database - return opTupleIdOnNdb(aTableId, 0, 3); - - return theFirstTupleId[aTableId] + 1; + DBUG_ENTER("Ndb::readTupleIdFromNdb"); + if (info->m_first_tuple_id != info->m_last_tuple_id) + { + assert(info->m_first_tuple_id < info->m_last_tuple_id); + tupleId = info->m_first_tuple_id + 1; + } + else + { + /* + * peek at NEXTID. does not reserve it so the value is valid + * only if no other transactions are allowed. + */ + Uint64 opValue = 0; + if (opTupleIdOnNdb(info, opValue, 3) == -1) + DBUG_RETURN(-1); + tupleId = opValue; + } + DBUG_RETURN(0); } -bool -Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase) +int +Ndb::setAutoIncrementValue(const char* aTableName, + Uint64 tupleId, bool increase) { - DBUG_ENTER("setAutoIncrementValue"); + DBUG_ENTER("Ndb::setAutoIncrementValue"); BaseString internal_tabname(internalize_table_name(aTableName)); Ndb_local_table_info *info= theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { - theError= theDictionary->getNdbError(); - DBUG_RETURN(false); + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(-1); } - const NdbTableImpl* table= info->m_table_impl; - DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); + if (setTupleIdInNdb(info, tupleId, increase) == -1) + DBUG_RETURN(-1); + DBUG_RETURN(0); } -bool -Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase) +int +Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, + Uint64 tupleId, bool increase) { - DBUG_ENTER("setAutoIncrementValue"); - if (aTable == 0) - DBUG_RETURN(~(Uint64)0); + DBUG_ENTER("Ndb::setAutoIncrementValue"); + assert(aTable != 0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); -} + const BaseString& internal_tabname = table->m_internalName; -bool -Ndb::setTupleIdInNdb(const char* aTableName, Uint64 val, bool increase ) -{ - DBUG_ENTER("setTupleIdInNdb(const char*, ...)"); - const NdbTableImpl* table = theDictionary->getTable(aTableName); - if (table == 0) { - theError= theDictionary->getNdbError(); - DBUG_RETURN(false); + Ndb_local_table_info *info= + theDictionary->get_local_table_info(internal_tabname, false); + if (info == 0) { + theError.code = theDictionary->getNdbError().code; + DBUG_RETURN(-1); } - DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); + if (setTupleIdInNdb(info, tupleId, increase) == -1) + DBUG_RETURN(-1); + DBUG_RETURN(0); } -bool -Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase ) +int +Ndb::setTupleIdInNdb(Ndb_local_table_info* info, + Uint64 tupleId, bool increase) { - DBUG_ENTER("setTupleIdInNdb(Uint32, ...)"); + DBUG_ENTER("Ndb::setTupleIdInNdb"); if (increase) { - if (theFirstTupleId[aTableId] != theLastTupleId[aTableId]) + if (info->m_first_tuple_id != info->m_last_tuple_id) { - // We have a cache sequence - if (val <= theFirstTupleId[aTableId]+1) - DBUG_RETURN(false); - if (val <= theLastTupleId[aTableId]) + assert(info->m_first_tuple_id < info->m_last_tuple_id); + if (tupleId <= info->m_first_tuple_id + 1) + DBUG_RETURN(0); + if (tupleId <= info->m_last_tuple_id) { - theFirstTupleId[aTableId] = val - 1; - DBUG_RETURN(true); + info->m_first_tuple_id = tupleId - 1; + DBUG_PRINT("info", + ("Setting next auto increment cached value to %llu", + (ulonglong)tupleId)); + DBUG_RETURN(0); } - // else continue; } - DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 2) == val)); + /* + * if tupleId <= NEXTID, do nothing. otherwise update NEXTID to + * tupleId and set cached range to first = last = tupleId - 1. + */ + if (opTupleIdOnNdb(info, tupleId, 2) == -1) + DBUG_RETURN(-1); } else - DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 1) == val)); + { + /* + * update NEXTID to given value. reset cached range. + */ + if (opTupleIdOnNdb(info, tupleId, 1) == -1) + DBUG_RETURN(-1); + } + DBUG_RETURN(0); } -Uint64 -Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) +int +Ndb::opTupleIdOnNdb(Ndb_local_table_info* info, Uint64 & opValue, Uint32 op) { DBUG_ENTER("Ndb::opTupleIdOnNdb"); + Uint32 aTableId = info->m_table_impl->m_tableId; DBUG_PRINT("enter", ("table=%u value=%llu op=%u", aTableId, opValue, op)); NdbTransaction* tConnection; NdbOperation* tOperation= 0; // Compiler warning if not initialized Uint64 tValue; NdbRecAttr* tRecAttrResult; - int result; - Uint64 ret; CHECK_STATUS_MACRO_ZERO; @@ -958,42 +1012,45 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) tValue = tRecAttrResult->u_64_value(); - theFirstTupleId[aTableId] = tValue - opValue; - theLastTupleId[aTableId] = tValue - 1; - ret = theFirstTupleId[aTableId]; + info->m_first_tuple_id = tValue - opValue; + info->m_last_tuple_id = tValue - 1; + opValue = info->m_first_tuple_id; // out break; case 1: - tOperation->updateTuple(); + // create on first use + tOperation->writeTuple(); tOperation->equal("SYSKEY_0", aTableId ); tOperation->setValue("NEXTID", opValue); if (tConnection->execute( Commit ) == -1 ) goto error_handler; - theFirstTupleId[aTableId] = ~(Uint64)0; - theLastTupleId[aTableId] = ~(Uint64)0; - ret = opValue; + info->m_first_tuple_id = ~(Uint64)0; + info->m_last_tuple_id = ~(Uint64)0; break; case 2: tOperation->interpretedUpdateTuple(); tOperation->equal("SYSKEY_0", aTableId ); tOperation->load_const_u64(1, opValue); tOperation->read_attr("NEXTID", 2); + // compare NEXTID >= opValue tOperation->branch_le(2, 1, 0); tOperation->write_attr("NEXTID", 1); tOperation->interpret_exit_ok(); tOperation->def_label(0); tOperation->interpret_exit_nok(9999); - if ( (result = tConnection->execute( Commit )) == -1 ) - goto error_handler; - - if (result == 9999) - ret = ~(Uint64)0; + if (tConnection->execute( Commit ) == -1) + { + if (tConnection->theError.code != 9999) + goto error_handler; + } else { - theFirstTupleId[aTableId] = theLastTupleId[aTableId] = opValue - 1; - ret = opValue; + DBUG_PRINT("info", + ("Setting next auto increment value (db) to %llu", + (ulonglong)opValue)); + info->m_first_tuple_id = info->m_last_tuple_id = opValue - 1; } break; case 3: @@ -1002,7 +1059,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) tRecAttrResult = tOperation->getValue("NEXTID"); if (tConnection->execute( Commit ) == -1 ) goto error_handler; - ret = tRecAttrResult->u_64_value(); + opValue = tRecAttrResult->u_64_value(); // out break; default: goto error_handler; @@ -1014,7 +1071,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) setDatabaseName(currentDb.c_str()); setDatabaseSchemaName(currentSchema.c_str()); - DBUG_RETURN(ret); + DBUG_RETURN(0); error_handler: theError.code = tConnection->theError.code; @@ -1028,7 +1085,7 @@ Ndb::opTupleIdOnNdb(Uint32 aTableId, Uint64 opValue, Uint32 op) theError.code, tConnection ? tConnection->theError.code : -1, tOperation ? tOperation->theError.code : -1)); - DBUG_RETURN(~(Uint64)0); + DBUG_RETURN(-1); } Uint32 diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 6cb8e1f9a24..58452152dd9 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -759,10 +759,6 @@ NdbDictionaryImpl::fetchGlobalTableImpl(const BaseString& internalTableName) Ndb_local_table_info::create(impl, m_local_table_data_size); m_localHash.put(internalTableName.c_str(), info); - - m_ndb.theFirstTupleId[impl->getTableId()] = ~0; - m_ndb.theLastTupleId[impl->getTableId()] = ~0; - return info; } @@ -1746,14 +1742,11 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, DBUG_RETURN(ret); if (haveAutoIncrement) { - if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(), - autoIncrementValue)) { - if (ndb.theError.code == 0) { - m_error.code= 4336; - ndb.theError = m_error; - } else - m_error= ndb.theError; - ret = -1; // errorcode set in initialize_autoincrement + if (ndb.setAutoIncrementValue(impl.m_externalName.c_str(), + autoIncrementValue, false) == -1) { + DBUG_ASSERT(ndb.theError.code != 0); + m_error= ndb.theError; + ret = -1; } } } diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index d4ab30aec4e..d5ad7066273 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -96,10 +96,6 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, for (i = 0; i < MAX_NDB_NODES ; i++) { theConnectionArray[i] = NULL; }//forg - for (i = 0; i < 2048 ; i++) { - theFirstTupleId[i] = 0; - theLastTupleId[i] = 0; - }//for theImpl->m_dbname.assign(aDataBase); theImpl->m_schemaname.assign(aSchema); diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp index dd5846f0d62..710a47bf3dc 100644 --- a/ndb/test/ndbapi/testDict.cpp +++ b/ndb/test/ndbapi/testDict.cpp @@ -1139,9 +1139,13 @@ runCreateAutoincrementTable(NDBT_Context* ctx, NDBT_Step* step){ for (int i = 0; i < 16; i++) { - Uint64 value = myNdb->getAutoIncrementValue(tabname, 1); - - if (value != (startvalue+i)) { + Uint64 value; + if (myNdb->getAutoIncrementValue(tabname, value, 1) == -1) { + g_err << "getAutoIncrementValue failed on " << tabname << endl; + APIERROR(myNdb->getNdbError()); + return NDBT_FAILED; + } + else if (value != (startvalue+i)) { g_err << "value = " << value << " expected " << startvalue+i << endl;; APIERROR(myNdb->getNdbError()); // ret = NDBT_FAILED; diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index 038d57daf97..d62ca3f610a 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -148,9 +148,12 @@ BackupRestore::finalize_table(const TableS & table){ if (table.have_auto_inc()) { Uint64 max_val= table.get_max_auto_val(); - Uint64 auto_val= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable)); - if (max_val+1 > auto_val || auto_val == ~(Uint64)0) - ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false); + Uint64 auto_val; + int r= m_ndb->readAutoIncrementValue(get_table(table.m_dictTable), auto_val); + if (r == -1 && m_ndb->getNdbError().code != 626) + ret= false; + else if (r == -1 || max_val+1 > auto_val) + ret= m_ndb->setAutoIncrementValue(get_table(table.m_dictTable), max_val+1, false) != -1; } return ret; } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 3d9bd2dbe0f..5938d76e8a5 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -73,7 +73,6 @@ handlerton ndbcluster_hton = { HTON_NO_FLAGS }; -#define NDB_FAILED_AUTO_INCREMENT ~(Uint64)0 #define NDB_AUTO_INCREMENT_RETRIES 10 #define NDB_INVALID_SCHEMA_OBJECT 241 @@ -2112,14 +2111,15 @@ int ha_ndbcluster::write_row(byte *record) { // Table has hidden primary key Ndb *ndb= get_ndb(); - Uint64 auto_value= NDB_FAILED_AUTO_INCREMENT; + int ret; + Uint64 auto_value; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { - auto_value= ndb->getAutoIncrementValue((const NDBTAB *) m_table); - } while (auto_value == NDB_FAILED_AUTO_INCREMENT && + ret= ndb->getAutoIncrementValue((const NDBTAB *) m_table, auto_value, 1); + } while (ret == -1 && --retries && ndb->getNdbError().status == NdbError::TemporaryError); - if (auto_value == NDB_FAILED_AUTO_INCREMENT) + if (ret == -1) ERR_RETURN(ndb->getNdbError()); if (set_hidden_key(op, table->s->fields, (const byte*)&auto_value)) ERR_RETURN(op->getNdbError()); @@ -2197,11 +2197,11 @@ int ha_ndbcluster::write_row(byte *record) Ndb *ndb= get_ndb(); Uint64 next_val= (Uint64) table->next_number_field->val_int() + 1; DBUG_PRINT("info", - ("Trying to set next auto increment value to %lu", - (ulong) next_val)); - if (ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE)) - DBUG_PRINT("info", - ("Setting next auto increment value to %u", next_val)); + ("Trying to set next auto increment value to %llu", + (ulonglong) next_val)); + if (ndb->setAutoIncrementValue((const NDBTAB *) m_table, next_val, TRUE) + == -1) + ERR_RETURN(ndb->getNdbError()); } m_skip_auto_increment= TRUE; @@ -3047,8 +3047,16 @@ void ha_ndbcluster::info(uint flag) { Ndb *ndb= get_ndb(); - auto_increment_value= - ndb->readAutoIncrementValue((const NDBTAB *) m_table); + Uint64 auto_increment_value64; + if (ndb->readAutoIncrementValue((const NDBTAB *) m_table, + auto_increment_value64) == -1) + { + const NdbError err= ndb->getNdbError(); + sql_print_error("Error %lu in readAutoIncrementValue(): %s", + (ulong) err.code, err.message); + auto_increment_value= ~(Uint64)0; + } + auto_increment_value= (ulonglong)auto_increment_value64; } } DBUG_VOID_RETURN; @@ -4375,17 +4383,17 @@ ulonglong ha_ndbcluster::get_auto_increment() m_rows_to_insert - m_rows_inserted : ((m_rows_to_insert > m_autoincrement_prefetch) ? m_rows_to_insert : m_autoincrement_prefetch)); - auto_value= NDB_FAILED_AUTO_INCREMENT; + int ret; uint retries= NDB_AUTO_INCREMENT_RETRIES; do { - auto_value= - (m_skip_auto_increment) ? - ndb->readAutoIncrementValue((const NDBTAB *) m_table) - : ndb->getAutoIncrementValue((const NDBTAB *) m_table, cache_size); - } while (auto_value == NDB_FAILED_AUTO_INCREMENT && + ret= + m_skip_auto_increment ? + ndb->readAutoIncrementValue((const NDBTAB *) m_table, auto_value) : + ndb->getAutoIncrementValue((const NDBTAB *) m_table, auto_value, cache_size); + } while (ret == -1 && --retries && ndb->getNdbError().status == NdbError::TemporaryError); - if (auto_value == NDB_FAILED_AUTO_INCREMENT) + if (ret == -1) { const NdbError err= ndb->getNdbError(); sql_print_error("Error %lu in ::get_auto_increment(): %s", diff --git a/sql/item.h b/sql/item.h index de9e9737187..2311133b86b 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2245,6 +2245,7 @@ public: max_length= item->max_length; decimals= item->decimals; collation.set(item->collation); + unsigned_flag= item->unsigned_flag; return 0; }; virtual void store(Item *)= 0; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 87ef0fc080e..dda1b46ab10 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -404,6 +404,7 @@ void Item_singlerow_subselect::fix_length_and_dec() engine->fix_length_and_dec(row); value= *row; } + unsigned_flag= value->unsigned_flag; /* If there are not tables in subquery then ability to have NULL value depends on SELECT list (if single row subquery have tables then it diff --git a/sql/lock.cc b/sql/lock.cc index 8ea13b2117c..71384fe7fc6 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1138,16 +1138,17 @@ bool lock_global_read_lock(THD *thd) if (!thd->global_read_lock) { + const char *old_message; (void) pthread_mutex_lock(&LOCK_global_read_lock); - const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, - "Waiting to get readlock"); + old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, + "Waiting to get readlock"); DBUG_PRINT("info", ("waiting_for: %d protect_against: %d", waiting_for_read_lock, protect_against_global_read_lock)); waiting_for_read_lock++; while (protect_against_global_read_lock && !thd->killed) - pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); + pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); waiting_for_read_lock--; if (thd->killed) { @@ -1169,9 +1170,15 @@ bool lock_global_read_lock(THD *thd) DBUG_RETURN(0); } + void unlock_global_read_lock(THD *thd) { uint tmp; + DBUG_ENTER("unlock_global_read_lock"); + DBUG_PRINT("info", + ("global_read_lock: %u global_read_lock_blocks_commit: %u", + global_read_lock, global_read_lock_blocks_commit)); + pthread_mutex_lock(&LOCK_global_read_lock); tmp= --global_read_lock; if (thd->global_read_lock == MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT) @@ -1179,8 +1186,13 @@ void unlock_global_read_lock(THD *thd) pthread_mutex_unlock(&LOCK_global_read_lock); /* Send the signal outside the mutex to avoid a context switch */ if (!tmp) - pthread_cond_broadcast(&COND_refresh); + { + DBUG_PRINT("signal", ("Broadcasting COND_global_read_lock")); + pthread_cond_broadcast(&COND_global_read_lock); + } thd->global_read_lock= 0; + + DBUG_VOID_RETURN; } #define must_wait (global_read_lock && \ @@ -1218,11 +1230,15 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, */ DBUG_RETURN(is_not_commit); } - old_message=thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, + old_message=thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting for release of readlock"); while (must_wait && ! thd->killed && (!abort_on_refresh || thd->version == refresh_version)) - (void) pthread_cond_wait(&COND_refresh,&LOCK_global_read_lock); + { + DBUG_PRINT("signal", ("Waiting for COND_global_read_lock")); + (void) pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); + DBUG_PRINT("signal", ("Got COND_global_read_lock")); + } if (thd->killed) result=1; } @@ -1251,7 +1267,7 @@ void start_waiting_global_read_lock(THD *thd) (waiting_for_read_lock || global_read_lock_blocks_commit)); (void) pthread_mutex_unlock(&LOCK_global_read_lock); if (tmp) - pthread_cond_broadcast(&COND_refresh); + pthread_cond_broadcast(&COND_global_read_lock); DBUG_VOID_RETURN; } @@ -1273,10 +1289,10 @@ bool make_global_read_lock_block_commit(THD *thd) /* For testing we set up some blocking, to see if we can be killed */ DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock++;); - old_message= thd->enter_cond(&COND_refresh, &LOCK_global_read_lock, + old_message= thd->enter_cond(&COND_global_read_lock, &LOCK_global_read_lock, "Waiting for all running commits to finish"); while (protect_against_global_read_lock && !thd->killed) - pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); + pthread_cond_wait(&COND_global_read_lock, &LOCK_global_read_lock); DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock--;); if ((error= test(thd->killed))) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d1781c0ebbf..6d39f2f7440 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -947,6 +947,13 @@ bool insert_fields(THD *thd, Name_resolution_context *context, bool setup_tables(THD *thd, Name_resolution_context *context, List<TABLE_LIST> *from_clause, TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert); +bool setup_tables_and_check_access (THD *thd, + Name_resolution_context *context, + List<TABLE_LIST> *from_clause, + TABLE_LIST *tables, Item **conds, + TABLE_LIST **leaves, + bool select_insert, + ulong want_access); int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, List<Item> *sum_func_list, uint wild_num); bool setup_fields(THD *thd, Item** ref_pointer_array, @@ -1220,6 +1227,7 @@ extern pthread_mutex_t LOCK_des_key_file; #endif extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; +extern pthread_cond_t COND_global_read_lock; extern pthread_attr_t connection_attrib; extern I_List<THD> threads; extern I_List<NAMED_LIST> key_caches; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a306ec392ed..158f707d782 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -516,7 +516,7 @@ pthread_mutex_t LOCK_prepared_stmt_count; pthread_mutex_t LOCK_des_key_file; #endif rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; -pthread_cond_t COND_refresh,COND_thread_count; +pthread_cond_t COND_refresh,COND_thread_count, COND_global_read_lock; pthread_t signal_thread; pthread_attr_t connection_attrib; @@ -1248,6 +1248,7 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_prepared_stmt_count); (void) pthread_cond_destroy(&COND_thread_count); (void) pthread_cond_destroy(&COND_refresh); + (void) pthread_cond_destroy(&COND_global_read_lock); (void) pthread_cond_destroy(&COND_thread_cache); (void) pthread_cond_destroy(&COND_flush_thread_cache); (void) pthread_cond_destroy(&COND_manager); @@ -1670,13 +1671,11 @@ void end_thread(THD *thd, bool put_in_cache) } } - DBUG_PRINT("info", ("sending a broadcast")) - /* Tell main we are ready */ (void) pthread_mutex_unlock(&LOCK_thread_count); /* It's safe to broadcast outside a lock (COND... is not deleted here) */ + DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); (void) pthread_cond_broadcast(&COND_thread_count); - DBUG_PRINT("info", ("unlocked thread_count mutex")) #ifdef ONE_THREAD if (!(test_flags & TEST_NO_THREADS)) // For debugging under Linux #endif @@ -2824,6 +2823,7 @@ static int init_thread_environment() (void) my_rwlock_init(&LOCK_grant, NULL); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); + (void) pthread_cond_init(&COND_global_read_lock,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); (void) pthread_cond_init(&COND_flush_thread_cache,NULL); (void) pthread_cond_init(&COND_manager,NULL); @@ -4827,7 +4827,8 @@ Disable with --skip-bdb (will save memory).", 0, GET_BOOL, NO_ARG, 0, 0, 0, 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.", + {"external-locking", OPT_USE_LOCKING, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. \ +Disable with --skip-external-locking.", (gptr*) &opt_external_locking, (gptr*) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"flush", OPT_FLUSH, "Flush tables to disk between SQL commands.", 0, 0, 0, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 02b2f88676f..46b1b8795b6 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -959,6 +959,8 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, sctx->master_access= 0; sctx->db_access= 0; + sctx->priv_user= (char *) ""; + *sctx->priv_host= 0; /* Find acl entry in user database. @@ -3562,6 +3564,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table(); Security_context *sctx= thd->security_ctx; uint i; + ulong orig_want_access= want_access; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); @@ -3583,18 +3586,22 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); } - want_access&= ~sctx->master_access; - if (!want_access) - DBUG_RETURN(0); // ok - rw_rdlock(&LOCK_grant); for (table= tables; table && number-- && table != first_not_own_table; table= table->next_global) { GRANT_TABLE *grant_table; + sctx = test(table->security_ctx) ? + table->security_ctx : thd->security_ctx; + + want_access= orig_want_access; + want_access&= ~sctx->master_access; + if (!want_access) + continue; // ok + if (!(~table->grant.privilege & want_access) || - table->derived || table->schema_table || table->belong_to_view) + table->derived || table->schema_table) { /* It is subquery in the FROM clause. VIEW set table->derived after diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1f3b9e14631..75b69c91846 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -316,7 +316,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", - ("Waiting for others threads to close their open tables")); + ("Waiting for other threads to close their open tables")); while (found && ! thd->killed) { found=0; @@ -326,6 +326,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, if ((table->s->version) < refresh_version && table->db_stat) { found=1; + DBUG_PRINT("signal", ("Waiting for COND_refresh")); pthread_cond_wait(&COND_refresh,&LOCK_open); break; } @@ -1046,6 +1047,7 @@ TABLE *unlink_open_table(THD *thd, TABLE *list, TABLE *find) void wait_for_refresh(THD *thd) { + DBUG_ENTER("wait_for_refresh"); safe_mutex_assert_owner(&LOCK_open); /* Wait until the current table is up to date */ @@ -1063,6 +1065,7 @@ void wait_for_refresh(THD *thd) thd->mysys_var->current_cond= 0; thd->proc_info= proc_info; pthread_mutex_unlock(&thd->mysys_var->mutex); + DBUG_VOID_RETURN; } @@ -1346,6 +1349,9 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { if (table->s->version != refresh_version) { + DBUG_PRINT("note", + ("Found table '%s.%s' with different refresh version", + table_list->db, table_list->table_name)); if (flags & MYSQL_LOCK_IGNORE_FLUSH) { /* Force close at once after usage */ @@ -4498,6 +4504,58 @@ bool setup_tables(THD *thd, Name_resolution_context *context, /* + prepare tables and check access for the view tables + + SYNOPSIS + setup_tables_and_check_view_access() + thd Thread handler + context name resolution contest to setup table list there + from_clause Top-level list of table references in the FROM clause + tables Table list (select_lex->table_list) + conds Condition of current SELECT (can be changed by VIEW) + leaves List of join table leaves list (select_lex->leaf_tables) + refresh It is onle refresh for subquery + select_insert It is SELECT ... INSERT command + want_access what access is needed + + NOTE + a wrapper for check_tables that will also check the resulting + table leaves list for access to all the tables that belong to a view + + RETURN + FALSE ok; In this case *map will include the chosen index + TRUE error +*/ +bool setup_tables_and_check_access(THD *thd, + Name_resolution_context *context, + List<TABLE_LIST> *from_clause, + TABLE_LIST *tables, + Item **conds, TABLE_LIST **leaves, + bool select_insert, + ulong want_access) +{ + TABLE_LIST *leaves_tmp = NULL; + + if (setup_tables (thd, context, from_clause, tables, conds, + &leaves_tmp, select_insert)) + return TRUE; + + if (leaves) + *leaves = leaves_tmp; + + for (; leaves_tmp; leaves_tmp= leaves_tmp->next_leaf) + if (leaves_tmp->belong_to_view && + check_one_table_access(thd, want_access, leaves_tmp)) + { + tables->hide_view_error(thd); + return TRUE; + } + + return FALSE; +} + + +/* Create a key_map from a list of index names SYNOPSIS @@ -5123,6 +5181,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, TABLE *table; bool result=0, signalled= 0; DBUG_ENTER("remove_table_from_cache"); + DBUG_PRINT("enter", ("Table: '%s.%s' flags: %u", db, table_name, flags)); key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; for (;;) @@ -5147,7 +5206,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, { in_use->some_tables_deleted=1; if (table->db_stat) + { + DBUG_PRINT("info", ("Found another active instance of the table")); result=1; + } /* Kill delayed insert threads */ if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) && ! in_use->killed) @@ -5182,6 +5244,12 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, VOID(hash_delete(&open_cache,(byte*) unused_tables)); if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG)) { + /* + Signal any thread waiting for tables to be freed to + reopen their tables + */ + (void) pthread_cond_broadcast(&COND_refresh); + DBUG_PRINT("info", ("Waiting for refresh signal")); if (!(flags & RTFC_CHECK_KILLED_FLAG) || !thd->killed) { dropping_tables++; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 37c4f9a3256..af20b770c56 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -334,10 +334,11 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) DBUG_ENTER("mysql_prepare_delete"); thd->lex->allow_sum_func= 0; - if (setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, - table_list, conds, &select_lex->leaf_tables, - FALSE) || + if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, + table_list, conds, + &select_lex->leaf_tables, FALSE, + DELETE_ACL) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -396,10 +397,11 @@ bool mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, - lex->query_tables, &lex->select_lex.where, - &lex->select_lex.leaf_tables, FALSE)) + if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, + lex->query_tables, &lex->select_lex.where, + &lex->select_lex.leaf_tables, FALSE, + DELETE_ACL)) DBUG_RETURN(TRUE); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f57856dc4b3..26f3b6f5faa 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -743,10 +743,11 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, bool insert_into_view= (table_list->view != 0); DBUG_ENTER("mysql_prepare_insert_check_table"); - if (setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, - table_list, where, &thd->lex->select_lex.leaf_tables, - select_insert)) + if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, + table_list, where, + &thd->lex->select_lex.leaf_tables, + select_insert, INSERT_ACL)) DBUG_RETURN(TRUE); if (insert_into_view && !fields.elements) diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c4c72910265..d2699b88aa4 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -151,8 +151,7 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->found_semicolon= 0; lex->safe_to_cache_query= 1; lex->time_zone_tables_used= 0; - lex->leaf_tables_insert= lex->query_tables= 0; - lex->query_tables_last= &lex->query_tables; + lex->leaf_tables_insert= 0; lex->variables_used= 0; lex->empty_field_list_on_rset= 0; lex->select_lex.select_number= 1; @@ -175,14 +174,9 @@ void lex_start(THD *thd, uchar *buf,uint length) lex->sphead= NULL; lex->spcont= NULL; lex->proc_list.first= 0; - lex->query_tables_own_last= 0; lex->escape_used= FALSE; + lex->reset_query_tables_list(FALSE); - if (lex->sroutines.records) - my_hash_reset(&lex->sroutines); - lex->sroutines_list.empty(); - lex->sroutines_list_own_last= lex->sroutines_list.next; - lex->sroutines_list_own_elements= 0; lex->nest_level=0 ; lex->allow_sum_func= 0; lex->in_sum_func= NULL; @@ -1615,6 +1609,52 @@ void st_select_lex::print_limit(THD *thd, String *str) /* + Initialize (or reset) Query_tables_list object. + + SYNOPSIS + reset_query_tables_list() + init TRUE - we should perform full initialization of object with + allocating needed memory + FALSE - object is already initialized so we should only reset + its state so it can be used for parsing/processing + of new statement + + DESCRIPTION + This method initializes Query_tables_list so it can be used as part + of LEX object for parsing/processing of statement. One can also use + this method to reset state of already initialized Query_tables_list + so it can be used for processing of new statement. +*/ + +void Query_tables_list::reset_query_tables_list(bool init) +{ + query_tables= 0; + query_tables_last= &query_tables; + query_tables_own_last= 0; + if (init) + hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); + else if (sroutines.records) + my_hash_reset(&sroutines); + sroutines_list.empty(); + sroutines_list_own_last= sroutines_list.next; + sroutines_list_own_elements= 0; +} + + +/* + Destroy Query_tables_list object with freeing all resources used by it. + + SYNOPSIS + destroy_query_tables_list() +*/ + +void Query_tables_list::destroy_query_tables_list() +{ + hash_free(&sroutines); +} + + +/* Initialize LEX object. SYNOPSIS @@ -1630,12 +1670,9 @@ void st_select_lex::print_limit(THD *thd, String *str) st_lex::st_lex() :result(0), yacc_yyss(0), yacc_yyvs(0), - sql_command(SQLCOM_END), query_tables_own_last(0) + sql_command(SQLCOM_END) { - hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); - sroutines_list.empty(); - sroutines_list_own_last= sroutines_list.next; - sroutines_list_own_elements= 0; + reset_query_tables_list(TRUE); } @@ -2019,6 +2056,11 @@ void st_lex::link_first_table_back(TABLE_LIST *first, SYNOPSIS st_lex::cleanup_after_one_table_open() + + NOTE + This method is mostly responsible for cleaning up of selects lists and + derived tables state. To rollback changes in Query_tables_list one has + to call Query_tables_list::reset_query_tables_list(FALSE). */ void st_lex::cleanup_after_one_table_open() @@ -2045,11 +2087,41 @@ void st_lex::cleanup_after_one_table_open() select_lex.cut_subtree(); } time_zone_tables_used= 0; - if (sroutines.records) - my_hash_reset(&sroutines); - sroutines_list.empty(); - sroutines_list_own_last= sroutines_list.next; - sroutines_list_own_elements= 0; +} + + +/* + Save current state of Query_tables_list for this LEX, and prepare it + for processing of new statemnt. + + SYNOPSIS + reset_n_backup_query_tables_list() + backup Pointer to Query_tables_list instance to be used for backup +*/ + +void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup) +{ + backup->set_query_tables_list(this); + /* + We have to perform full initialization here since otherwise we + will damage backed up state. + */ + this->reset_query_tables_list(TRUE); +} + + +/* + Restore state of Query_tables_list for this LEX from backup. + + SYNOPSIS + restore_backup_query_tables_list() + backup Pointer to Query_tables_list instance used for backup +*/ + +void st_lex::restore_backup_query_tables_list(Query_tables_list *backup) +{ + this->destroy_query_tables_list(); + this->set_query_tables_list(backup); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 34e7ee969b6..6b5c6ddca60 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -702,9 +702,95 @@ extern sys_var_long_ptr trg_new_row_fake_var; enum xa_option_words {XA_NONE, XA_JOIN, XA_RESUME, XA_ONE_PHASE, XA_SUSPEND, XA_FOR_MIGRATE}; + +/* + Class representing list of all tables used by statement. + It also contains information about stored functions used by statement + since during its execution we may have to add all tables used by its + stored functions/triggers to this list in order to pre-open and lock + them. + + Also used by st_lex::reset_n_backup/restore_backup_query_tables_list() + methods to save and restore this information. +*/ + +class Query_tables_list +{ +public: + /* Global list of all tables used by this statement */ + TABLE_LIST *query_tables; + /* Pointer to next_global member of last element in the previous list. */ + TABLE_LIST **query_tables_last; + /* + If non-0 then indicates that query requires prelocking and points to + next_global member of last own element in query table list (i.e. last + table which was not added to it as part of preparation to prelocking). + 0 - indicates that this query does not need prelocking. + */ + TABLE_LIST **query_tables_own_last; + /* Set of stored routines called by statement. */ + HASH sroutines; + /* + List linking elements of 'sroutines' set. Allows you to add new elements + to this set as you iterate through the list of existing elements. + 'sroutines_list_own_last' is pointer to ::next member of last element of + this list which represents routine which is explicitly used by query. + 'sroutines_list_own_elements' number of explicitly used routines. + We use these two members for restoring of 'sroutines_list' to the state + in which it was right after query parsing. + */ + SQL_LIST sroutines_list; + byte **sroutines_list_own_last; + uint sroutines_list_own_elements; + + /* + These constructor and destructor serve for creation/destruction + of Query_tables_list instances which are used as backup storage. + */ + Query_tables_list() {} + ~Query_tables_list() {} + + /* Initializes (or resets) Query_tables_list object for "real" use. */ + void reset_query_tables_list(bool init); + void destroy_query_tables_list(); + void set_query_tables_list(Query_tables_list *state) + { + *this= *state; + } + + void add_to_query_tables(TABLE_LIST *table) + { + *(table->prev_global= query_tables_last)= table; + query_tables_last= &table->next_global; + } + bool requires_prelocking() + { + return test(query_tables_own_last); + } + void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last) + { + query_tables_own_last= tables_own_last; + } + /* Return pointer to first not-own table in query-tables or 0 */ + TABLE_LIST* first_not_own_table() + { + return ( query_tables_own_last ? *query_tables_own_last : 0); + } + void chop_off_not_own_tables() + { + if (query_tables_own_last) + { + *query_tables_own_last= 0; + query_tables_last= query_tables_own_last; + query_tables_own_last= 0; + } + } +}; + + /* The state of the lex parsing. This is saved in the THD struct */ -typedef struct st_lex +typedef struct st_lex : public Query_tables_list { uint yylineno,yytoklen; /* Simulate lex */ LEX_YYSTYPE yylval; @@ -736,14 +822,6 @@ typedef struct st_lex gptr yacc_yyss,yacc_yyvs; THD *thd; CHARSET_INFO *charset; - TABLE_LIST *query_tables; /* global list of all tables in this query */ - /* - last element next_global of previous list (used only for list building - during parsing and VIEW processing. This pointer could be invalid during - processing of information schema tables(see get_schema_tables_result - function) - */ - TABLE_LIST **query_tables_last; /* store original leaf_tables for INSERT SELECT and PS/SP */ TABLE_LIST *leaf_tables_insert; /* Position (first character index) of SELECT of CREATE VIEW statement */ @@ -876,20 +954,6 @@ typedef struct st_lex bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */ bool all_privileges; sp_pcontext *spcont; - /* Set of stored routines called by statement. */ - HASH sroutines; - /* - List linking elements of 'sroutines' set. Allows you to add new elements - to this set as you iterate through the list of existing elements. - 'sroutines_list_own_last' is pointer to ::next member of last element of - this list which represents routine which is explicitly used by query. - 'sroutines_list_own_elements' number of explicitly used routines. - We use these two members for restoring of 'sroutines_list' to the state - in which it was right after query parsing. - */ - SQL_LIST sroutines_list; - byte **sroutines_list_own_last; - uint sroutines_list_own_elements; st_sp_chistics sp_chistics; bool only_view; /* used for SHOW CREATE TABLE/VIEW */ @@ -926,14 +990,6 @@ typedef struct st_lex const char *stmt_definition_begin; /* - If non-0 then indicates that query requires prelocking and points to - next_global member of last own element in query table list (i.e. last - table which was not added to it as part of preparation to prelocking). - 0 - indicates that this query does not need prelocking. - */ - TABLE_LIST **query_tables_own_last; - - /* Pointers to part of LOAD DATA statement that should be rewritten during replication ("LOCAL 'filename' REPLACE INTO" part). */ @@ -945,7 +1001,7 @@ typedef struct st_lex virtual ~st_lex() { - hash_free(&sroutines); + destroy_query_tables_list(); } inline void uncacheable(uint8 cause) @@ -970,11 +1026,6 @@ typedef struct st_lex TABLE_LIST *unlink_first_table(bool *link_to_local); void link_first_table_back(TABLE_LIST *first, bool link_to_local); void first_lists_tables_same(); - inline void add_to_query_tables(TABLE_LIST *table) - { - *(table->prev_global= query_tables_last)= table; - query_tables_last= &table->next_global; - } bool add_time_zone_tables_to_query_tables(THD *thd); bool can_be_merged(); @@ -1006,28 +1057,7 @@ typedef struct st_lex return FALSE; } } - inline bool requires_prelocking() - { - return test(query_tables_own_last); - } - inline void mark_as_requiring_prelocking(TABLE_LIST **tables_own_last) - { - query_tables_own_last= tables_own_last; - } - /* Return pointer to first not-own table in query-tables or 0 */ - TABLE_LIST* first_not_own_table() - { - return ( query_tables_own_last ? *query_tables_own_last : 0); - } - void chop_off_not_own_tables() - { - if (query_tables_own_last) - { - *query_tables_own_last= 0; - query_tables_last= query_tables_own_last; - query_tables_own_last= 0; - } - } + void cleanup_after_one_table_open(); bool push_context(Name_resolution_context *context) @@ -1044,6 +1074,9 @@ typedef struct st_lex { return context_stack.head(); } + + void reset_n_backup_query_tables_list(Query_tables_list *backup); + void restore_backup_query_tables_list(Query_tables_list *backup); } LEX; struct st_lex_local: public st_lex diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0a667c887ef..eaee5edf9f1 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -153,10 +153,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ha_enable_transaction(thd, FALSE); if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); - if (setup_tables(thd, &thd->lex->select_lex.context, - &thd->lex->select_lex.top_join_list, - table_list, &unused_conds, - &thd->lex->select_lex.leaf_tables, FALSE)) + if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, + &thd->lex->select_lex.top_join_list, + table_list, &unused_conds, + &thd->lex->select_lex.leaf_tables, FALSE, + INSERT_ACL | UPDATE_ACL)) DBUG_RETURN(-1); if (!table_list->table || // do not suport join view !table_list->updatable || // and derived tables diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7d62e5bb405..37e45e999b3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4994,23 +4994,35 @@ error: bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) { + Security_context * backup_ctx= thd->security_ctx; + + /* we need to switch to the saved context (if any) */ + if (all_tables->security_ctx) + thd->security_ctx= all_tables->security_ctx; + if (check_access(thd, privilege, all_tables->db, &all_tables->grant.privilege, 0, 0, test(all_tables->schema_table))) - return 1; + goto deny; /* Show only 1 table for check_grant */ if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0)) - return 1; + goto deny; + + thd->security_ctx= backup_ctx; /* Check rights on tables of subselects and implictly opened tables */ TABLE_LIST *subselects_tables; if ((subselects_tables= all_tables->next_global)) { if ((check_table_access(thd, SELECT_ACL, subselects_tables, 0))) - return 1; + goto deny; } return 0; + +deny: + thd->security_ctx= backup_ctx; + return 1; } @@ -5191,6 +5203,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, ulong found_access=0; TABLE_LIST *org_tables= tables; TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); + Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx; /* The check that first_not_own_table is not reached is for the case when the given table list refers to the list for prelocking (contains tables @@ -5198,12 +5211,17 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, */ for (; tables != first_not_own_table; tables= tables->next_global) { + if (tables->security_ctx) + sctx= tables->security_ctx; + else + sctx= backup_ctx; + if (tables->schema_table && (want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL))) { if (!no_errors) my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->security_ctx->priv_user, thd->security_ctx->priv_host, + sctx->priv_user, sctx->priv_host, information_schema_name.str); return TRUE; } @@ -5212,12 +5230,13 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, Remove SHOW_VIEW_ACL, because it will be checked during making view */ tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); - if (tables->derived || tables->schema_table || tables->belong_to_view || + if (tables->derived || tables->schema_table || (tables->table && (int)tables->table->s->tmp_table) || my_tz_check_n_skip_implicit_tables(&tables, thd->lex->time_zone_tables_used)) continue; - if ((thd->security_ctx->master_access & want_access) == + thd->security_ctx= sctx; + if ((sctx->master_access & want_access) == (want_access & ~EXTRA_ACL) && thd->db) tables->grant.privilege= want_access; @@ -5229,19 +5248,23 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, { if (check_access(thd,want_access,tables->db,&tables->grant.privilege, 0, no_errors, test(tables->schema_table))) - return TRUE; // Access denied + goto deny; // Access denied found_access=tables->grant.privilege; found=1; } } else if (check_access(thd,want_access,tables->db,&tables->grant.privilege, 0, no_errors, test(tables->schema_table))) - return TRUE; + goto deny; } + thd->security_ctx= backup_ctx; if (grant_option) return check_grant(thd,want_access & ~EXTRA_ACL,org_tables, test(want_access & EXTRA_ACL), UINT_MAX, no_errors); return FALSE; +deny: + thd->security_ctx= backup_ctx; + return TRUE; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e5cf69f399b..505beedac3e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -337,9 +337,10 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ if ((!(select_options & OPTION_SETUP_TABLES_DONE) && - setup_tables(thd, &select_lex->context, join_list, - tables_list, &conds, &select_lex->leaf_tables, - FALSE)) || + setup_tables_and_check_access(thd, &select_lex->context, join_list, + tables_list, &conds, + &select_lex->leaf_tables, FALSE, + SELECT_ACL)) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || setup_fields(thd, (*rref_pointer_array), fields_list, 1, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9018b364ec9..246da4dfeec 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2065,7 +2065,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; SELECT_LEX *select_lex= &lex->select_lex; SELECT_LEX *old_all_select_lex= lex->all_selects_list; - TABLE_LIST **save_query_tables_last= lex->query_tables_last; enum_sql_command save_sql_command= lex->sql_command; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; @@ -2084,6 +2083,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) db_type not_used; Open_tables_state open_tables_state_backup; bool save_view_prepare_mode= lex->view_prepare_mode; + Query_tables_list query_tables_list_backup; lex->view_prepare_mode= TRUE; DBUG_ENTER("get_all_tables"); @@ -2096,6 +2096,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) */ lex->sql_command= SQLCOM_SHOW_FIELDS; + lex->reset_n_backup_query_tables_list(&query_tables_list_backup); + /* We should not introduce deadlocks even if we already have some tables open and locked, since we won't lock tables which we will @@ -2136,8 +2138,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) show_table_list->db), show_table_list->alias)); thd->temporary_tables= 0; - close_thread_tables(thd); - show_table_list->table= 0; + close_tables_for_reopen(thd, &show_table_list); goto err; } @@ -2248,9 +2249,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) in this case. */ res= schema_table->process_table(thd, show_table_list, table, - res, base_name, - show_table_list->alias); - close_thread_tables(thd); + res, base_name, + show_table_list->alias); + close_tables_for_reopen(thd, &show_table_list); + DBUG_ASSERT(!lex->query_tables_own_last); if (res) goto err; } @@ -2267,11 +2269,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) error= 0; err: thd->restore_backup_open_tables_state(&open_tables_state_backup); + lex->restore_backup_query_tables_list(&query_tables_list_backup); lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; - lex->query_tables_last= save_query_tables_last; lex->view_prepare_mode= save_view_prepare_mode; - *save_query_tables_last= 0; lex->sql_command= save_sql_command; DBUG_RETURN(error); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 32a86b0f39a..9ec8e8db1fb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2240,6 +2240,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, tables can be left opening */ close_thread_tables(thd); + lex->reset_query_tables_list(FALSE); if (protocol->write()) goto err; continue; @@ -2487,6 +2488,7 @@ send_result_message: } } close_thread_tables(thd); + lex->reset_query_tables_list(FALSE); table->table=0; // For query cache if (protocol->write()) goto err; @@ -3140,7 +3142,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, uint db_create_options, used_fields; enum db_type old_db_type,new_db_type; bool need_copy_table; - bool no_table_reopen= FALSE; + bool no_table_reopen= FALSE, varchar= FALSE; DBUG_ENTER("mysql_alter_table"); thd->proc_info="init"; @@ -3344,6 +3346,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Field **f_ptr,*field; for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++) { + if (field->type() == MYSQL_TYPE_STRING) + varchar= TRUE; /* Check if field should be dropped */ Alter_drop *drop; drop_it.rewind(); @@ -3605,12 +3609,18 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, better have a negative test here, instead of positive, like alter_info->flags & ALTER_ADD_COLUMN|ALTER_ADD_INDEX|... so that ALTER TABLE won't break when somebody will add new flag + + MySQL uses frm version to determine the type of the data fields and + their layout. See Field_string::type() for details. + Thus, if the table is too old we may have to rebuild the data to + update the layout. */ need_copy_table= (alter_info->flags & ~(ALTER_CHANGE_COLUMN_DEFAULT|ALTER_OPTIONS) || (create_info->used_fields & ~(HA_CREATE_USED_COMMENT|HA_CREATE_USED_PASSWORD)) || - table->s->tmp_table); + table->s->tmp_table || + (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)); create_info->frm_only= !need_copy_table; /* diff --git a/sql/sql_update.cc b/sql/sql_update.cc index dfe23c9a503..b4ae779f9e2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -613,9 +613,11 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.alias= table_list->alias; thd->lex->allow_sum_func= 0; - if (setup_tables(thd, &select_lex->context, &select_lex->top_join_list, - table_list, conds, &select_lex->leaf_tables, - FALSE) || + if (setup_tables_and_check_access(thd, &select_lex->context, + &select_lex->top_join_list, + table_list, conds, + &select_lex->leaf_tables, + FALSE, UPDATE_ACL) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || select_lex->setup_ref_array(thd, order_num) || setup_order(thd, select_lex->ref_pointer_array, @@ -706,10 +708,11 @@ reopen_tables: call in setup_tables()). */ - if (setup_tables(thd, &lex->select_lex.context, - &lex->select_lex.top_join_list, - table_list, &lex->select_lex.where, - &lex->select_lex.leaf_tables, FALSE)) + if (setup_tables_and_check_access(thd, &lex->select_lex.context, + &lex->select_lex.top_join_list, + table_list, &lex->select_lex.where, + &lex->select_lex.leaf_tables, FALSE, + UPDATE_ACL)) DBUG_RETURN(TRUE); if (setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) diff --git a/sql/table.cc b/sql/table.cc index 8e23bea2540..cfdb9bd93aa 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2068,7 +2068,8 @@ void st_table_list::hide_view_error(THD *thd) if (thd->net.last_errno == ER_BAD_FIELD_ERROR || thd->net.last_errno == ER_SP_DOES_NOT_EXIST || thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR || - thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR) + thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR || + thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR) { TABLE_LIST *top= top_table(); thd->clear_error(); @@ -2428,8 +2429,18 @@ bool st_table_list::prepare_view_securety_context(THD *thd) definer.host.str, thd->db)) { - my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str); - DBUG_RETURN(TRUE); + if (thd->lex->sql_command == SQLCOM_SHOW_CREATE) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_NO_SUCH_USER, + ER(ER_NO_SUCH_USER), + definer.user.str, definer.host.str); + } + else + { + my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str); + DBUG_RETURN(TRUE); + } } } DBUG_RETURN(FALSE); |