diff options
190 files changed, 5293 insertions, 2769 deletions
diff --git a/Makefile.am b/Makefile.am index d7059c6adaf..6eb7421880e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -23,7 +23,7 @@ EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT SUBDIRS = . include @docs_dirs@ @zlib_dir@ @yassl_dir@ \ @readline_topdir@ sql-common \ @thread_dirs@ pstack \ - @sql_union_dirs@ scripts man tests \ + @sql_union_dirs@ scripts @man_dirs@ tests \ netware @libmysqld_dirs@ \ @bench_dirs@ support-files @tools_dirs@ diff --git a/client/mysqldump.c b/client/mysqldump.c index 66bc4fcb896..b2bf23c3e3a 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -539,6 +539,12 @@ static void write_footer(FILE *sql_file) } } /* write_footer */ +static void free_table_ent(char *key) + +{ + my_free((gptr) key, MYF(0)); +} + byte* get_table_key(const char *entry, uint *length, my_bool not_used __attribute__((unused))) @@ -550,8 +556,9 @@ byte* get_table_key(const char *entry, uint *length, void init_table_rule_hash(HASH* h) { - if(hash_init(h, charset_info, 16, 0, 0, - (hash_get_key) get_table_key, 0, 0)) + if (hash_init(h, charset_info, 16, 0, 0, + (hash_get_key) get_table_key, + (hash_free_key) free_table_ent, 0)) exit(EX_EOM); } @@ -806,7 +813,8 @@ static void DB_error(MYSQL *mysql, const char *when) SYNOPSIS mysql_query_with_error_report() mysql_con connection to use - res if non zero, result will be put there with mysql_store_result + res if non zero, result will be put there with + mysql_store_result() query query to send to server RETURN VALUES @@ -958,13 +966,14 @@ static char *quote_name(const char *name, char *buff, my_bool force) return buff; } /* quote_name */ + /* Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>" SYNOPSIS - quote_for_like - name - name of the table - buff - quoted name of the table + quote_for_like() + name name of the table + buff quoted name of the table DESCRIPTION Quote \, _, ' and % characters @@ -980,7 +989,6 @@ static char *quote_name(const char *name, char *buff, my_bool force) Example: "t\1" => "t\\\\1" */ - static char *quote_for_like(const char *name, char *buff) { char *to= buff; @@ -1252,7 +1260,54 @@ static uint get_table_structure(char *table, char *db) if (strcmp(field->name, "View") == 0) { if (verbose) - fprintf(stderr, "-- It's a view, skipped\n"); + fprintf(stderr, "-- It's a view, create dummy table for view\n"); + + mysql_free_result(tableRes); + + /* Create a dummy table for the view. ie. a table which has the + same columns as the view should have. This table is dropped + just before the view is created. The table is used to handle the + case where a view references another view, which hasn't yet been + created(during the load of the dump). BUG#10927 */ + + /* Create temp table by selecting from the view */ + my_snprintf(query_buff, sizeof(query_buff), + "CREATE TEMPORARY TABLE %s SELECT * FROM %s WHERE 0", + result_table, result_table); + if (mysql_query_with_error_report(sock, 0, query_buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + + /* Get CREATE statement for the temp table */ + my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE TABLE %s", + result_table); + if (mysql_query_with_error_report(sock, 0, query_buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + tableRes= mysql_store_result(sock); + row= mysql_fetch_row(tableRes); + + if (opt_drop) + fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table); + + /* Print CREATE statement but remove TEMPORARY */ + fprintf(sql_file, "CREATE %s;\n", row[1]+17); + check_io(sql_file); + + mysql_free_result(tableRes); + + /* Drop the temp table */ + my_snprintf(buff, sizeof(buff), + "DROP TEMPORARY TABLE %s", result_table); + if (mysql_query_with_error_report(sock, 0, buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } was_views= 1; DBUG_RETURN(0); } @@ -1643,7 +1698,7 @@ static void dump_table(uint numFields, char *table) } /* Check that there are any fields in the table */ - if(numFields == 0) + if (numFields == 0) { if (verbose) fprintf(stderr, @@ -2398,7 +2453,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) char new_table_name[NAME_LEN]; DYNAMIC_STRING lock_tables_query; HASH dump_tables; - + char *table_name; DBUG_ENTER("dump_selected_tables"); if (init_dumping(db)) @@ -2406,15 +2461,16 @@ static int dump_selected_tables(char *db, char **table_names, int tables) /* 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, 0, 0)) + (hash_get_key) get_table_key, (hash_free_key) free_table_ent, + 0)) 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 (!get_actual_table_name(*table_names, + new_table_name, sizeof(new_table_name))) { /* Add found table name to lock_tables_query */ if (lock_tables) @@ -2457,12 +2513,11 @@ 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 */ - const char *table_name; for (i= 0; i < dump_tables.records; i++) { table_name= hash_element(&dump_tables, i); DBUG_PRINT("info",("Dumping table %s", table_name)); - numrows = get_table_structure(table_name, db); + numrows= get_table_structure(table_name, db); dump_table(numrows, table_name); } @@ -2855,6 +2910,7 @@ static my_bool get_view_structure(char *table, char* db) } if (opt_drop) { + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table); check_io(sql_file); } @@ -2878,6 +2934,7 @@ int main(int argc, char **argv) { compatible_mode_normal_str[0]= 0; default_charset= (char *)mysql_universal_client_charset; + bzero((char*) &ignore_table, sizeof(ignore_table)); MY_INIT("mysqldump"); if (get_options(&argc, &argv)) @@ -2936,6 +2993,8 @@ err: if (md_result_file != stdout) my_fclose(md_result_file, MYF(0)); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + if (hash_inited(&ignore_table)) + hash_free(&ignore_table); if (extended_insert) dynstr_free(&extended_row); if (insert_pat_inited) diff --git a/client/mysqltest.c b/client/mysqltest.c index 7fdaf1098c2..67fa931a3f3 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -60,7 +60,12 @@ #include <sys/stat.h> #include <violite.h> #include <regex.h> /* Our own version of lib */ +#ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 #define MAX_COLUMNS 256 @@ -989,28 +994,29 @@ static void do_exec(struct st_query* q) error= pclose(res_file); if (error != 0) { - uint status= WEXITSTATUS(error); - if(q->abort_on_error) + uint status= WEXITSTATUS(error), i; + my_bool ok= 0; + + if (q->abort_on_error) die("At line %u: command \"%s\" failed", start_lineno, cmd); - else + + DBUG_PRINT("info", + ("error: %d, status: %d", error, status)); + for (i=0 ; (uint) i < q->expected_errors ; i++) { DBUG_PRINT("info", ("error: %d, status: %d", error, status)); - bool ok= 0; - uint i; - for (i=0 ; (uint) i < q->expected_errors ; i++) - { - DBUG_PRINT("info", ("expected error: %d", q->expected_errno[i].code.errnum)); - if ((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == status)) - ok= 1; - verbose_msg("At line %u: command \"%s\" failed with expected error: %d", - start_lineno, cmd, status); - } - if (!ok) - die("At line: %u: command \"%s\" failed with wrong error: %d", - start_lineno, cmd, status); + DBUG_PRINT("info", ("expected error: %d", + q->expected_errno[i].code.errnum)); + if ((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == status)) + ok= 1; + verbose_msg("At line %u: command \"%s\" failed with expected error: %d", + start_lineno, cmd, status); } + if (!ok) + die("At line: %u: command \"%s\" failed with wrong error: %d", + start_lineno, cmd, status); } else if (q->expected_errno[0].type == ERR_ERRNO && q->expected_errno[0].code.errnum != 0) diff --git a/configure.in b/configure.in index 9e294a35223..a37963911b9 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. -AC_PREREQ(2.50)dnl Minimum Autoconf version required. +AC_PREREQ(2.58)dnl Minimum Autoconf version required. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM diff --git a/extra/yassl/include/yassl_types.hpp b/extra/yassl/include/yassl_types.hpp index 01b82d95039..ec9e6fb7ceb 100644 --- a/extra/yassl/include/yassl_types.hpp +++ b/extra/yassl/include/yassl_types.hpp @@ -445,7 +445,7 @@ const opaque master_label[MASTER_LABEL_SZ + 1] = "master secret"; const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion"; -} // namespace +} // naemspace #if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 /* @@ -456,4 +456,5 @@ const opaque key_label [KEY_LABEL_SZ + 1] = "key expansion"; using yaSSL::byte; #endif + #endif // yaSSL_TYPES_HPP diff --git a/extra/yassl/src/Makefile.am b/extra/yassl/src/Makefile.am index 1f5f1ee7a4e..4ebb9a2d862 100644 --- a/extra/yassl/src/Makefile.am +++ b/extra/yassl/src/Makefile.am @@ -5,3 +5,4 @@ libyassl_a_SOURCES = buffer.cpp cert_wrapper.cpp crypto_wrapper.cpp \ handshake.cpp lock.cpp log.cpp socket_wrapper.cpp ssl.cpp \ template_instnt.cpp timer.cpp yassl_imp.cpp yassl_error.cpp yassl_int.cpp EXTRA_DIST = ../include/*.hpp ../include/openssl/*.h +AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/extra/yassl/src/buffer.cpp b/extra/yassl/src/buffer.cpp index 1da0827ac4e..56d355bea80 100644 --- a/extra/yassl/src/buffer.cpp +++ b/extra/yassl/src/buffer.cpp @@ -25,6 +25,7 @@ */ #include <string.h> // memcpy +#include "runtime.hpp" #include "buffer.hpp" #include "yassl_types.hpp" diff --git a/extra/yassl/src/cert_wrapper.cpp b/extra/yassl/src/cert_wrapper.cpp index 7a8c7dfe253..a775c366a92 100644 --- a/extra/yassl/src/cert_wrapper.cpp +++ b/extra/yassl/src/cert_wrapper.cpp @@ -24,6 +24,7 @@ * */ +#include "runtime.hpp" #include "cert_wrapper.hpp" #include "yassl_int.hpp" diff --git a/extra/yassl/src/lock.cpp b/extra/yassl/src/lock.cpp index 8a0b66ead42..4827d396e81 100644 --- a/extra/yassl/src/lock.cpp +++ b/extra/yassl/src/lock.cpp @@ -22,6 +22,7 @@ /* Locking functions */ +#include "runtime.hpp" #include "lock.hpp" diff --git a/extra/yassl/src/log.cpp b/extra/yassl/src/log.cpp index 38633cd1210..8ab351ee2b1 100644 --- a/extra/yassl/src/log.cpp +++ b/extra/yassl/src/log.cpp @@ -22,6 +22,8 @@ /* Debug logging functions */ + +#include "runtime.hpp" #include "log.hpp" #ifdef YASSL_LOG diff --git a/extra/yassl/src/socket_wrapper.cpp b/extra/yassl/src/socket_wrapper.cpp index 00f9c8d170c..2252dfafdc5 100644 --- a/extra/yassl/src/socket_wrapper.cpp +++ b/extra/yassl/src/socket_wrapper.cpp @@ -26,6 +26,7 @@ */ +#include "runtime.hpp" #include "socket_wrapper.hpp" #ifndef _WIN32 diff --git a/extra/yassl/src/template_instnt.cpp b/extra/yassl/src/template_instnt.cpp index 5cf4f8c39f8..5ee57e76aed 100644 --- a/extra/yassl/src/template_instnt.cpp +++ b/extra/yassl/src/template_instnt.cpp @@ -1,3 +1,29 @@ +/* template_instnt.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 + */ + + +/* Explicit template instantiation requests + */ + + #include "runtime.hpp" #include "handshake.hpp" #include "yassl_int.hpp" @@ -15,7 +41,7 @@ template class HMAC<MD5>; template class HMAC<SHA>; template class HMAC<RIPEMD160>; } -#endif +#endif // USE_CRYPTOPP_LIB namespace mySTL { template class list<unsigned char*>; @@ -64,4 +90,6 @@ template void ysDelete<Message>(Message*); template void ysArrayDelete<unsigned char>(unsigned char*); template void ysArrayDelete<char>(char*); } -#endif + +#endif // HAVE_EXPLICIT_TEMPLATE_INSTANTIATION + diff --git a/extra/yassl/src/timer.cpp b/extra/yassl/src/timer.cpp index cfa1319ae80..4fe0d3aa4f9 100644 --- a/extra/yassl/src/timer.cpp +++ b/extra/yassl/src/timer.cpp @@ -23,6 +23,7 @@ * */ +#include "runtime.hpp" #include "timer.hpp" namespace yaSSL { diff --git a/extra/yassl/src/yassl_error.cpp b/extra/yassl/src/yassl_error.cpp index 6ae5a9f6663..c53aef2068d 100644 --- a/extra/yassl/src/yassl_error.cpp +++ b/extra/yassl/src/yassl_error.cpp @@ -23,6 +23,7 @@ /* yaSSL error implements and an exception class */ +#include "runtime.hpp" #include "yassl_error.hpp" namespace yaSSL { diff --git a/extra/yassl/src/yassl_int.cpp b/extra/yassl/src/yassl_int.cpp index e9c1ed53816..740618ce701 100644 --- a/extra/yassl/src/yassl_int.cpp +++ b/extra/yassl/src/yassl_int.cpp @@ -33,28 +33,36 @@ void* operator new(size_t sz, yaSSL::new_t) { +#ifdef YASSL_PURE_C void* ptr = malloc(sz ? sz : 1); if (!ptr) abort(); return ptr; +#else + return ::operator new(sz); +#endif } -void* operator new[](size_t sz, yaSSL::new_t) -{ - void* ptr = malloc(sz ? sz : 1); - if (!ptr) abort(); - - return ptr; -} void operator delete(void* ptr, yaSSL::new_t) { +#ifdef YASSL_PURE_C if (ptr) free(ptr); +#else + ::operator delete(ptr); +#endif +} + + +void* operator new[](size_t sz, yaSSL::new_t nt) +{ + return ::operator new(sz, nt); } -void operator delete[](void* ptr, yaSSL::new_t) + +void operator delete[](void* ptr, yaSSL::new_t nt) { - if (ptr) free(ptr); + ::operator delete(ptr, nt); } @@ -923,7 +931,7 @@ void SSL::setKeys() // local functors -namespace yassl_int_cpp_local1 { +namespace yassl_int_cpp_local1 { // for explicit templates struct SumData { uint total_; @@ -1385,7 +1393,8 @@ Sessions::~Sessions() } -namespace yassl_int_cpp_local2 { // locals +// locals +namespace yassl_int_cpp_local2 { // for explicit templates typedef mySTL::list<SSL_SESSION*>::iterator iterator; @@ -1974,6 +1983,8 @@ X509_NAME* X509::GetSubject() return &subject_; } + + } // namespace #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION @@ -1983,3 +1994,4 @@ template yaSSL::yassl_int_cpp_local1::SumBuffer for_each<mySTL::list<yaSSL::outp template mySTL::list<yaSSL::SSL_SESSION*>::iterator find_if<mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match>(mySTL::list<yaSSL::SSL_SESSION*>::iterator, mySTL::list<yaSSL::SSL_SESSION*>::iterator, yaSSL::yassl_int_cpp_local2::sess_match); } #endif + diff --git a/extra/yassl/taocrypt/include/types.hpp b/extra/yassl/taocrypt/include/types.hpp index 18961cf4d6f..92164eaaab4 100644 --- a/extra/yassl/taocrypt/include/types.hpp +++ b/extra/yassl/taocrypt/include/types.hpp @@ -31,10 +31,8 @@ namespace TaoCrypt { -// define this if running on a big-endian CPU -#if !defined(LITTLE_ENDIAN_ORDER) && (defined(__BIG_ENDIAN__) || \ - defined(__sparc) || defined(__sparc__) || defined(__hppa__) || \ - defined(__mips__) || (defined(__MWERKS__) && !defined(__INTEL__))) + +#if defined(WORDS_BIGENDIAN) || (defined(__MWERKS__) && !defined(__INTEL__)) #define BIG_ENDIAN_ORDER #endif @@ -47,34 +45,28 @@ typedef unsigned char byte; typedef unsigned short word16; typedef unsigned int word32; -#if defined(__GNUC__) || defined(__MWERKS__) || defined(_LONGLONG_TYPE) - #define WORD64_AVAILABLE - #define WORD64_IS_DISTINCT_TYPE - typedef unsigned long long word64; - #define W64LIT(x) x##LL -#elif defined(_MSC_VER) || defined(__BCPLUSPLUS__) +#if defined(_MSC_VER) || defined(__BCPLUSPLUS__) #define WORD64_AVAILABLE #define WORD64_IS_DISTINCT_TYPE typedef unsigned __int64 word64; - #define W64LIT(x) x##ui64 -#elif defined(__DECCXX) +#elif SIZEOF_LONG == 8 #define WORD64_AVAILABLE typedef unsigned long word64; +#elif SIZEOF_LONG_LONG == 8 + #define WORD64_AVAILABLE + #define WORD64_IS_DISTINCT_TYPE + typedef unsigned long long word64; #endif -// define largest word type -#ifdef WORD64_AVAILABLE - typedef word64 lword; -#else - typedef word32 lword; -#endif +// compilers we've found 64-bit multiply insructions for +#if defined(__GNUC__) || defined(_MSC_VER) || defined(__DECCXX) + #define HAVE_64_MULTIPLY +#endif -// TODO: FIXME, add asm multiply for x86_64 on Solaris and remove !__sun -#if defined(__alpha__) || (defined(__ia64__) && !defined(__INTEL_COMPILER)) || \ - defined(_ARCH_PPC64) || defined(__mips64) || \ - (defined(__x86_64__) && !defined(__sun)) +#if defined(HAVE_64_MULTIPLY) && (defined(__alpha__) || defined(__ia64__) \ + || defined(_ARCH_PPC64) || defined(__mips64) || defined(__x86_64__)) // These platforms have 64-bit CPU registers. Unfortunately most C++ compilers // don't allow any way to access the 64-bit by 64-bit multiply instruction // without using assembly, so in order to use word64 as word, the assembly @@ -84,7 +76,7 @@ typedef unsigned int word32; #else #define TAOCRYPT_NATIVE_DWORD_AVAILABLE #ifdef WORD64_AVAILABLE - #define TAOCRYPT_SLOW_WORD64 + #define TAOCRYPT_SLOW_WORD64 typedef word16 hword; typedef word32 word; typedef word64 dword; diff --git a/extra/yassl/taocrypt/src/Makefile.am b/extra/yassl/taocrypt/src/Makefile.am index 4005be94fb2..5bf45074a98 100644 --- a/extra/yassl/taocrypt/src/Makefile.am +++ b/extra/yassl/taocrypt/src/Makefile.am @@ -6,3 +6,4 @@ libtaocrypt_a_SOURCES = aes.cpp aestables.cpp algebra.cpp arc4.cpp asn.cpp \ md2.cpp md5.cpp misc.cpp random.cpp ripemd.cpp rsa.cpp sha.cpp \ template_instnt.cpp EXTRA_DIST = ../include/*.hpp +AM_CXXFLAGS = -DYASSL_PURE_C diff --git a/extra/yassl/taocrypt/src/aestables.cpp b/extra/yassl/taocrypt/src/aestables.cpp index 5a125dfd44d..7ba25bc9ffb 100644 --- a/extra/yassl/taocrypt/src/aestables.cpp +++ b/extra/yassl/taocrypt/src/aestables.cpp @@ -21,6 +21,7 @@ /* based on Wei Dai's aestables.cpp from CryptoPP */ +#include "runtime.hpp" #include "aes.hpp" diff --git a/extra/yassl/taocrypt/src/algebra.cpp b/extra/yassl/taocrypt/src/algebra.cpp index e0472f2fc76..45bbcfa662a 100644 --- a/extra/yassl/taocrypt/src/algebra.cpp +++ b/extra/yassl/taocrypt/src/algebra.cpp @@ -319,9 +319,11 @@ void AbstractRing::SimultaneousExponentiate(Integer *results, } // namespace + #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION namespace mySTL { template TaoCrypt::WindowSlider* uninit_copy<TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*); template void destroy<TaoCrypt::WindowSlider*>(TaoCrypt::WindowSlider*, TaoCrypt::WindowSlider*); } #endif + diff --git a/extra/yassl/taocrypt/src/arc4.cpp b/extra/yassl/taocrypt/src/arc4.cpp index bbd77cd822c..1e521b48f0c 100644 --- a/extra/yassl/taocrypt/src/arc4.cpp +++ b/extra/yassl/taocrypt/src/arc4.cpp @@ -21,6 +21,7 @@ /* based on Wei Dai's arc4.cpp from CryptoPP */ +#include "runtime.hpp" #include "arc4.hpp" diff --git a/extra/yassl/taocrypt/src/coding.cpp b/extra/yassl/taocrypt/src/coding.cpp index 6514ed4d46d..944a47c288e 100644 --- a/extra/yassl/taocrypt/src/coding.cpp +++ b/extra/yassl/taocrypt/src/coding.cpp @@ -22,6 +22,7 @@ /* coding.cpp implements hex and base64 encoding/decoing */ +#include "runtime.hpp" #include "coding.hpp" #include "file.hpp" diff --git a/extra/yassl/taocrypt/src/file.cpp b/extra/yassl/taocrypt/src/file.cpp index 75df80608ae..4d48b9e7bca 100644 --- a/extra/yassl/taocrypt/src/file.cpp +++ b/extra/yassl/taocrypt/src/file.cpp @@ -22,6 +22,7 @@ /* file.cpp implements File Sources and Sinks */ +#include "runtime.hpp" #include "file.hpp" diff --git a/extra/yassl/taocrypt/src/integer.cpp b/extra/yassl/taocrypt/src/integer.cpp index 460b2d31426..71324b04b92 100644 --- a/extra/yassl/taocrypt/src/integer.cpp +++ b/extra/yassl/taocrypt/src/integer.cpp @@ -35,8 +35,9 @@ #endif -#if defined(_MSC_VER) && defined(_WIN64) && \ - !defined(__INTEL_COMPILER) // 64 bit X overflow intrinsic +// 64bit multiply overflow intrinsic +#if defined(_MSC_VER) && defined(_WIN64) && !defined(__INTEL_COMPILER) && \ + !defined(TAOCRYPT_NATIVE_DWORD_AVAILABLE) #ifdef __ia64__ #define myUMULH __UMULH #elif __x86_64__ @@ -3957,6 +3958,7 @@ Integer CRT(const Integer &xp, const Integer &p, const Integer &xq, return p * (u * (xq-xp) % q) + xp; } + #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION #ifndef TAOCRYPT_NATIVE_DWORD_AVAILABLE template hword DivideThreeWordsByTwo<hword, Word>(hword*, hword, hword, Word*); diff --git a/extra/yassl/taocrypt/src/misc.cpp b/extra/yassl/taocrypt/src/misc.cpp index 6a801a9995a..ef051332098 100644 --- a/extra/yassl/taocrypt/src/misc.cpp +++ b/extra/yassl/taocrypt/src/misc.cpp @@ -22,34 +22,43 @@ /* based on Wei Dai's misc.cpp from CryptoPP */ +#include "runtime.hpp" #include "misc.hpp" #include <new> // for NewHandler void* operator new(size_t sz, TaoCrypt::new_t) { +#ifdef YASSL_PURE_C void* ptr = malloc(sz ? sz : 1); if (!ptr) abort(); return ptr; +#else + return ::operator new(sz); +#endif } -void* operator new[](size_t sz, TaoCrypt::new_t) -{ - void* ptr = malloc(sz ? sz : 1); - if (!ptr) abort(); - - return ptr; -} void operator delete(void* ptr, TaoCrypt::new_t) { +#ifdef YASSL_PURE_C if (ptr) free(ptr); +#else + ::operator delete(ptr); +#endif } -void operator delete[](void* ptr, TaoCrypt::new_t) + +void* operator new[](size_t sz, TaoCrypt::new_t nt) { - if (ptr) free(ptr); + return ::operator new(sz, nt); +} + + +void operator delete[](void* ptr, TaoCrypt::new_t nt) +{ + ::operator delete(ptr, nt); } diff --git a/extra/yassl/taocrypt/src/random.cpp b/extra/yassl/taocrypt/src/random.cpp index 69fb180720a..e1e6416eb00 100644 --- a/extra/yassl/taocrypt/src/random.cpp +++ b/extra/yassl/taocrypt/src/random.cpp @@ -24,6 +24,7 @@ specific seed, switch to /dev/random for more security but may block */ +#include "runtime.hpp" #include "random.hpp" #if defined(_WIN32) diff --git a/extra/yassl/taocrypt/src/template_instnt.cpp b/extra/yassl/taocrypt/src/template_instnt.cpp index 28994282669..9a3c12badfc 100644 --- a/extra/yassl/taocrypt/src/template_instnt.cpp +++ b/extra/yassl/taocrypt/src/template_instnt.cpp @@ -1,3 +1,29 @@ +/* template_instnt.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 + */ + + +/* Explicit template instantiation requests + */ + + #include "integer.hpp" #include "rsa.hpp" #include "algebra.hpp" @@ -6,9 +32,11 @@ #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION namespace TaoCrypt { + #if defined(SSE2_INTRINSICS_AVAILABLE) template AlignedAllocator<unsigned int>::pointer StdReallocate<unsigned int, AlignedAllocator<unsigned int> >(AlignedAllocator<unsigned int>&, unsigned int*, AlignedAllocator<unsigned int>::size_type, AlignedAllocator<unsigned int>::size_type, bool); #endif + template class RSA_Decryptor<RSA_BlockType2>; template class RSA_Encryptor<RSA_BlockType1>; template class RSA_Encryptor<RSA_BlockType2>; @@ -17,10 +45,12 @@ template void tcArrayDelete<byte>(byte*); template AllocatorWithCleanup<byte>::pointer StdReallocate<byte, AllocatorWithCleanup<byte> >(AllocatorWithCleanup<byte>&, byte*, AllocatorWithCleanup<byte>::size_type, AllocatorWithCleanup<byte>::size_type, bool); template void tcArrayDelete<word>(word*); template AllocatorWithCleanup<word>::pointer StdReallocate<word, AllocatorWithCleanup<word> >(AllocatorWithCleanup<word>&, word*, AllocatorWithCleanup<word>::size_type, AllocatorWithCleanup<word>::size_type, bool); + #ifndef TAOCRYPT_SLOW_WORD64 // defined when word != word32 template void tcArrayDelete<word32>(word32*); template AllocatorWithCleanup<word32>::pointer StdReallocate<word32, AllocatorWithCleanup<word32> >(AllocatorWithCleanup<word32>&, word32*, AllocatorWithCleanup<word32>::size_type, AllocatorWithCleanup<word32>::size_type, bool); #endif + template void tcArrayDelete<char>(char*); } diff --git a/include/config-netware.h b/include/config-netware.h index 4a6dc3b1bb9..906f557f608 100644 --- a/include/config-netware.h +++ b/include/config-netware.h @@ -46,11 +46,21 @@ extern "C" { #undef HAVE_SYS_MMAN_H #undef HAVE_SYNCH_H #undef HAVE_MMAP + #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 #define HAVE_PTHREAD_SIGMASK 1 #define HAVE_PTHREAD_YIELD_ZERO_ARG 1 #define HAVE_BROKEN_REALPATH 1 +#undef HAVE_POSIX_SIGNALS +#undef HAVE_PTHREAD_ATTR_SETSCOPE +#undef HAVE_ALLOC_A +#undef HAVE_FINITE +#undef HAVE_GETPWNAM +#undef HAVE_GETPWUID +#undef HAVE_PTHREAD_SETSCHEDPARAM +#undef HAVE_READLINK +#undef HAVE_STPCPY /* no libc crypt() function */ #ifdef HAVE_OPENSSL #define HAVE_CRYPT 1 diff --git a/include/my_bitmap.h b/include/my_bitmap.h index 4caa3b85456..84a5d8bd18a 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -45,6 +45,8 @@ extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); extern my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_is_set_all(const MY_BITMAP *map); extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2); +extern my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit); +extern my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit); extern uint bitmap_set_next(MY_BITMAP *map); extern uint bitmap_get_first(const MY_BITMAP *map); extern uint bitmap_bits_set(const MY_BITMAP *map); diff --git a/include/my_sys.h b/include/my_sys.h index ee4312be058..a3d6f6827d3 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -263,6 +263,7 @@ extern my_bool NEAR my_disable_locking,NEAR my_disable_async_io, extern char wild_many,wild_one,wild_prefix; extern const char *charsets_dir; extern char *defaults_extra_file; +extern const char *defaults_instance; extern my_bool timed_mutexes; diff --git a/include/mysql_com.h b/include/mysql_com.h index 2293476c76c..88a614bc4a3 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -137,14 +137,14 @@ enum enum_server_command #define SERVER_QUERY_NO_GOOD_INDEX_USED 16 #define SERVER_QUERY_NO_INDEX_USED 32 /* - The server was able to fulfill client request and open read-only - non-scrollable cursor for the query. This flag comes in server - status with reply to COM_EXECUTE and COM_EXECUTE_DIRECT commands. + The server was able to fulfill the clients request and opened a + read-only non-scrollable cursor for a query. This flag comes + in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands. */ #define SERVER_STATUS_CURSOR_EXISTS 64 /* - This flag is sent with last row of read-only cursor, in reply to - COM_FETCH command. + This flag is sent when a read-only cursor is exhausted, in reply to + COM_STMT_FETCH command. */ #define SERVER_STATUS_LAST_ROW_SENT 128 #define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */ diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index e236304b388..20f522c1a60 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -3410,9 +3410,9 @@ fil_extend_space_to_desired_size( fil_space_t* space; byte* buf2; byte* buf; + ulint buf_size; ulint start_page_no; ulint file_start_page_no; - ulint n_pages; ulint offset_high; ulint offset_low; ibool success = TRUE; @@ -3437,22 +3437,20 @@ fil_extend_space_to_desired_size( fil_node_prepare_for_io(node, system, space); - /* Extend 1 MB at a time */ - - buf2 = mem_alloc(1024 * 1024 + UNIV_PAGE_SIZE); - buf = ut_align(buf2, UNIV_PAGE_SIZE); - - memset(buf, '\0', 1024 * 1024); - start_page_no = space->size; file_start_page_no = space->size - node->size; - while (start_page_no < size_after_extend) { - n_pages = size_after_extend - start_page_no; + /* Extend at most 64 pages at a time */ + buf_size = ut_min(64, size_after_extend - start_page_no) + * UNIV_PAGE_SIZE; + buf2 = mem_alloc(buf_size + UNIV_PAGE_SIZE); + buf = ut_align(buf2, UNIV_PAGE_SIZE); - if (n_pages > (1024 * 1024) / UNIV_PAGE_SIZE) { - n_pages = (1024 * 1024) / UNIV_PAGE_SIZE; - } + memset(buf, 0, buf_size); + + while (start_page_no < size_after_extend) { + ulint n_pages = ut_min(buf_size / UNIV_PAGE_SIZE, + size_after_extend - start_page_no); offset_high = (start_page_no - file_start_page_no) / (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE)); diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index e75281dd93c..362e3552411 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -373,7 +373,7 @@ os_file_get_size_as_iblonglong( /* out: size in bytes, -1 if error */ os_file_t file); /* in: handle to a file */ /*************************************************************************** -Sets a file size. This function can be used to extend or truncate a file. */ +Write the specified number of zeros to a newly created file. */ ibool os_file_set_size( diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 4bb9fa63cd1..4e6ff73b0f8 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -243,17 +243,27 @@ row_update_for_mysql( the MySQL format */ row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL handle */ - /************************************************************************* -Does an unlock of a row for MySQL. */ +This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +calling this function we must use trx_reset_new_rec_lock_info() and +trx_register_new_rec_lock() to store the information which new record locks +really were set. This function removes a newly set lock under prebuilt->pcur, +and also under prebuilt->clust_pcur. Currently, this is only used and tested +in the case of an UPDATE or a DELETE statement, where the row lock is of the +LOCK_X type. +Thus, this implements a 'mini-rollback' that releases the latest record +locks we set. */ int row_unlock_for_mysql( /*=================*/ /* out: error code or DB_SUCCESS */ - row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL + row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL handle */ - + ibool has_latches_on_recs);/* TRUE if called so that we have + the latches on the records under pcur + and clust_pcur, and we do not need to + reposition the cursors. */ /************************************************************************* Creates an query graph node of 'update' type to be used in the MySQL interface. */ diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 8df50d6703d..146730d46f8 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -16,10 +16,39 @@ Created 3/26/1996 Heikki Tuuri #include "que0types.h" #include "mem0mem.h" #include "read0types.h" +#include "dict0types.h" #include "trx0xa.h" extern ulint trx_n_mysql_transactions; +/***************************************************************** +Resets the new record lock info in a transaction struct. */ +UNIV_INLINE +void +trx_reset_new_rec_lock_info( +/*========================*/ + trx_t* trx); /* in: transaction struct */ +/***************************************************************** +Registers that we have set a new record lock on an index. We only have space +to store 2 indexes! If this is called to store more than 2 indexes after +trx_reset_new_rec_lock_info(), then this function does nothing. */ +UNIV_INLINE +void +trx_register_new_rec_lock( +/*======================*/ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index); /* in: trx sets a new record lock on this + index */ +/***************************************************************** +Checks if trx has set a new record lock on an index. */ +UNIV_INLINE +ibool +trx_new_rec_locks_contain( +/*======================*/ + /* out: TRUE if trx has set a new record lock + on index */ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index); /* in: index */ /************************************************************************ Releases the search latch if trx has reserved it. */ @@ -495,8 +524,18 @@ struct trx_struct{ lock_t* auto_inc_lock; /* possible auto-inc lock reserved by the transaction; note that it is also in the lock list trx_locks */ - ibool trx_create_lock;/* this is TRUE if we have created a - new lock for a record accessed */ + dict_index_t* new_rec_locks[2];/* these are normally NULL; if + srv_locks_unsafe_for_binlog is TRUE, + in a cursor search, if we set a new + record lock on an index, this is set + to point to the index; this is + used in releasing the locks under the + cursors if we are performing an UPDATE + and we determine after retrieving + the row that it does not need to be + locked; thus, these can be used to + implement a 'mini-rollback' that + releases the latest record locks */ UT_LIST_NODE_T(trx_t) trx_list; /* list of transactions */ UT_LIST_NODE_T(trx_t) diff --git a/innobase/include/trx0trx.ic b/innobase/include/trx0trx.ic index 78e5acda148..54cf2ff331f 100644 --- a/innobase/include/trx0trx.ic +++ b/innobase/include/trx0trx.ic @@ -39,4 +39,60 @@ trx_start_if_not_started_low( } } +/***************************************************************** +Resets the new record lock info in a transaction struct. */ +UNIV_INLINE +void +trx_reset_new_rec_lock_info( +/*========================*/ + trx_t* trx) /* in: transaction struct */ +{ + trx->new_rec_locks[0] = NULL; + trx->new_rec_locks[1] = NULL; +} + +/***************************************************************** +Registers that we have set a new record lock on an index. We only have space +to store 2 indexes! If this is called to store more than 2 indexes after +trx_reset_new_rec_lock_info(), then this function does nothing. */ +UNIV_INLINE +void +trx_register_new_rec_lock( +/*======================*/ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index) /* in: trx sets a new record lock on this + index */ +{ + if (trx->new_rec_locks[0] == NULL) { + trx->new_rec_locks[0] = index; + + return; + } + + if (trx->new_rec_locks[0] == index) { + return; + } + + if (trx->new_rec_locks[1] != NULL) { + + return; + } + + trx->new_rec_locks[1] = index; +} + +/***************************************************************** +Checks if trx has set a new record lock on an index. */ +UNIV_INLINE +ibool +trx_new_rec_locks_contain( +/*======================*/ + /* out: TRUE if trx has set a new record lock + on index */ + trx_t* trx, /* in: transaction struct */ + dict_index_t* index) /* in: index */ +{ + return(trx->new_rec_locks[0] == index + || trx->new_rec_locks[1] == index); +} diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 48db7ced0cb..280c4871ee9 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -956,7 +956,7 @@ lock_rec_has_to_wait( cause waits */ if ((lock_is_on_supremum || (type_mode & LOCK_GAP)) - && !(type_mode & LOCK_INSERT_INTENTION)) { + && !(type_mode & LOCK_INSERT_INTENTION)) { /* Gap type locks without LOCK_INSERT_INTENTION flag do not need to wait for anything. This is because @@ -1765,10 +1765,7 @@ lock_rec_create( lock_rec_set_nth_bit(lock, heap_no); HASH_INSERT(lock_t, hash, lock_sys->rec_hash, - lock_rec_fold(space, page_no), lock); - /* Note that we have create a new lock */ - trx->trx_create_lock = TRUE; - + lock_rec_fold(space, page_no), lock); if (type_mode & LOCK_WAIT) { lock_set_lock_and_trx_wait(lock, trx); @@ -1945,15 +1942,6 @@ lock_rec_add_to_queue( if (similar_lock && !somebody_waits && !(type_mode & LOCK_WAIT)) { - /* If the nth bit of a record lock is already set then we - do not set a new lock bit, otherwice we set */ - - if (lock_rec_get_nth_bit(similar_lock, heap_no)) { - trx->trx_create_lock = FALSE; - } else { - trx->trx_create_lock = TRUE; - } - lock_rec_set_nth_bit(similar_lock, heap_no); return(similar_lock); @@ -2005,11 +1993,14 @@ lock_rec_lock_fast( lock = lock_rec_get_first_on_page(rec); trx = thr_get_trx(thr); - trx->trx_create_lock = FALSE; if (lock == NULL) { if (!impl) { lock_rec_create(mode, rec, index, trx); + + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } return(TRUE); @@ -2021,23 +2012,22 @@ lock_rec_lock_fast( } if (lock->trx != trx - || lock->type_mode != (mode | LOCK_REC) - || lock_rec_get_n_bits(lock) <= heap_no) { + || lock->type_mode != (mode | LOCK_REC) + || lock_rec_get_n_bits(lock) <= heap_no) { + return(FALSE); } if (!impl) { + /* If the nth bit of the record lock is already set then we + do not set a new lock bit, otherwise we do set */ - /* If the nth bit of a record lock is already set then we - do not set a new lock bit, otherwice we set */ - - if (lock_rec_get_nth_bit(lock, heap_no)) { - trx->trx_create_lock = FALSE; - } else { - trx->trx_create_lock = TRUE; + if (!lock_rec_get_nth_bit(lock, heap_no)) { + lock_rec_set_nth_bit(lock, heap_no); + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } - - lock_rec_set_nth_bit(lock, heap_no); } return(TRUE); @@ -2093,12 +2083,19 @@ lock_rec_lock_slow( enough already granted on the record, we have to wait. */ err = lock_rec_enqueue_waiting(mode, rec, index, thr); + + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } else { if (!impl) { /* Set the requested lock on the record */ lock_rec_add_to_queue(LOCK_REC | mode, rec, index, trx); + if (srv_locks_unsafe_for_binlog) { + trx_register_new_rec_lock(trx, index); + } } err = DB_SUCCESS; @@ -2436,8 +2433,15 @@ lock_rec_inherit_to_gap( lock = lock_rec_get_first(rec); + /* If srv_locks_unsafe_for_binlog is TRUE, we do not want locks set + by an UPDATE or a DELETE to be inherited as gap type locks. But we + DO want S-locks set by a consistency constraint to be inherited also + then. */ + while (lock != NULL) { - if (!lock_rec_get_insert_intention(lock)) { + if (!lock_rec_get_insert_intention(lock) + && !(srv_locks_unsafe_for_binlog + && lock_get_mode(lock) == LOCK_X)) { lock_rec_add_to_queue(LOCK_REC | lock_get_mode(lock) | LOCK_GAP, @@ -3069,7 +3073,7 @@ lock_update_insert( lock_rec_inherit_to_gap_if_gap_lock(rec, page_rec_get_next(rec)); lock_mutex_exit_kernel(); -} +} /***************************************************************** Updates the lock table when a record is removed. */ diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index d99b849157a..48dc808e36c 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -1653,7 +1653,7 @@ os_file_get_size_as_iblonglong( } /*************************************************************************** -Sets a file size. This function can be used to extend or truncate a file. */ +Write the specified number of zeros to a newly created file. */ ibool os_file_set_size( @@ -1666,44 +1666,46 @@ os_file_set_size( size */ ulint size_high)/* in: most significant 32 bits of size */ { - ib_longlong offset; - ib_longlong low; - ulint n_bytes; + ib_longlong current_size; + ib_longlong desired_size; ibool ret; byte* buf; byte* buf2; + ulint buf_size; ut_a(size == (size & 0xFFFFFFFF)); - /* We use a very big 8 MB buffer in writing because Linux may be - extremely slow in fsync on 1 MB writes */ + current_size = 0; + desired_size = (ib_longlong)size + (((ib_longlong)size_high) << 32); - buf2 = ut_malloc(UNIV_PAGE_SIZE * 513); + /* Write up to 1 megabyte at a time. */ + buf_size = ut_min(64, (ulint) (desired_size / UNIV_PAGE_SIZE)) + * UNIV_PAGE_SIZE; + buf2 = ut_malloc(buf_size + UNIV_PAGE_SIZE); /* Align the buffer for possible raw i/o */ buf = ut_align(buf2, UNIV_PAGE_SIZE); /* Write buffer full of zeros */ - memset(buf, 0, UNIV_PAGE_SIZE * 512); + memset(buf, 0, buf_size); - offset = 0; - low = (ib_longlong)size + (((ib_longlong)size_high) << 32); - - if (low >= (ib_longlong)(100 * 1024 * 1024)) { + if (desired_size >= (ib_longlong)(100 * 1024 * 1024)) { fprintf(stderr, "InnoDB: Progress in MB:"); } - while (offset < low) { - if (low - offset < UNIV_PAGE_SIZE * 512) { - n_bytes = (ulint)(low - offset); - } else { - n_bytes = UNIV_PAGE_SIZE * 512; - } - + while (current_size < desired_size) { + ulint n_bytes; + + if (desired_size - current_size < (ib_longlong) buf_size) { + n_bytes = (ulint) (desired_size - current_size); + } else { + n_bytes = buf_size; + } + ret = os_file_write(name, file, buf, - (ulint)(offset & 0xFFFFFFFF), - (ulint)(offset >> 32), + (ulint)(current_size & 0xFFFFFFFF), + (ulint)(current_size >> 32), n_bytes); if (!ret) { ut_free(buf2); @@ -1711,18 +1713,18 @@ os_file_set_size( } /* Print about progress for each 100 MB written */ - if ((ib_longlong) (offset + n_bytes) / (ib_longlong)(100 * 1024 * 1024) - != offset / (ib_longlong)(100 * 1024 * 1024)) { + if ((current_size + n_bytes) / (ib_longlong)(100 * 1024 * 1024) + != current_size / (ib_longlong)(100 * 1024 * 1024)) { fprintf(stderr, " %lu00", - (ulong) ((offset + n_bytes) + (ulong) ((current_size + n_bytes) / (ib_longlong)(100 * 1024 * 1024))); } - offset += n_bytes; + current_size += n_bytes; } - if (low >= (ib_longlong)(100 * 1024 * 1024)) { + if (desired_size >= (ib_longlong)(100 * 1024 * 1024)) { fprintf(stderr, "\n"); } diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index eb50b83a4d5..2ac0824b331 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1429,51 +1429,106 @@ run_again: } /************************************************************************* -Does an unlock of a row for MySQL. */ +This can only be used when srv_locks_unsafe_for_binlog is TRUE. Before +calling this function we must use trx_reset_new_rec_lock_info() and +trx_register_new_rec_lock() to store the information which new record locks +really were set. This function removes a newly set lock under prebuilt->pcur, +and also under prebuilt->clust_pcur. Currently, this is only used and tested +in the case of an UPDATE or a DELETE statement, where the row lock is of the +LOCK_X type. +Thus, this implements a 'mini-rollback' that releases the latest record +locks we set. */ int row_unlock_for_mysql( /*=================*/ /* out: error code or DB_SUCCESS */ - row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL + row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL handle */ + ibool has_latches_on_recs)/* TRUE if called so that we have + the latches on the records under pcur + and clust_pcur, and we do not need to + reposition the cursors. */ { - rec_t* rec; - btr_pcur_t* cur = prebuilt->pcur; + dict_index_t* index; + btr_pcur_t* pcur = prebuilt->pcur; + btr_pcur_t* clust_pcur = prebuilt->clust_pcur; trx_t* trx = prebuilt->trx; + rec_t* rec; mtr_t mtr; ut_ad(prebuilt && trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - + + if (!srv_locks_unsafe_for_binlog) { + + fprintf(stderr, +"InnoDB: Error: calling row_unlock_for_mysql though\n" +"InnoDB: srv_locks_unsafe_for_binlog is FALSE.\n"); + + return(DB_SUCCESS); + } + trx->op_info = "unlock_row"; - - if (srv_locks_unsafe_for_binlog) { - if (trx->trx_create_lock == TRUE) { - mtr_start(&mtr); + index = btr_pcur_get_btr_cur(pcur)->index; + + if (index != NULL && trx_new_rec_locks_contain(trx, index)) { + + mtr_start(&mtr); - /* Restore a cursor position and find a record */ - btr_pcur_restore_position(BTR_SEARCH_LEAF, cur, &mtr); - rec = btr_pcur_get_rec(cur); + /* Restore the cursor position and find the record */ + + if (!has_latches_on_recs) { + btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr); + } - if (rec) { + rec = btr_pcur_get_rec(pcur); - lock_rec_reset_and_release_wait(rec); - } else { - fputs("InnoDB: Error: " - "Record for the lock not found\n", - stderr); - mem_analyze_corruption((byte*) trx); - ut_error; - } + mutex_enter(&kernel_mutex); - trx->trx_create_lock = FALSE; - mtr_commit(&mtr); + lock_rec_reset_and_release_wait(rec); + + mutex_exit(&kernel_mutex); + + mtr_commit(&mtr); + + /* If the search was done through the clustered index, then + we have not used clust_pcur at all, and we must NOT try to + reset locks on clust_pcur. The values in clust_pcur may be + garbage! */ + + if (index->type & DICT_CLUSTERED) { + + goto func_exit; } - + } + + index = btr_pcur_get_btr_cur(clust_pcur)->index; + + if (index != NULL && trx_new_rec_locks_contain(trx, index)) { + + mtr_start(&mtr); + + /* Restore the cursor position and find the record */ + + if (!has_latches_on_recs) { + btr_pcur_restore_position(BTR_SEARCH_LEAF, clust_pcur, + &mtr); + } + + rec = btr_pcur_get_rec(clust_pcur); + + mutex_enter(&kernel_mutex); + + lock_rec_reset_and_release_wait(rec); + + mutex_exit(&kernel_mutex); + + mtr_commit(&mtr); } +func_exit: trx->op_info = ""; return(DB_SUCCESS); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index c7a548fe448..15439bed7e7 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2784,6 +2784,10 @@ sel_restore_position_for_mysql( process the record the cursor is now positioned on (i.e. we should not go to the next record yet) */ + ibool* same_user_rec, /* out: TRUE if we were able to restore + the cursor on a user record with the + same ordering prefix in in the + B-tree index */ ulint latch_mode, /* in: latch mode wished in restoration */ btr_pcur_t* pcur, /* in: cursor whose position @@ -2800,6 +2804,8 @@ sel_restore_position_for_mysql( success = btr_pcur_restore_position(latch_mode, pcur, mtr); + *same_user_rec = success; + if (relative_position == BTR_PCUR_ON) { if (success) { return(FALSE); @@ -3064,10 +3070,12 @@ row_search_for_mysql( ulint cnt = 0; #endif /* UNIV_SEARCH_DEBUG */ ulint next_offs; + ibool same_user_rec; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; + *offsets_ = (sizeof offsets_) / sizeof *offsets_; ut_ad(index && pcur && search_tuple); @@ -3138,6 +3146,16 @@ row_search_for_mysql( trx->search_latch_timeout = BTR_SEA_TIMEOUT; } + /* Reset the new record lock info if we srv_locks_unsafe_for_binlog + is set. Then we are able to remove the record locks set here on an + individual row. */ + + if (srv_locks_unsafe_for_binlog + && prebuilt->select_lock_type != LOCK_NONE) { + + trx_reset_new_rec_lock_info(trx); + } + /*-------------------------------------------------------------*/ /* PHASE 1: Try to pop the row from the prefetch cache */ @@ -3396,8 +3414,9 @@ shortcut_fails_too_big_rec: clust_index = dict_table_get_first_index(index->table); if (UNIV_LIKELY(direction != 0)) { - if (!sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur, - moves_up, &mtr)) { + if (!sel_restore_position_for_mysql(&same_user_rec, + BTR_SEARCH_LEAF, + pcur, moves_up, &mtr)) { goto next_rec; } @@ -3659,7 +3678,7 @@ rec_loop: goto normal_return; } } - + /* We are ready to look at a possible new index entry in the result set: the cursor is now placed on a user record */ @@ -3679,6 +3698,7 @@ rec_loop: || srv_locks_unsafe_for_binlog || (unique_search && !UNIV_UNLIKELY(rec_get_deleted_flag( rec, page_rec_is_comp(rec))))) { + goto no_gap_lock; } else { lock_type = LOCK_ORDINARY; @@ -3701,7 +3721,7 @@ rec_loop: && dtuple_get_n_fields_cmp(search_tuple) == dict_index_get_n_unique(index) && 0 == cmp_dtuple_rec(search_tuple, rec, offsets)) { - no_gap_lock: +no_gap_lock: lock_type = LOCK_REC_NOT_GAP; } @@ -3764,6 +3784,7 @@ rec_loop: /* Get the clustered index record if needed */ index_rec = rec; ut_ad(index != clust_index); + goto requires_clust_rec; } } @@ -3773,6 +3794,17 @@ rec_loop: /* The record is delete-marked: we can skip it if this is not a consistent read which might see an earlier version of a non-clustered index record */ + + if (srv_locks_unsafe_for_binlog + && prebuilt->select_lock_type != LOCK_NONE) { + + /* No need to keep a lock on a delete-marked record + if we do not want to use next-key locking. */ + + row_unlock_for_mysql(prebuilt, TRUE); + + trx_reset_new_rec_lock_info(trx); + } goto next_rec; } @@ -3783,7 +3815,8 @@ rec_loop: index_rec = rec; if (index != clust_index && prebuilt->need_to_access_clustered) { - requires_clust_rec: + +requires_clust_rec: /* Before and after this "if" block, "offsets" will be related to "rec", which may be in a secondary index "index" or the clustered index ("clust_index"). However, after this @@ -3816,6 +3849,18 @@ rec_loop: /* The record is delete marked: we can skip it */ + if (srv_locks_unsafe_for_binlog + && prebuilt->select_lock_type != LOCK_NONE) { + + /* No need to keep a lock on a delete-marked + record if we do not want to use next-key + locking. */ + + row_unlock_for_mysql(prebuilt, TRUE); + + trx_reset_new_rec_lock_info(trx); + } + goto next_rec; } @@ -3908,7 +3953,7 @@ got_row: next_rec: /*-------------------------------------------------------------*/ /* PHASE 5: Move the cursor to the next index record */ - + if (UNIV_UNLIKELY(mtr_has_extra_clust_latch)) { /* We must commit mtr if we are moving to the next non-clustered index record, because we could break the @@ -3921,8 +3966,9 @@ next_rec: mtr_has_extra_clust_latch = FALSE; mtr_start(&mtr); - if (sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur, - moves_up, &mtr)) { + if (sel_restore_position_for_mysql(&same_user_rec, + BTR_SEARCH_LEAF, + pcur, moves_up, &mtr)) { #ifdef UNIV_SEARCH_DEBUG cnt++; #endif /* UNIV_SEARCH_DEBUG */ @@ -3973,11 +4019,34 @@ lock_wait_or_error: thr->lock_state = QUE_THR_LOCK_ROW; if (row_mysql_handle_errors(&err, trx, thr, NULL)) { + /* It was a lock wait, and it ended */ + thr->lock_state = QUE_THR_LOCK_NOLOCK; mtr_start(&mtr); - sel_restore_position_for_mysql(BTR_SEARCH_LEAF, pcur, - moves_up, &mtr); + sel_restore_position_for_mysql(&same_user_rec, + BTR_SEARCH_LEAF, pcur, + moves_up, &mtr); + if (srv_locks_unsafe_for_binlog && !same_user_rec) { + /* Since we were not able to restore the cursor + on the same user record, we cannot use + row_unlock_for_mysql() to unlock any records, and + we must thus reset the new rec lock info. Since + in lock0lock.c we have blocked the inheriting of gap + X-locks, we actually do not have any new record locks + set in this case. + + Note that if we were able to restore on the 'same' + user record, it is still possible that we were actually + waiting on a delete-marked record, and meanwhile + it was removed by purge and inserted again by some + other user. But that is no problem, because in + rec_loop we will again try to set a lock, and + new_rec_lock_info in trx will be right at the end. */ + + trx_reset_new_rec_lock_info(trx); + } + mode = pcur->search_mode; goto rec_loop; diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index 9e155ee1de0..10fbf3468c0 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -166,6 +166,8 @@ trx_create( memset(&trx->xid, 0, sizeof(trx->xid)); trx->xid.formatID = -1; + trx_reset_new_rec_lock_info(trx); + return(trx); } diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 8ee11519615..e33fd470582 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -2726,7 +2726,6 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row) set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate); return 1; } - stmt->server_status= mysql->server_status; if (cli_read_binary_rows(stmt)) return 1; stmt->server_status= mysql->server_status; diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index dd4ba939ebe..c3b239ac7b9 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -773,7 +773,7 @@ send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message) } void -send_eof(THD *thd, bool no_flush) +send_eof(THD *thd) { } diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 47332b02a72..33b344405ec 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -770,10 +770,13 @@ err: uint mi_get_pointer_length(ulonglong file_length, uint def) { + DBUG_ASSERT(def >= 2 && def <= 7); if (file_length) /* If not default */ { +#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS if (file_length >= (longlong) 1 << 56) def=8; +#endif if (file_length >= (longlong) 1 << 48) def=7; if (file_length >= (longlong) 1 << 40) diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 456b87b7799..74b97a65609 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -78,7 +78,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) int lock_error,kfile,open_mode,save_errno,have_rtree=0; uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, key_parts,unique_key_parts,fulltext_keys,uniques; - char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN], + char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN], data_name[FN_REFLEN]; char *disk_cache, *disk_pos, *end_pos; MI_INFO info,*m_info,*old_info; diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 338fc429090..dd1fb491064 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -638,6 +638,17 @@ Warnings: Warning 1264 Out of range value adjusted for column 'Field1' at row 1 DROP TABLE t1; SET NAMES latin1; +CREATE TABLE t1 ( +a varchar(255) NOT NULL default '', +KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=ucs2 COLLATE ucs2_general_ci; +insert into t1 values (0x803d); +insert into t1 values (0x005b); +select hex(a) from t1; +hex(a) +005B +803D +drop table t1; CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); INSERT INTO t1 VALUES ("1.1", 0), ("2.1", 0); update t1 set b=a; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0407a7f388c..b8ff3c70aa1 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -939,3 +939,14 @@ content msisdn ERR Имри.Афимим.Аеимимримдмримрмрирор имримримримр имридм ирбднримрфмририримрфмфмим.Ад.Д имдимримрад.Адимримримрмдиримримримр м.Дадимфшьмримд им.Адимимрн имадми 1234567890 11 g 1234567890 DROP TABLE t1,t2; +CREATE TABLE t1 ( +a varchar(255) NOT NULL default '', +KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; +insert into t1 values (_utf8 0xe880bd); +insert into t1 values (_utf8 0x5b); +select hex(a) from t1; +hex(a) +5B +E880BD +drop table t1; diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result index 992d01c66cd..3eb8ec4354c 100644 --- a/mysql-test/r/func_encrypt.result +++ b/mysql-test/r/func_encrypt.result @@ -128,18 +128,12 @@ Error 1108 Incorrect parameters to procedure 'des_encrypt' select des_encrypt(NULL); des_encrypt(NULL) NULL -Warnings: -Error 1108 Incorrect parameters to procedure 'des_encrypt' select des_encrypt(NULL, 10); des_encrypt(NULL, 10) NULL -Warnings: -Error 1108 Incorrect parameters to procedure 'des_encrypt' select des_encrypt(NULL, NULL); des_encrypt(NULL, NULL) NULL -Warnings: -Error 1108 Incorrect parameters to procedure 'des_encrypt' select des_encrypt(10, NULL); des_encrypt(10, NULL) NULL @@ -156,18 +150,12 @@ hello select des_decrypt(NULL); des_decrypt(NULL) NULL -Warnings: -Error 1108 Incorrect parameters to procedure 'des_decrypt' select des_decrypt(NULL, 10); des_decrypt(NULL, 10) NULL -Warnings: -Error 1108 Incorrect parameters to procedure 'des_decrypt' select des_decrypt(NULL, NULL); des_decrypt(NULL, NULL) NULL -Warnings: -Error 1108 Incorrect parameters to procedure 'des_decrypt' select des_decrypt(10, NULL); des_decrypt(10, NULL) 10 diff --git a/mysql-test/r/func_encrypt_nossl.result b/mysql-test/r/func_encrypt_nossl.result index fea752f4a4a..d0df2335afa 100644 --- a/mysql-test/r/func_encrypt_nossl.result +++ b/mysql-test/r/func_encrypt_nossl.result @@ -23,6 +23,11 @@ des_encrypt("test", NULL) NULL Warnings: Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt(NULL, NULL); +des_encrypt(NULL, NULL) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working select des_decrypt("test", 'anotherkeystr'); des_decrypt("test", 'anotherkeystr') NULL diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 3ae2adaf5e7..a725f1fe7ab 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -811,3 +811,53 @@ SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6); str num notnumber 0 DROP TABLE t1,t2; +CREATE TABLE t1( +id int(11) NOT NULL auto_increment, +pc int(11) NOT NULL default '0', +title varchar(20) default NULL, +PRIMARY KEY (id) +); +INSERT INTO t1 VALUES +(1, 0, 'Main'), +(2, 1, 'Toys'), +(3, 1, 'Games'); +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 +FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id +LEFT JOIN t1 AS t3 ON t2.pc=t3.id; +id col1 +1 Main +2 Main->Toys +3 Main->Games +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 +FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id +LEFT JOIN t1 AS t3 ON t2.pc=t3.id +WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%'; +id col1 +2 Main->Toys +DROP TABLE t1; +CREATE TABLE t1( +trackid int(10) unsigned NOT NULL auto_increment, +trackname varchar(100) NOT NULL default '', +PRIMARY KEY (trackid) +); +CREATE TABLE t2( +artistid int(10) unsigned NOT NULL auto_increment, +artistname varchar(100) NOT NULL default '', +PRIMARY KEY (artistid) +); +CREATE TABLE t3( +trackid int(10) unsigned NOT NULL, +artistid int(10) unsigned NOT NULL, +PRIMARY KEY (trackid,artistid) +); +INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York'); +INSERT INTO t2 VALUES (1, 'Vernon Duke'); +INSERT INTO t3 VALUES (1,1); +SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname +FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid +LEFT JOIN t2 ON t2.artistid=t3.artistid +WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%'; +trackname artistname +April In Paris Vernon Duke Vernon Duke +Autumn In New York NULL +DROP TABLE t1,t2,t3; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 7cbd8c7d095..34a9cc4221f 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -723,6 +723,14 @@ WHERE hostname LIKE '%aol%' hostname no cache-dtc-af05.proxy.aol.com 1 DROP TABLE t1; +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +SELECT n+1 AS n FROM t1 GROUP BY n; +n +2 +Warnings: +Warning 1052 Column 'n' in group statement is ambiguous +DROP TABLE t1; create table t1 (c1 char(3), c2 char(3)); create table t2 (c3 char(3), c4 char(3)); insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 026dae8381a..f745af182eb 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2; +drop table if exists t1,t2,t3; create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); insert into t1 (bandID,payoutID) VALUES (1,6),(2,6),(3,4),(4,9),(5,10),(6,1),(7,12),(8,12); create table t2 (payoutID SMALLINT UNSIGNED NOT NULL PRIMARY KEY); @@ -636,16 +636,35 @@ ff1 ff2 drop table t1, t2; create table t1 (a int unique); create table t2 (a int, b int); +create table t3 (c int, d int); insert into t1 values (1),(2); insert into t2 values (1,2); +insert into t3 values (1,6),(3,7); select * from t1; a 1 2 -insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b; select * from t1; a 2 3 -drop table t1; -drop table t2; +insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1; +select * from t1; +a +3 +5 +insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d; +select * from t1; +a +1 +5 +10 +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10; +insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +ERROR 23000: Column 'a' in field list is ambiguous +insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; +ERROR 42S02: Unknown table 't2' in field list +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; +ERROR 42S02: Unknown table 't2' in field list +drop table t1,t2,t3; diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result index 739beea6286..fc157093a7f 100644 --- a/mysql-test/r/insert_update.result +++ b/mysql-test/r/insert_update.result @@ -143,7 +143,7 @@ INSERT t1 VALUES (1,2,10), (3,4,20); CREATE TABLE t2 (a INT, b INT, c INT, d INT); INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1); INSERT t2 VALUES (2,1,11,2), (7,4,40,2); -INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=c+100; +INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; SELECT * FROM t1; a b c 1 2 10 @@ -158,6 +158,8 @@ a b c 5 0 30 8 9 60 INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); +ERROR 23000: Column 'c' in field list is ambiguous +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); SELECT *, VALUES(a) FROM t1; a b c VALUES(a) 1 2 10 NULL @@ -174,7 +176,7 @@ select * from t1; a 1 2 -insert ignore into t1 select a from t1 on duplicate key update a=a+1 ; +insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; select * from t1; a 1 @@ -185,5 +187,7 @@ a 2 3 insert into t1 select a from t1 on duplicate key update a=a+1 ; -ERROR 23000: Duplicate entry '3' for key 1 +ERROR 23000: Column 'a' in field list is ambiguous +insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; +ERROR 23000: Column 't1.a' in field list is ambiguous drop table t1; diff --git a/mysql-test/r/lowercase_table2.result b/mysql-test/r/lowercase_table2.result index db833bcd970..f93a10dfbad 100644 --- a/mysql-test/r/lowercase_table2.result +++ b/mysql-test/r/lowercase_table2.result @@ -1,6 +1,7 @@ -DROP TABLE IF EXISTS t1,t2,t3; +DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa; DROP DATABASE IF EXISTS `TEST_$1`; DROP DATABASE IF EXISTS `test_$1`; +DROP DATABASE mysqltest_LC2; CREATE TABLE T1 (a int); INSERT INTO T1 VALUES (1); SHOW TABLES LIKE "T1"; diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 573b2b54141..091d21cfa20 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1,7 +1,7 @@ DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; drop database if exists db1; -drop view if exists v1, v2; +drop view if exists v1, v2, v3; CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); <?xml version="1.0"?> @@ -380,6 +380,11 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t1` ENABLE KEYS */; DROP TABLE IF EXISTS `v1`; DROP VIEW IF EXISTS `v1`; +CREATE TABLE `v1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `v1`; +DROP VIEW IF EXISTS `v1`; CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`t1`.`a` AS `a` from `test`.`t1`; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1458,6 +1463,11 @@ UNLOCK TABLES; /*!40000 ALTER TABLE `t2` ENABLE KEYS */; DROP TABLE IF EXISTS `v2`; DROP VIEW IF EXISTS `v2`; +CREATE TABLE `v2` ( + `a` varchar(30) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `v2`; +DROP VIEW IF EXISTS `v2`; CREATE ALGORITHM=UNDEFINED VIEW `db1`.`v2` AS select `db1`.`t2`.`a` AS `a` from `db1`.`t2` where (`db1`.`t2`.`a` like _latin1'a%') WITH CASCADED CHECK OPTION; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; @@ -1637,3 +1647,29 @@ insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thir </database> </mysqldump> drop table t1, t2; +create table t1(a int, b int, c varchar(30)); +insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three"); +create view v3 as +select * from t1; +create view v1 as +select * from v3 where b in (1, 2, 3, 4, 5, 6, 7); +create view v2 as +select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; +drop view v1, v2, v3; +drop table t1; +show full tables; +Tables_in_test Table_type +t1 BASE TABLE +v1 VIEW +v2 VIEW +v3 VIEW +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED VIEW `test`.`v1` AS select `test`.`v3`.`a` AS `a`,`test`.`v3`.`b` AS `b`,`test`.`v3`.`c` AS `c` from `test`.`v3` where (`test`.`v3`.`b` in (1,2,3,4,5,6,7)) +select * from v1; +a b c +1 2 one +2 4 two +3 6 three +drop view v1, v2, v3; +drop table t1; diff --git a/mysql-test/r/ndb_subquery.result b/mysql-test/r/ndb_subquery.result index f65f09b71b3..b19571b05c1 100644 --- a/mysql-test/r/ndb_subquery.result +++ b/mysql-test/r/ndb_subquery.result @@ -40,3 +40,22 @@ p u o 5 5 5 drop table t1; drop table t2; +create table t1 (p int not null primary key, u int not null) engine=ndb; +insert into t1 values (1,1),(2,2),(3,3); +create table t2 as +select t1.* +from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8 +where t1.u = t2.u +and t2.u = t3.u +and t3.u = t4.u +and t4.u = t5.u +and t5.u = t6.u +and t6.u = t7.u +and t7.u = t8.u; +select * from t2 order by 1; +p u +1 1 +2 2 +3 3 +drop table t1; +drop table t2; diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index c37a42d3fa7..a19734d55b5 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -555,3 +555,25 @@ IFNULL(a, 'TEST') COALESCE(b, 'TEST') 4 TEST TEST TEST DROP TABLE t1,t2; +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES +(1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), +(6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +type +A +B +C +NULL +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +type +A +B +C +NULL +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 10 Using filesort +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index ae7d0474e24..6f9b4e41b22 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -720,3 +720,27 @@ id status 59 C 60 C DROP TABLE t1; +CREATE TABLE t1 (a int, b int, primary key(a,b)); +INSERT INTO t1 VALUES +(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3); +CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3; +EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +EXPLAIN SELECT a,b FROM t1 WHERE a < 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +EXPLAIN SELECT a,b FROM v1 WHERE a < 2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 range PRIMARY PRIMARY 4 NULL 4 Using where; Using index +SELECT a,b FROM t1 WHERE a < 2 and b=3; +a b +1 3 +SELECT a,b FROM v1 WHERE a < 2 and b=3; +a b +1 3 +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 9f1ff2cd835..d02c28a0a97 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2423,12 +2423,130 @@ ERROR HY000: Incorrect usage of ALL and DISTINCT select distinct all * from t1; ERROR HY000: Incorrect usage of ALL and DISTINCT drop table t1; +CREATE TABLE t1 ( +kunde_intern_id int(10) unsigned NOT NULL default '0', +kunde_id int(10) unsigned NOT NULL default '0', +FK_firma_id int(10) unsigned NOT NULL default '0', +aktuell enum('Ja','Nein') NOT NULL default 'Ja', +vorname varchar(128) NOT NULL default '', +nachname varchar(128) NOT NULL default '', +geloescht enum('Ja','Nein') NOT NULL default 'Nein', +firma varchar(128) NOT NULL default '' +); +INSERT INTO t1 VALUES +(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), +(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 +WHERE +( +( +( '' != '' AND firma LIKE CONCAT('%', '', '%')) +OR +(vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND +'Vorname1' != '' AND 'xxxx' != '') +) +AND +( +aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 +) +) +; +kunde_id FK_firma_id aktuell vorname nachname geloescht +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, +geloescht FROM t1 +WHERE +( +( +aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 +) +AND +( +( '' != '' AND firma LIKE CONCAT('%', '', '%') ) +OR +( vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND +'xxxx' != '') +) +) +; +kunde_id FK_firma_id aktuell vorname nachname geloescht +SELECT COUNT(*) FROM t1 WHERE +( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) +AND FK_firma_id = 2; +COUNT(*) +0 +drop table t1; CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b)); INSERT INTO t1 VALUES (0x8000000000000000); SELECT b FROM t1 WHERE b=0x8000000000000000; b 9223372036854775808 DROP TABLE t1; +CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL); +CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL); +INSERT INTO `t2` VALUES (0,'READ'); +CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL); +INSERT INTO `t3` VALUES (1,'fs'); +select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0); +id name gid uid ident level +1 fs NULL NULL 0 READ +drop table t1,t2,t3; +CREATE TABLE t1 ( city char(30) ); +INSERT INTO t1 VALUES ('London'); +INSERT INTO t1 VALUES ('Paris'); +SELECT * FROM t1 WHERE city='London'; +city +London +SELECT * FROM t1 WHERE city='london'; +city +London +EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 WHERE city='London' AND city='london'; +city +London +EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where +SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +city +London +DROP TABLE t1; +create table t1 (a int(11) unsigned, b int(11) unsigned); +insert into t1 values (1,0), (1,1), (1,2); +select a-b from t1 order by 1; +a-b +0 +1 +18446744073709551615 +select a-b , (a-b < 0) from t1 order by 1; +a-b (a-b < 0) +0 0 +1 0 +18446744073709551615 0 +select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; +d (a-b >= 0) b +1 1 0 +0 1 1 +18446744073709551615 1 2 +select cast((a - b) as unsigned) from t1 order by 1; +cast((a - b) as unsigned) +0 +1 +18446744073709551615 +drop table t1; +create table t1 (a int(11)); +select all all * from t1; +a +select distinct distinct * from t1; +a +select all distinct * from t1; +ERROR HY000: Incorrect usage of ALL and DISTINCT +select distinct all * from t1; +ERROR HY000: Incorrect usage of ALL and DISTINCT +drop table t1; CREATE TABLE t1 ( K2C4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '', K4N4 varchar(4) character set latin1 collate latin1_bin NOT NULL default '0000', @@ -2573,115 +2691,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 5 1 SIMPLE t2 ref a a 23 test.t1.a 2 DROP TABLE t1, t2; -CREATE TABLE t1 ( city char(30) ); -INSERT INTO t1 VALUES ('London'); -INSERT INTO t1 VALUES ('Paris'); -SELECT * FROM t1 WHERE city='London'; -city -London -SELECT * FROM t1 WHERE city='london'; -city -London -EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -SELECT * FROM t1 WHERE city='London' AND city='london'; -city -London -EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where -SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -city -London -DROP TABLE t1; -create table t1 (a int(11) unsigned, b int(11) unsigned); -insert into t1 values (1,0), (1,1), (1,2); -select a-b from t1 order by 1; -a-b -0 -1 -18446744073709551615 -select a-b , (a-b < 0) from t1 order by 1; -a-b (a-b < 0) -0 0 -1 0 -18446744073709551615 0 -select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; -d (a-b >= 0) b -1 1 0 -0 1 1 -18446744073709551615 1 2 -select cast((a - b) as unsigned) from t1 order by 1; -cast((a - b) as unsigned) -0 -1 -18446744073709551615 -drop table t1; -create table t1 (a int(11)); -select all all * from t1; -a -select distinct distinct * from t1; -a -select all distinct * from t1; -ERROR HY000: Incorrect usage of ALL and DISTINCT -select distinct all * from t1; -ERROR HY000: Incorrect usage of ALL and DISTINCT -drop table t1; -CREATE TABLE t1 ( -kunde_intern_id int(10) unsigned NOT NULL default '0', -kunde_id int(10) unsigned NOT NULL default '0', -FK_firma_id int(10) unsigned NOT NULL default '0', -aktuell enum('Ja','Nein') NOT NULL default 'Ja', -vorname varchar(128) NOT NULL default '', -nachname varchar(128) NOT NULL default '', -geloescht enum('Ja','Nein') NOT NULL default 'Nein', -firma varchar(128) NOT NULL default '' -); -INSERT INTO t1 VALUES -(3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), -(3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 -WHERE -( -( -( '' != '' AND firma LIKE CONCAT('%', '', '%')) -OR -(vorname LIKE CONCAT('%', 'Vorname1', '%') AND -nachname LIKE CONCAT('%', '1Nachname', '%') AND -'Vorname1' != '' AND 'xxxx' != '') -) -AND -( -aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 -) -) -; -kunde_id FK_firma_id aktuell vorname nachname geloescht -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, -geloescht FROM t1 -WHERE -( -( -aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 -) -AND -( -( '' != '' AND firma LIKE CONCAT('%', '', '%') ) -OR -( vorname LIKE CONCAT('%', 'Vorname1', '%') AND -nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND -'xxxx' != '') -) -) -; -kunde_id FK_firma_id aktuell vorname nachname geloescht -SELECT COUNT(*) FROM t1 WHERE -( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) -AND FK_firma_id = 2; -COUNT(*) -0 -drop table t1; CREATE TABLE t1 (a int); CREATE TABLE t2 (a int); INSERT INTO t1 VALUES (1), (2), (3), (4), (5); diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index b6ba737a8ba..bfbfb87ac43 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -65,47 +65,6 @@ iterate foo; end| ERROR 42000: ITERATE with no matching label: foo create procedure foo() -begin -goto foo; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -begin -label foo; -end; -goto foo; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -goto foo; -begin -label foo; -end; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -begin -goto foo; -end; -begin -label foo; -end; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() -begin -begin -label foo; -end; -begin -goto foo; -end; -end| -ERROR 42000: GOTO with no matching label: foo -create procedure foo() foo: loop foo: loop set @x=2; @@ -308,16 +267,6 @@ declare continue handler for sqlstate '42S99' set x = 1; declare c cursor for select * from t1; end| ERROR 42000: Cursor declaration after handler declaration -create procedure p() -begin -declare continue handler for sqlexception -begin -goto L1; -end; -select field from t1; -label L1; -end| -ERROR HY000: GOTO is not allowed in a stored procedure handler drop procedure if exists p| create procedure p(in x int, inout y int, out z int) begin diff --git a/mysql-test/r/sp-goto.result b/mysql-test/r/sp-goto.result new file mode 100644 index 00000000000..ca560f62318 --- /dev/null +++ b/mysql-test/r/sp-goto.result @@ -0,0 +1,205 @@ +drop table if exists t1; +create table t1 ( +id char(16) not null default '', +data int not null +); +drop procedure if exists goto1// +create procedure goto1() +begin +declare y int; +label a; +select * from t1; +select count(*) into y from t1; +if y > 2 then +goto b; +end if; +insert into t1 values ("j", y); +goto a; +label b; +end// +call goto1()// +id data +id data +j 0 +id data +j 0 +j 1 +id data +j 0 +j 1 +j 2 +drop procedure goto1// +drop procedure if exists goto2// +create procedure goto2(a int) +begin +declare x int default 0; +declare continue handler for sqlstate '42S98' set x = 1; +label a; +select * from t1; +b: +while x < 2 do +begin +declare continue handler for sqlstate '42S99' set x = 2; +if a = 0 then +set x = x + 1; +iterate b; +elseif a = 1 then +leave b; +elseif a = 2 then +set a = 1; +goto a; +end if; +end; +end while b; +select * from t1; +end// +call goto2(0)// +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +call goto2(1)// +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +call goto2(2)// +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +id data +j 0 +j 1 +j 2 +drop procedure goto2// +delete from t1// +drop procedure if exists goto3// +create procedure goto3() +begin +label L1; +begin +end; +goto L1; +end// +drop procedure goto3// +drop procedure if exists goto4// +create procedure goto4() +begin +begin +label lab1; +begin +goto lab1; +end; +end; +end// +drop procedure goto4// +drop procedure if exists goto5// +create procedure goto5() +begin +begin +begin +goto lab1; +end; +label lab1; +end; +end// +drop procedure goto5// +drop procedure if exists goto6// +create procedure goto6() +begin +label L1; +goto L5; +begin +label L2; +goto L1; +goto L5; +begin +label L3; +goto L1; +goto L2; +goto L3; +goto L4; +goto L5; +end; +goto L2; +goto L4; +label L4; +end; +label L5; +goto L1; +end// +drop procedure goto6// +create procedure foo() +begin +goto foo; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +begin +label foo; +end; +goto foo; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +goto foo; +begin +label foo; +end; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +begin +goto foo; +end; +begin +label foo; +end; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure foo() +begin +begin +label foo; +end; +begin +goto foo; +end; +end// +ERROR 42000: GOTO with no matching label: foo +create procedure p() +begin +declare continue handler for sqlexception +begin +goto L1; +end; +select field from t1; +label L1; +end// +ERROR HY000: GOTO is not allowed in a stored procedure handler +drop procedure if exists bug6898// +create procedure bug6898() +begin +goto label1; +label label1; +begin end; +goto label1; +end// +drop procedure bug6898// +drop table t1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ed858ba27ee..7b99a3bacd0 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -438,145 +438,6 @@ id data i 3 delete from t1| drop procedure i| -drop procedure if exists goto1| -create procedure goto1() -begin -declare y int; -label a; -select * from t1; -select count(*) into y from t1; -if y > 2 then -goto b; -end if; -insert into t1 values ("j", y); -goto a; -label b; -end| -call goto1()| -id data -id data -j 0 -id data -j 0 -j 1 -id data -j 0 -j 1 -j 2 -drop procedure goto1| -drop procedure if exists goto2| -create procedure goto2(a int) -begin -declare x int default 0; -declare continue handler for sqlstate '42S98' set x = 1; -label a; -select * from t1; -b: -while x < 2 do -begin -declare continue handler for sqlstate '42S99' set x = 2; -if a = 0 then -set x = x + 1; -iterate b; -elseif a = 1 then -leave b; -elseif a = 2 then -set a = 1; -goto a; -end if; -end; -end while b; -select * from t1; -end| -call goto2(0)| -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -call goto2(1)| -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -call goto2(2)| -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -id data -j 0 -j 1 -j 2 -drop procedure goto2| -delete from t1| -drop procedure if exists goto3| -create procedure goto3() -begin -label L1; -begin -end; -goto L1; -end| -drop procedure goto3| -drop procedure if exists goto4| -create procedure goto4() -begin -begin -label lab1; -begin -goto lab1; -end; -end; -end| -drop procedure goto4| -drop procedure if exists goto5| -create procedure goto5() -begin -begin -begin -goto lab1; -end; -label lab1; -end; -end| -drop procedure goto5| -drop procedure if exists goto6| -create procedure goto6() -begin -label L1; -goto L5; -begin -label L2; -goto L1; -goto L5; -begin -label L3; -goto L1; -goto L2; -goto L3; -goto L4; -goto L5; -end; -goto L2; -goto L4; -label L4; -end; -label L5; -goto L1; -end| -drop procedure goto6| insert into t1 values ("foo", 3), ("bar", 19)| insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)| drop procedure if exists sel1| @@ -2971,15 +2832,6 @@ select @x| set global query_cache_size = @qcs1| delete from t1| drop function bug9902| -drop procedure if exists bug6898| -create procedure bug6898() -begin -goto label1; -label label1; -begin end; -goto label1; -end| -drop procedure bug6898| drop function if exists bug9102| create function bug9102() returns blob return 'a'| select bug9102()| @@ -3224,4 +3076,29 @@ bbbbb 2 ccccc 3 drop procedure bug10136| drop table t3| +drop procedure if exists bug11529| +create procedure bug11529() +begin +declare c cursor for select id, data from t1 where data in (10,13); +open c; +begin +declare vid char(16); +declare vdata int; +declare exit handler for not found begin end; +while true do +fetch c into vid, vdata; +end while; +end; +close c; +end| +insert into t1 values +('Name1', 10), +('Name2', 11), +('Name3', 12), +('Name4', 13), +('Name5', 14)| +call bug11529()| +call bug11529()| +delete from t1| +drop procedure bug11529| drop table t1,t2; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 996a692d531..0bb1fd1d550 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -482,3 +482,12 @@ i k ts 1 1 0000-00-00 00:00:00 2 2 0000-00-00 00:00:00 drop table t1, t2; +drop function if exists bug5893; +create table t1 (col1 int, col2 int); +insert into t1 values (1, 2); +create function bug5893 () returns int return 5; +create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); +drop function bug5893; +update t1 set col2 = 4; +ERROR 42000: FUNCTION test.bug5893 does not exist +drop table t1; diff --git a/mysql-test/r/type_bit.result b/mysql-test/r/type_bit.result index 4d9bc0c7fe1..4aa8587d6e1 100644 --- a/mysql-test/r/type_bit.result +++ b/mysql-test/r/type_bit.result @@ -466,3 +466,90 @@ select a+0 from t1; a+0 255 drop table t1; +create table t1 (a bit(7)); +insert into t1 values (120), (0), (111); +select a+0 from t1 union select a+0 from t1; +a+0 +120 +0 +111 +select a+0 from t1 union select NULL; +a+0 +120 +0 +111 +NULL +select NULL union select a+0 from t1; +NULL +NULL +120 +0 +111 +create table t2 select a from t1 union select a from t1; +select a+0 from t2; +a+0 +120 +0 +111 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` bit(7) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1, t2; +create table t1 (id1 int(11), b1 bit(1)); +create table t2 (id2 int(11), b2 bit(1)); +insert into t1 values (1, 1), (2, 0), (3, 1); +insert into t2 values (2, 1), (3, 0), (4, 0); +create algorithm=undefined view v1 as +select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0 +union +select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1; +select * from v1; +b1+0 b2+0 +0 1 +drop table t1, t2; +drop view v1; +create table t1(a bit(4)); +insert into t1(a) values (1), (2), (5), (4), (3); +insert into t1 select * from t1; +select a+0 from t1; +a+0 +1 +2 +5 +4 +3 +1 +2 +5 +4 +3 +drop table t1; +create table t1 (a1 int(11), b1 bit(2)); +create table t2 (a2 int(11), b2 bit(2)); +insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2); +insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2); +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; +a1 a2 b1+0 b2+0 +2 2 0 1 +3 3 1 0 +4 4 2 1 +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; +a1 a2 b1+0 b2+0 +2 2 0 1 +3 3 1 0 +4 4 2 1 +select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; +a1 a2 b1+0 b2+0 +1 2 1 1 +3 2 1 1 +2 3 0 0 +1 4 1 1 +3 4 1 1 +4 5 2 2 +select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; +sum(a1) b1+0 b2+0 +2 0 0 +4 2 2 +8 1 1 diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 67a011231be..193ed298339 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -703,3 +703,18 @@ select max(i) from t1 where c = ''; max(i) 4 drop table t1; +create table t1 (a int, b int, c tinyblob, d int, e int); +alter table t1 add primary key (a,b,c(255),d); +alter table t1 add key (a,b,d,e); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL default '0', + `b` int(11) NOT NULL default '0', + `c` tinyblob NOT NULL, + `d` int(11) NOT NULL default '0', + `e` int(11) default NULL, + PRIMARY KEY (`a`,`b`,`c`(255),`d`), + KEY `a` (`a`,`b`,`d`,`e`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index b406dbab82f..79943df18c5 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -928,3 +928,9 @@ select * from t1 where a = -0.00; a 0.00 drop table t1; +create table t1 (col1 bigint default -9223372036854775808); +insert into t1 values (default); +select * from t1; +col1 +-9223372036854775808 +drop table t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 99b4f0529e6..5468508165c 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -504,10 +504,10 @@ t1 CREATE TABLE `t1` ( `c4` double default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; -SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8; +SET GLOBAL MYISAM_DATA_POINTER_SIZE= 7; SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE'; Variable_name Value -myisam_data_pointer_size 8 +myisam_data_pointer_size 7 SET GLOBAL table_cache=-1; SHOW VARIABLES LIKE 'table_cache'; Variable_name Value diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 4c1db618b4b..cad86dc94b8 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1561,7 +1561,7 @@ one 1025,2025,3025 two 1050,1050 select col1,group_concat(col2,col3) from v1 group by col1; col1 group_concat(col2,col3) -two 1025,2025,3025 +one 1025,2025,3025 two 1050,1050 drop view v1; drop table t1; @@ -1850,3 +1850,16 @@ SELECT * FROM v1; SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1) dkjhgd drop view v1; +set sql_mode='strict_all_tables'; +CREATE TABLE t1 (col1 INT NOT NULL, col2 INT NOT NULL) ENGINE = INNODB; +CREATE VIEW v1 (vcol1) AS SELECT col1 FROM t1; +CREATE VIEW v2 (vcol1) AS SELECT col1 FROM t1 WHERE col2 > 2; +INSERT INTO t1 (col1) VALUES(12); +ERROR HY000: Field 'col2' doesn't have a default value +INSERT INTO v1 (vcol1) VALUES(12); +ERROR HY000: Field of view 'test.v1' underlying table doesn't have a default value +INSERT INTO v2 (vcol1) VALUES(12); +ERROR HY000: Field of view 'test.v2' underlying table doesn't have a default value +set sql_mode=default; +drop view v2,v1; +drop table t1; diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 2722e8572b0..f4327536795 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -408,6 +408,18 @@ DROP TABLE t1; SET NAMES latin1; # +# Bug#9557 MyISAM utf8 table crash +# +CREATE TABLE t1 ( + a varchar(255) NOT NULL default '', + KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=ucs2 COLLATE ucs2_general_ci; +insert into t1 values (0x803d); +insert into t1 values (0x005b); +select hex(a) from t1; +drop table t1; + +# # Conversion from an UCS2 string to a decimal column # CREATE TABLE t1 (a varchar(64) character set ucs2, b decimal(10,3)); diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 343b7c867e7..0a847057258 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -788,3 +788,15 @@ INSERT INTO t2 VALUES ('1234567890',2,'2005-05-24 13:53:25'); SELECT content, t2.msisdn FROM t1, t2 WHERE t1.msisdn = '1234567890'; DROP TABLE t1,t2; + +# +# Bug#9557 MyISAM utf8 table crash +# +CREATE TABLE t1 ( + a varchar(255) NOT NULL default '', + KEY a (a) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE utf8_general_ci; +insert into t1 values (_utf8 0xe880bd); +insert into t1 values (_utf8 0x5b); +select hex(a) from t1; +drop table t1; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 9bfe9567d83..c5f96ec4201 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -10,3 +10,4 @@ # ############################################################################## +sp-goto:GOTO is currently is disabled - will be fixed in the future diff --git a/mysql-test/t/func_encrypt_nossl.test b/mysql-test/t/func_encrypt_nossl.test index 0e9d93f5968..95c104ce046 100644 --- a/mysql-test/t/func_encrypt_nossl.test +++ b/mysql-test/t/func_encrypt_nossl.test @@ -9,6 +9,7 @@ select des_encrypt("test", 1); select des_encrypt("test", 9); select des_encrypt("test", 100); select des_encrypt("test", NULL); +select des_encrypt(NULL, NULL); select des_decrypt("test", 'anotherkeystr'); select des_decrypt(1, 1); select des_decrypt(des_encrypt("test", 'thekey')); diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 617de1b3cc5..2cb7dfe4824 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -543,3 +543,59 @@ SELECT * FROM t1, t2 WHERE num=str; SELECT * FROM t1, t2 WHERE num=substring(str from 1 for 6); DROP TABLE t1,t2; + +# +# Bug #11469: NOT NULL optimization wrongly used for arguments of CONCAT_WS +# + +CREATE TABLE t1( + id int(11) NOT NULL auto_increment, + pc int(11) NOT NULL default '0', + title varchar(20) default NULL, + PRIMARY KEY (id) +); + +INSERT INTO t1 VALUES + (1, 0, 'Main'), + (2, 1, 'Toys'), + (3, 1, 'Games'); + +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 + FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id + LEFT JOIN t1 AS t3 ON t2.pc=t3.id; +SELECT t1.id, CONCAT_WS('->', t3.title, t2.title, t1.title) as col1 + FROM t1 LEFT JOIN t1 AS t2 ON t1.pc=t2.id + LEFT JOIN t1 AS t3 ON t2.pc=t3.id + WHERE CONCAT_WS('->', t3.title, t2.title, t1.title) LIKE '%Toys%'; + +DROP TABLE t1; + + +CREATE TABLE t1( + trackid int(10) unsigned NOT NULL auto_increment, + trackname varchar(100) NOT NULL default '', + PRIMARY KEY (trackid) +); + +CREATE TABLE t2( + artistid int(10) unsigned NOT NULL auto_increment, + artistname varchar(100) NOT NULL default '', + PRIMARY KEY (artistid) +); + +CREATE TABLE t3( + trackid int(10) unsigned NOT NULL, + artistid int(10) unsigned NOT NULL, + PRIMARY KEY (trackid,artistid) +); + +INSERT INTO t1 VALUES (1, 'April In Paris'), (2, 'Autumn In New York'); +INSERT INTO t2 VALUES (1, 'Vernon Duke'); +INSERT INTO t3 VALUES (1,1); + +SELECT CONCAT_WS(' ', trackname, artistname) trackname, artistname + FROM t1 LEFT JOIN t3 ON t1.trackid=t3.trackid + LEFT JOIN t2 ON t2.artistid=t3.artistid + WHERE CONCAT_WS(' ', trackname, artistname) LIKE '%In%'; + +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 5d84098a84a..2defb480deb 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -566,6 +566,16 @@ show warnings; drop table t1, t2; # +# Test for bug #11414: crash on Windows for a simple GROUP BY query +# + +CREATE TABLE t1 (n int); +INSERT INTO t1 VALUES (1); +--disable_ps_protocol +SELECT n+1 AS n FROM t1 GROUP BY n; +--enable_ps_protocol +DROP TABLE t1; + # Test for bug #8614: GROUP BY 'const' with DISTINCT # diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index a6468c52645..92e8c7f1231 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -3,7 +3,7 @@ # --disable_warnings -drop table if exists t1,t2; +drop table if exists t1,t2,t3; --enable_warnings create table t1 (bandID MEDIUMINT UNSIGNED NOT NULL PRIMARY KEY, payoutID SMALLINT UNSIGNED NOT NULL); @@ -180,10 +180,24 @@ drop table t1, t2; # create table t1 (a int unique); create table t2 (a int, b int); +create table t3 (c int, d int); insert into t1 values (1),(2); insert into t2 values (1,2); +insert into t3 values (1,6),(3,7); select * from t1; -insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +insert into t1 select a from t2 on duplicate key update a= t1.a + t2.b; select * from t1; -drop table t1; -drop table t2; +insert into t1 select a+1 from t2 on duplicate key update t1.a= t1.a + t2.b+1; +select * from t1; +insert into t1 select t3.c from t3 on duplicate key update a= a + t3.d; +select * from t1; +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= a + 10; + +#Some error cases +--error 1052 +insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b; +--error 1109 +insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; +--error 1109 +insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; +drop table t1,t2,t3; diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test index 7653fd8dd42..64a76aafa5e 100644 --- a/mysql-test/t/insert_update.test +++ b/mysql-test/t/insert_update.test @@ -72,11 +72,13 @@ CREATE TABLE t2 (a INT, b INT, c INT, d INT); # column names deliberately clash with columns in t1 (Bug#8147) INSERT t2 VALUES (5,6,30,1), (7,4,40,1), (8,9,60,1); INSERT t2 VALUES (2,1,11,2), (7,4,40,2); -INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=c+100; +INSERT t1 SELECT a,b,c FROM t2 WHERE d=1 ON DUPLICATE KEY UPDATE c=t1.c+100; SELECT * FROM t1; INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0; SELECT * FROM t1; +--error 1052 INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=c+VALUES(a); +INSERT t1 SELECT a,b,c FROM t2 WHERE d=2 ON DUPLICATE KEY UPDATE c=t1.c+VALUES(t1.a); SELECT *, VALUES(a) FROM t1; DROP TABLE t1; DROP TABLE t2; @@ -89,10 +91,12 @@ create table t1 (a int not null unique) engine=myisam; insert into t1 values (1),(2); insert ignore into t1 select 1 on duplicate key update a=2; select * from t1; -insert ignore into t1 select a from t1 on duplicate key update a=a+1 ; +insert ignore into t1 select a from t1 as t2 on duplicate key update a=t1.a+1 ; select * from t1; insert into t1 select 1 on duplicate key update a=2; select * from t1; ---error 1062 +--error 1052 insert into t1 select a from t1 on duplicate key update a=a+1 ; +--error 1052 +insert ignore into t1 select a from t1 on duplicate key update a=t1.a+1 ; drop table t1; diff --git a/mysql-test/t/lowercase_table2.test b/mysql-test/t/lowercase_table2.test index 51c6f6b5ac3..5e38c59386d 100644 --- a/mysql-test/t/lowercase_table2.test +++ b/mysql-test/t/lowercase_table2.test @@ -10,9 +10,10 @@ show variables like "lower_case_table_names"; enable_query_log; --disable_warnings -DROP TABLE IF EXISTS t1,t2,t3; +DROP TABLE IF EXISTS t1,t2,t3,t2aA,t1Aa; DROP DATABASE IF EXISTS `TEST_$1`; DROP DATABASE IF EXISTS `test_$1`; +DROP DATABASE mysqltest_LC2; --enable_warnings CREATE TABLE T1 (a int); diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index ec49eec8b46..811875a36f5 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -5,7 +5,7 @@ DROP TABLE IF EXISTS t1, `"t"1`, t1aa, t2, t2aa; drop database if exists mysqldump_test_db; drop database if exists db1; -drop view if exists v1, v2; +drop view if exists v1, v2, v3; --enable_warnings # XML output @@ -678,3 +678,34 @@ insert into t2 (a, b) values (NULL, NULL),(10, NULL),(NULL, "twenty"),(30, "thir --exec $MYSQL_DUMP --skip-comments --xml --no-create-info test drop table t1, t2; +# +# Bug #10927 mysqldump: Can't reload dump with view that consist of other view +# + +create table t1(a int, b int, c varchar(30)); + +insert into t1 values(1, 2, "one"), (2, 4, "two"), (3, 6, "three"); + +create view v3 as +select * from t1; + +create view v1 as +select * from v3 where b in (1, 2, 3, 4, 5, 6, 7); + +create view v2 as +select v3.a from v3, v1 where v1.a=v3.a and v3.b=3 limit 1; + +--exec $MYSQL_DUMP test > var/tmp/bug10927.sql +drop view v1, v2, v3; +drop table t1; +--exec $MYSQL test < var/tmp/bug10927.sql + +# Without dropping the original tables in between +--exec $MYSQL_DUMP test > var/tmp/bug10927.sql +--exec $MYSQL test < var/tmp/bug10927.sql +show full tables; +show create view v1; +select * from v1; + +drop view v1, v2, v3; +drop table t1; diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index 1e5c31da98e..2e5e2293b5c 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -7,6 +7,13 @@ DROP TABLE IF EXISTS t1; drop database if exists mysqltest; --enable_warnings +connect (con1,localhost,root,,test); +connect (con2,localhost,root,,test); + +connection con2; +-- sleep 2 +connection con1; + # # Basic test to show that the ALTER TABLE # is working @@ -92,10 +99,6 @@ CREATE TABLE t1 ( INSERT INTO t1 VALUES (9410,9412); -connect (con1,localhost,,,test); -connect (con2,localhost,,,test); - -connection con1; ALTER TABLE t1 ADD COLUMN c int not null; select * from t1 order by a; diff --git a/mysql-test/t/ndb_subquery.test b/mysql-test/t/ndb_subquery.test index 9d3a256a263..095fdbcfa13 100644 --- a/mysql-test/t/ndb_subquery.test +++ b/mysql-test/t/ndb_subquery.test @@ -37,3 +37,26 @@ drop table t1; drop table t2; # bug#5367 ########## + +### +# bug#11205 +create table t1 (p int not null primary key, u int not null) engine=ndb; +insert into t1 values (1,1),(2,2),(3,3); + +create table t2 as +select t1.* +from t1 as t1, t1 as t2, t1 as t3, t1 as t4, t1 as t5, t1 as t6, t1 as t7, t1 as t8 +where t1.u = t2.u + and t2.u = t3.u + and t3.u = t4.u + and t4.u = t5.u + and t5.u = t6.u + and t6.u = t7.u + and t7.u = t8.u; + +select * from t2 order by 1; + +drop table t1; +drop table t2; + + diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index c75cad0b051..26fcc7463d6 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -250,3 +250,19 @@ SELECT IFNULL(a, 'TEST'), COALESCE(b, 'TEST') FROM t2 DROP TABLE t1,t2; +# +# Tests for bug #11639: ROLLUP over view executed through filesort +# + +CREATE TABLE t1(id int, type char(1)); +INSERT INTO t1 VALUES + (1,"A"),(2,"C"),(3,"A"),(4,"A"),(5,"B"), + (6,"B"),(7,"A"),(8,"C"),(9,"A"),(10,"C"); +CREATE VIEW v1 AS SELECT * FROM t1; + +SELECT type FROM t1 GROUP BY type WITH ROLLUP; +SELECT type FROM v1 GROUP BY type WITH ROLLUP; +EXPLAIN SELECT type FROM v1 GROUP BY type WITH ROLLUP; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index a285a4b312c..3d2285b1633 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -530,3 +530,26 @@ SELECT * FROM t1 WHERE status NOT BETWEEN 'A' AND 'B'; SELECT * FROM t1 WHERE status < 'A' OR status > 'B'; DROP TABLE t1; + +# +# Test for bug #10031: range to be used over a view +# + +CREATE TABLE t1 (a int, b int, primary key(a,b)); + +INSERT INTO t1 VALUES + (1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3),(4,1),(4,2),(4,3); + +CREATE VIEW v1 as SELECT a,b FROM t1 WHERE b=3; + +EXPLAIN SELECT a,b FROM t1 WHERE a < 2 and b=3; +EXPLAIN SELECT a,b FROM v1 WHERE a < 2 and b=3; + +EXPLAIN SELECT a,b FROM t1 WHERE a < 2; +EXPLAIN SELECT a,b FROM v1 WHERE a < 2; + +SELECT a,b FROM t1 WHERE a < 2 and b=3; +SELECT a,b FROM v1 WHERE a < 2 and b=3; + +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index e131c3d0517..2e4bb3e13ad 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1954,7 +1954,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; DROP TABLE t1, t2; - # # Test case for bug 7098: substitution of a constant for a string field # @@ -1998,6 +1997,64 @@ select distinct all * from t1; drop table t1; # +# Test for BUG#10095 +# +CREATE TABLE t1 ( + kunde_intern_id int(10) unsigned NOT NULL default '0', + kunde_id int(10) unsigned NOT NULL default '0', + FK_firma_id int(10) unsigned NOT NULL default '0', + aktuell enum('Ja','Nein') NOT NULL default 'Ja', + vorname varchar(128) NOT NULL default '', + nachname varchar(128) NOT NULL default '', + geloescht enum('Ja','Nein') NOT NULL default 'Nein', + firma varchar(128) NOT NULL default '' +); + +INSERT INTO t1 VALUES + (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), + (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); + + +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 + WHERE + ( + ( + ( '' != '' AND firma LIKE CONCAT('%', '', '%')) + OR + (vorname LIKE CONCAT('%', 'Vorname1', '%') AND + nachname LIKE CONCAT('%', '1Nachname', '%') AND + 'Vorname1' != '' AND 'xxxx' != '') + ) + AND + ( + aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 + ) + ) + ; + +SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, +geloescht FROM t1 + WHERE + ( + ( + aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 + ) + AND + ( + ( '' != '' AND firma LIKE CONCAT('%', '', '%') ) + OR + ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND +nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND +'xxxx' != '') + ) + ) + ; + +SELECT COUNT(*) FROM t1 WHERE +( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) +AND FK_firma_id = 2; + +drop table t1; # # Test for Bug#8009, SELECT failed on bigint unsigned when using HEX @@ -2007,6 +2064,65 @@ CREATE TABLE t1 (b BIGINT(20) UNSIGNED NOT NULL, PRIMARY KEY (b)); INSERT INTO t1 VALUES (0x8000000000000000); SELECT b FROM t1 WHERE b=0x8000000000000000; DROP TABLE t1; + +# +# IN with outer join condition (BUG#9393) +# +CREATE TABLE `t1` ( `gid` int(11) default NULL, `uid` int(11) default NULL); + +CREATE TABLE `t2` ( `ident` int(11) default NULL, `level` char(16) default NULL); +INSERT INTO `t2` VALUES (0,'READ'); + +CREATE TABLE `t3` ( `id` int(11) default NULL, `name` char(16) default NULL); +INSERT INTO `t3` VALUES (1,'fs'); + +select * from t3 left join t1 on t3.id = t1.uid, t2 where t2.ident in (0, t1.gid, t3.id, 0); + +drop table t1,t2,t3; + +# +# Test case for bug 7098: substitution of a constant for a string field +# + +CREATE TABLE t1 ( city char(30) ); +INSERT INTO t1 VALUES ('London'); +INSERT INTO t1 VALUES ('Paris'); + +SELECT * FROM t1 WHERE city='London'; +SELECT * FROM t1 WHERE city='london'; +EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; +SELECT * FROM t1 WHERE city='London' AND city='london'; +EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; +SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; + +DROP TABLE t1; + +# +# Bug#7425 inconsistent sort order on unsigned columns result of substraction +# + +create table t1 (a int(11) unsigned, b int(11) unsigned); +insert into t1 values (1,0), (1,1), (1,2); +select a-b from t1 order by 1; +select a-b , (a-b < 0) from t1 order by 1; +select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; +select cast((a - b) as unsigned) from t1 order by 1; +drop table t1; + + +# +# Bug#8733 server accepts malformed query (multiply mentioned distinct) +# +create table t1 (a int(11)); +select all all * from t1; +select distinct distinct * from t1; +--error 1221 +select all distinct * from t1; +--error 1221 +select distinct all * from t1; +drop table t1; + +# # Test for bug #6474 # @@ -2154,108 +2270,6 @@ EXPLAIN SELECT * FROM t1 LEFT JOIN t2 FORCE INDEX (a) ON t1.a=t2.a; DROP TABLE t1, t2; # -# Test case for bug 7098: substitution of a constant for a string field -# - -CREATE TABLE t1 ( city char(30) ); -INSERT INTO t1 VALUES ('London'); -INSERT INTO t1 VALUES ('Paris'); - -SELECT * FROM t1 WHERE city='London'; -SELECT * FROM t1 WHERE city='london'; -EXPLAIN SELECT * FROM t1 WHERE city='London' AND city='london'; -SELECT * FROM t1 WHERE city='London' AND city='london'; -EXPLAIN SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; -SELECT * FROM t1 WHERE city LIKE '%london%' AND city='London'; - -DROP TABLE t1; - -# -# Bug#7425 inconsistent sort order on unsigned columns result of substraction -# - -create table t1 (a int(11) unsigned, b int(11) unsigned); -insert into t1 values (1,0), (1,1), (1,2); -select a-b from t1 order by 1; -select a-b , (a-b < 0) from t1 order by 1; -select a-b as d, (a-b >= 0), b from t1 group by b having d >= 0; -select cast((a - b) as unsigned) from t1 order by 1; -drop table t1; - - -# -# Bug#8733 server accepts malformed query (multiply mentioned distinct) -# -create table t1 (a int(11)); -select all all * from t1; -select distinct distinct * from t1; ---error 1221 -select all distinct * from t1; ---error 1221 -select distinct all * from t1; -drop table t1; - -# -# Test for BUG#10095 -# -CREATE TABLE t1 ( - kunde_intern_id int(10) unsigned NOT NULL default '0', - kunde_id int(10) unsigned NOT NULL default '0', - FK_firma_id int(10) unsigned NOT NULL default '0', - aktuell enum('Ja','Nein') NOT NULL default 'Ja', - vorname varchar(128) NOT NULL default '', - nachname varchar(128) NOT NULL default '', - geloescht enum('Ja','Nein') NOT NULL default 'Nein', - firma varchar(128) NOT NULL default '' -); - -INSERT INTO t1 VALUES - (3964,3051,1,'Ja','Vorname1','1Nachname','Nein','Print Schau XXXX'), - (3965,3051111,1,'Ja','Vorname1111','1111Nachname','Nein','Print Schau XXXX'); - - -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, geloescht FROM t1 - WHERE - ( - ( - ( '' != '' AND firma LIKE CONCAT('%', '', '%')) - OR - (vorname LIKE CONCAT('%', 'Vorname1', '%') AND - nachname LIKE CONCAT('%', '1Nachname', '%') AND - 'Vorname1' != '' AND 'xxxx' != '') - ) - AND - ( - aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 - ) - ) - ; - -SELECT kunde_id ,FK_firma_id ,aktuell, vorname, nachname, -geloescht FROM t1 - WHERE - ( - ( - aktuell = 'Ja' AND geloescht = 'Nein' AND FK_firma_id = 2 - ) - AND - ( - ( '' != '' AND firma LIKE CONCAT('%', '', '%') ) - OR - ( vorname LIKE CONCAT('%', 'Vorname1', '%') AND -nachname LIKE CONCAT('%', '1Nachname', '%') AND 'Vorname1' != '' AND -'xxxx' != '') - ) - ) - ; - -SELECT COUNT(*) FROM t1 WHERE -( 0 OR (vorname LIKE '%Vorname1%' AND nachname LIKE '%1Nachname%' AND 1)) -AND FK_firma_id = 2; - -drop table t1; - -# # Test for bug #10084: STRAIGHT_JOIN with ON expression # diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index faf6d8b4de3..f5a9e53e710 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -84,7 +84,7 @@ show create procedure foo| --error 1305 show create function foo| -# LEAVE/ITERATE/GOTO with no match +# LEAVE/ITERATE with no match --error 1308 create procedure foo() foo: loop @@ -100,47 +100,6 @@ create procedure foo() foo: begin iterate foo; end| ---error 1308 -create procedure foo() -begin - goto foo; -end| ---error 1308 -create procedure foo() -begin - begin - label foo; - end; - goto foo; -end| ---error 1308 -create procedure foo() -begin - goto foo; - begin - label foo; - end; -end| ---error 1308 -create procedure foo() -begin - begin - goto foo; - end; - begin - label foo; - end; -end| ---error 1308 -create procedure foo() -begin - begin - label foo; - end; - begin - goto foo; - end; -end| # Redefining label --error 1309 @@ -398,18 +357,6 @@ begin declare c cursor for select * from t1; end| ---error 1358 -create procedure p() -begin - declare continue handler for sqlexception - begin - goto L1; - end; - - select field from t1; - label L1; -end| - # Check in and inout arguments. --disable_warnings drop procedure if exists p| diff --git a/mysql-test/t/sp-goto.test b/mysql-test/t/sp-goto.test new file mode 100644 index 00000000000..e770dd285ff --- /dev/null +++ b/mysql-test/t/sp-goto.test @@ -0,0 +1,238 @@ +# +# The non-standard GOTO, for compatibility +# +# QQQ The "label" syntax is temporary, it will (hopefully) +# change to the more common "L:" syntax soon. +# For the time being, this feature is disabled, until +# the syntax (and some other known bugs) can be fixed. +# +# Test cases for bugs are added at the end. See template there. +# + +--disable_warnings +drop table if exists t1; +--enable_warnings +create table t1 ( + id char(16) not null default '', + data int not null +); + +delimiter //; + +--disable_warnings +drop procedure if exists goto1// +--enable_warnings +create procedure goto1() +begin + declare y int; + +label a; + select * from t1; + select count(*) into y from t1; + if y > 2 then + goto b; + end if; + insert into t1 values ("j", y); + goto a; +label b; +end// + +call goto1()// +drop procedure goto1// + +# With dummy handlers, just to test restore of contexts with jumps +--disable_warnings +drop procedure if exists goto2// +--enable_warnings +create procedure goto2(a int) +begin + declare x int default 0; + declare continue handler for sqlstate '42S98' set x = 1; + +label a; + select * from t1; +b: + while x < 2 do + begin + declare continue handler for sqlstate '42S99' set x = 2; + + if a = 0 then + set x = x + 1; + iterate b; + elseif a = 1 then + leave b; + elseif a = 2 then + set a = 1; + goto a; + end if; + end; + end while b; + + select * from t1; +end// + +call goto2(0)// +call goto2(1)// +call goto2(2)// + +drop procedure goto2// +delete from t1// + +# Check label visibility for some more cases. We don't call these. +--disable_warnings +drop procedure if exists goto3// +--enable_warnings +create procedure goto3() +begin + label L1; + begin + end; + goto L1; +end// +drop procedure goto3// + +--disable_warnings +drop procedure if exists goto4// +--enable_warnings +create procedure goto4() +begin + begin + label lab1; + begin + goto lab1; + end; + end; +end// +drop procedure goto4// + +--disable_warnings +drop procedure if exists goto5// +--enable_warnings +create procedure goto5() +begin + begin + begin + goto lab1; + end; + label lab1; + end; +end// +drop procedure goto5// + +--disable_warnings +drop procedure if exists goto6// +--enable_warnings +create procedure goto6() +begin + label L1; + goto L5; + begin + label L2; + goto L1; + goto L5; + begin + label L3; + goto L1; + goto L2; + goto L3; + goto L4; + goto L5; + end; + goto L2; + goto L4; + label L4; + end; + label L5; + goto L1; +end// +drop procedure goto6// + +# Mismatching labels +--error 1308 +create procedure foo() +begin + goto foo; +end// +--error 1308 +create procedure foo() +begin + begin + label foo; + end; + goto foo; +end// +--error 1308 +create procedure foo() +begin + goto foo; + begin + label foo; + end; +end// +--error 1308 +create procedure foo() +begin + begin + goto foo; + end; + begin + label foo; + end; +end// +--error 1308 +create procedure foo() +begin + begin + label foo; + end; + begin + goto foo; + end; +end// + +# No goto in a handler +--error 1358 +create procedure p() +begin + declare continue handler for sqlexception + begin + goto L1; + end; + + select field from t1; + label L1; +end// + + +# +# Test cases for old bugs +# + +# +# BUG#6898: Stored procedure crash if GOTO statements exist +# +--disable_warnings +drop procedure if exists bug6898// +--enable_warnings +create procedure bug6898() +begin + goto label1; + label label1; + begin end; + goto label1; +end// +drop procedure bug6898// + +# +# BUG#NNNN: New bug synopsis +# +#--disable_warnings +#drop procedure if exists bugNNNN// +#--enable_warnings +#create procedure bugNNNN... + + +# Add bugs above this line. Use existing tables t1 and t2 when +# practical, or create table t3, t4 etc temporarily (and drop them). +delimiter ;// +drop table t1; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index e7ee4b134ba..7455bc139dc 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -12,6 +12,7 @@ # Tests that check privilege and security issues go to sp-security.test. # Tests that require multiple connections, except security/privilege tests, # go to sp-thread. +# Tests that uses 'goto' to into sp-goto.test (currently disabled) use test; @@ -585,139 +586,6 @@ delete from t1| drop procedure i| -# The non-standard GOTO, for compatibility -# -# QQQ The "label" syntax is temporary, it will (hopefully) -# change to the more common "L:" syntax soon. -# ---disable_warnings -drop procedure if exists goto1| ---enable_warnings -create procedure goto1() -begin - declare y int; - -label a; - select * from t1; - select count(*) into y from t1; - if y > 2 then - goto b; - end if; - insert into t1 values ("j", y); - goto a; -label b; -end| - -call goto1()| -drop procedure goto1| - -# With dummy handlers, just to test restore of contexts with jumps ---disable_warnings -drop procedure if exists goto2| ---enable_warnings -create procedure goto2(a int) -begin - declare x int default 0; - declare continue handler for sqlstate '42S98' set x = 1; - -label a; - select * from t1; -b: - while x < 2 do - begin - declare continue handler for sqlstate '42S99' set x = 2; - - if a = 0 then - set x = x + 1; - iterate b; - elseif a = 1 then - leave b; - elseif a = 2 then - set a = 1; - goto a; - end if; - end; - end while b; - - select * from t1; -end| - -call goto2(0)| -call goto2(1)| -call goto2(2)| - -drop procedure goto2| -delete from t1| - -# Check label visibility for some more cases. We don't call these. ---disable_warnings -drop procedure if exists goto3| ---enable_warnings -create procedure goto3() -begin - label L1; - begin - end; - goto L1; -end| -drop procedure goto3| - ---disable_warnings -drop procedure if exists goto4| ---enable_warnings -create procedure goto4() -begin - begin - label lab1; - begin - goto lab1; - end; - end; -end| -drop procedure goto4| - ---disable_warnings -drop procedure if exists goto5| ---enable_warnings -create procedure goto5() -begin - begin - begin - goto lab1; - end; - label lab1; - end; -end| -drop procedure goto5| - ---disable_warnings -drop procedure if exists goto6| ---enable_warnings -create procedure goto6() -begin - label L1; - goto L5; - begin - label L2; - goto L1; - goto L5; - begin - label L3; - goto L1; - goto L2; - goto L3; - goto L4; - goto L5; - end; - goto L2; - goto L4; - label L4; - end; - label L5; - goto L1; -end| -drop procedure goto6| - # SELECT with one of more result set sent back to the clinet insert into t1 values ("foo", 3), ("bar", 19)| insert into t2 values ("x", 9, 4.1), ("y", -1, 19.2), ("z", 3, 2.2)| @@ -3635,22 +3503,6 @@ drop function bug9902| # -# BUG#6898: Stored procedure crash if GOTO statements exist -# ---disable_warnings -drop procedure if exists bug6898| ---enable_warnings -create procedure bug6898() -begin - goto label1; - label label1; - begin end; - goto label1; -end| -drop procedure bug6898| - - -# # BUG#9102: Stored proccedures: function which returns blob causes crash # --disable_warnings @@ -3912,6 +3764,42 @@ drop procedure bug10136| drop table t3| # +# BUG#11529: crash server after use stored procedure +# +--disable_warnings +drop procedure if exists bug11529| +--enable_warnings +create procedure bug11529() +begin + declare c cursor for select id, data from t1 where data in (10,13); + + open c; + begin + declare vid char(16); + declare vdata int; + declare exit handler for not found begin end; + + while true do + fetch c into vid, vdata; + end while; + end; + close c; +end| + +insert into t1 values + ('Name1', 10), + ('Name2', 11), + ('Name3', 12), + ('Name4', 13), + ('Name5', 14)| + +call bug11529()| +call bug11529()| +delete from t1| +drop procedure bug11529| + + +# # BUG#NNNN: New bug synopsis # #--disable_warnings @@ -3921,7 +3809,7 @@ drop table t3| # Add bugs above this line. Use existing tables t1 and t2 when -# practical, or create table t3, t3 etc temporarily (and drop them). +# practical, or create table t3, t4 etc temporarily (and drop them). delimiter ;| drop table t1,t2; diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 0c5ef077159..05241772693 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -494,3 +494,17 @@ replace into t1 (i, k) values (2, 11); select * from t1; # Also drops all triggers drop table t1, t2; + +# Test for bug #5893 "Triggers with dropped functions cause crashes" +# Appropriate error should be reported instead of crash. +--disable_warnings +drop function if exists bug5893; +--enable_warnings +create table t1 (col1 int, col2 int); +insert into t1 values (1, 2); +create function bug5893 () returns int return 5; +create trigger t1_bu before update on t1 for each row set new.col1= bug5893(); +drop function bug5893; +--error 1305 +update t1 set col2 = 4; +drop table t1; diff --git a/mysql-test/t/type_bit.test b/mysql-test/t/type_bit.test index 2df5f0ed05d..fd5eb49858c 100644 --- a/mysql-test/t/type_bit.test +++ b/mysql-test/t/type_bit.test @@ -171,3 +171,56 @@ create table t1 (a bit(8)) engine=heap; insert into t1 values ('1111100000'); select a+0 from t1; drop table t1; + +# +# Bug #11091: union +# + +create table t1 (a bit(7)); +insert into t1 values (120), (0), (111); +select a+0 from t1 union select a+0 from t1; +select a+0 from t1 union select NULL; +select NULL union select a+0 from t1; +create table t2 select a from t1 union select a from t1; +select a+0 from t2; +show create table t2; +drop table t1, t2; + +# +# Bug #11572: view +# + +create table t1 (id1 int(11), b1 bit(1)); +create table t2 (id2 int(11), b2 bit(1)); +insert into t1 values (1, 1), (2, 0), (3, 1); +insert into t2 values (2, 1), (3, 0), (4, 0); +create algorithm=undefined view v1 as + select b1+0, b2+0 from t1, t2 where id1 = id2 and b1 = 0 + union + select b1+0, b2+0 from t1, t2 where id1 = id2 and b2 = 1; +select * from v1; +drop table t1, t2; +drop view v1; + +# +# Bug #10617: bulk-insert +# + +create table t1(a bit(4)); +insert into t1(a) values (1), (2), (5), (4), (3); +insert into t1 select * from t1; +select a+0 from t1; +drop table t1; + +# +# join +# + +create table t1 (a1 int(11), b1 bit(2)); +create table t2 (a2 int(11), b2 bit(2)); +insert into t1 values (1, 1), (2, 0), (3, 1), (4, 2); +insert into t2 values (2, 1), (3, 0), (4, 1), (5, 2); +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2; +select a1, a2, b1+0, b2+0 from t1 join t2 on a1 = a2 order by a1; +select a1, a2, b1+0, b2+0 from t1 join t2 on b1 = b2; +select sum(a1), b1+0, b2+0 from t1 join t2 on b1 = b2 group by b1 order by 1; diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index c33ea3f435d..80aabf6c5e0 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -394,4 +394,11 @@ INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,''); select max(i) from t1 where c = ''; drop table t1; - +# +# Bug#11657: Creation of secondary index fails +# +create table t1 (a int, b int, c tinyblob, d int, e int); +alter table t1 add primary key (a,b,c(255),d); +alter table t1 add key (a,b,d,e); +show create table t1; +drop table t1; diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 6199bd34fa9..5c4f288983b 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -964,3 +964,12 @@ insert into t1 values (0.00); select * from t1 where a > -0.00; select * from t1 where a = -0.00; drop table t1; + +# +# Bug #11215: a problem with LONGLONG_MIN +# + +create table t1 (col1 bigint default -9223372036854775808); +insert into t1 values (default); +select * from t1; +drop table t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index f8d833b6b73..c3ffdc79c16 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -373,9 +373,13 @@ drop table t1; # # Bug #6993: myisam_data_pointer_size +# Wrong bug report, data pointer size must be restricted to 7, +# setting to 8 will not work on all computers, myisamchk and +# the server may see a wrong value, such as 0 or negative number +# if 8 bytes is set. # -SET GLOBAL MYISAM_DATA_POINTER_SIZE= 8; +SET GLOBAL MYISAM_DATA_POINTER_SIZE= 7; SHOW VARIABLES LIKE 'MYISAM_DATA_POINTER_SIZE'; # diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 06b523b3610..78d992163fe 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1696,3 +1696,21 @@ drop view v1; CREATE VIEW v1 AS SELECT SUBSTRING_INDEX("dkjhgd:kjhdjh", ":", 1); SELECT * FROM v1; drop view v1; + +# +# Correct inserting data check (absence of default value) for view +# underlying tables (BUG#6443) +# +set sql_mode='strict_all_tables'; +CREATE TABLE t1 (col1 INT NOT NULL, col2 INT NOT NULL) ENGINE = INNODB; +CREATE VIEW v1 (vcol1) AS SELECT col1 FROM t1; +CREATE VIEW v2 (vcol1) AS SELECT col1 FROM t1 WHERE col2 > 2; +-- error 1364 +INSERT INTO t1 (col1) VALUES(12); +-- error 1423 +INSERT INTO v1 (vcol1) VALUES(12); +-- error 1423 +INSERT INTO v2 (vcol1) VALUES(12); +set sql_mode=default; +drop view v2,v1; +drop table t1; diff --git a/mysys/default.c b/mysys/default.c index cffd57c37f1..1fa8deaa65c 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -31,6 +31,7 @@ --defaults-file=full-path-to-default-file ; Only this file will be read. --defaults-extra-file=full-path-to-default-file ; Read this file before ~/ --print-defaults ; Print the modified command line and exit + --instance ; also read groups with concat(group, instance) ****************************************************************************/ #include "mysys_priv.h" @@ -41,6 +42,8 @@ #include <winbase.h> #endif +const char *defaults_instance=0; +static const char instance_option[] = "--instance="; char *defaults_extra_file=0; /* Which directories are searched for options (and in which order) */ @@ -115,7 +118,7 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, DBUG_ENTER("my_search_option_files"); /* Check if we want to force the use a specific default file */ - get_defaults_files(*argc, *argv, + get_defaults_files(*argc - *args_used, *argv + *args_used, (char **)&forced_default_file, (char **)&forced_extra_defaults); if (forced_default_file) @@ -325,6 +328,49 @@ int load_defaults(const char *conf_file, const char **groups, ctx.args= &args; ctx.group= &group; + if (*argc >= 2 + args_used && + is_prefix(argv[0][1+args_used], instance_option)) + { + args_used++; + defaults_instance= argv[0][args_used]+sizeof(instance_option)-1; + } + else + { + defaults_instance= getenv("MYSQL_INSTANCE"); + } + + if (defaults_instance) + { + /** Handle --instance= */ + uint i, len; + const char **extra_groups; + const uint instance_len= strlen(defaults_instance); + + if (!(extra_groups= + (const char**)alloc_root(&alloc, (2*group.count+1)*sizeof(char*)))) + goto err; + + for (i= 0; i<group.count; i++) + { + extra_groups[i]= group.type_names[i]; /** copy group */ + + len= strlen(extra_groups[i]); + if (!(ptr= alloc_root(&alloc, len+instance_len+1))) + goto err; + + extra_groups[i+group.count]= ptr; + + /** Construct new group */ + memcpy(ptr, extra_groups[i], len); + ptr+= len; + memcpy(ptr, defaults_instance, instance_len+1); + } + + group.count*= 2; + group.type_names= extra_groups; + group.type_names[group.count]= 0; + } + error= my_search_option_files(conf_file, argc, argv, &args_used, handle_default_option, (void *) &ctx); /* @@ -794,6 +840,7 @@ void my_print_default_files(const char *conf_file) void print_defaults(const char *conf_file, const char **groups) { + const char **groups_save= groups; my_print_default_files(conf_file); fputs("The following groups are read:",stdout); @@ -802,6 +849,17 @@ void print_defaults(const char *conf_file, const char **groups) fputc(' ',stdout); fputs(*groups,stdout); } + + if (defaults_instance) + { + groups= groups_save; + for ( ; *groups ; groups++) + { + fputc(' ',stdout); + fputs(*groups,stdout); + fputs(defaults_instance,stdout); + } + } puts("\nThe following options may be given as the first argument:\n\ --print-defaults Print the program argument list and exit\n\ --no-defaults Don't read default options from any options file\n\ diff --git a/mysys/default_modify.c b/mysys/default_modify.c index 00caa7beed6..ea384f9f27a 100644 --- a/mysys/default_modify.c +++ b/mysys/default_modify.c @@ -20,6 +20,8 @@ #include <my_dir.h> #define BUFF_SIZE 1024 +/* should be big enough to handle at least one line */ +#define RESERVE 1024 #ifdef __WIN__ #define NEWLINE "\r\n" @@ -66,8 +68,11 @@ int modify_defaults_file(const char *file_location, const char *option, FILE *cnf_file; MY_STAT file_stat; char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer; - uint opt_len, optval_len, sect_len, nr_newlines= 0; + uint opt_len, optval_len, sect_len, nr_newlines= 0, buffer_size; my_bool in_section= FALSE, opt_applied= 0; + uint reserve_extended= 1, old_opt_len= 0; + uint new_opt_len; + int reserve_occupied= 0; DBUG_ENTER("modify_defaults_file"); if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0)))) @@ -75,28 +80,33 @@ int modify_defaults_file(const char *file_location, const char *option, /* my_fstat doesn't use the flag parameter */ if (my_fstat(fileno(cnf_file), &file_stat, MYF(0))) - goto err; + goto malloc_err; opt_len= (uint) strlen(option); optval_len= (uint) strlen(option_value); + new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN; + + /* calculate the size of the buffer we need */ + buffer_size= sizeof(char) * (file_stat.st_size + + /* option name len */ + opt_len + + /* reserve for '=' char */ + 1 + + /* option value len */ + optval_len + + /* reserve space for newline */ + NEWLINE_LEN + + /* The ending zero */ + 1 + + /* reserve some additional space */ + RESERVE); + /* Reserve space to read the contents of the file and some more for the option we want to add. */ - if (!(file_buffer= (char*) my_malloc(sizeof(char) * - (file_stat.st_size + - /* option name len */ - opt_len + - /* reserve space for newline */ - NEWLINE_LEN + - /* reserve for '=' char */ - 1 + - /* option value len */ - optval_len + - /* The ending zero */ - 1), MYF(MY_WME)))) - + if (!(file_buffer= (char*) my_malloc(buffer_size, MYF(MY_WME)))) goto malloc_err; sect_len= (uint) strlen(section_name); @@ -115,13 +125,37 @@ int modify_defaults_file(const char *file_location, const char *option, } /* correct the option */ - if (!opt_applied && in_section && !strncmp(src_ptr, option, opt_len) && + if (in_section && !strncmp(src_ptr, option, opt_len) && (*(src_ptr + opt_len) == '=' || my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) || *(src_ptr + opt_len) == '\0')) { + /* + we should change all options. If opt_applied is set, we are running + into reserved memory area. Hence we should check for overruns. + */ + if (opt_applied) + { + src_ptr+= opt_len; /* If we correct an option, we know it's name */ + old_opt_len= opt_len; + + while (*src_ptr++) /* Find the end of the line */ + old_opt_len++; + + /* could be negative */ + reserve_occupied+= (int) new_opt_len - (int) old_opt_len; + if ((int) reserve_occupied > (int) (RESERVE*reserve_extended)) + { + if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size + + RESERVE*reserve_extended, + MYF(MY_WME|MY_FREE_ON_ERROR)))) + goto malloc_err; + reserve_extended++; + } + } + else + opt_applied= 1; dst_ptr= add_option(dst_ptr, option_value, option, remove_option); - opt_applied= 1; } else { diff --git a/mysys/my_access.c b/mysys/my_access.c index c01031827c0..256749ed447 100644 --- a/mysys/my_access.c +++ b/mysys/my_access.c @@ -98,17 +98,16 @@ int check_if_legal_filename(const char *path) for (reserved_name= reserved_names; *reserved_name; reserved_name++) { + const char *reserved= *reserved_name; /* never empty */ const char *name= path; - const char *current_reserved_name= *reserved_name; - while (name != end && *current_reserved_name) + do { - if (*current_reserved_name != my_toupper(&my_charset_latin1, *name)) + if (*reserved != my_toupper(&my_charset_latin1, *name)) break; - current_reserved_name++; if (++name == end) DBUG_RETURN(1); /* Found wrong path */ - } + } while (*++reserved); } DBUG_RETURN(0); } diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index c0eb6f15548..ba958b234d2 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -109,6 +109,51 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit) } +/* + test if bit already set and set it if it was not (thread unsafe method) + + SYNOPSIS + bitmap_fast_test_and_set() + MAP bit map struct + BIT bit number + + RETURN + 0 bit was not set + !=0 bit was set +*/ + +my_bool bitmap_fast_test_and_set(MY_BITMAP *map, uint bitmap_bit) +{ + uchar *byte= map->bitmap + (bitmap_bit / 8); + uchar bit= 1 << ((bitmap_bit) & 7); + uchar res= (*byte) & bit; + *byte|= bit; + return res; +} + + +/* + test if bit already set and set it if it was not (thread safe method) + + SYNOPSIS + bitmap_fast_test_and_set() + map bit map struct + bitmap_bit bit number + + RETURN + 0 bit was not set + !=0 bit was set +*/ + +my_bool bitmap_test_and_set(MY_BITMAP *map, uint bitmap_bit) +{ + my_bool res; + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); + bitmap_lock(map); + res= bitmap_fast_test_and_set(map, bitmap_bit); + bitmap_unlock(map); +} + uint bitmap_set_next(MY_BITMAP *map) { uchar *bitmap=map->bitmap; diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c index 002e5ca0f06..f07beec9f39 100644 --- a/mysys/my_fopen.c +++ b/mysys/my_fopen.c @@ -19,27 +19,36 @@ #include <errno.h> #include "mysys_err.h" -static void make_ftype(my_string to,int flag); +static void make_ftype(my_string to,int flag); - /* Open a file as stream */ +/* + Open a file as stream -FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) - /* Path-name of file */ - /* Read | write .. */ - /* Special flags */ + SYNOPSIS + my_fopen() + FileName Path-name of file + Flags Read | write | append | trunc (like for open()) + MyFlags Flags for handling errors + + RETURN + 0 Error + # File handler +*/ + +FILE *my_fopen(const char *filename, int flags, myf MyFlags) { FILE *fd; char type[5]; DBUG_ENTER("my_fopen"); - DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d", - FileName, Flags, MyFlags)); + DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d", + filename, flags, MyFlags)); /* if we are not creating, then we need to use my_access to make sure the file exists since Windows doesn't handle files like "com1.sym" very well */ #ifdef __WIN__ - if (check_if_legal_filename(FileName)) + if (check_if_legal_filename(filename)) { errno= EACCES; fd= 0; @@ -47,8 +56,8 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) else #endif { - make_ftype(type,Flags); - fd = fopen(FileName, type); + make_ftype(type,flags); + fd = fopen(filename, type); } if (fd != 0) @@ -65,7 +74,7 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) } pthread_mutex_lock(&THR_LOCK_open); if ((my_file_info[fileno(fd)].name = (char*) - my_strdup(FileName,MyFlags))) + my_strdup(filename,MyFlags))) { my_stream_opened++; my_file_info[fileno(fd)].type = STREAM_BY_FOPEN; @@ -81,9 +90,9 @@ FILE *my_fopen(const char *FileName, int Flags, myf MyFlags) my_errno=errno; DBUG_PRINT("error",("Got error %d on open",my_errno)); if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) - my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND : + my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND : EE_CANTCREATEFILE, - MYF(ME_BELL+ME_WAITTANG), FileName,my_errno); + MYF(ME_BELL+ME_WAITTANG), filename, my_errno); DBUG_RETURN((FILE*) 0); } /* my_fopen */ @@ -158,33 +167,39 @@ FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) DBUG_RETURN(fd); } /* my_fdopen */ + /* - make_ftype - Make a filehandler-open-typestring from ordinary inputflags + Make a fopen() typestring from a open() type bitmap + + SYNOPSIS + make_ftype() + to String for fopen() is stored here + flag Flag used by open() - Note: This routine attempts to find the best possible match - between a numeric option and a string option that could be - fed to fopen. There is not a 1 to 1 mapping between the two. + IMPLEMENTATION + This routine attempts to find the best possible match + between a numeric option and a string option that could be + fed to fopen. There is not a 1 to 1 mapping between the two. - r == O_RDONLY - w == O_WRONLY|O_TRUNC|O_CREAT - a == O_WRONLY|O_APPEND|O_CREAT - r+ == O_RDWR - w+ == O_RDWR|O_TRUNC|O_CREAT - a+ == O_RDWR|O_APPEND|O_CREAT + NOTE + On Unix, O_RDONLY is usually 0 + + MAPPING + r == O_RDONLY + w == O_WRONLY|O_TRUNC|O_CREAT + a == O_WRONLY|O_APPEND|O_CREAT + r+ == O_RDWR + w+ == O_RDWR|O_TRUNC|O_CREAT + a+ == O_RDWR|O_APPEND|O_CREAT */ + static void make_ftype(register my_string to, register int flag) { -#if FILE_BINARY - /* If we have binary-files */ - reg3 int org_flag=flag; -#endif - flag&= ~FILE_BINARY; /* remove binary bit */ - /* check some possible invalid combinations */ - DBUG_ASSERT(flag & (O_TRUNC|O_APPEND) != O_TRUNC|O_APPEND); + DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND)); + DBUG_ASSERT((flag & (O_WRONLY | O_RDWR)) != (O_WRONLY | O_RDWR)); - if (flag & (O_RDONLY|O_WRONLY) == O_WRONLY) + if ((flag & (O_RDONLY|O_WRONLY)) == O_WRONLY) *to++= (flag & O_APPEND) ? 'a' : 'w'; else if (flag & O_RDWR) { @@ -201,9 +216,8 @@ static void make_ftype(register my_string to, register int flag) *to++= 'r'; #if FILE_BINARY /* If we have binary-files */ - if (org_flag & FILE_BINARY) + if (flag & FILE_BINARY) *to++='b'; #endif *to='\0'; } /* make_ftype */ - diff --git a/ndb/include/kernel/AttributeList.hpp b/ndb/include/kernel/AttributeList.hpp index 7c6f71df3d2..70b178c6c79 100644 --- a/ndb/include/kernel/AttributeList.hpp +++ b/ndb/include/kernel/AttributeList.hpp @@ -17,6 +17,8 @@ #ifndef ATTRIBUTE_LIST_HPP #define ATTRIBUTE_LIST_HPP +#include "ndb_limits.h" + /** * Masks and lists used by index and trigger. Must be plain old Uint32 data. * XXX depends on other headers XXX move to some common file diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index a36cdc2b475..db2212075e8 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -1583,15 +1583,17 @@ private: void abortTransactionsAfterNodeFailure(Uint16 aNodeId); static - const char * externalizeTableName(const char * internalTableName, bool fullyQualifiedNames); + const char * externalizeTableName(const char * internalTableName, + bool fullyQualifiedNames); const char * externalizeTableName(const char * internalTableName); - const char * internalizeTableName(const char * externalTableName); + const BaseString internalize_table_name(const char * external_name) const; static - const char * externalizeIndexName(const char * internalIndexName, bool fullyQualifiedNames); + const char * externalizeIndexName(const char * internalIndexName, + bool fullyQualifiedNames); const char * externalizeIndexName(const char * internalIndexName); - const char * internalizeIndexName(const NdbTableImpl * table, - const char * externalIndexName); + const BaseString internalize_index_name(const NdbTableImpl * table, + const char * external_name) const; static const BaseString getDatabaseFromInternalName(const char * internalName); @@ -1614,7 +1616,7 @@ private: Uint32 theNoOfPreparedTransactions; Uint32 theNoOfSentTransactions; Uint32 theNoOfCompletedTransactions; - Uint32 theNoOfAllocatedTransactions; + Uint32 theRemainingStartTransactions; Uint32 theMaxNoOfTransactions; Uint32 theMinNoOfEventsToWakeUp; diff --git a/ndb/include/transporter/TransporterDefinitions.hpp b/ndb/include/transporter/TransporterDefinitions.hpp index 8fc407b6d9c..e9c5ffa2c80 100644 --- a/ndb/include/transporter/TransporterDefinitions.hpp +++ b/ndb/include/transporter/TransporterDefinitions.hpp @@ -45,9 +45,8 @@ enum SendStatus { * Protocol6 Header + * (optional signal id) + (optional checksum) + (signal data) */ -const Uint32 MAX_SECTION_SIZE= 4096; //const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)); -const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)+(3*4)+4*MAX_SECTION_SIZE); +const Uint32 MAX_MESSAGE_SIZE = (12+4+4+(4*25)+(3*4)+4*4096); /** * TransporterConfiguration diff --git a/ndb/include/util/SimpleProperties.hpp b/ndb/include/util/SimpleProperties.hpp index 356f3406f38..438426fb62b 100644 --- a/ndb/include/util/SimpleProperties.hpp +++ b/ndb/include/util/SimpleProperties.hpp @@ -172,6 +172,8 @@ public: virtual bool reset() = 0; virtual bool putWord(Uint32 val) = 0; virtual bool putWords(const Uint32 * src, Uint32 len) = 0; + private: + bool add(const char* value, int len); }; }; @@ -211,7 +213,7 @@ private: }; /** - * Writer for linear memory + * Writer for UtilBuffer */ class UtilBufferWriter : public SimpleProperties::Writer { public: diff --git a/ndb/src/common/transporter/SCI_Transporter.cpp b/ndb/src/common/transporter/SCI_Transporter.cpp index c96f84a4f4f..1fe276249e5 100644 --- a/ndb/src/common/transporter/SCI_Transporter.cpp +++ b/ndb/src/common/transporter/SCI_Transporter.cpp @@ -48,7 +48,7 @@ SCI_Transporter::SCI_Transporter(TransporterRegistry &t_reg, Uint32 reportFreq) : Transporter(t_reg, tt_SCI_TRANSPORTER, lHostName, rHostName, r_port, isMgmConnection, _localNodeId, - _remoteNodeId, serverNodeID, 0, false, chksm, signalId) + _remoteNodeId, serverNodeId, 0, false, chksm, signalId) { DBUG_ENTER("SCI_Transporter::SCI_Transporter"); m_PacketSize = (packetSize + 3)/4 ; diff --git a/ndb/src/common/util/SimpleProperties.cpp b/ndb/src/common/util/SimpleProperties.cpp index 00c440fcb4e..c25aaea491a 100644 --- a/ndb/src/common/util/SimpleProperties.cpp +++ b/ndb/src/common/util/SimpleProperties.cpp @@ -37,6 +37,28 @@ SimpleProperties::Writer::add(Uint16 key, Uint32 value){ } bool +SimpleProperties::Writer::add(const char * value, int len){ + const Uint32 valLen = (len + 3) / 4; + + if ((len % 4) == 0) + return putWords((Uint32*)value, valLen); + + const Uint32 putLen= valLen - 1; + if (!putWords((Uint32*)value, putLen)) + return false; + + // Special handling of last bytes + union { + Uint32 lastWord; + char lastBytes[4]; + }; + memcpy(lastBytes, + value + putLen*4, + len - putLen*4); + return putWord(lastWord); +} + +bool SimpleProperties::Writer::add(Uint16 key, const char * value){ Uint32 head = StringValue; head <<= 16; @@ -46,9 +68,9 @@ SimpleProperties::Writer::add(Uint16 key, const char * value){ Uint32 strLen = strlen(value) + 1; // Including NULL-byte if(!putWord(htonl(strLen))) return false; - - const Uint32 valLen = (strLen + 3) / 4; - return putWords((Uint32*)value, valLen); + + return add(value, (int)strLen); + } bool @@ -60,9 +82,8 @@ SimpleProperties::Writer::add(Uint16 key, const void* value, int len){ return false; if(!putWord(htonl(len))) return false; - - const Uint32 valLen = (len + 3) / 4; - return putWords((Uint32*)value, valLen); + + return add((const char*)value, len); } SimpleProperties::Reader::Reader(){ @@ -392,6 +413,7 @@ UtilBufferWriter::putWords(const Uint32 * src, Uint32 len){ return (m_buf.append(src, 4 * len) == 0); } + Uint32 UtilBufferWriter::getWordsUsed() const { return m_buf.length() / 4;} diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 03309f3ac67..2a661104347 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -6458,6 +6458,7 @@ void Dbdih::execDIADDTABREQ(Signal* signal) ndbrequire(noReplicas == cnoReplicas); // Only allowed if (ERROR_INSERTED(7173)) { + CLEAR_ERROR_INSERT_VALUE; addtabrefuseLab(signal, connectPtr, ZREPLERROR1); return; } diff --git a/ndb/src/ndbapi/DictCache.cpp b/ndb/src/ndbapi/DictCache.cpp index ccc45a04824..3d14df908a0 100644 --- a/ndb/src/ndbapi/DictCache.cpp +++ b/ndb/src/ndbapi/DictCache.cpp @@ -80,11 +80,14 @@ LocalDictCache::drop(const char * name){ * Global cache */ GlobalDictCache::GlobalDictCache(){ + DBUG_ENTER("GlobalDictCache::GlobalDictCache"); m_tableHash.createHashTable(); m_waitForTableCondition = NdbCondition_Create(); + DBUG_VOID_RETURN; } GlobalDictCache::~GlobalDictCache(){ + DBUG_ENTER("GlobalDictCache::~GlobalDictCache"); NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0); while(curr != 0){ Vector<TableVersion> * vers = curr->theData; @@ -94,20 +97,52 @@ GlobalDictCache::~GlobalDictCache(){ delete (* vers)[i].m_impl; } delete curr->theData; + curr->theData= NULL; curr = m_tableHash.getNext(curr); } - m_tableHash.releaseHashTable(); NdbCondition_Destroy(m_waitForTableCondition); + DBUG_VOID_RETURN; } -#include <NdbOut.hpp> +void GlobalDictCache::printCache() +{ + DBUG_ENTER("GlobalDictCache::printCache"); + NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0); + while(curr != 0){ + DBUG_PRINT("curr", ("len: %d, hash: %d, lk: %d, str: %s", + curr->len, curr->hash, curr->localkey1, curr->str)); + if (curr->theData){ + Vector<TableVersion> * vers = curr->theData; + const unsigned sz = vers->size(); + for(unsigned i = 0; i<sz ; i++){ + TableVersion tv= (*vers)[i]; + DBUG_PRINT(" ", ("vers[%d]: ver: %d, refCount: %d, status: %d", + sz, tv.m_version, tv.m_refCount, tv.m_status)); + if(tv.m_impl != 0) + { + DBUG_PRINT(" ", ("m_impl: internalname: %s", + tv.m_impl->m_internalName.c_str())); + } + } + } + else + { + DBUG_PRINT(" ", ("NULL")); + } + curr = m_tableHash.getNext(curr); + } + DBUG_VOID_RETURN; +} -NdbTableImpl * +NdbTableImpl * GlobalDictCache::get(const char * name) { + DBUG_ENTER("GlobalDictCache::get"); + DBUG_PRINT("enter", ("name: %s", name)); + const Uint32 len = strlen(name); - Vector<TableVersion> * versions = 0; + Vector<TableVersion> * versions = 0; versions = m_tableHash.getData(name, len); if(versions == 0){ versions = new Vector<TableVersion>(2); @@ -122,7 +157,7 @@ GlobalDictCache::get(const char * name) switch(ver->m_status){ case OK: ver->m_refCount++; - return ver->m_impl; + DBUG_RETURN(ver->m_impl); case DROPPED: retreive = true; // Break loop break; @@ -141,24 +176,28 @@ GlobalDictCache::get(const char * name) tmp.m_status = RETREIVING; tmp.m_refCount = 1; // The one retreiving it versions->push_back(tmp); - return 0; + DBUG_RETURN(0); } NdbTableImpl * GlobalDictCache::put(const char * name, NdbTableImpl * tab) { + DBUG_ENTER("GlobalDictCache::put"); + DBUG_PRINT("enter", ("name: %s, internal_name: %s", + name, tab ? tab->m_internalName.c_str() : "tab NULL")); + const Uint32 len = strlen(name); Vector<TableVersion> * vers = m_tableHash.getData(name, len); if(vers == 0){ // Should always tried to retreive it first - // and then there should be a record + // and thus there should be a record abort(); } const Uint32 sz = vers->size(); if(sz == 0){ // Should always tried to retreive it first - // and then there should be a record + // and thus there should be a record abort(); } @@ -171,7 +210,7 @@ GlobalDictCache::put(const char * name, NdbTableImpl * tab) } if(tab == 0){ - // No table found in db + DBUG_PRINT("info", ("No table found in db")); vers->erase(sz - 1); } else { ver.m_impl = tab; @@ -180,74 +219,84 @@ GlobalDictCache::put(const char * name, NdbTableImpl * tab) } NdbCondition_Broadcast(m_waitForTableCondition); - return tab; + DBUG_RETURN(tab); } void GlobalDictCache::drop(NdbTableImpl * tab) { + DBUG_ENTER("GlobalDictCache::drop"); + DBUG_PRINT("enter", ("internal_name: %s", tab->m_internalName.c_str())); + unsigned i; const Uint32 len = strlen(tab->m_internalName.c_str()); Vector<TableVersion> * vers = m_tableHash.getData(tab->m_internalName.c_str(), len); if(vers == 0){ // Should always tried to retreive it first - // and then there should be a record + // and thus there should be a record abort(); } const Uint32 sz = vers->size(); if(sz == 0){ // Should always tried to retreive it first - // and then there should be a record + // and thus there should be a record abort(); } - + for(i = 0; i < sz; i++){ TableVersion & ver = (* vers)[i]; if(ver.m_impl == tab){ - if(ver.m_refCount == 0 || ver.m_status == RETREIVING || + if(ver.m_refCount == 0 || ver.m_status == RETREIVING || ver.m_version != tab->m_version){ - ndbout_c("Dropping with refCount=%d status=%d impl=%p", - ver.m_refCount, ver.m_status, ver.m_impl); + DBUG_PRINT("info", ("Dropping with refCount=%d status=%d impl=%p", + ver.m_refCount, ver.m_status, ver.m_impl)); break; } - + DBUG_PRINT("info", ("Found table to drop, i: %d, name: %s", + i, ver.m_impl->m_internalName.c_str())); ver.m_refCount--; ver.m_status = DROPPED; if(ver.m_refCount == 0){ + DBUG_PRINT("info", ("refCount is zero, deleting m_impl")) delete ver.m_impl; vers->erase(i); } - return; + DBUG_VOID_RETURN; } } - + for(i = 0; i<sz; i++){ TableVersion & ver = (* vers)[i]; - ndbout_c("%d: version: %d refCount: %d status: %d impl: %p", - i, ver.m_version, ver.m_refCount, ver.m_status, ver.m_impl); + DBUG_PRINT("info", ("%d: version: %d refCount: %d status: %d impl: %p", + i, ver.m_version, ver.m_refCount, + ver.m_status, ver.m_impl)); } abort(); } void -GlobalDictCache::release(NdbTableImpl * tab){ +GlobalDictCache::release(NdbTableImpl * tab) +{ + DBUG_ENTER("GlobalDictCache::release"); + DBUG_PRINT("enter", ("internal_name: %s", tab->m_internalName.c_str())); + unsigned i; const Uint32 len = strlen(tab->m_internalName.c_str()); Vector<TableVersion> * vers = m_tableHash.getData(tab->m_internalName.c_str(), len); if(vers == 0){ // Should always tried to retreive it first - // and then there should be a record + // and thus there should be a record abort(); } const Uint32 sz = vers->size(); if(sz == 0){ // Should always tried to retreive it first - // and then there should be a record + // and thus there should be a record abort(); } @@ -256,20 +305,21 @@ GlobalDictCache::release(NdbTableImpl * tab){ if(ver.m_impl == tab){ if(ver.m_refCount == 0 || ver.m_status == RETREIVING || ver.m_version != tab->m_version){ - ndbout_c("Releasing with refCount=%d status=%d impl=%p", - ver.m_refCount, ver.m_status, ver.m_impl); + DBUG_PRINT("info", ("Releasing with refCount=%d status=%d impl=%p", + ver.m_refCount, ver.m_status, ver.m_impl)); break; } ver.m_refCount--; - return; + DBUG_VOID_RETURN; } } for(i = 0; i<sz; i++){ TableVersion & ver = (* vers)[i]; - ndbout_c("%d: version: %d refCount: %d status: %d impl: %p", - i, ver.m_version, ver.m_refCount, ver.m_status, ver.m_impl); + DBUG_PRINT("info", ("%d: version: %d refCount: %d status: %d impl: %p", + i, ver.m_version, ver.m_refCount, + ver.m_status, ver.m_impl)); } abort(); diff --git a/ndb/src/ndbapi/DictCache.hpp b/ndb/src/ndbapi/DictCache.hpp index ca31c345396..d9bf810a685 100644 --- a/ndb/src/ndbapi/DictCache.hpp +++ b/ndb/src/ndbapi/DictCache.hpp @@ -76,6 +76,8 @@ public: }; private: + void printCache(); + struct TableVersion { Uint32 m_version; Uint32 m_refCount; diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index c48e70f1d51..7893aaae15c 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -425,12 +425,20 @@ Ndb::startTransactionLocal(Uint32 aPriority, Uint32 nodeId) DBUG_ENTER("Ndb::startTransactionLocal"); DBUG_PRINT("enter", ("nodeid: %d", nodeId)); + if(unlikely(theRemainingStartTransactions == 0)) + { + theError.code = 4006; + DBUG_RETURN(0); + } + NdbTransaction* tConnection; Uint64 tFirstTransId = theFirstTransId; tConnection = doConnect(nodeId); if (tConnection == NULL) { DBUG_RETURN(NULL); }//if + + theRemainingStartTransactions--; NdbTransaction* tConNext = theTransactionList; tConnection->init(); theTransactionList = tConnection; // into a transaction list. @@ -481,6 +489,7 @@ Ndb::closeTransaction(NdbTransaction* aConnection) CHECK_STATUS_MACRO_VOID; tCon = theTransactionList; + theRemainingStartTransactions++; DBUG_PRINT("info",("close trans: 0x%x transid: 0x%llx", aConnection, aConnection->getTransactionId())); @@ -751,16 +760,14 @@ 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. ****************************************************************************/ -#define DEBUG_TRACE(msg) \ -// ndbout << __FILE__ << " line: " << __LINE__ << " msg: " << msg << endl - Uint64 Ndb::getAutoIncrementValue(const char* aTableName, Uint32 cacheSize) { DBUG_ENTER("getAutoIncrementValue"); - const char * internalTableName = internalizeTableName(aTableName); + BaseString internal_tabname(internalize_table_name(aTableName)); + Ndb_local_table_info *info= - theDictionary->get_local_table_info(internalTableName, false); + theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) DBUG_RETURN(~(Uint64)0); const NdbTableImpl *table= info->m_table_impl; @@ -812,7 +819,7 @@ Ndb::getTupleIdFromNdb(Uint32 aTableId, Uint32 cacheSize) Uint64 Ndb::readAutoIncrementValue(const char* aTableName) { - DBUG_ENTER("readtAutoIncrementValue"); + DBUG_ENTER("readAutoIncrementValue"); const NdbTableImpl* table = theDictionary->getTable(aTableName); if (table == 0) { theError= theDictionary->getNdbError(); @@ -826,7 +833,7 @@ Ndb::readAutoIncrementValue(const char* aTableName) Uint64 Ndb::readAutoIncrementValue(const NdbDictionary::Table * aTable) { - DBUG_ENTER("readtAutoIncrementValue"); + DBUG_ENTER("readAutoIncrementValue"); if (aTable == 0) DBUG_RETURN(~(Uint64)0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); @@ -848,62 +855,63 @@ Ndb::readTupleIdFromNdb(Uint32 aTableId) bool Ndb::setAutoIncrementValue(const char* aTableName, Uint64 val, bool increase) { - DEBUG_TRACE("setAutoIncrementValue " << val); - const char * internalTableName= internalizeTableName(aTableName); + DBUG_ENTER("setAutoIncrementValue"); + BaseString internal_tabname(internalize_table_name(aTableName)); + Ndb_local_table_info *info= - theDictionary->get_local_table_info(internalTableName, false); + theDictionary->get_local_table_info(internal_tabname, false); if (info == 0) { theError= theDictionary->getNdbError(); - return false; + DBUG_RETURN(false); } const NdbTableImpl* table= info->m_table_impl; - return setTupleIdInNdb(table->m_tableId, val, increase); + DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); } bool Ndb::setAutoIncrementValue(const NdbDictionary::Table * aTable, Uint64 val, bool increase) { - DEBUG_TRACE("setAutoIncrementValue " << val); + DBUG_ENTER("setAutoIncrementValue"); if (aTable == 0) - return ~(Uint64)0; + DBUG_RETURN(~(Uint64)0); const NdbTableImpl* table = & NdbTableImpl::getImpl(*aTable); - return setTupleIdInNdb(table->m_tableId, val, increase); + DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); } -bool +bool Ndb::setTupleIdInNdb(const char* aTableName, Uint64 val, bool increase ) { - DEBUG_TRACE("setTupleIdInNdb"); + DBUG_ENTER("setTupleIdInNdb(const char*, ...)"); const NdbTableImpl* table = theDictionary->getTable(aTableName); if (table == 0) { theError= theDictionary->getNdbError(); - return false; + DBUG_RETURN(false); } - return setTupleIdInNdb(table->m_tableId, val, increase); + DBUG_RETURN(setTupleIdInNdb(table->m_tableId, val, increase)); } bool Ndb::setTupleIdInNdb(Uint32 aTableId, Uint64 val, bool increase ) { - DEBUG_TRACE("setTupleIdInNdb"); + DBUG_ENTER("setTupleIdInNdb(Uint32, ...)"); if (increase) { if (theFirstTupleId[aTableId] != theLastTupleId[aTableId]) { // We have a cache sequence if (val <= theFirstTupleId[aTableId]+1) - return false; + DBUG_RETURN(false); if (val <= theLastTupleId[aTableId]) { theFirstTupleId[aTableId] = val - 1; - return true; + DBUG_RETURN(true); } // else continue; - } - return (opTupleIdOnNdb(aTableId, val, 2) == val); + } + DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 2) == val)); } else - return (opTupleIdOnNdb(aTableId, val, 1) == val); + DBUG_RETURN((opTupleIdOnNdb(aTableId, val, 1) == val)); } Uint64 @@ -1143,25 +1151,63 @@ Ndb::externalizeIndexName(const char * internalIndexName) return externalizeIndexName(internalIndexName, usingFullyQualifiedNames()); } -const char * -Ndb::internalizeTableName(const char * externalTableName) + +const BaseString +Ndb::internalize_table_name(const char *external_name) const { + BaseString ret; + DBUG_ENTER("internalize_table_name"); + DBUG_PRINT("enter", ("external_name: %s", external_name)); + if (fullyQualifiedNames) - return theImpl->internalize_table_name(externalTableName); + { + /* Internal table name format <db>/<schema>/<table> + <db>/<schema> is already available in m_prefix + so just concat the two strings + */ + ret.assfmt("%s%s", + theImpl->m_prefix.c_str(), + external_name); + } else - return externalTableName; + ret.assign(external_name); + + DBUG_PRINT("exit", ("internal_name: %s", ret.c_str())); + DBUG_RETURN(ret); } - -const char * -Ndb::internalizeIndexName(const NdbTableImpl * table, - const char * externalIndexName) + + +const BaseString +Ndb::internalize_index_name(const NdbTableImpl * table, + const char * external_name) const { + BaseString ret; + DBUG_ENTER("internalize_index_name"); + DBUG_PRINT("enter", ("external_name: %s, table_id: %d", + external_name, table ? table->m_tableId : ~0)); + if (!table) + { + DBUG_PRINT("error", ("!table")); + return ret; + } + if (fullyQualifiedNames) - return theImpl->internalize_index_name(table, externalIndexName); + { + /* Internal index name format <db>/<schema>/<tabid>/<table> */ + ret.assfmt("%s%d%c%s", + theImpl->m_prefix.c_str(), + table->m_tableId, + table_name_separator, + external_name); + } else - return externalIndexName; + ret.assign(external_name); + + DBUG_PRINT("exit", ("internal_name: %s", ret.c_str())); + DBUG_RETURN(ret); } + const BaseString Ndb::getDatabaseFromInternalName(const char * internalName) { diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index 0638f6e4c51..d06d6b4ef4d 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -24,34 +24,6 @@ #include "NdbBlobImpl.hpp" #include <NdbScanOperation.hpp> -#ifdef NDB_BLOB_DEBUG -#define DBG(x) \ - do { \ - static const char* p = getenv("NDB_BLOB_DEBUG"); \ - if (p == 0 || *p == 0 || *p == '0') break; \ - static char* prefix = "BLOB"; \ - const char* cname = theColumn == NULL ? "-" : theColumn->m_name.c_str(); \ - ndbout << prefix << " " << hex << (void*)this << " " << cname; \ - ndbout << " " << dec << __LINE__ << " " << x << " " << *this << endl; \ - } while (0) - -static char* -ndb_blob_debug(const Uint32* data, unsigned size) -{ - static char buf[200]; // MT irrelevant - buf[0] = 0; - for (unsigned i = 0; i < size; i++) { - unsigned n = strlen(buf); - if (n + 10 < sizeof(buf)) - sprintf(buf + n, "%*s%08x", i != 0, "", data[i]); - } - return buf; -} - -#else -#define DBG(x) -#endif - /* * Reading index table directly (as a table) is faster but there are * bugs or limitations. Keep the code and make possible to choose. @@ -63,8 +35,10 @@ static const bool g_ndb_blob_ok_to_read_index_table = false; inline void NdbBlob::setState(State newState) { - DBG("setState " << newState); + DBUG_ENTER("NdbBlob::setState"); + DBUG_PRINT("info", ("this=%p newState=%u", this, newState)); theState = newState; + DBUG_VOID_RETURN; } // define blob table @@ -319,9 +293,9 @@ NdbBlob::getDistKey(Uint32 part) int NdbBlob::getTableKeyValue(NdbOperation* anOp) { + DBUG_ENTER("NdbBlob::getTableKeyValue"); Uint32* data = (Uint32*)theKeyBuf.data; unsigned pos = 0; - DBG("getTableKeyValue"); for (unsigned i = 0; i < theTable->m_columns.size(); i++) { NdbColumnImpl* c = theTable->m_columns[i]; assert(c != NULL); @@ -329,7 +303,7 @@ NdbBlob::getTableKeyValue(NdbOperation* anOp) unsigned len = c->m_attrSize * c->m_arraySize; if (anOp->getValue_impl(c, (char*)&data[pos]) == NULL) { setErrorCode(anOp); - return -1; + DBUG_RETURN(-1); } // odd bytes receive no data and must be zeroed while (len % 4 != 0) { @@ -340,14 +314,15 @@ NdbBlob::getTableKeyValue(NdbOperation* anOp) } } assert(pos == theKeyBuf.size / 4); - return 0; + DBUG_RETURN(0); } int NdbBlob::setTableKeyValue(NdbOperation* anOp) { + DBUG_ENTER("NdbBlob::setTableKeyValue"); + DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords); const Uint32* data = (const Uint32*)theKeyBuf.data; - DBG("setTableKeyValue key=" << ndb_blob_debug(data, theTable->m_keyLenInWords)); const unsigned columns = theTable->m_columns.size(); unsigned pos = 0; for (unsigned i = 0; i < columns; i++) { @@ -357,20 +332,21 @@ NdbBlob::setTableKeyValue(NdbOperation* anOp) unsigned len = c->m_attrSize * c->m_arraySize; if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) { setErrorCode(anOp); - return -1; + DBUG_RETURN(-1); } pos += (len + 3) / 4; } } assert(pos == theKeyBuf.size / 4); - return 0; + DBUG_RETURN(0); } int NdbBlob::setAccessKeyValue(NdbOperation* anOp) { + DBUG_ENTER("NdbBlob::setAccessKeyValue"); + DBUG_DUMP("info", theAccessKeyBuf.data, 4 * theAccessTable->m_keyLenInWords); const Uint32* data = (const Uint32*)theAccessKeyBuf.data; - DBG("setAccessKeyValue key=" << ndb_blob_debug(data, theAccessTable->m_keyLenInWords)); const unsigned columns = theAccessTable->m_columns.size(); unsigned pos = 0; for (unsigned i = 0; i < columns; i++) { @@ -380,57 +356,60 @@ NdbBlob::setAccessKeyValue(NdbOperation* anOp) unsigned len = c->m_attrSize * c->m_arraySize; if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) { setErrorCode(anOp); - return -1; + DBUG_RETURN(-1); } pos += (len + 3) / 4; } } assert(pos == theAccessKeyBuf.size / 4); - return 0; + DBUG_RETURN(0); } int NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part) { + DBUG_ENTER("NdbBlob::setPartKeyValue"); + DBUG_PRINT("info", ("dist=%u part=%u key=", getDistKey(part), part)); + DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords); Uint32* data = (Uint32*)theKeyBuf.data; unsigned size = theTable->m_keyLenInWords; - DBG("setPartKeyValue dist=" << getDistKey(part) << " part=" << part << " key=" << ndb_blob_debug(data, size)); // TODO use attr ids after compatibility with 4.1.7 not needed if (anOp->equal("PK", theKeyBuf.data) == -1 || anOp->equal("DIST", getDistKey(part)) == -1 || anOp->equal("PART", part) == -1) { setErrorCode(anOp); - return -1; + DBUG_RETURN(-1); } - return 0; + DBUG_RETURN(0); } int NdbBlob::getHeadInlineValue(NdbOperation* anOp) { - DBG("getHeadInlineValue"); + DBUG_ENTER("NdbBlob::getHeadInlineValue"); theHeadInlineRecAttr = anOp->getValue_impl(theColumn, theHeadInlineBuf.data); if (theHeadInlineRecAttr == NULL) { setErrorCode(anOp); - return -1; + DBUG_RETURN(-1); } - return 0; + DBUG_RETURN(0); } void NdbBlob::getHeadFromRecAttr() { + DBUG_ENTER("NdbBlob::getHeadFromRecAttr"); assert(theHeadInlineRecAttr != NULL); theNullFlag = theHeadInlineRecAttr->isNULL(); assert(theNullFlag != -1); theLength = ! theNullFlag ? theHead->length : 0; - DBG("getHeadFromRecAttr [out]"); + DBUG_VOID_RETURN; } int NdbBlob::setHeadInlineValue(NdbOperation* anOp) { - DBG("setHeadInlineValue"); + DBUG_ENTER("NdbBlob::setHeadInlineValue"); theHead->length = theLength; if (theLength < theInlineSize) memset(theInlineData + theLength, 0, theInlineSize - theLength); @@ -438,10 +417,10 @@ NdbBlob::setHeadInlineValue(NdbOperation* anOp) const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data; if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) { setErrorCode(anOp); - return -1; + DBUG_RETURN(-1); } theHeadInlineUpdateFlag = false; - return 0; + DBUG_RETURN(0); } // getValue/setValue @@ -449,40 +428,42 @@ NdbBlob::setHeadInlineValue(NdbOperation* anOp) int NdbBlob::getValue(void* data, Uint32 bytes) { - DBG("getValue data=" << hex << data << " bytes=" << dec << bytes); + DBUG_ENTER("NdbBlob::getValue"); + DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes)); if (theGetFlag || theState != Prepared) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } if (! isReadOp() && ! isScanOp()) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } if (data == NULL && bytes != 0) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } theGetFlag = true; theGetBuf = static_cast<char*>(data); theGetSetBytes = bytes; - return 0; + DBUG_RETURN(0); } int NdbBlob::setValue(const void* data, Uint32 bytes) { - DBG("setValue data=" << hex << data << " bytes=" << dec << bytes); + DBUG_ENTER("NdbBlob::setValue"); + DBUG_PRINT("info", ("data=%p bytes=%u", data, bytes)); if (theSetFlag || theState != Prepared) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } if (! isInsertOp() && ! isUpdateOp() && ! isWriteOp()) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } if (data == NULL && bytes != 0) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } theSetFlag = true; theSetBuf = static_cast<const char*>(data); @@ -495,15 +476,15 @@ NdbBlob::setValue(const void* data, Uint32 bytes) n = theInlineSize; assert(thePos == 0); if (writeDataPrivate(theSetBuf, n) == -1) - return -1; + DBUG_RETURN(-1); } else { theNullFlag = true; theLength = 0; } if (setHeadInlineValue(theNdbOp) == -1) - return -1; + DBUG_RETURN(-1); } - return 0; + DBUG_RETURN(0); } // activation hook @@ -511,14 +492,15 @@ NdbBlob::setValue(const void* data, Uint32 bytes) int NdbBlob::setActiveHook(ActiveHook activeHook, void* arg) { - DBG("setActiveHook hook=" << hex << (void*)activeHook << " arg=" << hex << arg); + DBUG_ENTER("NdbBlob::setActiveHook"); + DBUG_PRINT("info", ("hook=%p arg=%p", (void*)activeHook, arg)); if (theState != Prepared) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } theActiveHook = activeHook; theActiveHookArg = arg; - return 0; + DBUG_RETURN(0); } // misc operations @@ -526,63 +508,64 @@ NdbBlob::setActiveHook(ActiveHook activeHook, void* arg) int NdbBlob::getNull(bool& isNull) { - DBG("getNull"); + DBUG_ENTER("NdbBlob::getNull"); if (theState == Prepared && theSetFlag) { isNull = (theSetBuf == NULL); - return 0; + DBUG_RETURN(0); } if (theNullFlag == -1) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } isNull = theNullFlag; - return 0; + DBUG_RETURN(0); } int NdbBlob::setNull() { - DBG("setNull"); + DBUG_ENTER("NdbBlob::setNull"); if (theNullFlag == -1) { if (theState == Prepared) { - return setValue(0, 0); + DBUG_RETURN(setValue(0, 0)); } setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } if (theNullFlag) - return 0; + DBUG_RETURN(0); if (deleteParts(0, getPartCount()) == -1) - return -1; + DBUG_RETURN(-1); theNullFlag = true; theLength = 0; theHeadInlineUpdateFlag = true; - return 0; + DBUG_RETURN(0); } int NdbBlob::getLength(Uint64& len) { - DBG("getLength"); + DBUG_ENTER("NdbBlob::getLength"); if (theState == Prepared && theSetFlag) { len = theGetSetBytes; - return 0; + DBUG_RETURN(0); } if (theNullFlag == -1) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } len = theLength; - return 0; + DBUG_RETURN(0); } int NdbBlob::truncate(Uint64 length) { - DBG("truncate [in] length=" << length); + DBUG_ENTER("NdbBlob::truncate"); + DBUG_PRINT("info", ("length=%llu", length)); if (theNullFlag == -1) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } if (theLength > length) { if (length > theInlineSize) { @@ -590,46 +573,46 @@ NdbBlob::truncate(Uint64 length) Uint32 part2 = getPartNumber(theLength - 1); assert(part2 >= part1); if (part2 > part1 && deleteParts(part1 + 1, part2 - part1) == -1) - return -1; + DBUG_RETURN(-1); } else { if (deleteParts(0, getPartCount()) == -1) - return -1; + DBUG_RETURN(-1); } theLength = length; theHeadInlineUpdateFlag = true; if (thePos > length) thePos = length; } - DBG("truncate [out]"); - return 0; + DBUG_RETURN(0); } int NdbBlob::getPos(Uint64& pos) { - DBG("getPos"); + DBUG_ENTER("NdbBlob::getPos"); if (theNullFlag == -1) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } pos = thePos; - return 0; + DBUG_RETURN(0); } int NdbBlob::setPos(Uint64 pos) { - DBG("setPos pos=" << pos); + DBUG_ENTER("NdbBlob::setPos"); + DBUG_PRINT("info", ("pos=%llu", pos)); if (theNullFlag == -1) { setErrorCode(NdbBlobImpl::ErrState); - return -1; + DBUG_RETURN(-1); } if (pos > theLength) { setErrorCode(NdbBlobImpl::ErrSeek); - return -1; + DBUG_RETURN(-1); } thePos = pos; - return 0; + DBUG_RETURN(0); } // read/write @@ -648,7 +631,8 @@ NdbBlob::readData(void* data, Uint32& bytes) int NdbBlob::readDataPrivate(char* buf, Uint32& bytes) { - DBG("readData [in] bytes=" << bytes); + DBUG_ENTER("NdbBlob::readDataPrivate"); + DBUG_PRINT("info", ("bytes=%u", bytes)); assert(thePos <= theLength); Uint64 pos = thePos; if (bytes > theLength - pos) @@ -668,20 +652,20 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes) } if (len > 0 && thePartSize == 0) { setErrorCode(NdbBlobImpl::ErrSeek); - return -1; + DBUG_RETURN(-1); } if (len > 0) { assert(pos >= theInlineSize); Uint32 off = (pos - theInlineSize) % thePartSize; // partial first block if (off != 0) { - DBG("partial first block pos=" << pos << " len=" << len); + DBUG_PRINT("info", ("partial first block pos=%llu len=%u", pos, len)); Uint32 part = (pos - theInlineSize) / thePartSize; if (readParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); // need result now if (executePendingBlobReads() == -1) - return -1; + DBUG_RETURN(-1); Uint32 n = thePartSize - off; if (n > len) n = len; @@ -698,7 +682,7 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes) Uint32 part = (pos - theInlineSize) / thePartSize; Uint32 count = len / thePartSize; if (readParts(buf, part, count) == -1) - return -1; + DBUG_RETURN(-1); Uint32 n = thePartSize * count; pos += n; buf += n; @@ -707,14 +691,14 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes) } if (len > 0) { // partial last block - DBG("partial last block pos=" << pos << " len=" << len); + DBUG_PRINT("info", ("partial last block pos=%llu len=%u", pos, len)); assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize); Uint32 part = (pos - theInlineSize) / thePartSize; if (readParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); // need result now if (executePendingBlobReads() == -1) - return -1; + DBUG_RETURN(-1); memcpy(buf, thePartBuf.data, len); Uint32 n = len; pos += n; @@ -724,8 +708,7 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes) assert(len == 0); thePos = pos; assert(thePos <= theLength); - DBG("readData [out]"); - return 0; + DBUG_RETURN(0); } int @@ -742,7 +725,8 @@ NdbBlob::writeData(const void* data, Uint32 bytes) int NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) { - DBG("writeData [in] bytes=" << bytes); + DBUG_ENTER("NdbBlob::writeDataPrivate"); + DBUG_PRINT("info", ("bytes=%u", bytes)); assert(thePos <= theLength); Uint64 pos = thePos; Uint32 len = bytes; @@ -766,23 +750,23 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) } if (len > 0 && thePartSize == 0) { setErrorCode(NdbBlobImpl::ErrSeek); - return -1; + DBUG_RETURN(-1); } if (len > 0) { assert(pos >= theInlineSize); Uint32 off = (pos - theInlineSize) % thePartSize; // partial first block if (off != 0) { - DBG("partial first block pos=" << pos << " len=" << len); + DBUG_PRINT("info", ("partial first block pos=%llu len=%u", pos, len)); // flush writes to guarantee correct read if (executePendingBlobWrites() == -1) - return -1; + DBUG_RETURN(-1); Uint32 part = (pos - theInlineSize) / thePartSize; if (readParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); // need result now if (executePendingBlobReads() == -1) - return -1; + DBUG_RETURN(-1); Uint32 n = thePartSize - off; if (n > len) { memset(thePartBuf.data + off + len, theFillChar, n - len); @@ -790,7 +774,7 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) } memcpy(thePartBuf.data + off, buf, n); if (updateParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); pos += n; buf += n; len -= n; @@ -805,10 +789,10 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) for (unsigned i = 0; i < count; i++) { if (part + i < getPartCount()) { if (updateParts(buf, part + i, 1) == -1) - return -1; + DBUG_RETURN(-1); } else { if (insertParts(buf, part + i, 1) == -1) - return -1; + DBUG_RETURN(-1); } Uint32 n = thePartSize; pos += n; @@ -819,30 +803,30 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) } if (len > 0) { // partial last block - DBG("partial last block pos=" << pos << " len=" << len); + DBUG_PRINT("info", ("partial last block pos=%llu len=%u", pos, len)); assert((pos - theInlineSize) % thePartSize == 0 && len < thePartSize); Uint32 part = (pos - theInlineSize) / thePartSize; if (theLength > pos + len) { // flush writes to guarantee correct read if (executePendingBlobWrites() == -1) - return -1; + DBUG_RETURN(-1); if (readParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); // need result now if (executePendingBlobReads() == -1) - return -1; + DBUG_RETURN(-1); memcpy(thePartBuf.data, buf, len); if (updateParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); } else { memcpy(thePartBuf.data, buf, len); memset(thePartBuf.data + len, theFillChar, thePartSize - len); if (part < getPartCount()) { if (updateParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); } else { if (insertParts(thePartBuf.data, part, 1) == -1) - return -1; + DBUG_RETURN(-1); } } Uint32 n = len; @@ -857,14 +841,14 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) } thePos = pos; assert(thePos <= theLength); - DBG("writeData [out]"); - return 0; + DBUG_RETURN(0); } int NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) { - DBG("readParts [in] part=" << part << " count=" << count); + DBUG_ENTER("NdbBlob::readParts"); + DBUG_PRINT("info", ("part=%u count=%u", part, count)); Uint32 n = 0; while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); @@ -873,7 +857,7 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) setPartKeyValue(tOp, part + n) == -1 || tOp->getValue((Uint32)3, buf) == NULL) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption = NdbTransaction::AbortOnError; buf += thePartSize; @@ -881,13 +865,14 @@ NdbBlob::readParts(char* buf, Uint32 part, Uint32 count) thePendingBlobOps |= (1 << NdbOperation::ReadRequest); theNdbCon->thePendingBlobOps |= (1 << NdbOperation::ReadRequest); } - return 0; + DBUG_RETURN(0); } int NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count) { - DBG("insertParts [in] part=" << part << " count=" << count); + DBUG_ENTER("NdbBlob::insertParts"); + DBUG_PRINT("info", ("part=%u count=%u", part, count)); Uint32 n = 0; while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); @@ -896,7 +881,7 @@ NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count) setPartKeyValue(tOp, part + n) == -1 || tOp->setValue((Uint32)3, buf) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption = NdbTransaction::AbortOnError; buf += thePartSize; @@ -904,13 +889,14 @@ NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count) thePendingBlobOps |= (1 << NdbOperation::InsertRequest); theNdbCon->thePendingBlobOps |= (1 << NdbOperation::InsertRequest); } - return 0; + DBUG_RETURN(0); } int NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count) { - DBG("updateParts [in] part=" << part << " count=" << count); + DBUG_ENTER("NdbBlob::updateParts"); + DBUG_PRINT("info", ("part=%u count=%u", part, count)); Uint32 n = 0; while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); @@ -919,7 +905,7 @@ NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count) setPartKeyValue(tOp, part + n) == -1 || tOp->setValue((Uint32)3, buf) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption = NdbTransaction::AbortOnError; buf += thePartSize; @@ -927,13 +913,14 @@ NdbBlob::updateParts(const char* buf, Uint32 part, Uint32 count) thePendingBlobOps |= (1 << NdbOperation::UpdateRequest); theNdbCon->thePendingBlobOps |= (1 << NdbOperation::UpdateRequest); } - return 0; + DBUG_RETURN(0); } int NdbBlob::deleteParts(Uint32 part, Uint32 count) { - DBG("deleteParts [in] part=" << part << " count=" << count); + DBUG_ENTER("NdbBlob::deleteParts"); + DBUG_PRINT("info", ("part=%u count=%u", part, count)); Uint32 n = 0; while (n < count) { NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable); @@ -941,14 +928,14 @@ NdbBlob::deleteParts(Uint32 part, Uint32 count) tOp->deleteTuple() == -1 || setPartKeyValue(tOp, part + n) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption = NdbTransaction::AbortOnError; n++; thePendingBlobOps |= (1 << NdbOperation::DeleteRequest); theNdbCon->thePendingBlobOps |= (1 << NdbOperation::DeleteRequest); } - return 0; + DBUG_RETURN(0); } /* @@ -958,7 +945,8 @@ NdbBlob::deleteParts(Uint32 part, Uint32 count) int NdbBlob::deletePartsUnknown(Uint32 part) { - DBG("deletePartsUnknown [in] part=" << part << " count=all"); + DBUG_ENTER("NdbBlob::deletePartsUnknown"); + DBUG_PRINT("info", ("part=%u count=all", part)); static const unsigned maxbat = 256; static const unsigned minbat = 1; unsigned bat = minbat; @@ -974,26 +962,25 @@ NdbBlob::deletePartsUnknown(Uint32 part) tOp->deleteTuple() == -1 || setPartKeyValue(tOp, part + count + n) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption= NdbTransaction::AO_IgnoreError; n++; } - DBG("deletePartsUnknown: executeNoBlobs [in] bat=" << bat); + DBUG_PRINT("info", ("bat=%u", bat)); if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1) - return -1; - DBG("deletePartsUnknown: executeNoBlobs [out]"); + DBUG_RETURN(-1); n = 0; while (n < bat) { NdbOperation* tOp = tOpList[n]; if (tOp->theError.code != 0) { if (tOp->theError.code != 626) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } // first non-existent part - DBG("deletePartsUnknown [out] count=" << count); - return 0; + DBUG_PRINT("info", ("count=%u", count)); + DBUG_RETURN(0); } n++; count++; @@ -1009,31 +996,29 @@ NdbBlob::deletePartsUnknown(Uint32 part) int NdbBlob::executePendingBlobReads() { + DBUG_ENTER("NdbBlob::executePendingBlobReads"); Uint8 flags = (1 << NdbOperation::ReadRequest); if (thePendingBlobOps & flags) { - DBG("executePendingBlobReads: executeNoBlobs [in]"); if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1) - return -1; - DBG("executePendingBlobReads: executeNoBlobs [out]"); + DBUG_RETURN(-1); thePendingBlobOps = 0; theNdbCon->thePendingBlobOps = 0; } - return 0; + DBUG_RETURN(0); } int NdbBlob::executePendingBlobWrites() { + DBUG_ENTER("NdbBlob::executePendingBlobWrites"); Uint8 flags = 0xFF & ~(1 << NdbOperation::ReadRequest); if (thePendingBlobOps & flags) { - DBG("executePendingBlobWrites: executeNoBlobs [in]"); if (theNdbCon->executeNoBlobs(NdbTransaction::NoCommit) == -1) - return -1; - DBG("executePendingBlobWrites: executeNoBlobs [out]"); + DBUG_RETURN(-1); thePendingBlobOps = 0; theNdbCon->thePendingBlobOps = 0; } - return 0; + DBUG_RETURN(0); } // callbacks @@ -1041,15 +1026,14 @@ NdbBlob::executePendingBlobWrites() int NdbBlob::invokeActiveHook() { - DBG("invokeActiveHook [in]"); + DBUG_ENTER("NdbBlob::invokeActiveHook"); assert(theState == Active && theActiveHook != NULL); int ret = (*theActiveHook)(this, theActiveHookArg); - DBG("invokeActiveHook [out] ret=" << ret); if (ret != 0) { // no error is set on blob level - return -1; + DBUG_RETURN(-1); } - return 0; + DBUG_RETURN(0); } // blob handle maintenance @@ -1062,6 +1046,8 @@ NdbBlob::invokeActiveHook() int NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl* aColumn) { + DBUG_ENTER("NdbBlob::atPrepare"); + DBUG_PRINT("info", ("this=%p op=%p con=%p", this, anOp, aCon)); assert(theState == Idle); // ndb api stuff theNdb = anOp->theNdb; @@ -1070,7 +1056,6 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl theTable = anOp->m_currentTable; theAccessTable = anOp->m_accessTable; theColumn = aColumn; - DBG("atPrepare [in]"); NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined; switch (theColumn->getType()) { case NdbDictionary::Column::Blob: @@ -1083,7 +1068,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl break; default: setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } // sizes theInlineSize = theColumn->getInlineSize(); @@ -1101,7 +1086,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl bc->getType() != partType || bc->getLength() != (int)thePartSize) { setErrorCode(NdbBlobImpl::ErrTable); - return -1; + DBUG_RETURN(-1); } theBlobTable = &NdbTableImpl::getImpl(*bt); } @@ -1122,7 +1107,7 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl unsigned size = theTable->m_keyLenInWords; if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } } if (isIndexOp()) { @@ -1131,13 +1116,13 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl unsigned size = theAccessTable->m_keyLenInWords; if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } } if (isReadOp()) { // add read of head+inline in this op if (getHeadInlineValue(theNdbOp) == -1) - return -1; + DBUG_RETURN(-1); } if (isInsertOp()) { // becomes NULL unless set before execute @@ -1155,16 +1140,15 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl if (isScanOp()) { // add read of head+inline in this op if (getHeadInlineValue(theNdbOp) == -1) - return -1; + DBUG_RETURN(-1); supportedOp = true; } if (! supportedOp) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } setState(Prepared); - DBG("atPrepare [out]"); - return 0; + DBUG_RETURN(0); } /* @@ -1177,9 +1161,10 @@ NdbBlob::atPrepare(NdbTransaction* aCon, NdbOperation* anOp, const NdbColumnImpl int NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) { - DBG("preExecute [in]"); + DBUG_ENTER("NdbBlob::preExecute"); + DBUG_PRINT("info", ("this=%p op=%p con=%p", this, theNdbOp, theNdbCon)); if (theState == Invalid) - return -1; + DBUG_RETURN(-1); assert(theState == Prepared); // handle different operation types assert(isKeyOp()); @@ -1197,7 +1182,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) Uint32 bytes = theGetSetBytes - theInlineSize; assert(thePos == theInlineSize); if (writeDataPrivate(buf, bytes) == -1) - return -1; + DBUG_RETURN(-1); if (theHeadInlineUpdateFlag) { // add an operation to update head+inline NdbOperation* tOp = theNdbCon->getNdbOperation(theTable); @@ -1206,9 +1191,9 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) setTableKeyValue(tOp) == -1 || setHeadInlineValue(tOp) == -1) { setErrorCode(NdbBlobImpl::ErrAbort); - return -1; + DBUG_RETURN(-1); } - DBG("add op to update head+inline"); + DBUG_PRINT("info", ("add op to update head+inline")); } } } @@ -1221,7 +1206,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) setTableKeyValue(tOp) == -1 || getHeadInlineValue(tOp) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } if (isWriteOp()) { tOp->m_abortOption = NdbTransaction::AO_IgnoreError; @@ -1229,7 +1214,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) theHeadInlineReadOp = tOp; // execute immediately batch = true; - DBG("add op before to read head+inline"); + DBUG_PRINT("info", ("add op before to read head+inline")); } } if (isIndexOp()) { @@ -1245,7 +1230,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) setAccessKeyValue(tOp) == -1 || tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } } else { NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp); @@ -1254,11 +1239,11 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) setAccessKeyValue(tOp) == -1 || getTableKeyValue(tOp) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } } } - DBG("added op before to read table key"); + DBUG_PRINT("info", ("added op before to read table key")); if (isUpdateOp() || isDeleteOp()) { // add op before this one to read head+inline via index NdbIndexOperation* tOp = theNdbCon->getNdbIndexOperation(theAccessTable->m_index, theTable, theNdbOp); @@ -1267,7 +1252,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) setAccessKeyValue(tOp) == -1 || getHeadInlineValue(tOp) == -1) { setErrorCode(tOp); - return -1; + DBUG_RETURN(-1); } if (isWriteOp()) { tOp->m_abortOption = NdbTransaction::AO_IgnoreError; @@ -1275,7 +1260,7 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) theHeadInlineReadOp = tOp; // execute immediately batch = true; - DBG("added index op before to read head+inline"); + DBUG_PRINT("info", ("added index op before to read head+inline")); } if (isWriteOp()) { // XXX until IgnoreError fixed for index op @@ -1293,10 +1278,10 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) n = theInlineSize; assert(thePos == 0); if (writeDataPrivate(theSetBuf, n) == -1) - return -1; + DBUG_RETURN(-1); } if (setHeadInlineValue(theNdbOp) == -1) - return -1; + DBUG_RETURN(-1); // the read op before us may overwrite theHeadInlineCopyBuf.copyfrom(theHeadInlineBuf); } @@ -1305,8 +1290,8 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) // need blob head for callback batch = true; } - DBG("preExecute [out] batch=" << batch); - return 0; + DBUG_PRINT("info", ("batch=%u", batch)); + DBUG_RETURN(0); } /* @@ -1318,13 +1303,14 @@ NdbBlob::preExecute(NdbTransaction::ExecType anExecType, bool& batch) int NdbBlob::postExecute(NdbTransaction::ExecType anExecType) { - DBG("postExecute [in] type=" << anExecType); + DBUG_ENTER("NdbBlob::postExecute"); + DBUG_PRINT("info", ("this=%p op=%p con=%p anExecType=%u", this, theNdbOp, theNdbCon, anExecType)); if (theState == Invalid) - return -1; + DBUG_RETURN(-1); if (theState == Active) { setState(anExecType == NdbTransaction::NoCommit ? Active : Closed); - DBG("postExecute [skip]"); - return 0; + DBUG_PRINT("info", ("skip active")); + DBUG_RETURN(0); } assert(theState == Prepared); setState(anExecType == NdbTransaction::NoCommit ? Active : Closed); @@ -1340,14 +1326,14 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) if (isReadOp()) { getHeadFromRecAttr(); if (setPos(0) == -1) - return -1; + DBUG_RETURN(-1); if (theGetFlag) { assert(theGetSetBytes == 0 || theGetBuf != 0); assert(theGetSetBytes <= theInlineSize || anExecType == NdbTransaction::NoCommit); Uint32 bytes = theGetSetBytes; if (readDataPrivate(theGetBuf, bytes) == -1) - return -1; + DBUG_RETURN(-1); } } if (isUpdateOp()) { @@ -1357,13 +1343,13 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) // setValue overwrites everything if (theSetBuf != NULL) { if (truncate(0) == -1) - return -1; + DBUG_RETURN(-1); assert(thePos == 0); if (writeDataPrivate(theSetBuf, theGetSetBytes) == -1) - return -1; + DBUG_RETURN(-1); } else { if (setNull() == -1) - return -1; + DBUG_RETURN(-1); } } } @@ -1374,9 +1360,9 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) Uint64 tLength = theLength; Uint64 tPos = thePos; getHeadFromRecAttr(); - DBG("tuple found"); + DBUG_PRINT("info", ("tuple found")); if (truncate(0) == -1) - return -1; + DBUG_RETURN(-1); // restore previous head+inline theHeadInlineBuf.copyfrom(theHeadInlineCopyBuf); theNullFlag = tNullFlag; @@ -1385,16 +1371,16 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) } else { if (theHeadInlineReadOp->theError.code != 626) { setErrorCode(theHeadInlineReadOp); - return -1; + DBUG_RETURN(-1); } - DBG("tuple not found"); + DBUG_PRINT("info", ("tuple not found")); /* * Read found no tuple but it is possible that a tuple was * created after the read by another transaction. Delete all * blob parts which may exist. */ if (deletePartsUnknown(0) == -1) - return -1; + DBUG_RETURN(-1); } if (theSetFlag && theGetSetBytes > theInlineSize) { assert(theSetBuf != NULL); @@ -1402,33 +1388,33 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) Uint32 bytes = theGetSetBytes - theInlineSize; assert(thePos == theInlineSize); if (writeDataPrivate(buf, bytes) == -1) - return -1; + DBUG_RETURN(-1); } } if (isWriteOp() && isIndexOp()) { // XXX until IgnoreError fixed for index op if (deletePartsUnknown(0) == -1) - return -1; + DBUG_RETURN(-1); if (theSetFlag && theGetSetBytes > theInlineSize) { assert(theSetBuf != NULL); const char* buf = theSetBuf + theInlineSize; Uint32 bytes = theGetSetBytes - theInlineSize; assert(thePos == theInlineSize); if (writeDataPrivate(buf, bytes) == -1) - return -1; + DBUG_RETURN(-1); } } if (isDeleteOp()) { assert(anExecType == NdbTransaction::NoCommit); getHeadFromRecAttr(); if (deleteParts(0, getPartCount()) == -1) - return -1; + DBUG_RETURN(-1); } setState(anExecType == NdbTransaction::NoCommit ? Active : Closed); // activation callback if (theActiveHook != NULL) { if (invokeActiveHook() == -1) - return -1; + DBUG_RETURN(-1); } if (anExecType == NdbTransaction::NoCommit && theHeadInlineUpdateFlag) { NdbOperation* tOp = theNdbCon->getNdbOperation(theTable); @@ -1437,13 +1423,12 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) setTableKeyValue(tOp) == -1 || setHeadInlineValue(tOp) == -1) { setErrorCode(NdbBlobImpl::ErrAbort); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption = NdbTransaction::AbortOnError; - DBG("added op to update head+inline"); + DBUG_PRINT("info", ("added op to update head+inline")); } - DBG("postExecute [out]"); - return 0; + DBUG_RETURN(0); } /* @@ -1453,9 +1438,10 @@ NdbBlob::postExecute(NdbTransaction::ExecType anExecType) int NdbBlob::preCommit() { - DBG("preCommit [in]"); + DBUG_ENTER("NdbBlob::preCommit"); + DBUG_PRINT("info", ("this=%p op=%p con=%p", this, theNdbOp, theNdbCon)); if (theState == Invalid) - return -1; + DBUG_RETURN(-1); assert(theState == Active); assert(isKeyOp()); if (isInsertOp() || isUpdateOp() || isWriteOp()) { @@ -1467,14 +1453,13 @@ NdbBlob::preCommit() setTableKeyValue(tOp) == -1 || setHeadInlineValue(tOp) == -1) { setErrorCode(NdbBlobImpl::ErrAbort); - return -1; + DBUG_RETURN(-1); } tOp->m_abortOption = NdbTransaction::AbortOnError; - DBG("added op to update head+inline"); + DBUG_PRINT("info", ("added op to update head+inline")); } } - DBG("preCommit [out]"); - return 0; + DBUG_RETURN(0); } /* @@ -1483,35 +1468,35 @@ NdbBlob::preCommit() int NdbBlob::atNextResult() { - DBG("atNextResult [in]"); + DBUG_ENTER("NdbBlob::atNextResult"); + DBUG_PRINT("info", ("this=%p op=%p con=%p", this, theNdbOp, theNdbCon)); if (theState == Invalid) - return -1; + DBUG_RETURN(-1); assert(isScanOp()); // get primary key { Uint32* data = (Uint32*)theKeyBuf.data; unsigned size = theTable->m_keyLenInWords; if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) { setErrorCode(NdbBlobImpl::ErrUsage); - return -1; + DBUG_RETURN(-1); } } getHeadFromRecAttr(); if (setPos(0) == -1) - return -1; + DBUG_RETURN(-1); if (theGetFlag) { assert(theGetSetBytes == 0 || theGetBuf != 0); Uint32 bytes = theGetSetBytes; if (readDataPrivate(theGetBuf, bytes) == -1) - return -1; + DBUG_RETURN(-1); } setState(Active); // activation callback if (theActiveHook != NULL) { if (invokeActiveHook() == -1) - return -1; + DBUG_RETURN(-1); } - DBG("atNextResult [out]"); - return 0; + DBUG_RETURN(0); } // misc @@ -1527,13 +1512,15 @@ NdbBlob::getColumn() void NdbBlob::setErrorCode(int anErrorCode, bool invalidFlag) { - DBG("setErrorCode code=" << anErrorCode); + DBUG_ENTER("NdbBlob::setErrorCode"); + DBUG_PRINT("info", ("this=%p code=%u", this, anErrorCode)); theError.code = anErrorCode; // conditionally copy error to operation level if (theNdbOp != NULL && theNdbOp->theError.code == 0) theNdbOp->setErrorCode(theError.code); if (invalidFlag) setState(Invalid); + DBUG_VOID_RETURN; } void diff --git a/ndb/src/ndbapi/NdbDictionary.cpp b/ndb/src/ndbapi/NdbDictionary.cpp index 4cc47543cec..79b6fb4c0e8 100644 --- a/ndb/src/ndbapi/NdbDictionary.cpp +++ b/ndb/src/ndbapi/NdbDictionary.cpp @@ -773,9 +773,11 @@ NdbDictionary::Dictionary::getTable(const char * name) const void NdbDictionary::Dictionary::invalidateTable(const char * name){ + DBUG_ENTER("NdbDictionaryImpl::invalidateTable"); NdbTableImpl * t = m_impl.getTable(name); if(t) m_impl.invalidateObject(* t); + DBUG_VOID_RETURN; } void @@ -811,11 +813,13 @@ NdbDictionary::Dictionary::getIndex(const char * indexName, void NdbDictionary::Dictionary::invalidateIndex(const char * indexName, const char * tableName){ + DBUG_ENTER("NdbDictionaryImpl::invalidateIndex"); NdbIndexImpl * i = m_impl.getIndex(indexName, tableName); if(i) { assert(i->m_table != 0); m_impl.invalidateObject(* i->m_table); } + DBUG_VOID_RETURN; } void diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 6ecaf54b888..34d1614d043 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -735,19 +735,19 @@ NdbDictionaryImpl::~NdbDictionaryImpl() } Ndb_local_table_info * -NdbDictionaryImpl::fetchGlobalTableImpl(const char * internalTableName) +NdbDictionaryImpl::fetchGlobalTableImpl(const BaseString& internalTableName) { NdbTableImpl *impl; m_globalHash->lock(); - impl = m_globalHash->get(internalTableName); + impl = m_globalHash->get(internalTableName.c_str()); m_globalHash->unlock(); if (impl == 0){ impl = m_receiver.getTable(internalTableName, m_ndb.usingFullyQualifiedNames()); m_globalHash->lock(); - m_globalHash->put(internalTableName, impl); + m_globalHash->put(internalTableName.c_str(), impl); m_globalHash->unlock(); if(impl == 0){ @@ -758,7 +758,7 @@ NdbDictionaryImpl::fetchGlobalTableImpl(const char * internalTableName) Ndb_local_table_info *info= Ndb_local_table_info::create(impl, m_local_table_data_size); - m_localHash.put(internalTableName, info); + m_localHash.put(internalTableName.c_str(), info); m_ndb.theFirstTupleId[impl->getTableId()] = ~0; m_ndb.theLastTupleId[impl->getTableId()] = ~0; @@ -806,14 +806,13 @@ NdbDictionaryImpl::setTransporter(class Ndb* ndb, return false; } -NdbTableImpl * -NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index, +NdbTableImpl * +NdbDictionaryImpl::getIndexTable(NdbIndexImpl * index, NdbTableImpl * table) { - const char * internalName = - m_ndb.internalizeIndexName(table, index->getName()); - - return getTable(m_ndb.externalizeTableName(internalName)); + const BaseString internalName( + m_ndb.internalize_index_name(table, index->getName())); + return getTable(m_ndb.externalizeTableName(internalName.c_str())); } #if 0 @@ -1055,7 +1054,7 @@ NdbDictInterface::dictSignal(NdbApiSignal* signal, } DBUG_RETURN(-1); } - +#if 0 /* Get dictionary information for a table using table id as reference @@ -1079,6 +1078,7 @@ NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames) return getTable(&tSignal, 0, 0, fullyQualifiedNames); } +#endif /* @@ -1090,36 +1090,31 @@ NdbDictInterface::getTable(int tableId, bool fullyQualifiedNames) */ NdbTableImpl * -NdbDictInterface::getTable(const char * name, bool fullyQualifiedNames) +NdbDictInterface::getTable(const BaseString& name, bool fullyQualifiedNames) { NdbApiSignal tSignal(m_reference); GetTabInfoReq* const req = CAST_PTR(GetTabInfoReq, tSignal.getDataPtrSend()); - const Uint32 str_len= strlen(name) + 1; // NULL terminated - const Uint32 str_len_words= (str_len + 3) / 4; // Size in words - - if (str_len > MAX_SECTION_SIZE) - { - m_error.code= 4307; - return 0; - } - - m_namebuf.clear(); - m_namebuf.grow(str_len_words*4); // Word size aligned number of bytes - m_namebuf.append(name, str_len); + const Uint32 namelen= name.length() + 1; // NULL terminated + const Uint32 namelen_words= (namelen + 3) >> 2; // Size in words req->senderRef= m_reference; req->senderData= 0; req->requestType= GetTabInfoReq::RequestByName | GetTabInfoReq::LongSignalConf; - req->tableNameLen= str_len; + req->tableNameLen= namelen; tSignal.theReceiversBlockNumber= DBDICT; tSignal.theVerId_signalNumber= GSN_GET_TABINFOREQ; tSignal.theLength= GetTabInfoReq::SignalLength; + // Copy name to m_buffer to get a word sized buffer + m_buffer.clear(); + m_buffer.grow(namelen_words*4); + m_buffer.append(name.c_str(), namelen); + LinearSectionPtr ptr[1]; - ptr[0].p= (Uint32*)m_namebuf.get_data(); - ptr[0].sz= str_len_words; + ptr[0].p= (Uint32*)m_buffer.get_data(); + ptr[0].sz= namelen_words; return getTable(&tSignal, ptr, 1, fullyQualifiedNames); } @@ -1463,7 +1458,7 @@ NdbDictionaryImpl::createTable(NdbTableImpl &t) return 0; // update table def from DICT Ndb_local_table_info *info= - get_local_table_info(t.m_internalName.c_str(),false); + get_local_table_info(t.m_internalName,false); if (info == NULL) { m_error.code= 709; return -1; @@ -1490,7 +1485,7 @@ NdbDictionaryImpl::createBlobTables(NdbTableImpl &t) return -1; // Save BLOB table handle Ndb_local_table_info *info= - get_local_table_info(bt.m_internalName.c_str(), false); + get_local_table_info(bt.m_internalName, false); if (info == 0) { return -1; } @@ -1534,12 +1529,11 @@ NdbDictInterface::createTable(Ndb & ndb, int NdbDictionaryImpl::alterTable(NdbTableImpl &impl) { - BaseString internalName = impl.m_internalName; + BaseString internalName(impl.m_internalName); const char * originalInternalName = internalName.c_str(); - BaseString externalName = impl.m_externalName; DBUG_ENTER("NdbDictionaryImpl::alterTable"); - if(!get_local_table_info(originalInternalName, false)){ + if(!get_local_table_info(internalName, false)){ m_error.code= 709; DBUG_RETURN(-1); } @@ -1594,14 +1588,14 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, //validate(); //aggregate(); - const char * internalName = - ndb.internalizeTableName(impl.m_externalName.c_str()); + const BaseString internalName( + ndb.internalize_table_name(impl.m_externalName.c_str())); impl.m_internalName.assign(internalName); UtilBufferWriter w(m_buffer); DictTabInfo::Table tmpTab; tmpTab.init(); - BaseString::snprintf(tmpTab.TableName, - sizeof(tmpTab.TableName), - internalName); + BaseString::snprintf(tmpTab.TableName, + sizeof(tmpTab.TableName), + internalName.c_str()); bool haveAutoIncrement = false; Uint64 autoIncrementValue = 0; @@ -1865,14 +1859,14 @@ NdbDictionaryImpl::dropTable(const char * name) // If table stored in cache is incompatible with the one in the kernel // we must clear the cache and try again if (ret == INCOMPATIBLE_VERSION) { - const char * internalTableName = m_ndb.internalizeTableName(name); + const BaseString internalTableName(m_ndb.internalize_table_name(name)); - DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName)); - m_localHash.drop(internalTableName); + DBUG_PRINT("info",("INCOMPATIBLE_VERSION internal_name: %s", internalTableName.c_str())); + m_localHash.drop(internalTableName.c_str()); m_globalHash->lock(); tab->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(tab); - m_globalHash->unlock(); + m_globalHash->unlock(); DBUG_RETURN(dropTable(name)); } @@ -2013,13 +2007,14 @@ int NdbDictionaryImpl::invalidateObject(NdbTableImpl & impl) { const char * internalTableName = impl.m_internalName.c_str(); - - m_localHash.drop(internalTableName); + DBUG_ENTER("NdbDictionaryImpl::invalidateObject"); + DBUG_PRINT("enter", ("internal_name: %s", internalTableName)); + m_localHash.drop(internalTableName); m_globalHash->lock(); impl.m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(&impl); m_globalHash->unlock(); - return 0; + DBUG_RETURN(0); } int @@ -2038,8 +2033,8 @@ NdbDictionaryImpl::removeCachedObject(NdbTableImpl & impl) * Get index info */ NdbIndexImpl* -NdbDictionaryImpl::getIndexImpl(const char * externalName, - const char * internalName) +NdbDictionaryImpl::getIndexImpl(const char * externalName, + const BaseString& internalName) { Ndb_local_table_info * info = get_local_table_info(internalName, false); @@ -2055,21 +2050,11 @@ NdbDictionaryImpl::getIndexImpl(const char * externalName, return 0; } - /* - * internalName may be pointer to m_ndb.theImpl->m_internalname.c_str() - * and may get deallocated in next call. - * - * Passing around pointers to volatile internal members may not be - * optimal. Suggest use BaseString instances passed by value. - */ - - BaseString save_me(internalName); NdbTableImpl* prim = getTable(tab->m_primaryTable.c_str()); if(prim == 0){ m_error.code = 4243; return 0; } - internalName = save_me.c_str(); /** * Create index impl @@ -2175,12 +2160,11 @@ NdbDictInterface::createIndex(Ndb & ndb, m_error.code = 4241; return -1; } - const char * internalName = - ndb.internalizeIndexName(&table, impl.getName()); - + const BaseString internalName( + ndb.internalize_index_name(&table, impl.getName())); impl.m_internalName.assign(internalName); - w.add(DictTabInfo::TableName, internalName); + w.add(DictTabInfo::TableName, internalName.c_str()); w.add(DictTabInfo::TableLoggedFlag, impl.m_logging); NdbApiSignal tSignal(m_reference); @@ -2286,20 +2270,20 @@ NdbDictionaryImpl::dropIndex(const char * indexName, // If index stored in cache is incompatible with the one in the kernel // we must clear the cache and try again if (ret == INCOMPATIBLE_VERSION) { - const char * internalIndexName = (tableName) + const BaseString internalIndexName((tableName) ? - m_ndb.internalizeIndexName(getTable(tableName), indexName) + m_ndb.internalize_index_name(getTable(tableName), indexName) : - m_ndb.internalizeTableName(indexName); // Index is also a table - - m_localHash.drop(internalIndexName); + m_ndb.internalize_table_name(indexName)); // Index is also a table + + m_localHash.drop(internalIndexName.c_str()); m_globalHash->lock(); idx->m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(idx->m_table); - m_globalHash->unlock(); + m_globalHash->unlock(); return dropIndex(indexName, tableName); } - + return ret; } @@ -2315,19 +2299,19 @@ NdbDictionaryImpl::dropIndex(NdbIndexImpl & impl, const char * tableName) return -1; } - const char * internalIndexName = (tableName) + const BaseString internalIndexName((tableName) ? - m_ndb.internalizeIndexName(getTable(tableName), indexName) + m_ndb.internalize_index_name(getTable(tableName), indexName) : - m_ndb.internalizeTableName(indexName); // Index is also a table + m_ndb.internalize_table_name(indexName)); // Index is also a table if(impl.m_status == NdbDictionary::Object::New){ return dropIndex(indexName, tableName); } - + int ret = m_receiver.dropIndex(impl, *timpl); if(ret == 0){ - m_localHash.drop(internalIndexName); + m_localHash.drop(internalIndexName.c_str()); m_globalHash->lock(); impl.m_table->m_status = NdbDictionary::Object::Invalid; m_globalHash->drop(impl.m_table); @@ -2532,8 +2516,12 @@ NdbDictInterface::createEvent(class Ndb & ndb, w.add(SimpleProperties::StringValue, evnt.m_externalName.c_str()); if (getFlag == 0) + { + const BaseString internal_tabname( + ndb.internalize_table_name(evnt.m_tableName.c_str())); w.add(SimpleProperties::StringValue, - ndb.internalizeTableName(evnt.m_tableName.c_str())); + internal_tabname.c_str()); + } LinearSectionPtr ptr[1]; ptr[0].p = (Uint32*)m_buffer.get_data(); diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.hpp b/ndb/src/ndbapi/NdbDictionaryImpl.hpp index 7e3e3b19294..754d0000718 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.hpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.hpp @@ -19,7 +19,6 @@ #include <ndb_types.h> #include <kernel_types.h> -#include <ndb_limits.h> #include <NdbError.hpp> #include <BaseString.hpp> #include <Vector.hpp> @@ -309,8 +308,8 @@ public: int listObjects(NdbDictionary::Dictionary::List& list, Uint32 requestData, bool fullyQualifiedNames); int listObjects(NdbApiSignal* signal); - NdbTableImpl * getTable(int tableId, bool fullyQualifiedNames); - NdbTableImpl * getTable(const char * name, bool fullyQualifiedNames); +/* NdbTableImpl * getTable(int tableId, bool fullyQualifiedNames); */ + NdbTableImpl * getTable(const BaseString& name, bool fullyQualifiedNames); NdbTableImpl * getTable(class NdbApiSignal * signal, LinearSectionPtr ptr[3], Uint32 noOfSections, bool fullyQualifiedNames); @@ -368,8 +367,6 @@ private: Uint32 m_fragmentId; UtilBuffer m_buffer; - // Buffer used when requesting a table by name - UtilBuffer m_namebuf; }; class NdbDictionaryImpl : public NdbDictionary::Dictionary { @@ -406,13 +403,12 @@ public: int listObjects(List& list, NdbDictionary::Object::Type type); int listIndexes(List& list, Uint32 indexId); - + NdbTableImpl * getTable(const char * tableName, void **data= 0); - Ndb_local_table_info * get_local_table_info(const char * internalName, - bool do_add_blob_tables); + Ndb_local_table_info* get_local_table_info( + const BaseString& internalTableName, bool do_add_blob_tables); NdbIndexImpl * getIndex(const char * indexName, const char * tableName); - NdbIndexImpl * getIndexImpl(const char * name, const char * internalName); NdbEventImpl * getEvent(const char * eventName); NdbEventImpl * getEventImpl(const char * internalName); @@ -430,7 +426,9 @@ public: NdbDictInterface m_receiver; Ndb & m_ndb; private: - Ndb_local_table_info * fetchGlobalTableImpl(const char * internalName); + NdbIndexImpl * getIndexImpl(const char * name, + const BaseString& internalName); + Ndb_local_table_info * fetchGlobalTableImpl(const BaseString& internalName); }; inline @@ -638,26 +636,27 @@ NdbDictionaryImpl::getImpl(const NdbDictionary::Dictionary & t){ */ inline -NdbTableImpl * -NdbDictionaryImpl::getTable(const char * tableName, void **data) +NdbTableImpl * +NdbDictionaryImpl::getTable(const char * table_name, void **data) { + const BaseString internal_tabname(m_ndb.internalize_table_name(table_name)); Ndb_local_table_info *info= - get_local_table_info(m_ndb.internalizeTableName(tableName), true); - if (info == 0) { + get_local_table_info(internal_tabname, true); + if (info == 0) return 0; - } - if (data) { + + if (data) *data= info->m_local_data; - } + return info->m_table_impl; } inline Ndb_local_table_info * -NdbDictionaryImpl::get_local_table_info(const char * internalTableName, +NdbDictionaryImpl::get_local_table_info(const BaseString& internalTableName, bool do_add_blob_tables) { - Ndb_local_table_info *info= m_localHash.get(internalTableName); + Ndb_local_table_info *info= m_localHash.get(internalTableName.c_str()); if (info == 0) { info= fetchGlobalTableImpl(internalTableName); if (info == 0) { @@ -672,34 +671,35 @@ NdbDictionaryImpl::get_local_table_info(const char * internalTableName, inline NdbIndexImpl * -NdbDictionaryImpl::getIndex(const char * indexName, - const char * tableName) +NdbDictionaryImpl::getIndex(const char * index_name, + const char * table_name) { - if (tableName || m_ndb.usingFullyQualifiedNames()) { - const char * internalIndexName = 0; - if (tableName) { - NdbTableImpl * t = getTable(tableName); - if (t != 0) - internalIndexName = m_ndb.internalizeIndexName(t, indexName); - } else { - internalIndexName = - m_ndb.internalizeTableName(indexName); // Index is also a table - } - if (internalIndexName) { - Ndb_local_table_info * info = get_local_table_info(internalIndexName, - false); - if (info) { - NdbTableImpl * tab = info->m_table_impl; + if (table_name || m_ndb.usingFullyQualifiedNames()) + { + const BaseString internal_indexname( + (table_name) + ? + m_ndb.internalize_index_name(getTable(table_name), index_name) + : + m_ndb.internalize_table_name(index_name)); // Index is also a table + + if (internal_indexname.length()) + { + Ndb_local_table_info * info= + get_local_table_info(internal_indexname, false); + if (info) + { + NdbTableImpl * tab= info->m_table_impl; if (tab->m_index == 0) - tab->m_index = getIndexImpl(indexName, internalIndexName); + tab->m_index= getIndexImpl(index_name, internal_indexname); if (tab->m_index != 0) - tab->m_index->m_table = tab; + tab->m_index->m_table= tab; return tab->m_index; } } } - m_error.code = 4243; + m_error.code= 4243; return 0; } diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp index f4ce76fee61..d73b8afe10c 100644 --- a/ndb/src/ndbapi/NdbImpl.hpp +++ b/ndb/src/ndbapi/NdbImpl.hpp @@ -65,7 +65,6 @@ public: BaseString m_schemaname; // Schema name BaseString m_prefix; // Buffer for preformatted internal name <db>/<schema>/ - BaseString m_internalname; void update_prefix() { @@ -73,23 +72,6 @@ public: m_schemaname.c_str(), table_name_separator); } - const char* internalize_table_name(const char* ext_name) - { - // Internal table name format <db>/<schema>/<table> - return m_internalname.assign(m_prefix).append(ext_name).c_str(); - } - - const char* internalize_index_name(const NdbTableImpl *table, - const char* ext_name) - { - // Internal index name format <db>/<schema>/<tabid>/<table> - return m_internalname.assign(m_prefix).appfmt("%d%c%s", - table->m_tableId, - table_name_separator, - ext_name).c_str(); - } - - }; #ifdef VM_TRACE diff --git a/ndb/src/ndbapi/NdbLinHash.hpp b/ndb/src/ndbapi/NdbLinHash.hpp index f245a261a04..05670534c95 100644 --- a/ndb/src/ndbapi/NdbLinHash.hpp +++ b/ndb/src/ndbapi/NdbLinHash.hpp @@ -192,7 +192,7 @@ template <class C> inline Int32 NdbLinHash<C>::insertKey( const char* str, Uint32 len, Uint32 lkey1, C* data ) -{ +{ const Uint32 hash = Hash(str, len); int dir, seg; getBucket(hash, &dir, &seg); @@ -219,8 +219,9 @@ NdbLinHash<C>::insertKey( const char* str, Uint32 len, Uint32 lkey1, C* data ) chain->localkey1 = lkey1; chain->next = 0; chain->theData = data; + len++; // Null terminated chain->str = new Uint32[((len + 3) >> 2)]; - memcpy( &chain->str[0], str, len ); + memcpy( &chain->str[0], str, len); if (oldChain != 0) oldChain->next = chain; else diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 6898639e059..e0a480e02f7 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -89,15 +89,18 @@ int NdbScanOperation::init(const NdbTableImpl* tab, NdbTransaction* myConnection) { m_transConnection = myConnection; - //NdbTransaction* aScanConnection = theNdb->startTransaction(myConnection); + //NdbConnection* aScanConnection = theNdb->startTransaction(myConnection); + theNdb->theRemainingStartTransactions++; // will be checked in hupp... NdbTransaction* aScanConnection = theNdb->hupp(myConnection); if (!aScanConnection){ + theNdb->theRemainingStartTransactions--; setErrorCodeAbort(theNdb->getNdbError().code); return -1; } // NOTE! The hupped trans becomes the owner of the operation if(NdbOperation::init(tab, aScanConnection) != 0){ + theNdb->theRemainingStartTransactions--; return -1; } @@ -675,6 +678,7 @@ void NdbScanOperation::close(bool forceSend, bool releaseOp) tCon->theScanningOp = 0; theNdb->closeTransaction(tCon); + theNdb->theRemainingStartTransactions--; DBUG_VOID_RETURN; } diff --git a/ndb/src/ndbapi/NdbTransaction.cpp b/ndb/src/ndbapi/NdbTransaction.cpp index d0d664c9a3c..675c9383c6e 100644 --- a/ndb/src/ndbapi/NdbTransaction.cpp +++ b/ndb/src/ndbapi/NdbTransaction.cpp @@ -25,7 +25,6 @@ #include "TransporterFacade.hpp" #include "API.hpp" #include "NdbBlob.hpp" -#include <ndb_limits.h> #include <signaldata/TcKeyConf.hpp> #include <signaldata/TcIndx.hpp> @@ -1287,10 +1286,9 @@ NdbTransaction::getNdbIndexOperation(const char* anIndexName, { // This unique index is defined from SQL level static const char* uniqueSuffix= "$unique"; - char uniqueIndexName[MAX_TAB_NAME_SIZE]; - - strxnmov(uniqueIndexName, MAX_TAB_NAME_SIZE, anIndexName, uniqueSuffix, NullS); - index = theNdb->theDictionary->getIndex(uniqueIndexName, + BaseString uniqueIndexName(anIndexName); + uniqueIndexName.append(uniqueSuffix); + index = theNdb->theDictionary->getIndex(uniqueIndexName.c_str(), aTableName); } else diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index c550701229c..fee6f0930ad 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -107,12 +107,10 @@ Ndb::init(int aMaxNoOfTransactions) goto error_handler; } - tMaxNoOfTransactions = aMaxNoOfTransactions * 3; - if (tMaxNoOfTransactions > 1024) { - tMaxNoOfTransactions = 1024; - }//if + + tMaxNoOfTransactions = aMaxNoOfTransactions; theMaxNoOfTransactions = tMaxNoOfTransactions; - + theRemainingStartTransactions= tMaxNoOfTransactions; thePreparedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions]; theSentTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions]; theCompletedTransactionsArray = new NdbTransaction* [tMaxNoOfTransactions]; diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index ccd0cf85c5e..bbc1474f45d 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -59,7 +59,7 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theNoOfPreparedTransactions= 0; theNoOfSentTransactions= 0; theNoOfCompletedTransactions= 0; - theNoOfAllocatedTransactions= 0; + theRemainingStartTransactions= 0; theMaxNoOfTransactions= 0; theMinNoOfEventsToWakeUp= 0; theConIdleList= NULL; diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index 6dfd76c160b..96d0f4d7de5 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -93,7 +93,6 @@ Ndb::createConIdleList(int aNrOfCon) } tNdbCon->Status(NdbTransaction::NotConnected); } - theNoOfAllocatedTransactions = aNrOfCon; return aNrOfCon; } @@ -193,14 +192,8 @@ Ndb::getNdbCon() { NdbTransaction* tNdbCon; if ( theConIdleList == NULL ) { - if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) { - tNdbCon = new NdbTransaction(this); - if (tNdbCon == NULL) { - return NULL; - }//if - theNoOfAllocatedTransactions++; - } else { - ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl; + tNdbCon = new NdbTransaction(this); + if (tNdbCon == NULL) { return NULL; }//if tNdbCon->next(NULL); diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp index 786e8eb1f2e..a88d7d21820 100644 --- a/ndb/test/ndbapi/testBlobs.cpp +++ b/ndb/test/ndbapi/testBlobs.cpp @@ -23,14 +23,13 @@ #include <NdbOut.hpp> #include <NdbTest.hpp> #include <NdbTick.h> -#include <ndb/src/ndbapi/NdbBlobImpl.hpp> struct Bcol { bool m_nullable; unsigned m_inline; unsigned m_partsize; unsigned m_stripe; - char m_btname[NdbBlobImpl::BlobTableNameSize]; + char m_btname[200]; Bcol(bool a, unsigned b, unsigned c, unsigned d) : m_nullable(a), m_inline(b), diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp index aca8b299b49..dd5846f0d62 100644 --- a/ndb/test/ndbapi/testDict.cpp +++ b/ndb/test/ndbapi/testDict.cpp @@ -1009,10 +1009,10 @@ int runGetPrimaryKey(NDBT_Context* ctx, NDBT_Step* step){ struct ErrorCodes { int error_id; bool crash;}; ErrorCodes NF_codes[] = { - {6003, true}, - {6004, true}, + {6003, true} + ,{6004, true} //,6005, true, - {7173, false} + //{7173, false} }; int @@ -1031,17 +1031,6 @@ runNF1(NDBT_Context* ctx, NDBT_Step* step){ int result = NDBT_OK; - /** - * Need to run LCP at high rate otherwise - * packed replicas become "to many" - */ - int val = DumpStateOrd::DihMinTimeBetweenLCP; - if(restarter.dumpStateAllNodes(&val, 1) != 0){ - do { CHECK(0); } while(0); - g_err << "Failed to set LCP to min value" << endl; - return NDBT_FAILED; - } - const int loops = ctx->getNumLoops(); for (int l = 0; l < loops && result == NDBT_OK ; l++){ const int sz = sizeof(NF_codes)/sizeof(NF_codes[0]); @@ -1064,7 +1053,7 @@ runNF1(NDBT_Context* ctx, NDBT_Step* step){ CHECK2(dict->createTable(* pTab) == 0, "failed to create table"); - + if (crash) { CHECK2(restarter.waitNodesNoStart(&nodeId, 1) == 0, "waitNodesNoStart failed"); @@ -1088,9 +1077,6 @@ runNF1(NDBT_Context* ctx, NDBT_Step* step){ CHECK2(restarter.waitClusterStarted() == 0, "waitClusterStarted failed"); } - - CHECK2(restarter.dumpStateOneNode(nodeId, &val, 1) == 0, - "Failed to set LCP to min value"); } } } diff --git a/ndb/test/ndbapi/testNdbApi.cpp b/ndb/test/ndbapi/testNdbApi.cpp index 65324af6fe6..137a1d51d82 100644 --- a/ndb/test/ndbapi/testNdbApi.cpp +++ b/ndb/test/ndbapi/testNdbApi.cpp @@ -1269,6 +1269,101 @@ int runBug_11133(NDBT_Context* ctx, NDBT_Step* step){ return result; } +int runScan_4006(NDBT_Context* ctx, NDBT_Step* step){ + int result = NDBT_OK; + const Uint32 max= 5; + const NdbDictionary::Table* pTab = ctx->getTab(); + + Ndb* pNdb = new Ndb(&ctx->m_cluster_connection, "TEST_DB"); + if (pNdb == NULL){ + ndbout << "pNdb == NULL" << endl; + return NDBT_FAILED; + } + if (pNdb->init(max)){ + ERR(pNdb->getNdbError()); + delete pNdb; + return NDBT_FAILED; + } + + NdbConnection* pCon = pNdb->startTransaction(); + if (pCon == NULL){ + pNdb->closeTransaction(pCon); + delete pNdb; + return NDBT_FAILED; + } + + Uint32 i; + Vector<NdbScanOperation*> scans; + for(i = 0; i<10*max; i++) + { + NdbScanOperation* pOp = pCon->getNdbScanOperation(pTab->getName()); + if (pOp == NULL){ + ERR(pCon->getNdbError()); + pNdb->closeTransaction(pCon); + delete pNdb; + return NDBT_FAILED; + } + + if (pOp->readTuples() != 0){ + pNdb->closeTransaction(pCon); + ERR(pOp->getNdbError()); + delete pNdb; + return NDBT_FAILED; + } + scans.push_back(pOp); + } + + // Dont' call any equal or setValues + + // Execute should not work + int check = pCon->execute(NoCommit); + if (check == 0){ + ndbout << "execute worked" << endl; + } else { + ERR(pCon->getNdbError()); + } + + for(i= 0; i<scans.size(); i++) + { + NdbScanOperation* pOp= scans[i]; + while((check= pOp->nextResult()) == 0); + if(check != 1) + { + ERR(pOp->getNdbError()); + pNdb->closeTransaction(pCon); + delete pNdb; + return NDBT_FAILED; + } + } + + pNdb->closeTransaction(pCon); + + Vector<NdbConnection*> cons; + for(i= 0; i<10*max; i++) + { + pCon= pNdb->startTransaction(); + if(pCon) + cons.push_back(pCon); + else + break; + } + + for(i= 0; i<cons.size(); i++) + { + cons[i]->close(); + } + + if(cons.size() != max) + { + result= NDBT_FAILED; + } + + delete pNdb; + + return result; +} + +template class Vector<NdbScanOperation*>; NDBT_TESTSUITE(testNdbApi); @@ -1351,6 +1446,12 @@ TESTCASE("Bug_11133", INITIALIZER(runBug_11133); FINALIZER(runClearTable); } +TESTCASE("Scan_4006", + "Check that getNdbScanOperation does not get 4006\n"){ + INITIALIZER(runLoadTable); + INITIALIZER(runScan_4006); + FINALIZER(runClearTable); +} NDBT_TESTSUITE_END(testNdbApi); int main(int argc, const char** argv){ diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index b6fc2e29bf5..942ee2ec966 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -31,6 +31,7 @@ #include <NdbSleep.h> #include <my_sys.h> #include <NdbSqlUtil.hpp> +#include <ndb_version.h> // options @@ -171,6 +172,47 @@ randompct(unsigned pct) return urandom(100) < pct; } +static unsigned +random_coprime(unsigned n) +{ + unsigned prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 }; + unsigned count = sizeof(prime) / sizeof(prime[0]); + if (n == 0) + return 0; + while (1) { + unsigned i = urandom(count); + if (n % prime[i] != 0) + return prime[i]; + } +} + +// random re-sequence of 0...(n-1) + +struct Rsq { + Rsq(unsigned n); + unsigned next(); +private: + unsigned m_n; + unsigned m_i; + unsigned m_start; + unsigned m_prime; +}; + +Rsq::Rsq(unsigned n) +{ + m_n = n; + m_i = 0; + m_start = urandom(n); + m_prime = random_coprime(n); +} + +unsigned +Rsq::next() +{ + assert(m_n != 0); + return (m_start + m_i++ * m_prime) % m_n; +} + // log and error macros static NdbMutex *ndbout_mutex = NULL; @@ -1032,8 +1074,8 @@ makebuiltintables(Par par) // name - pk - type - length - nullable - cs t->coladd(0, new Col(*t, 0, "a", 0, Col::Unsigned, 1, 0, 0)); t->coladd(1, new Col(*t, 1, "b", 1, Col::Unsigned, 1, 0, 0)); - t->coladd(2, new Col(*t, 2, "c", 0, Col::Char, 20, 1, getcs(par))); - t->coladd(3, new Col(*t, 3, "d", 0, Col::Varchar, 5, 0, getcs(par))); + t->coladd(2, new Col(*t, 2, "c", 0, Col::Varchar, 20, 0, getcs(par))); + t->coladd(3, new Col(*t, 3, "d", 0, Col::Char, 5, 0, getcs(par))); t->coladd(4, new Col(*t, 4, "e", 0, Col::Longvarchar, 5, 1, getcs(par))); if (useindex(par, 0)) { // b @@ -1071,10 +1113,10 @@ makebuiltintables(Par par) t->itabadd(4, x); } if (useindex(par, 5)) { - // a, b, d + // b, c, d ITab* x = new ITab(*t, "ti1z5", ITab::UniqueHashIndex, 3); - x->icoladd(0, new ICol(*x, 0, *t->m_col[0])); - x->icoladd(1, new ICol(*x, 1, *t->m_col[1])); + x->icoladd(0, new ICol(*x, 0, *t->m_col[1])); + x->icoladd(1, new ICol(*x, 1, *t->m_col[2])); x->icoladd(2, new ICol(*x, 2, *t->m_col[3])); t->itabadd(5, x); } @@ -2254,14 +2296,18 @@ Row::insrow(Par par) assert(! m_exist); CHK(con.getNdbOperation(tab) == 0); CHKCON(con.m_op->insertTuple() == 0, con); + Rsq rsq1(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq1.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (col.m_pk) CHK(val.equal(par) == 0); } + Rsq rsq2(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq2.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (! col.m_pk) CHK(val.setval(par) == 0); @@ -2278,14 +2324,18 @@ Row::updrow(Par par) assert(m_exist); CHK(con.getNdbOperation(tab) == 0); CHKCON(con.m_op->updateTuple() == 0, con); + Rsq rsq1(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq1.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (col.m_pk) CHK(val.equal(par) == 0); } + Rsq rsq2(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq2.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (! col.m_pk) CHK(val.setval(par) == 0); @@ -2303,15 +2353,19 @@ Row::updrow(Par par, const ITab& itab) assert(m_exist); CHK(con.getNdbIndexOperation(itab, tab) == 0); CHKCON(con.m_op->updateTuple() == 0, con); + Rsq rsq1(itab.m_icols); for (unsigned k = 0; k < itab.m_icols; k++) { - const ICol& icol = *itab.m_icol[k]; + unsigned k2 = rsq1.next(); + const ICol& icol = *itab.m_icol[k2]; const Col& col = icol.m_col; unsigned m = col.m_num; const Val& val = *m_val[m]; CHK(val.equal(par, icol) == 0); } + Rsq rsq2(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq2.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (! col.m_pk) CHK(val.setval(par) == 0); @@ -2328,8 +2382,10 @@ Row::delrow(Par par) assert(m_exist); CHK(con.getNdbOperation(m_tab) == 0); CHKCON(con.m_op->deleteTuple() == 0, con); + Rsq rsq1(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq1.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (col.m_pk) CHK(val.equal(par) == 0); @@ -2347,8 +2403,10 @@ Row::delrow(Par par, const ITab& itab) assert(m_exist); CHK(con.getNdbIndexOperation(itab, tab) == 0); CHKCON(con.m_op->deleteTuple() == 0, con); + Rsq rsq1(itab.m_icols); for (unsigned k = 0; k < itab.m_icols; k++) { - const ICol& icol = *itab.m_icol[k]; + unsigned k2 = rsq1.next(); + const ICol& icol = *itab.m_icol[k2]; const Col& col = icol.m_col; unsigned m = col.m_num; const Val& val = *m_val[m]; @@ -2365,8 +2423,10 @@ Row::selrow(Par par) const Tab& tab = m_tab; CHK(con.getNdbOperation(m_tab) == 0); CHKCON(con.m_op->readTuple() == 0, con); + Rsq rsq1(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq1.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (col.m_pk) CHK(val.equal(par) == 0); @@ -2382,8 +2442,10 @@ Row::selrow(Par par, const ITab& itab) assert(itab.m_type == ITab::UniqueHashIndex && &itab.m_tab == &tab); CHK(con.getNdbIndexOperation(itab, tab) == 0); CHKCON(con.m_op->readTuple() == 0, con); + Rsq rsq1(itab.m_icols); for (unsigned k = 0; k < itab.m_icols; k++) { - const ICol& icol = *itab.m_icol[k]; + unsigned k2 = rsq1.next(); + const ICol& icol = *itab.m_icol[k2]; const Col& col = icol.m_col; unsigned m = col.m_num; const Val& val = *m_val[m]; @@ -2397,8 +2459,10 @@ Row::setrow(Par par) { Con& con = par.con(); const Tab& tab = m_tab; + Rsq rsq1(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - const Val& val = *m_val[k]; + unsigned k2 = rsq1.next(); + const Val& val = *m_val[k2]; const Col& col = val.m_col; if (! col.m_pk) CHK(val.setval(par) == 0); @@ -2810,8 +2874,10 @@ Set::getval(Par par) { Con& con = par.con(); const Tab& tab = m_tab; + Rsq rsq1(tab.m_cols); for (unsigned k = 0; k < tab.m_cols; k++) { - CHK(con.getValue(k, m_rec[k]) == 0); + unsigned k2 = rsq1.next(); + CHK(con.getValue(k2, m_rec[k2]) == 0); } return 0; } @@ -3093,18 +3159,16 @@ int BSet::setbnd(Par par) const { if (m_bvals != 0) { - unsigned p1 = urandom(m_bvals); - unsigned p2 = 10009; // prime - // random order + Rsq rsq1(m_bvals); for (unsigned j = 0; j < m_bvals; j++) { - unsigned k = p1 + p2 * j; - const BVal& bval = *m_bval[k % m_bvals]; + unsigned j2 = rsq1.next(); + const BVal& bval = *m_bval[j2]; CHK(bval.setbnd(par) == 0); } // duplicate if (urandom(5) == 0) { - unsigned k = urandom(m_bvals); - const BVal& bval = *m_bval[k]; + unsigned j3 = urandom(m_bvals); + const BVal& bval = *m_bval[j3]; CHK(bval.setbnd(par) == 0); } } @@ -3118,19 +3182,16 @@ BSet::setflt(Par par) const CHK(con.getNdbScanFilter() == 0); CHK(con.beginFilter(NdbScanFilter::AND) == 0); if (m_bvals != 0) { - unsigned p1 = urandom(m_bvals); - unsigned p2 = 10009; // prime - const unsigned extras = 5; - // random order - for (unsigned j = 0; j < m_bvals + extras; j++) { - unsigned k = p1 + p2 * j; - const BVal& bval = *m_bval[k % m_bvals]; + Rsq rsq1(m_bvals); + for (unsigned j = 0; j < m_bvals; j++) { + unsigned j2 = rsq1.next(); + const BVal& bval = *m_bval[j2]; CHK(bval.setflt(par) == 0); } // duplicate if (urandom(5) == 0) { - unsigned k = urandom(m_bvals); - const BVal& bval = *m_bval[k]; + unsigned j3 = urandom(m_bvals); + const BVal& bval = *m_bval[j3]; CHK(bval.setflt(par) == 0); } } @@ -4176,7 +4237,8 @@ readverifyfull(Par par) CHK(scanreadtable(par) == 0); // once more via tup scan par.m_tupscan = true; - CHK(scanreadtable(par) == 0); + if (NDB_VERSION < MAKE_VERSION(5, 1, 0)) //TODO + CHK(scanreadtable(par) == 0); } // each thread scans different indexes for (unsigned i = 0; i < tab.m_itabs; i++) { diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index ce9f97a9cb2..5d7d7f58f89 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -520,6 +520,10 @@ max-time: 500 cmd: testNdbApi args: -n Bug_11133 T1 +max-time: 500 +cmd: testNdbApi +args: -n Scan_4006 T1 + #max-time: 500 #cmd: testInterpreter #args: T1 diff --git a/netware/my_print_defaults.def b/netware/my_print_defaults.def index 826981256b5..d88c5adf4cc 100644 --- a/netware/my_print_defaults.def +++ b/netware/my_print_defaults.def @@ -4,7 +4,8 @@ MODULE libc.nlm COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Print Defaults Tool" -VERSION 4, 0 +VERSION 5, 0, 8 +STACKSIZE 32767 XDCDATA ../netware/mysql.xdc #DEBUG diff --git a/scripts/make_win_src_distribution.sh b/scripts/make_win_src_distribution.sh index 6165a31fac2..c79433f97c1 100644 --- a/scripts/make_win_src_distribution.sh +++ b/scripts/make_win_src_distribution.sh @@ -361,6 +361,9 @@ if [ -d $BASE/SSL/SCCS ] then find $BASE/ -type d -name SCCS -printf " \"%p\"" | xargs rm -r -f fi +find $BASE/ -type d -name .deps -printf " \"%p\"" | xargs rm -r -f +find $BASE/ -type d -name .libs -printf " \"%p\"" | xargs rm -r -f +rm -r -f "$BASE/mysql-test/var" # # Initialize the initial data directory diff --git a/sql/field.cc b/sql/field.cc index 2ce3228be0a..925fca8ac43 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1444,6 +1444,7 @@ my_decimal *Field_str::val_decimal(my_decimal *decimal_value) uint Field::fill_cache_field(CACHE_FIELD *copy) { + uint store_length; copy->str=ptr; copy->length=pack_length(); copy->blob_field=0; @@ -1457,10 +1458,16 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) else if (!zero_pack() && (type() == MYSQL_TYPE_STRING && copy->length >= 4 && copy->length < 256)) + { copy->strip=1; /* Remove end space */ + store_length= 2; + } else + { copy->strip=0; - return copy->length+(int) copy->strip; + store_length= 0; + } + return copy->length+ store_length; } diff --git a/sql/field.h b/sql/field.h index ebf48568c04..523cf444c30 100644 --- a/sql/field.h +++ b/sql/field.h @@ -86,6 +86,7 @@ public: utype unireg_check; uint32 field_length; // Length of field + uint field_index; // field number in fields array uint16 flags; uchar null_bit; // Bit used to test null bit @@ -1288,7 +1289,7 @@ public: enum_field_types type() const { return FIELD_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) field_length + (bit_len > 0); } - uint32 max_length() { return (uint32) field_length + (bit_len > 0); } + uint32 max_length() { return (uint32) field_length * 8 + bit_len; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } void reset(void) { bzero(ptr, field_length); } @@ -1320,6 +1321,11 @@ public: Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, char *new_ptr, uchar *new_null_ptr, uint new_null_bit); + void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) + { + bit_ptr= bit_ptr_arg; + bit_ofs= bit_ofs_arg; + } }; @@ -1331,6 +1337,7 @@ public: enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg); enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uint32 max_length() { return (uint32) create_length; } uint size_of() const { return sizeof(*this); } int store(const char *to, uint length, CHARSET_INFO *charset); int store(double nr) { return Field_bit::store(nr); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index db354066849..8b12b43d3d9 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1496,8 +1496,8 @@ innobase_start_trx_and_assign_read_view( /********************************************************************* Commits a transaction in an InnoDB database or marks an SQL statement ended. */ - -static int +static +int innobase_commit( /*============*/ /* out: 0 */ @@ -3538,7 +3538,9 @@ ha_innobase::delete_row( } /************************************************************************** -Deletes a lock set to a row */ +Removes a new lock set on a row. This can be called after a row has been read +in the processing of an UPDATE or a DELETE query, if the option +innodb_locks_unsafe_for_binlog is set. */ void ha_innobase::unlock_row(void) @@ -3556,8 +3558,10 @@ ha_innobase::unlock_row(void) mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } - - row_unlock_for_mysql(prebuilt); + + if (srv_locks_unsafe_for_binlog) { + row_unlock_for_mysql(prebuilt, FALSE); + } } /********************************************************************** @@ -5991,6 +5995,7 @@ ha_innobase::external_lock( reads. */ prebuilt->select_lock_type = LOCK_S; + prebuilt->stored_select_lock_type = LOCK_S; } /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK @@ -6030,7 +6035,6 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use--; prebuilt->mysql_has_locked = FALSE; - /* If the MySQL lock count drops to zero we know that the current SQL statement has ended */ @@ -6563,12 +6567,14 @@ the value of the auto-inc counter. */ int ha_innobase::innobase_read_and_init_auto_inc( /*=========================================*/ - /* out: 0 or error code: deadlock or - lock wait timeout */ + /* out: 0 or error code: deadlock or lock wait + timeout */ longlong* ret) /* out: auto-inc value */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; longlong auto_inc; + ulint old_select_lock_type; + ibool trx_was_not_started = FALSE; int error; ut_a(prebuilt); @@ -6576,6 +6582,10 @@ ha_innobase::innobase_read_and_init_auto_inc( (trx_t*) current_thd->ha_data[innobase_hton.slot]); ut_a(prebuilt->table); + if (prebuilt->trx->conc_state == TRX_NOT_STARTED) { + trx_was_not_started = TRUE; + } + /* In case MySQL calls this in the middle of a SELECT query, release possible adaptive hash latch to avoid deadlocks of threads */ @@ -6587,7 +6597,9 @@ ha_innobase::innobase_read_and_init_auto_inc( /* Already initialized */ *ret = auto_inc; - return(0); + error = 0; + + goto func_exit_early; } error = row_lock_table_autoinc_for_mysql(prebuilt); @@ -6595,7 +6607,7 @@ ha_innobase::innobase_read_and_init_auto_inc( if (error != DB_SUCCESS) { error = convert_error_code_to_mysql(error, user_thd); - goto func_exit; + goto func_exit_early; } /* Check again if someone has initialized the counter meanwhile */ @@ -6604,30 +6616,37 @@ ha_innobase::innobase_read_and_init_auto_inc( if (auto_inc != 0) { *ret = auto_inc; - return(0); + error = 0; + + goto func_exit_early; } (void) extra(HA_EXTRA_KEYREAD); index_init(table->s->next_number_index); - /* We use an exclusive lock when we read the max key value from the - auto-increment column index. This is because then build_template will - advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query - id of the auto-increment column is not changed, and previously InnoDB - did not fetch it, causing SHOW TABLE STATUS to show wrong values - for the autoinc column. */ - - prebuilt->select_lock_type = LOCK_X; + /* Starting from 5.0.9, we use a consistent read to read the auto-inc + column maximum value. This eliminates the spurious deadlocks caused + by the row X-lock that we previously used. Note the following flaw + in our algorithm: if some other user meanwhile UPDATEs the auto-inc + column, our consistent read will not return the largest value. We + accept this flaw, since the deadlocks were a bigger trouble. */ - /* Play safe and also give in another way the hint to fetch - all columns in the key: */ + /* Fetch all the columns in the key */ prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; - prebuilt->trx->mysql_n_tables_locked += 1; - + old_select_lock_type = prebuilt->select_lock_type; + prebuilt->select_lock_type = LOCK_NONE; + + /* Eliminate an InnoDB error print that happens when we try to SELECT + from a table when no table has been locked in ::external_lock(). */ + prebuilt->trx->n_mysql_tables_in_use++; + error = index_last(table->record[1]); + prebuilt->trx->n_mysql_tables_in_use--; + prebuilt->select_lock_type = old_select_lock_type; + if (error) { if (error == HA_ERR_END_OF_FILE) { /* The table was empty, initialize to 1 */ @@ -6635,7 +6654,10 @@ ha_innobase::innobase_read_and_init_auto_inc( error = 0; } else { - /* Deadlock or a lock wait timeout */ + /* This should not happen in a consistent read */ + fprintf(stderr, +"InnoDB: Error: consistent read of auto-inc column returned %lu\n", + (ulong)error); auto_inc = -1; goto func_exit; @@ -6655,7 +6677,18 @@ func_exit: *ret = auto_inc; - return(error); +func_exit_early: + /* Since MySQL does not seem to call autocommit after SHOW TABLE + STATUS (even if we would register the trx here), we must commit our + transaction here if it was started here. This is to eliminate a + dangling transaction. */ + + if (trx_was_not_started) { + + innobase_commit_low(prebuilt->trx); + } + + return(error); } /*********************************************************************** diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 976a3eeead0..def99b51f95 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -41,7 +41,7 @@ static const int parallelism= 0; // Default value for max number of transactions // createable against NDB from this handler -static const int max_transactions= 256; +static const int max_transactions= 2; static const char *ha_ndb_ext=".ndb"; @@ -516,7 +516,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) m_dupkey= table->s->primary_key; else { - // We are batching inserts, offending key is not available + /* We are batching inserts, offending key is not available */ m_dupkey= (uint) -1; } } @@ -4709,7 +4709,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, List_iterator_fast<char> it2(create_list); while ((file_name=it2++)) { - DBUG_PRINT("info", ("Table %s need discovery", name)); + DBUG_PRINT("info", ("Table %s need discovery", file_name)); if (ha_create_table_from_engine(thd, db, file_name) == 0) files->push_back(thd->strdup(file_name)); } diff --git a/sql/handler.cc b/sql/handler.cc index 4480dbf3777..a61dce35501 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1949,14 +1949,12 @@ int ha_create_table_from_engine(THD* thd, HA_CREATE_INFO create_info; TABLE table; DBUG_ENTER("ha_create_table_from_engine"); - DBUG_PRINT("enter", ("name '%s'.'%s'", - db, name)); + DBUG_PRINT("enter", ("name '%s'.'%s'", db, name)); bzero((char*) &create_info,sizeof(create_info)); - if ((error= ha_discover(thd, db, name, &frmblob, &frmlen))) { - // Table could not be discovered and thus not created + /* Table could not be discovered and thus not created */ DBUG_RETURN(error); } @@ -1967,11 +1965,10 @@ int ha_create_table_from_engine(THD* thd, (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); // Save the frm file - if (writefrm(path, frmblob, frmlen)) - { - my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); + error= writefrm(path, frmblob, frmlen); + my_free((char*) frmblob, MYF(0)); + if (error) DBUG_RETURN(2); - } if (openfrm(thd, path,"",0,(uint) READ_ALL, 0, &table)) DBUG_RETURN(3); @@ -1987,7 +1984,6 @@ int ha_create_table_from_engine(THD* thd, } error=table.file->create(path,&table,&create_info); VOID(closefrm(&table)); - my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN(error != 0); } diff --git a/sql/item.cc b/sql/item.cc index deab704fa24..e53c1ebf734 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -338,7 +338,6 @@ Item::Item(): place == IN_HAVING) thd->lex->current_select->select_n_having_items++; } - item_flags= 0; } /* @@ -359,8 +358,7 @@ Item::Item(THD *thd, Item *item): unsigned_flag(item->unsigned_flag), with_sum_func(item->with_sum_func), fixed(item->fixed), - collation(item->collation), - item_flags(item->item_flags) + collation(item->collation) { next= thd->free_list; // Put in free list thd->free_list= this; @@ -440,16 +438,17 @@ void Item::rename(char *new_name) } -Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par) - :orig_db_name(db_name_par), orig_table_name(table_name_par), - orig_field_name(field_name_par), - db_name(db_name_par), table_name(table_name_par), - field_name(field_name_par), +Item_ident::Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg,const char *table_name_arg, + const char *field_name_arg) + :orig_db_name(db_name_arg), orig_table_name(table_name_arg), + orig_field_name(field_name_arg), context(context_arg), + db_name(db_name_arg), table_name(table_name_arg), + field_name(field_name_arg), alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX), cached_table(0), depended_from(0) { - name = (char*) field_name_par; + name = (char*) field_name_arg; } @@ -460,6 +459,7 @@ Item_ident::Item_ident(THD *thd, Item_ident *item) orig_db_name(item->orig_db_name), orig_table_name(item->orig_table_name), orig_field_name(item->orig_field_name), + context(item->context), db_name(item->db_name), table_name(item->table_name), field_name(item->field_name), @@ -785,7 +785,7 @@ Item_splocal::type() const } -bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **) +bool Item_splocal::fix_fields(THD *, Item **) { Item *it= this_item(); DBUG_ASSERT(it->fixed); @@ -855,7 +855,8 @@ void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, uint el= fields.elements; Item *new_item; ref_pointer_array[el]= this; - if (!(new_item= new Item_ref(ref_pointer_array + el, 0, name))) + if (!(new_item= new Item_ref(&thd->lex->current_select->context, + ref_pointer_array + el, 0, name))) return; // fatal_error is set fields.push_front(this); ref_pointer_array[el]= this; @@ -995,7 +996,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) } Item_field::Item_field(Field *f) - :Item_ident(NullS, *f->table_name, f->field_name), + :Item_ident(0, NullS, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1007,8 +1008,9 @@ Item_field::Item_field(Field *f) orig_table_name= orig_field_name= ""; } -Item_field::Item_field(THD *thd, Field *f) - :Item_ident(f->table->s->db, *f->table_name, f->field_name), +Item_field::Item_field(THD *thd, Name_resolution_context *context_arg, + Field *f) + :Item_ident(context_arg, f->table->s->db, *f->table_name, f->field_name), item_equal(0), no_const_subst(0), have_privileges(0), any_privileges(0) { @@ -1043,6 +1045,17 @@ Item_field::Item_field(THD *thd, Field *f) set_field(f); } + +Item_field::Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg,table_name_arg,field_name_arg), + field(0), result_field(0), item_equal(0), no_const_subst(0), + have_privileges(0), any_privileges(0) +{ + collation.set(DERIVATION_IMPLICIT); +} + // Constructor need to process subselect with temporary tables (see Item) Item_field::Item_field(THD *thd, Item_field *item) :Item_ident(thd, item), @@ -2233,7 +2246,7 @@ bool Item_param::convert_str_value(THD *thd) return rc; } -bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); SELECT_LEX *cursel= (SELECT_LEX *) thd->lex->current_select; @@ -2393,9 +2406,7 @@ int Item_copy_string::save_in_field(Field *field, bool no_conversions) */ /* ARGSUSED */ -bool Item::fix_fields(THD *thd, - struct st_table_list *list, - Item ** ref) +bool Item::fix_fields(THD *thd, Item ** ref) { // We do not check fields which are fixed during construction @@ -2762,7 +2773,6 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) SYNOPSIS Item_field::fix_fields() thd [in] current thread - tables [in] the tables in a FROM clause reference [in/out] view column if this item was resolved to a view column DESCRIPTION @@ -2808,7 +2818,7 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select) FALSE on success */ -bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) +bool Item_field::fix_fields(THD *thd, Item **reference) { enum_parsing_place place= NO_MATTER; DBUG_ASSERT(fixed == 0); @@ -2821,135 +2831,131 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) expression to 'reference', i.e. it substitute that expression instead of this Item_field */ - if ((from_field= find_field_in_tables(thd, this, tables, reference, - IGNORE_EXCEPT_NON_UNIQUE, - !any_privileges)) == + if ((from_field= find_field_in_tables(thd, this, context->table_list, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + !any_privileges && + context->check_privileges, + TRUE)) == not_found_field) { - SELECT_LEX *last= 0; - TABLE_LIST *table_list; - Item **ref= (Item **) not_found_item; - SELECT_LEX *current_sel= (SELECT_LEX *) thd->lex->current_select; /* - If there is an outer select, and it is not a derived table (which do - not support the use of outer fields for now), try to resolve this - reference in the outer select(s). - + If there is an outer contexts (outer selects, but current select is + not derived table or view) try to resolve this reference in the + outer contexts. + We treat each subselect as a separate namespace, so that different subselects may contain columns with the same names. The subselects are - searched starting from the innermost. + searched starting from the innermost. */ - if (current_sel->master_unit()->first_select()->linkage != - DERIVED_TABLE_TYPE) + Name_resolution_context *last_checked_context= context; + Item **ref= (Item **) not_found_item; + Name_resolution_context *outer_context= context->outer_context; + for (; + outer_context; + outer_context= outer_context->outer_context) { - SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); - SELECT_LEX *outer_sel= prev_unit->outer_select(); - for ( ; outer_sel ; - outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) - { - last= outer_sel; - Item_subselect *prev_subselect_item= prev_unit->item; - upward_lookup= TRUE; - - /* Search in the tables of the FROM clause of the outer select. */ - table_list= outer_sel->get_table_list(); - if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) - { - /* - It is a primary INSERT st_select_lex => do not resolve against the - first table. - */ - table_list= table_list->next_local; - } - place= prev_subselect_item->parsing_place; - /* - Check table fields only if the subquery is used somewhere out of - HAVING, or the outer SELECT does not use grouping (i.e. tables are - accessible). + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; + upward_lookup= TRUE; - In case of view, find_field_in_tables() write pointer to view - field expression to 'reference', i.e. it substitute that - expression instead of this Item_field - */ - if ((place != IN_HAVING || - (outer_sel->with_sum_func == 0 && - outer_sel->group_list.elements == 0)) && - (from_field= find_field_in_tables(thd, this, table_list, - reference, - IGNORE_EXCEPT_NON_UNIQUE, - TRUE)) != - not_found_field) - { - if (from_field) - { - if (from_field != view_ref_found) - { - prev_subselect_item->used_tables_cache|= from_field->table->map; - prev_subselect_item->const_item_cache= 0; - } - else - { - Item::Type type= (*reference)->type(); - prev_subselect_item->used_tables_cache|= - (*reference)->used_tables(); - prev_subselect_item->const_item_cache&= - (*reference)->const_item(); - mark_as_dependent(thd, last, current_sel, this, - ((type == REF_ITEM || type == FIELD_ITEM) ? - (Item_ident*) (*reference) : - 0)); - /* - view reference found, we substituted it instead of this - Item (find_field_in_tables do it by assigning new value to - *reference), so can quit - */ - return FALSE; - } - } - break; - } + place= prev_subselect_item->parsing_place; + /* + Check table fields only if the subquery is used somewhere out of + HAVING, or the outer SELECT does not use grouping (i.e. tables are + accessible). - /* Search in the SELECT and GROUP lists of the outer select. */ - if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) + In case of a view, find_field_in_tables() writes the pointer to + the found view field into '*reference', in other words, it + substitutes this Item_field with the found expression. + */ + if ((place != IN_HAVING || + (!select->with_sum_func && + select->group_list.elements == 0)) && + (from_field= find_field_in_tables(thd, this, + outer_context->table_list, + reference, + IGNORE_EXCEPT_NON_UNIQUE, + outer_context-> + check_privileges, + TRUE)) != + not_found_field) + { + if (from_field) { - if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ - if (ref != not_found_item) + if (from_field != view_ref_found) { - DBUG_ASSERT(*ref && (*ref)->fixed); - prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); - prev_subselect_item->const_item_cache&= (*ref)->const_item(); - break; + prev_subselect_item->used_tables_cache|= from_field->table->map; + prev_subselect_item->const_item_cache= 0; } - } + else + { + Item::Type type= (*reference)->type(); + prev_subselect_item->used_tables_cache|= + (*reference)->used_tables(); + prev_subselect_item->const_item_cache&= + (*reference)->const_item(); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + ((type == REF_ITEM || type == FIELD_ITEM) ? + (Item_ident*) (*reference) : + 0)); + /* + A reference to a view field had been found and we + substituted it instead of this Item (find_field_in_tables + does it by assigning the new value to *reference), so now + we can return from this function. + */ + return FALSE; + } + } + break; + } - // Reference is not found => depend from outer (or just error) - prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; - prev_subselect_item->const_item_cache= 0; + /* Search in SELECT and GROUP lists of the outer select. */ + if (outer_context->resolve_in_select_list) + { + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + goto error; /* Some error occurred (e.g. ambiguous names). */ + if (ref != not_found_item) + { + DBUG_ASSERT(*ref && (*ref)->fixed); + prev_subselect_item->used_tables_cache|= (*ref)->used_tables(); + prev_subselect_item->const_item_cache&= (*ref)->const_item(); + break; + } + } - if (outer_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE) - break; // do not look over derived table - } + /* + Reference is not found in this select => this subquery depend on + outer select (or we just trying to find wrong identifier, in this + case it does not matter which used tables bits we set) + */ + prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; + prev_subselect_item->const_item_cache= 0; } DBUG_ASSERT(ref != 0); if (!from_field) - return TRUE; + goto error; if (ref == not_found_item && from_field == not_found_field) { if (upward_lookup) { - // We can't say exactly what absent table or field + // We can't say exactly what absent table or field my_error(ER_BAD_FIELD_ERROR, MYF(0), full_name(), thd->where); } else { - // Call to report error - find_field_in_tables(thd, this, tables, reference, REPORT_ALL_ERRORS, - TRUE); + /* Call find_field_in_tables only to report the error */ + find_field_in_tables(thd, this, context->table_list, + reference, REPORT_ALL_ERRORS, + !any_privileges && + context->check_privileges, TRUE); } - return TRUE; + goto error; } else if (ref != not_found_item) { @@ -2967,45 +2973,54 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) save= *ref; *ref= NULL; // Don't call set_properties() rf= (place == IN_HAVING ? - new Item_ref(ref, (char*) table_name, (char*) field_name) : - new Item_direct_ref(ref, (char*) table_name, (char*) field_name)); + new Item_ref(context, ref, (char*) table_name, + (char*) field_name) : + new Item_direct_ref(context, ref, (char*) table_name, + (char*) field_name)); *ref= save; if (!rf) - return TRUE; + goto error; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)) - return TRUE; + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + goto error; - mark_as_dependent(thd, last, current_sel, this, rf); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, + rf); return FALSE; } else { - mark_as_dependent(thd, last, current_sel, this, this); - if (last->having_fix_field) + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, + this, this); + if (last_checked_context->select_lex->having_fix_field) { Item_ref *rf; - rf= new Item_ref((cached_table->db[0] ? cached_table->db : 0), + rf= new Item_ref(context, + (cached_table->db[0] ? cached_table->db : 0), (char*) cached_table->alias, (char*) field_name); if (!rf) - return TRUE; + goto error; thd->change_item_tree(reference, rf); /* rf is Item_ref => never substitute other items (in this case) during fix_fields() => we can use rf after fix_fields() */ DBUG_ASSERT(!rf->fixed); // Assured by Item_ref() - return (rf->fix_fields(thd, tables, reference) || rf->check_cols(1)); + if (rf->fix_fields(thd, reference) || rf->check_cols(1)) + goto error; + return FALSE; } } } else if (!from_field) - return TRUE; + goto error; /* if it is not expression from merged VIEW we will set this field. @@ -3053,12 +3068,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY", thd->priv_user, thd->host_or_ip, field_name, tab); - return TRUE; + goto error; } } #endif fixed= 1; return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -3347,6 +3366,9 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table) case MYSQL_TYPE_YEAR: return new Field_year((char*) 0, max_length, null_ptr, 0, Field::NONE, name, table); + case MYSQL_TYPE_BIT: + return new Field_bit_as_char(NULL, max_length, null_ptr, 0, NULL, 0, + Field::NONE, name, table); default: /* This case should never be chosen */ DBUG_ASSERT(0); @@ -3573,7 +3595,7 @@ Item *Item_int_with_ref::new_item() Item_num *Item_uint::neg() { - Item_decimal *item= new Item_decimal(value, 0); + Item_decimal *item= new Item_decimal(value, 1); return item->neg(); } @@ -3919,16 +3941,17 @@ bool Item_field::send(Protocol *protocol, String *buffer) } -Item_ref::Item_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ident(NullS, table_name_par, field_name_par), result_field(0), - ref(item) +Item_ref::Item_ref(Name_resolution_context *context_arg, + Item **item, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, NullS, table_name_arg, field_name_arg), + result_field(0), ref(item) { /* This constructor used to create some internals references over fixed items */ DBUG_ASSERT(ref != 0); - if (*ref) + if (*ref && (*ref)->fixed) set_properties(); } @@ -3939,7 +3962,6 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, SYNOPSIS Item_ref::fix_fields() thd [in] current thread - tables [in] the tables in a FROM clause reference [in/out] view column if this item was resolved to a view column DESCRIPTION @@ -3991,59 +4013,56 @@ Item_ref::Item_ref(Item **item, const char *table_name_par, FALSE on success */ -bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) +bool Item_ref::fix_fields(THD *thd, Item **reference) { - DBUG_ASSERT(fixed == 0); enum_parsing_place place= NO_MATTER; + DBUG_ASSERT(fixed == 0); SELECT_LEX *current_sel= thd->lex->current_select; if (!ref || ref == not_found_item) { - SELECT_LEX_UNIT *prev_unit= current_sel->master_unit(); - SELECT_LEX *outer_sel= prev_unit->outer_select(); - - if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ + if (!(ref= resolve_ref_in_select_and_group(thd, this, + context->select_lex))) + goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref == not_found_item) /* This reference was not resolved. */ { - TABLE_LIST *table_list; + Name_resolution_context *last_checked_context= context; + Name_resolution_context *outer_context= context->outer_context; Field *from_field; - SELECT_LEX *last; ref= 0; - if (!outer_sel || (current_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE)) + if (!outer_context) { /* The current reference cannot be resolved in this query. */ my_error(ER_BAD_FIELD_ERROR,MYF(0), this->full_name(), current_thd->where); - return TRUE; + goto error; } + /* - If there is an outer select, and it is not a derived table (which do - not support the use of outer fields for now), try to resolve this - reference in the outer select(s). + If there is an outer context (select), and it is not a derived table + (which do not support the use of outer fields for now), try to + resolve this reference in the outer select(s). We treat each subselect as a separate namespace, so that different subselects may contain columns with the same names. The subselects are searched starting from the innermost. */ from_field= (Field*) not_found_field; - last= 0; - /* The following loop will always be excuted at least once */ - for ( ; outer_sel ; - outer_sel= (prev_unit= outer_sel->master_unit())->outer_select()) + do { - last= outer_sel; - Item_subselect *prev_subselect_item= prev_unit->item; + SELECT_LEX *select= outer_context->select_lex; + Item_subselect *prev_subselect_item= + last_checked_context->select_lex->master_unit()->item; + last_checked_context= outer_context; /* Search in the SELECT and GROUP lists of the outer select. */ - if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE) + if (outer_context->resolve_in_select_list) { - if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel))) - return TRUE; /* Some error occurred (e.g. ambiguous names). */ + if (!(ref= resolve_ref_in_select_and_group(thd, this, select))) + goto error; /* Some error occurred (e.g. ambiguous names). */ if (ref != not_found_item) { DBUG_ASSERT(*ref && (*ref)->fixed); @@ -4059,43 +4078,34 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) ref= 0; } - /* Search in the tables of the FROM clause of the outer select. */ - table_list= outer_sel->get_table_list(); - if (outer_sel->resolve_mode == SELECT_LEX::INSERT_MODE && table_list) - { - /* - It is a primary INSERT st_select_lex => do not resolve against - the first table. - */ - table_list= table_list->next_local; - } - place= prev_subselect_item->parsing_place; /* Check table fields only if the subquery is used somewhere out of HAVING or the outer SELECT does not use grouping (i.e. tables are accessible). - TODO: + TODO: Here we could first find the field anyway, and then test this condition, so that we can give a better error message - ER_WRONG_FIELD_WITH_GROUP, instead of the less informative ER_BAD_FIELD_ERROR which we produce now. */ if ((place != IN_HAVING || - (!outer_sel->with_sum_func && - outer_sel->group_list.elements == 0))) + (!select->with_sum_func && + select->group_list.elements == 0))) { /* In case of view, find_field_in_tables() write pointer to view field expression to 'reference', i.e. it substitute that expression instead of this Item_ref */ - from_field= find_field_in_tables(thd, this, table_list, + from_field= find_field_in_tables(thd, this, + outer_context->table_list, reference, IGNORE_EXCEPT_NON_UNIQUE, + outer_context->check_privileges, TRUE); if (! from_field) - return TRUE; + goto error; if (from_field == view_ref_found) { Item::Type type= (*reference)->type(); @@ -4104,7 +4114,8 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) prev_subselect_item->const_item_cache&= (*reference)->const_item(); DBUG_ASSERT((*reference)->type() == REF_ITEM); - mark_as_dependent(thd, last, current_sel, this, + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, ((type == REF_ITEM || type == FIELD_ITEM) ? (Item_ident*) (*reference) : 0)); @@ -4127,19 +4138,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) prev_subselect_item->used_tables_cache|= OUTER_REF_TABLE_BIT; prev_subselect_item->const_item_cache= 0; - if (outer_sel->master_unit()->first_select()->linkage == - DERIVED_TABLE_TYPE) - break; /* Do not consider derived tables. */ - } + outer_context= outer_context->outer_context; + } while (outer_context); DBUG_ASSERT(from_field != 0 && from_field != view_ref_found); if (from_field != not_found_field) { Item_field* fld; if (!(fld= new Item_field(from_field))) - return TRUE; + goto error; thd->change_item_tree(reference, fld); - mark_as_dependent(thd, last, thd->lex->current_select, this, fld); + mark_as_dependent(thd, last_checked_context->select_lex, + thd->lex->current_select, this, fld); return FALSE; } if (ref == 0) @@ -4147,11 +4157,12 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) /* The item was not a table field and not a reference */ my_error(ER_BAD_FIELD_ERROR, MYF(0), this->full_name(), current_thd->where); - return TRUE; + goto error; } /* Should be checked in resolve_ref_in_select_and_group(). */ DBUG_ASSERT(*ref && (*ref)->fixed); - mark_as_dependent(thd, last, current_sel, this, this); + mark_as_dependent(thd, last_checked_context->select_lex, + context->select_lex, this, this); } } @@ -4171,14 +4182,18 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) name, ((*ref)->with_sum_func? "reference to group function": "forward reference in item list")); - return TRUE; + goto error; } set_properties(); if ((*ref)->check_cols(1)) - return TRUE; + goto error; return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -4384,6 +4399,19 @@ int Item_ref::save_in_field(Field *to, bool no_conversions) } +void Item_ref::make_field(Send_field *field) +{ + (*ref)->make_field(field); + /* Non-zero in case of a view */ + if (name) + field->col_name= name; + if (table_name) + field->table_name= table_name; + if (db_name) + field->db_name= db_name; +} + + void Item_ref_null_helper::print(String *str) { str->append("<ref_null_helper>(", 18); @@ -4447,6 +4475,31 @@ bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate) } +/* + Prepare referenced view viewld then call usual Item_direct_ref::fix_fields + + SYNOPSIS + Item_direct_view_ref::fix_fields() + thd thread handler + reference reference on reference where this item stored + + RETURN + FALSE OK + TRUE Error +*/ + +bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) +{ + /* view fild reference must be defined */ + DBUG_ASSERT(*ref); + /* (*ref)->check_cols() will be made in Item_direct_ref::fix_fields */ + if (!(*ref)->fixed && + ((*ref)->fix_fields(thd, ref))) + return TRUE; + return Item_direct_ref::fix_fields(thd, reference); +} + + void Item_null_helper::print(String *str) { str->append("<null_helper>(", 14); @@ -4462,9 +4515,7 @@ bool Item_default_value::eq(const Item *item, bool binary_cmp) const } -bool Item_default_value::fix_fields(THD *thd, - struct st_table_list *table_list, - Item **items) +bool Item_default_value::fix_fields(THD *thd, Item **items) { Item *real_arg; Item_field *field_arg; @@ -4476,29 +4527,34 @@ bool Item_default_value::fix_fields(THD *thd, fixed= 1; return FALSE; } - if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) - return TRUE; + if (!arg->fixed && arg->fix_fields(thd, &arg)) + goto error; + real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), arg->name); - return TRUE; + goto error; } field_arg= (Item_field *)real_arg; if (field_arg->field->flags & NO_DEFAULT_VALUE_FLAG) { my_error(ER_NO_DEFAULT_FOR_FIELD, MYF(0), field_arg->field->field_name); - return TRUE; + goto error; } if (!(def_field= (Field*) sql_alloc(field_arg->field->size_of()))) - return TRUE; + goto error; memcpy(def_field, field_arg->field, field_arg->field->size_of()); def_field->move_field(def_field->table->s->default_values - def_field->table->record[0]); set_field(def_field); return FALSE; + +error: + context->process_error(thd); + return TRUE; } @@ -4521,11 +4577,27 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (field_arg->flags & NO_DEFAULT_VALUE_FLAG) { - push_warning_printf(field_arg->table->in_use, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - field_arg->field_name); + if (context->error_processor == &view_error_processor) + { + TABLE_LIST *view= (cached_table->belong_to_view ? + cached_table->belong_to_view : + cached_table); + // TODO: make correct error message + push_warning_printf(field_arg->table->in_use, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + view->view_db.str, + view->view_name.str); + } + else + { + push_warning_printf(field_arg->table->in_use, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + field_arg->field_name); + } return 1; } field_arg->set_default(); @@ -4542,12 +4614,10 @@ bool Item_insert_value::eq(const Item *item, bool binary_cmp) const } -bool Item_insert_value::fix_fields(THD *thd, - struct st_table_list *table_list, - Item **items) +bool Item_insert_value::fix_fields(THD *thd, Item **items) { DBUG_ASSERT(fixed == 0); - if (!arg->fixed && arg->fix_fields(thd, table_list, &arg)) + if (!arg->fixed && arg->fix_fields(thd, &arg)) return TRUE; if (arg->type() == REF_ITEM) @@ -4636,9 +4706,7 @@ bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const } -bool Item_trigger_field::fix_fields(THD *thd, - TABLE_LIST *table_list, - Item **items) +bool Item_trigger_field::fix_fields(THD *thd, Item **items) { /* Since trigger is object tightly associated with TABLE object most @@ -5405,6 +5473,34 @@ void Item_result_field::cleanup() DBUG_VOID_RETURN; } +/* + Dummy error processor used by default by Name_resolution_context + + SYNOPSIS + dummy_error_processor() + + NOTE + do nothing +*/ + +void dummy_error_processor(THD *thd, void *data) +{} + +/* + Wrapper of hide_view_error call for Name_resolution_context error processor + + SYNOPSIS + view_error_processor() + + NOTE + hide view underlying tables details in error messages +*/ + +void view_error_processor(THD *thd, void *data) +{ + ((TABLE_LIST *)data)->hide_view_error(thd); +} + /***************************************************************************** ** Instantiate templates *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index bd843add4ef..560f1124fb4 100644 --- a/sql/item.h +++ b/sql/item.h @@ -24,7 +24,6 @@ struct st_table_list; void item_init(void); /* Init item functions */ class Item_field; - /* "Declared Type Collation" A combination of collation and its derivation. @@ -218,23 +217,110 @@ struct Hybrid_type_traits_integer: public Hybrid_type_traits static const Hybrid_type_traits_integer *instance(); }; + +void dummy_error_processor(THD *thd, void *data); + +void view_error_processor(THD *thd, void *data); + +/* + Instances of Name_resolution_context store the information necesary for + name resolution of Items and other context analysis of a query made in + fix_fields(). + + This structure is a part of SELECT_LEX, a pointer to this structure is + assigned when an item is created (which happens mostly during parsing + (sql_yacc.yy)), but the structure itself will be initialized after parsing + is complete + + TODO: move subquery of INSERT ... SELECT and CREATE ... SELECT to + separate SELECT_LEX which allow to remove tricks of changing this + structure before and after INSERT/CREATE and its SELECT to make correct + field name resolution. +*/ +struct Name_resolution_context +{ + /* + The name resolution context to search in when an Item cannot be + resolved in this context (the context of an outer select) + */ + Name_resolution_context *outer_context; + + /* + List of tables used to resolve the items of this context. Usually these + are tables from the FROM clause of SELECT statement. The exceptions are + INSERT ... SELECT and CREATE ... SELECT statements, where SELECT + subquery is not moved to a separate SELECT_LEX. For these types of + statements we have to change this member dynamically to ensure correct + name resolution of different parts of the statement. + */ + TABLE_LIST *table_list; + + /* + SELECT_LEX item belong to, in case of merged VIEW it can differ from + SELECT_LEX where item was created, so we can't use table_list/field_list + from there + */ + st_select_lex *select_lex; + + /* + Processor of errors caused during Item name resolving, now used only to + hide underlying tables in errors about views (i.e. it substitute some + errors for views) + */ + void (*error_processor)(THD *, void *); + void *error_processor_data; + + /* + When TRUE items are resolved in this context both against the + SELECT list and this->table_list. If FALSE, items are resolved + only against this->table_list. + */ + bool resolve_in_select_list; + + /* + When FALSE we do not check columns right of resolving items, used to + prevent rights check on underlying tables of view + */ + bool check_privileges; + + Name_resolution_context() + :outer_context(0), table_list(0), select_lex(0), + error_processor_data(0), + check_privileges(TRUE) + {} + + void init() + { + resolve_in_select_list= FALSE; + error_processor= &dummy_error_processor; + } + + void resolve_in_table_list_only(TABLE_LIST *tables) + { + table_list= tables; + resolve_in_select_list= FALSE; + } + + void process_error(THD *thd) + { + (*error_processor)(thd, error_processor_data); + } +}; + + /*************************************************************************/ typedef bool (Item::*Item_processor)(byte *arg); typedef Item* (Item::*Item_transformer) (byte *arg); - typedef void (*Cond_traverser) (const Item *item, void *arg); -/* - See comments for sql_yacc.yy: insert_update_elem rule - */ -#define MY_ITEM_PREFER_1ST_TABLE 1 class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { return (void*) sql_alloc((uint) size); } static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } /* Special for SP local variable assignment - reusing slots */ @@ -248,7 +334,8 @@ public: PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, + VIEW_FIXER_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -277,7 +364,6 @@ public: my_bool is_autogenerated_name; /* indicate was name of this Item autogenerated or set by user */ DTCollation collation; - uint8 item_flags; /* Flags on how item should be processed */ // alloc & destruct is done as start of select using sql_alloc Item(); @@ -302,7 +388,7 @@ public: virtual void cleanup(); virtual void make_field(Send_field *field); Field *make_string_field(TABLE *table); - virtual bool fix_fields(THD *, struct st_table_list *, Item **); + virtual bool fix_fields(THD *, Item **); /* should be used in case where we are sure that we do not need complete fix_fields() procedure. @@ -554,6 +640,8 @@ public: virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } virtual bool cleanup_processor(byte *arg); virtual bool collect_item_field_processor(byte * arg) { return 0; } + virtual bool change_context_processor(byte *context) { return 0; } + virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } virtual Item *replace_equal_field(byte * arg) { return this; } @@ -590,11 +678,6 @@ public: cleanup(); delete this; } - virtual bool set_flags_processor(byte *args) - { - this->item_flags|= *((uint8*)args); - return FALSE; - } virtual bool is_splocal() { return 0; } /* Needed for error checking */ }; @@ -631,7 +714,7 @@ public: Item **this_item_addr(THD *thd, Item **); Item *this_const_item() const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void cleanup(); inline uint get_offset() @@ -704,7 +787,9 @@ protected: const char *orig_db_name; const char *orig_table_name; const char *orig_field_name; + public: + Name_resolution_context *context; const char *db_name; const char *table_name; const char *field_name; @@ -722,13 +807,16 @@ public: */ TABLE_LIST *cached_table; st_select_lex *depended_from; - Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par); + Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg, const char *table_name_arg, + const char *field_name_arg); Item_ident(THD *thd, Item_ident *item); const char *full_name() const; void cleanup(); bool remove_dependence_processor(byte * arg); void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; class Item_equal; @@ -750,12 +838,9 @@ public: /* field need any privileges (for VIEW creation) */ bool any_privileges; - Item_field(const char *db_par,const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par,table_name_par,field_name_par), - field(0), result_field(0), item_equal(0), no_const_subst(0), - have_privileges(0), any_privileges(0) - { collation.set(DERIVATION_IMPLICIT); } + Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg); /* Constructor needed to process subselect with temporary tables (see Item) */ @@ -765,7 +850,7 @@ public: and database names will live as long as Item_field (this is important in prepared statements). */ - Item_field(THD *thd, Field *field); + Item_field(THD *thd, Name_resolution_context *context_arg, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call @@ -785,7 +870,7 @@ public: bool val_bool_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); @@ -946,7 +1031,7 @@ public: bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); int save_in_field(Field *field, bool no_conversions); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void set_null(); void set_int(longlong i, uint32 max_length_arg); @@ -1317,9 +1402,11 @@ protected: public: Field *result_field; /* Save result here */ Item **ref; - Item_ref(const char *db_par, const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par, table_name_par, field_name_par), result_field(0), ref(0) {} + Item_ref(Name_resolution_context *context_arg, + const char *db_arg, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), + result_field(0), ref(0) {} /* This constructor is used in two scenarios: A) *item = NULL @@ -1334,13 +1421,18 @@ public: TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ - Item_ref(Item **item, const char *table_name_par, const char *field_name_par); + Item_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, const char *field_name_arg); /* Constructor need to process subselect with temporary tables (see Item) */ - Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} + Item_ref(THD *thd, Item_ref *item) + :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const - { return ref && (*ref)->eq(item, binary_cmp); } + { + Item *it= ((Item *) item)->real_item(); + return ref && (*ref)->eq(it, binary_cmp); + } double val_real(); longlong val_int(); my_decimal *val_decimal(my_decimal *); @@ -1354,8 +1446,8 @@ public: my_decimal *val_decimal_result(my_decimal *); bool val_bool_result(); bool send(Protocol *prot, String *tmp); - void make_field(Send_field *field) { (*ref)->make_field(field); } - bool fix_fields(THD *, struct st_table_list *, Item **); + void make_field(Send_field *field); + bool fix_fields(THD *, Item **); int save_in_field(Field *field, bool no_conversions); void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } @@ -1380,6 +1472,8 @@ public: { return (*ref)->walk(processor, arg); } void print(String *str); void cleanup(); + Item_field *filed_for_view_update() + { return (*ref)->filed_for_view_update(); } }; @@ -1390,9 +1484,10 @@ public: class Item_direct_ref :public Item_ref { public: - Item_direct_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ref(item, table_name_par, field_name_par) {} + Item_direct_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg) {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} @@ -1405,6 +1500,24 @@ public: bool get_date(TIME *ltime,uint fuzzydate); }; +/* + Class for view fields, the same as Item_direct_ref, but call fix_fields + of reference if it is not called yet +*/ +class Item_direct_view_ref :public Item_direct_ref +{ +public: + Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {} + /* Constructor need to process subselect with temporary tables (see Item) */ + Item_direct_view_ref(THD *thd, Item_direct_ref *item) + :Item_direct_ref(thd, item) {} + + bool fix_fields(THD *, Item **); +}; + class Item_in_subselect; @@ -1413,9 +1526,11 @@ class Item_ref_null_helper: public Item_ref protected: Item_in_subselect* owner; public: - Item_ref_null_helper(Item_in_subselect* master, Item **item, - const char *table_name_par, const char *field_name_par): - Item_ref(item, table_name_par, field_name_par), owner(master) {} + Item_ref_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item **item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg), + owner(master) {} double val_real(); longlong val_int(); String* val_str(String* s); @@ -1429,10 +1544,11 @@ class Item_null_helper :public Item_ref_null_helper { Item *store; public: - Item_null_helper(Item_in_subselect* master, Item *item, - const char *table_name_par, const char *field_name_par) - :Item_ref_null_helper(master, (store= 0, &store), table_name_par, - field_name_par), + Item_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item *item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref_null_helper(context_arg, master, (store= 0, &store), + table_name_arg, field_name_arg), store(item) { ref= &store; } void print(String *str); @@ -1583,13 +1699,17 @@ class Item_default_value : public Item_field { public: Item *arg; - Item_default_value() : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {} - Item_default_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_default_value(Name_resolution_context *context_arg) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(NULL) {} + Item_default_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } @@ -1618,10 +1738,12 @@ class Item_insert_value : public Item_field { public: Item *arg; - Item_insert_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_insert_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions) { @@ -1683,15 +1805,17 @@ public: /* Pointer to Table_trigger_list object for table of this trigger */ Table_triggers_list *triggers; - Item_trigger_field(row_version_type row_ver_par, - const char *field_name_par): - Item_field((const char *)NULL, (const char *)NULL, field_name_par), - row_version(row_ver_par), field_idx((uint)-1) + Item_trigger_field(Name_resolution_context *context_arg, + row_version_type row_ver_arg, + const char *field_name_arg) + :Item_field(context_arg, + (const char *)NULL, (const char *)NULL, field_name_arg), + row_version(row_ver_arg), field_idx((uint)-1) {} void setup_field(THD *thd, TABLE *table); enum Type type() const { return TRIGGER_FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); table_map used_tables() const { return (table_map)0L; } void cleanup(); @@ -1880,7 +2004,7 @@ public: Item_type_holder(THD*, Item*); Item_result result_type() const; - virtual enum_field_types field_type() const { return fld_type; }; + enum_field_types field_type() const { return fld_type; }; enum Type type() const { return TYPE_HOLDER; } double val_real(); longlong val_int(); @@ -1892,6 +2016,7 @@ public: static enum_field_types get_real_type(Item *); }; + class st_select_lex; void mark_select_range_as_dependent(THD *thd, st_select_lex *last_select, diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a3be5ec6cd1..bce6a58330f 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -638,11 +638,9 @@ int Arg_comparator::compare_e_row() } -bool Item_in_optimizer::fix_left(THD *thd, - struct st_table_list *tables, - Item **ref) +bool Item_in_optimizer::fix_left(THD *thd, Item **ref) { - if (!args[0]->fixed && args[0]->fix_fields(thd, tables, args) || + if (!args[0]->fixed && args[0]->fix_fields(thd, args) || !cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) return 1; @@ -679,16 +677,15 @@ bool Item_in_optimizer::fix_left(THD *thd, } -bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, - Item ** ref) +bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (fix_left(thd, tables, ref)) + if (fix_left(thd, ref)) return TRUE; if (args[0]->maybe_null) maybe_null=1; - if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1)) + if (!args[1]->fixed && args[1]->fix_fields(thd, args+1)) return TRUE; Item_in_subselect * sub= (Item_in_subselect *)args[1]; if (args[0]->cols() != sub->engine->cols()) @@ -2327,7 +2324,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) bool -Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_cond::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); List_iterator<Item> li(list); @@ -2375,7 +2372,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) // item can be substituted in fix_fields if ((!item->fixed && - item->fix_fields(thd, tables, li.ref())) || + item->fix_fields(thd, li.ref())) || (item= *li.ref())->check_cols(1)) return TRUE; /* purecov: inspected */ used_tables_cache|= item->used_tables(); @@ -2762,11 +2759,11 @@ Item_func::optimize_type Item_func_like::select_optimize() const } -bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) +bool Item_func_like::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (Item_bool_func2::fix_fields(thd, tlist, ref) || - escape_item->fix_fields(thd, tlist, &escape_item)) + if (Item_bool_func2::fix_fields(thd, ref) || + escape_item->fix_fields(thd, &escape_item)) return TRUE; if (!escape_item->const_during_execution()) @@ -2830,13 +2827,13 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) #ifdef USE_REGEX bool -Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_regex::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); if ((!args[0]->fixed && - args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) || + args[0]->fix_fields(thd, args)) || args[0]->check_cols(1) || (!args[1]->fixed && - args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1)) + args[1]->fix_fields(thd, args + 1)) || args[1]->check_cols(1)) return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length= 1; @@ -3496,7 +3493,7 @@ void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) } while (swap); } -bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_equal::fix_fields(THD *thd, Item **ref) { List_iterator_fast<Item_field> li(fields); Item *item; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 33c9e518860..c21e9ba4925 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -108,8 +108,8 @@ public: Item_in_optimizer(Item *a, Item_in_subselect *b): Item_bool_func(a, my_reinterpret_cast(Item *)(b)), cache(0), save_cache(0) {} - bool fix_fields(THD *, struct st_table_list *, Item **); - bool fix_left(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *, Item **); + bool fix_left(THD *thd, Item **ref); bool is_null(); /* Item_in_optimizer item is special boolean function. On value request @@ -502,11 +502,11 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); args[0]->top_level_item(); - return Item_func::fix_fields(thd, tlist, ref); + return Item_func::fix_fields(thd, ref); } void fix_length_and_dec(); uint decimal_precision() const; @@ -850,6 +850,12 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } + /* + IN() protect from NULL only first argument, if construction like + "expression IN ()" will be allowed, we will need to check number of + argument here, because "NOT(NULL IN ())" is TRUE. + */ + table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ @@ -962,7 +968,7 @@ public: optimize_type select_optimize() const; cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); }; #ifdef USE_REGEX @@ -981,7 +987,7 @@ public: regex_compiled(0),regex_is_const(0) {} void cleanup(); longlong val_int(); - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); const char *func_name() const { return "regexp"; } void print(String *str) { print_op(str); } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } @@ -1025,7 +1031,7 @@ public: :Item_bool_func(), list(nlist), abort_on_null(0) {} bool add(Item *item) { return list.push_back(item); } void add_at_head(List<Item> *nlist) { list.prepand(nlist); } - bool fix_fields(THD *, struct st_table_list *, Item **ref); + bool fix_fields(THD *, Item **ref); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } @@ -1034,7 +1040,7 @@ public: void print(String *str); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, - COND **conds); + COND **conds); void top_level_item() { abort_on_null=1; } void copy_andor_arguments(THD *thd, Item_cond *item); bool walk(Item_processor processor, byte *arg); @@ -1142,7 +1148,7 @@ public: void sort(Item_field_cmpfunc cmp, void *arg); friend class Item_equal_iterator; void fix_length_and_dec(); - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void update_used_tables(); bool walk(Item_processor processor, byte *arg); Item *transform(Item_transformer transformer, byte *arg); diff --git a/sql/item_func.cc b/sql/item_func.cc index c347cd2913b..16296266234 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -194,11 +194,10 @@ bool Item_func::agg_arg_charsets(DTCollation &coll, ((Item_field *)(*arg))->no_const_subst= 1; /* We do not check conv->fixed, because Item_func_conv_charset which can - be return by safe_charset_converter can't be fixed at creation, also - it do not need tables (second argument) for name resolving + be return by safe_charset_converter can't be fixed at creation */ *arg= conv; - conv->fix_fields(thd, 0, arg); + conv->fix_fields(thd, arg); } if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -261,7 +260,6 @@ Item_func::Item_func(THD *thd, Item_func *item) SYNOPSIS: fix_fields() thd Thread object - tables List of all open tables involved in the query ref Pointer to where this object is used. This reference is used if we want to replace this object with another one (for example in the summary functions). @@ -290,7 +288,7 @@ Item_func::Item_func(THD *thd, Item_func *item) */ bool -Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); Item **arg,**arg_end; @@ -312,7 +310,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg))) + if ((!(*arg)->fixed && (*arg)->fix_fields(thd, arg))) return TRUE; /* purecov: inspected */ item= *arg; @@ -2010,10 +2008,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value) } -bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, - Item **ref) +bool Item_func_rand::fix_fields(THD *thd,Item **ref) { - if (Item_real_func::fix_fields(thd, tables, ref)) + if (Item_real_func::fix_fields(thd, ref)) return TRUE; used_tables_cache|= RAND_TABLE_BIT; if (arg_count) @@ -2604,7 +2601,7 @@ void udf_handler::cleanup() bool -udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, +udf_handler::fix_fields(THD *thd, Item_result_field *func, uint arg_count, Item **arguments) { #ifndef EMBEDDED_LIBRARY // Avoid compiler warning @@ -2646,7 +2643,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg++,i++) { if (!(*arg)->fixed && - (*arg)->fix_fields(thd, tables, arg)) + (*arg)->fix_fields(thd, arg)) DBUG_RETURN(1); // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; @@ -3458,12 +3455,11 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, SELECT @a:= ). */ -bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) +bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */ - if (Item_func::fix_fields(thd, tables, ref) || + if (Item_func::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; /* @@ -4127,11 +4123,10 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const } -bool Item_user_var_as_out_param::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) +bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (Item::fix_fields(thd, tables, ref) || + if (Item::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; entry->type= STRING_RESULT; @@ -4314,7 +4309,7 @@ void Item_func_match::init_search(bool no_order) } -bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) +bool Item_func_match::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); Item *item; @@ -4329,7 +4324,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) modifications to find_best and auto_close as complement to auto_init code above. */ - if (Item_func::fix_fields(thd, tlist, ref) || + if (Item_func::fix_fields(thd, ref) || !args[0]->const_during_execution()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); @@ -4691,8 +4686,9 @@ longlong Item_func_row_count::val_int() } -Item_func_sp::Item_func_sp(sp_name *name) - :Item_func(), m_name(name), m_sp(NULL), result_field(NULL) +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name) + :Item_func(), context(context_arg), m_name(name), m_sp(NULL), + result_field(NULL) { maybe_null= 1; m_name->init_qname(current_thd); @@ -4700,8 +4696,10 @@ Item_func_sp::Item_func_sp(sp_name *name) } -Item_func_sp::Item_func_sp(sp_name *name, List<Item> &list) - :Item_func(list), m_name(name), m_sp(NULL), result_field(NULL) +Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, + sp_name *name, List<Item> &list) + :Item_func(list), context(context_arg), m_name(name), m_sp(NULL), + result_field(NULL) { maybe_null= 1; m_name->init_qname(current_thd); @@ -4945,7 +4943,10 @@ Item_func_sp::fix_length_and_dec() } if (!(field= sp_result_field())) + { + context->process_error(current_thd); DBUG_VOID_RETURN; + } decimals= field->decimals(); max_length= field->field_length; maybe_null= 1; diff --git a/sql/item_func.h b/sql/item_func.h index e0f14ceac75..f6bc35e1617 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -116,7 +116,7 @@ public: Item_func(List<Item> &list); // Constructor used for Item_cond_and/or (see Item comment) Item_func(THD *thd, Item_func *item); - bool fix_fields(THD *,struct st_table_list *, Item **ref); + bool fix_fields(THD *, Item **ref); table_map used_tables() const; table_map not_null_tables() const; void update_used_tables(); @@ -630,7 +630,7 @@ public: const char *func_name() const { return "rand"; } bool const_item() const { return 0; } void update_used_tables(); - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); }; @@ -885,14 +885,15 @@ protected: udf_handler udf; public: - Item_udf_func(udf_func *udf_arg) :Item_func(), udf(udf_arg) {} + Item_udf_func(udf_func *udf_arg) + :Item_func(), udf(udf_arg) {} Item_udf_func(udf_func *udf_arg, List<Item> &list) :Item_func(list), udf(udf_arg) {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - bool res= udf.fix_fields(thd, tables, this, arg_count, args); + bool res= udf.fix_fields(thd, this, arg_count, args); used_tables_cache= udf.used_tables_cache; const_item_cache= udf.const_item_cache; fixed= 1; @@ -907,9 +908,11 @@ public: class Item_func_udf_float :public Item_udf_func { public: - Item_func_udf_float(udf_func *udf_arg) :Item_udf_func(udf_arg) {} - Item_func_udf_float(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + Item_func_udf_float(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} + Item_func_udf_float(udf_func *udf_arg, + List<Item> &list) + :Item_udf_func(udf_arg, list) {} longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -932,9 +935,11 @@ class Item_func_udf_float :public Item_udf_func class Item_func_udf_int :public Item_udf_func { public: - Item_func_udf_int(udf_func *udf_arg) :Item_udf_func(udf_arg) {} - Item_func_udf_int(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + Item_func_udf_int(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} + Item_func_udf_int(udf_func *udf_arg, + List<Item> &list) + :Item_udf_func(udf_arg, list) {} longlong val_int(); double val_real() { return (double) Item_func_udf_int::val_int(); } String *val_str(String *str); @@ -946,9 +951,10 @@ public: class Item_func_udf_decimal :public Item_udf_func { public: - Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_decimal(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + :Item_udf_func(udf_arg, list) {} longlong val_int(); double val_real(); my_decimal *val_decimal(my_decimal *); @@ -961,9 +967,10 @@ public: class Item_func_udf_str :public Item_udf_func { public: - Item_func_udf_str(udf_func *udf_arg) :Item_udf_func(udf_arg) {} + Item_func_udf_str(udf_func *udf_arg) + :Item_udf_func(udf_arg) {} Item_func_udf_str(udf_func *udf_arg, List<Item> &list) - :Item_udf_func(udf_arg,list) {} + :Item_udf_func(udf_arg, list) {} String *val_str(String *); double val_real() { @@ -998,8 +1005,10 @@ public: class Item_func_udf_float :public Item_real_func { public: - Item_func_udf_float(udf_func *udf_arg) :Item_real_func() {} - Item_func_udf_float(udf_func *udf_arg, List<Item> &list) :Item_real_func(list) {} + Item_func_udf_float(udf_func *udf_arg) + :Item_real_func() {} + Item_func_udf_float(udf_func *udf_arg, List<Item> &list) + :Item_real_func(list) {} double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } }; @@ -1007,8 +1016,10 @@ class Item_func_udf_float :public Item_real_func class Item_func_udf_int :public Item_int_func { public: - Item_func_udf_int(udf_func *udf_arg) :Item_int_func() {} - Item_func_udf_int(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + Item_func_udf_int(udf_func *udf_arg) + :Item_int_func() {} + Item_func_udf_int(udf_func *udf_arg, List<Item> &list) + :Item_int_func(list) {} longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -1016,8 +1027,10 @@ public: class Item_func_udf_decimal :public Item_int_func { public: - Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {} - Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {} + Item_func_udf_decimal(udf_func *udf_arg) + :Item_int_func() {} + Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_int_func(list) {} my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } }; @@ -1025,8 +1038,10 @@ public: class Item_func_udf_str :public Item_func { public: - Item_func_udf_str(udf_func *udf_arg) :Item_func() {} - Item_func_udf_str(udf_func *udf_arg, List<Item> &list) :Item_func(list) {} + Item_func_udf_str(udf_func *udf_arg) + :Item_func() {} + Item_func_udf_str(udf_func *udf_arg, List<Item> &list) + :Item_func(list) {} String *val_str(String *) { DBUG_ASSERT(fixed == 1); null_value=1; return 0; } double val_real() { DBUG_ASSERT(fixed == 1); null_value= 1; return 0.0; } @@ -1116,7 +1131,7 @@ public: bool check(); bool update(); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); void print(String *str); void print_as_stmt(String *str); @@ -1176,7 +1191,7 @@ public: String *val_str(String *str); my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ - bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void print(String *str); void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); @@ -1230,7 +1245,7 @@ public: const char *func_name() const { return "match"; } void update_used_tables() {} table_map not_null_tables() const { return 0; } - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); + bool fix_fields(THD *thd, Item **ref); bool eq(const Item *, bool binary_cmp) const; /* The following should be safe, even if we compare doubles */ longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; } @@ -1302,6 +1317,7 @@ class sp_name; class Item_func_sp :public Item_func { private: + Name_resolution_context *context; sp_name *m_name; mutable sp_head *m_sp; TABLE *dummy_table; @@ -1314,9 +1330,10 @@ private: public: - Item_func_sp(sp_name *name); + Item_func_sp(Name_resolution_context *context_arg, sp_name *name); - Item_func_sp(sp_name *name, List<Item> &list); + Item_func_sp(Name_resolution_context *context_arg, + sp_name *name, List<Item> &list); virtual ~Item_func_sp() {} @@ -1361,6 +1378,9 @@ public: return result_field->val_str(str); } + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } + void fix_length_and_dec(); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index 0c8baa332ca..9362518e6ef 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -53,7 +53,7 @@ void Item_row::illegal_method_call(const char *method) DBUG_VOID_RETURN; } -bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) +bool Item_row::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); null_value= 0; @@ -61,7 +61,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) Item **arg, **arg_end; for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++) { - if ((*arg)->fix_fields(thd, tabl, arg)) + if ((*arg)->fix_fields(thd, arg)) return TRUE; // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; diff --git a/sql/item_row.h b/sql/item_row.h index e6b23eebb49..6fbe7436b72 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -61,7 +61,7 @@ public: illegal_method_call((const char*)"val_decimal"); return 0; }; - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); table_map used_tables() const { return used_tables_cache; }; bool const_item() const { return const_item_cache; }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 06239de1f99..1ad65fb6208 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -371,8 +371,8 @@ String *Item_func_des_encrypt::val_str(String *str) uint key_number, res_length, tail; String *res= args[0]->val_str(str); - if ((null_value=args[0]->null_value)) - goto error; + if ((null_value= args[0]->null_value)) + return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) return &my_empty_string; @@ -461,10 +461,10 @@ String *Item_func_des_decrypt::val_str(String *str) struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; String *res= args[0]->val_str(str); - uint length=res->length(),tail; + uint length= 0, tail; if ((null_value=args[0]->null_value)) - goto error; + return 0; length=res->length(); if (length < 9 || (length % 8) != 1 || !((*res)[0] & 128)) return res; // Skip decryption if not encrypted diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index c4beb3b08cb..d85210984d9 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -95,6 +95,7 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "concat_ws"; } + table_map not_null_tables() const { return 0; } }; class Item_func_reverse :public Item_str_func @@ -415,12 +416,12 @@ class Item_func_make_set :public Item_str_func public: Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {} String *val_str(String *str); - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - return ((!item->fixed && item->fix_fields(thd, tlist, &item)) || + return ((!item->fixed && item->fix_fields(thd, &item)) || item->check_cols(1) || - Item_func::fix_fields(thd, tlist, ref)); + Item_func::fix_fields(thd, ref)); } void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); void fix_length_and_dec(); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7ea72f3c858..ad1c9977e5b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -130,7 +130,7 @@ Item_subselect::select_transformer(JOIN *join) } -bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) +bool Item_subselect::fix_fields(THD *thd_param, Item **ref) { char const *save_where= thd_param->where; bool res; @@ -165,7 +165,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) substitution= 0; thd->where= "checking transformed subquery"; if (!(*ref)->fixed) - ret= (*ref)->fix_fields(thd, tables, ref); + ret= (*ref)->fix_fields(thd, ref); thd->where= save_where; return ret; } @@ -194,15 +194,8 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) bool Item_subselect::exec() { int res; - MEM_ROOT *old_root= thd->mem_root; - /* - As this is execution, all objects should be allocated through the main - mem root - */ - thd->mem_root= &thd->main_mem_root; res= engine->exec(); - thd->mem_root= old_root; if (engine_changed) { @@ -840,7 +833,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, reference, also Item_sum_(max|min) can't be fixed after creation, so we do not check item->fixed */ - if (item->fix_fields(thd, join->tables_list, 0)) + if (item->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); /* we added aggregate function => we have to change statistic */ count_field_types(&join->tmp_table_param, join->all_fields, 0); @@ -869,7 +862,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, thd->lex->current_select= up= current->return_after_parsing(); //optimizer never use Item **ref => we can pass 0 as parameter - if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) + if (!optimizer || optimizer->fix_left(thd, 0)) { thd->lex->current_select= current; DBUG_RETURN(RES_ERROR); @@ -880,7 +873,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, As far as Item_ref_in_optimizer do not substitute itself on fix_fields we can use same item for all selects. */ - expr= new Item_direct_ref((Item**)optimizer->get_cache(), + expr= new Item_direct_ref(&select_lex->context, + (Item**)optimizer->get_cache(), (char *)"<no matter>", (char *)in_left_expr_name); @@ -900,7 +894,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, { bool tmp; Item *item= func->create(expr, - new Item_ref_null_helper(this, + new Item_ref_null_helper(&select_lex->context, + this, select_lex-> ref_pointer_array, (char *)"<ref>", @@ -920,7 +915,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, we do not check join->having->fixed, because Item_and (from and_items) or comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -956,7 +951,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, and_items) or comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -978,7 +973,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, we do not check join->conds->fixed, because Item_and can't be fixed after creation */ - if (join->conds->fix_fields(thd, join->tables_list, 0)) + if (join->conds->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); } else @@ -990,22 +985,23 @@ Item_in_subselect::single_value_transformer(JOIN *join, comparison functions can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() - */ - item= func->create(expr, - new Item_null_helper(this, item, - (char *)"<no matter>", - (char *)"<result>")); + */ + item= func->create(expr, + new Item_null_helper(&select_lex->context, + this, item, + (char *)"<no matter>", + (char *)"<result>")); #ifdef CORRECT_BUT_TOO_SLOW_TO_BE_USABLE if (!abort_on_null && left_expr->maybe_null) item= new Item_cond_or(new Item_func_isnull(left_expr), item); #endif - select_lex->having= join->having= item; + select_lex->having= join->having= item; select_lex->having_fix_field= 1; /* we do not check join->having->fixed, because comparison function (from func->create) can't be fixed after creation */ - tmp= join->having->fix_fields(thd, join->tables_list, 0); + tmp= join->having->fix_fields(thd, 0); select_lex->having_fix_field= 0; if (tmp) DBUG_RETURN(RES_ERROR); @@ -1055,7 +1051,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) SELECT_LEX *current= thd->lex->current_select, *up; thd->lex->current_select= up= current->return_after_parsing(); //optimizer never use Item **ref => we can pass 0 as parameter - if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) + if (!optimizer || optimizer->fix_left(thd, 0)) { thd->lex->current_select= current; DBUG_RETURN(RES_ERROR); @@ -1078,12 +1074,14 @@ Item_in_subselect::row_value_transformer(JOIN *join) if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->el(i)->cols())) DBUG_RETURN(RES_ERROR); - Item *func= new Item_ref_null_helper(this, + Item *func= new Item_ref_null_helper(&select_lex->context, + this, select_lex->ref_pointer_array+i, (char *) "<no matter>", (char *) "<list ref>"); func= - eq_creator.create(new Item_direct_ref((*optimizer->get_cache())-> + eq_creator.create(new Item_direct_ref(&select_lex->context, + (*optimizer->get_cache())-> addr(i), (char *)"<no matter>", (char *)in_left_expr_name), @@ -1106,7 +1104,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) join->having can't be fixed after creation, so we do not check join->having->fixed */ - if (join->having->fix_fields(thd, join->tables_list, 0)) + if (join->having->fix_fields(thd, 0)) { select_lex->having_fix_field= 0; DBUG_RETURN(RES_ERROR); @@ -1125,7 +1123,7 @@ Item_in_subselect::row_value_transformer(JOIN *join) join->conds can't be fixed after creation, so we do not check join->conds->fixed */ - if (join->conds->fix_fields(thd, join->tables_list, 0)) + if (join->conds->fix_fields(thd, 0)) DBUG_RETURN(RES_ERROR); } @@ -1196,8 +1194,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) thd->lex->current_select= up= current->return_after_parsing(); result= (!left_expr->fixed && - left_expr->fix_fields(thd, up->get_table_list(), - optimizer->arguments())); + left_expr->fix_fields(thd, optimizer->arguments())); /* fix_fields can change reference to left_expr, we need reassign it */ left_expr= optimizer->arguments()[0]; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 84935429353..e05db4a00cc 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -92,7 +92,7 @@ public: val_int(); return null_value; } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool fix_fields(THD *thd, Item **ref); virtual bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; @@ -119,9 +119,9 @@ public: friend class select_subselect; friend class Item_in_optimizer; - friend bool Item_field::fix_fields(THD *, TABLE_LIST *, Item **); - friend bool Item_ref::fix_fields(THD *, TABLE_LIST *, Item **); - friend bool Item_param::fix_fields(THD *, TABLE_LIST *, Item **); + friend bool Item_field::fix_fields(THD *, Item **); + friend bool Item_ref::fix_fields(THD *, Item **); + friend bool Item_param::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, Field*, Item*, Item_ident*); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 76f94801b49..d2f1016891b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -193,7 +193,7 @@ my_decimal *Item_sum_int::val_decimal(my_decimal *decimal_value) bool -Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_sum_num::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -208,7 +208,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) maybe_null=0; for (uint i=0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1)) + if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) return TRUE; set_if_bigger(decimals, args[i]->decimals); maybe_null |= args[i]->maybe_null; @@ -253,7 +253,7 @@ Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) } bool -Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_sum_hybrid::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); @@ -268,7 +268,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) // 'item' can be changed during fix_fields if (!item->fixed && - item->fix_fields(thd, tables, args) || + item->fix_fields(thd, args) || (item= args[0])->check_cols(1)) return TRUE; decimals=item->decimals; @@ -2766,11 +2766,12 @@ int dump_leaf_key(byte* key, element_count count __attribute__((unused)), */ Item_func_group_concat:: -Item_func_group_concat(bool distinct_arg, List<Item> *select_list, +Item_func_group_concat(Name_resolution_context *context_arg, + bool distinct_arg, List<Item> *select_list, SQL_LIST *order_list, String *separator_arg) :tmp_table_param(0), warning(0), separator(separator_arg), tree(0), table(0), - order(0), tables_list(0), + order(0), context(context_arg), arg_count_order(order_list ? order_list->elements : 0), arg_count_field(select_list->elements), count_cut_values(0), @@ -2826,7 +2827,7 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, tree(item->tree), table(item->table), order(item->order), - tables_list(item->tables_list), + context(item->context), arg_count_order(item->arg_count_order), arg_count_field(item->arg_count_field), count_cut_values(item->count_cut_values), @@ -2946,7 +2947,7 @@ bool Item_func_group_concat::add() bool -Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +Item_func_group_concat::fix_fields(THD *thd, Item **ref) { uint i; /* for loop variable */ DBUG_ASSERT(fixed == 0); @@ -2968,7 +2969,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) for (i=0 ; i < arg_count ; i++) { if ((!args[i]->fixed && - args[i]->fix_fields(thd, tables, args + i)) || + args[i]->fix_fields(thd, args + i)) || args[i]->check_cols(1)) return TRUE; if (i < arg_count_field) @@ -2979,7 +2980,6 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) null_value= 1; thd->allow_sum_func= 1; max_length= thd->variables.group_concat_max_len; - tables_list= tables; fixed= 1; return FALSE; } @@ -3029,7 +3029,7 @@ bool Item_func_group_concat::setup(THD *thd) tmp table columns. */ if (arg_count_order && - setup_order(thd, args, tables_list, list, all_fields, *order)) + setup_order(thd, args, context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); count_field_types(tmp_table_param,all_fields,0); diff --git a/sql/item_sum.h b/sql/item_sum.h index b9a90ee5de5..b02d18e9a55 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -98,7 +98,7 @@ public: */ virtual const char *func_name() const= 0; virtual Item *result_item(Field *field) - { return new Item_field(field);} + { return new Item_field(field); } table_map used_tables() const { return ~(table_map) 0; } /* Not used */ bool const_item() const { return 0; } bool is_null() { return null_value; } @@ -124,7 +124,7 @@ public: Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} Item_sum_num(THD *thd, Item_sum_num *item) :Item_sum(thd, item) {} - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -543,7 +543,7 @@ protected: was_values(TRUE) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item); - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -660,18 +660,21 @@ protected: udf_handler udf; public: - Item_udf_sum(udf_func *udf_arg) :Item_sum(), udf(udf_arg) { quick_group=0;} - Item_udf_sum( udf_func *udf_arg, List<Item> &list ) - :Item_sum( list ), udf(udf_arg) + Item_udf_sum(udf_func *udf_arg) + :Item_sum(), udf(udf_arg) + { quick_group=0; } + Item_udf_sum(udf_func *udf_arg, List<Item> &list) + :Item_sum(list), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } + :Item_sum(thd, item), udf(item->udf) + { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; - return udf.fix_fields(thd,tables,this,this->arg_count,this->args); + return udf.fix_fields(thd, this, this->arg_count, this->args); } enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } virtual bool have_field_update(void) const { return 0; } @@ -688,9 +691,10 @@ public: class Item_sum_udf_float :public Item_udf_sum { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_udf_sum(thd, item) {} longlong val_int() @@ -709,9 +713,10 @@ class Item_sum_udf_float :public Item_udf_sum class Item_sum_udf_int :public Item_udf_sum { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_udf_sum(thd, item) {} longlong val_int(); @@ -728,7 +733,8 @@ public: class Item_sum_udf_str :public Item_udf_sum { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_udf_sum(udf_arg,list) {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) @@ -766,9 +772,10 @@ public: class Item_sum_udf_decimal :public Item_udf_sum { public: - Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {} + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_udf_sum(udf_arg) {} Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) - :Item_udf_sum(udf_arg,list) {} + :Item_udf_sum(udf_arg, list) {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item) :Item_udf_sum(thd, item) {} String *val_str(String *); @@ -785,7 +792,8 @@ public: class Item_sum_udf_float :public Item_sum_num { public: - Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_float(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} Item_sum_udf_float(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} @@ -800,7 +808,8 @@ class Item_sum_udf_float :public Item_sum_num class Item_sum_udf_int :public Item_sum_num { public: - Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {} + Item_sum_udf_int(udf_func *udf_arg) + :Item_sum_num() {} Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} Item_sum_udf_int(THD *thd, Item_sum_udf_int *item) :Item_sum_num(thd, item) {} @@ -816,15 +825,17 @@ public: class Item_sum_udf_decimal :public Item_sum_num { public: - Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) + :Item_sum_num() {} Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item) :Item_sum_num(thd, item) {} enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; } double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; } my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; } void clear() {} - bool add() { return 0; } + bool add() { return 0; } void update_field() {} }; @@ -832,8 +843,10 @@ class Item_sum_udf_decimal :public Item_sum_num class Item_sum_udf_str :public Item_sum_num { public: - Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {} - Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg) + :Item_sum_num() {} + Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) + :Item_sum_num() {} Item_sum_udf_str(THD *thd, Item_sum_udf_str *item) :Item_sum_num(thd, item) {} String *val_str(String *) @@ -862,7 +875,7 @@ class Item_func_group_concat : public Item_sum TREE *tree; TABLE *table; ORDER **order; - TABLE_LIST *tables_list; + Name_resolution_context *context; uint arg_count_order; // total count of ORDER BY items uint arg_count_field; // count of arguments uint count_cut_values; @@ -887,8 +900,9 @@ class Item_func_group_concat : public Item_sum Item_func_group_concat *group_concat_item); public: - Item_func_group_concat(bool is_distinct,List<Item> *is_select, - SQL_LIST *is_order,String *is_separator); + Item_func_group_concat(Name_resolution_context *context_arg, + bool is_distinct, List<Item> *is_select, + SQL_LIST *is_order, String *is_separator); Item_func_group_concat(THD *thd, Item_func_group_concat *item); ~Item_func_group_concat() {} @@ -901,7 +915,7 @@ public: bool add(); void reset_field() {} // not used void update_field() {} // not used - bool fix_fields(THD *, TABLE_LIST *, Item **); + bool fix_fields(THD *,Item **); bool setup(THD *thd); void make_unique(); double val_real() @@ -927,4 +941,6 @@ public: Item *copy_or_same(THD* thd); void no_rows_in_result() {} void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 19386c15835..cac9613f1ad 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1753,10 +1753,10 @@ void Item_func_convert_tz::fix_length_and_dec() bool -Item_func_convert_tz::fix_fields(THD *thd_arg, TABLE_LIST *tables_arg, Item **ref) +Item_func_convert_tz::fix_fields(THD *thd_arg, Item **ref) { String str; - if (Item_date_func::fix_fields(thd_arg, tables_arg, ref)) + if (Item_date_func::fix_fields(thd_arg, ref)) return TRUE; tz_tables= thd_arg->lex->time_zone_tables_used; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a6dd9f7da91..107d12e6da2 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -561,7 +561,7 @@ class Item_func_convert_tz :public Item_date_func double val_real() { return (double) val_int(); } String *val_str(String *str); const char *func_name() const { return "convert_tz"; } - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void fix_length_and_dec(); bool get_date(TIME *res, uint fuzzy_date); void cleanup(); diff --git a/sql/item_uniq.h b/sql/item_uniq.h index e95aa35101e..c884c454dac 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -47,7 +47,7 @@ public: bool add() { return 0; } void reset_field() {} void update_field() {} - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) + bool fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); fixed= 1; diff --git a/sql/lex.h b/sql/lex.h index d0dc287775e..aa10328ced0 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -214,7 +214,9 @@ static SYMBOL symbols[] = { { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)}, { "GET_FORMAT", SYM(GET_FORMAT)}, { "GLOBAL", SYM(GLOBAL_SYM)}, +#ifdef SP_GOTO { "GOTO", SYM(GOTO_SYM)}, +#endif { "GRANT", SYM(GRANT)}, { "GRANTS", SYM(GRANTS)}, { "GROUP", SYM(GROUP)}, @@ -262,7 +264,10 @@ static SYMBOL symbols[] = { { "KEY", SYM(KEY_SYM)}, { "KEYS", SYM(KEYS)}, { "KILL", SYM(KILL_SYM)}, +#ifdef SP_GOTO + /* QQ This will go away when the GOTO label syntax is fixed */ { "LABEL", SYM(LABEL_SYM)}, +#endif { "LANGUAGE", SYM(LANGUAGE_SYM)}, { "LAST", SYM(LAST_SYM)}, { "LEADING", SYM(LEADING)}, diff --git a/sql/log_event.cc b/sql/log_event.cc index 8f109f00c5f..5a612791cdd 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2618,13 +2618,15 @@ void Load_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev #ifndef MYSQL_CLIENT void Load_log_event::set_fields(const char* affected_db, - List<Item> &field_list) + List<Item> &field_list, + Name_resolution_context *context) { uint i; const char* field = fields; for (i= 0; i < num_fields; i++) { - field_list.push_back(new Item_field(affected_db, table_name, field)); + field_list.push_back(new Item_field(context, + affected_db, table_name, field)); field+= field_lens[i] + 1; } } @@ -2789,7 +2791,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, ex.skip_lines = skip_lines; List<Item> field_list; - set_fields(thd->db,field_list); + thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables); + set_fields(thd->db, field_list, &thd->main_lex.select_lex.context); thd->variables.pseudo_thread_id= thread_id; List<Item> set_fields; if (net) @@ -3617,7 +3620,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - e.fix_fields(thd, 0, 0); + e.fix_fields(thd, 0); /* A variable can just be considered as a table with a single record and with a single column. Thus, like diff --git a/sql/log_event.h b/sql/log_event.h index b163a37e7cc..9f4681ae2c5 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -877,7 +877,8 @@ public: const char* table_name_arg, List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore, bool using_trans); - void set_fields(const char* db, List<Item> &fields_arg); + void set_fields(const char* db, List<Item> &fields_arg, + Name_resolution_context *context); const char* get_db() { return db; } #ifdef HAVE_REPLICATION void pack_info(Protocol* protocol); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2add9ac9269..9a3684c3865 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -667,6 +667,7 @@ int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t); Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, bool group, bool modify_item, + bool table_cant_handle_bit_fields, uint convert_blob_length); void sp_prepare_create_field(THD *thd, create_field *sql_field); int prepare_create_field(create_field *sql_field, @@ -725,7 +726,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields, List<List_item> &values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates flag, bool ignore); -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry); +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list); bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order, ha_rows rows, ulong options); @@ -756,7 +758,8 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Item **ref, find_item_error_report_type report_error, - bool check_privileges); + bool check_privileges, + bool register_tree_change); Field * find_field_in_table(THD *thd, TABLE_LIST *table_list, const char *name, const char *item_name, @@ -892,16 +895,29 @@ Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter, bool *unaliased); bool get_key_map_from_key_list(key_map *map, TABLE *table, List<String> *index_list); -bool insert_fields(THD *thd,TABLE_LIST *tables, +bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, - List_iterator<Item> *it, bool any_privileges); -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, + List_iterator<Item> *it, bool any_privileges); +bool setup_tables(THD *thd, Name_resolution_context *context, + TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert); 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, TABLE_LIST *tables, +bool setup_fields(THD *thd, Item** ref_pointer_array, List<Item> &item, bool set_query_id, List<Item> *sum_func_list, bool allow_sum_func); +inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array, + List<Item> &item, bool set_query_id, + List<Item> *sum_func_list, + bool allow_sum_func) +{ + bool res; + thd->lex->select_lex.no_wrap_view_item= TRUE; + res= setup_fields(thd, ref_pointer_array, item, set_query_id, sum_func_list, + allow_sum_func); + thd->lex->select_lex.no_wrap_view_item= FALSE; + return res; +} int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); int setup_ftfuncs(SELECT_LEX* select); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 915668aa7b1..78d9af387da 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -140,6 +140,7 @@ int deny_severity = LOG_WARNING; #define zVOLSTATE_DEACTIVE 2 #define zVOLSTATE_MAINTENANCE 3 +#include <nks/netware.h> #include <nks/vm.h> #include <library.h> #include <monitor.h> @@ -5386,7 +5387,7 @@ The minimum value for this variable is 4096.", "Default pointer size to be used for MyISAM tables.", (gptr*) &myisam_data_pointer_size, (gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, - 6, 2, 8, 0, 1, 0}, + 6, 2, 7, 0, 1, 0}, {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, "Deprecated option", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, @@ -6358,9 +6359,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_SLOW_QUERY_LOG: opt_slow_log=1; break; - case (int) OPT_LOG_SLOW_ADMIN_STATEMENTS: - opt_log_slow_admin_statements= 1; - break; case (int) OPT_SKIP_NEW: opt_specialflag|= SPECIAL_NO_NEW_FUNC; delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 65db1a290f6..c2760b08b6e 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -325,7 +325,7 @@ typedef struct st_qsel_param { TABLE *table; KEY_PART *key_parts,*key_parts_end; KEY_PART *key[MAX_KEY]; /* First key parts of keys used in the query */ - MEM_ROOT *mem_root; + MEM_ROOT *mem_root, *old_root; table_map prev_tables,read_tables,current_table; uint baseflag, max_key_part, range_count; @@ -1665,7 +1665,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, keys_to_use.intersect(head->keys_in_use_for_query); if (!keys_to_use.is_clear_all()) { - MEM_ROOT *old_root,alloc; + MEM_ROOT alloc; SEL_TREE *tree= NULL; KEY_PART *key_parts; KEY *key_info; @@ -1680,6 +1680,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.table=head; param.keys=0; param.mem_root= &alloc; + param.old_root= thd->mem_root; param.needed_reg= &needed_reg; param.imerge_cost_buff_size= 0; @@ -1695,7 +1696,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, DBUG_RETURN(0); // Can't use range } key_parts= param.key_parts; - old_root= thd->mem_root; thd->mem_root= &alloc; /* @@ -1845,7 +1845,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, } } - thd->mem_root= old_root; + thd->mem_root= param.old_root; /* If we got a read plan, create a quick select from it. */ if (best_trp) @@ -1860,7 +1860,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, free_mem: free_root(&alloc,MYF(0)); // Return memory & allocator - thd->mem_root= old_root; + thd->mem_root= param.old_root; thd->no_errors=0; } @@ -3578,15 +3578,16 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) DBUG_RETURN(ftree); } default: - if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM) + if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM) { - field_item= (Item_field*) (cond_func->arguments()[0]); + field_item= (Item_field*) (cond_func->arguments()[0]->real_item()); value= cond_func->arg_count > 1 ? cond_func->arguments()[1] : 0; } else if (cond_func->have_rev_func() && - cond_func->arguments()[1]->type() == Item::FIELD_ITEM) + cond_func->arguments()[1]->real_item()->type() == + Item::FIELD_ITEM) { - field_item= (Item_field*) (cond_func->arguments()[1]); + field_item= (Item_field*) (cond_func->arguments()[1]->real_item()); value= cond_func->arguments()[0]; } else @@ -3607,7 +3608,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) for (uint i= 0; i < cond_func->arg_count; i++) { - Item *arg= cond_func->arguments()[i]; + Item *arg= cond_func->arguments()[i]->real_item(); if (arg != field_item) ref_tables|= arg->used_tables(); } @@ -3692,24 +3693,38 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, { uint maybe_null=(uint) field->real_maybe_null(); bool optimize_range; - SEL_ARG *tree; + SEL_ARG *tree= 0; + MEM_ROOT *alloc= param->mem_root; char *str; DBUG_ENTER("get_mm_leaf"); + /* + We need to restore the runtime mem_root of the thread in this + function because it evaluates the value of its argument, while + the argument can be any, e.g. a subselect. The subselect + items, in turn, assume that all the memory allocated during + the evaluation has the same life span as the item itself. + TODO: opt_range.cc should not reset thd->mem_root at all. + */ + param->thd->mem_root= param->old_root; if (!value) // IS NULL or IS NOT NULL { if (field->table->maybe_null) // Can't use a key on this - DBUG_RETURN(0); + goto end; if (!maybe_null) // Not null field - DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0); - if (!(tree=new SEL_ARG(field,is_null_string,is_null_string))) - DBUG_RETURN(0); // out of memory + { + if (type == Item_func::ISNULL_FUNC) + tree= &null_element; + goto end; + } + if (!(tree= new (alloc) SEL_ARG(field,is_null_string,is_null_string))) + goto end; // out of memory if (type == Item_func::ISNOTNULL_FUNC) { tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */ tree->max_flag=NO_MAX_RANGE; } - DBUG_RETURN(tree); + goto end; } /* @@ -3729,7 +3744,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, key_part->image_type == Field::itRAW && ((Field_str*)field)->charset() != conf_func->compare_collation() && !(conf_func->compare_collation()->state & MY_CS_BINSORT)) - DBUG_RETURN(0); + goto end; optimize_range= field->optimize_range(param->real_keynr[key_part->key], key_part->part); @@ -3743,9 +3758,12 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, uint field_length= field->pack_length()+maybe_null; if (!optimize_range) - DBUG_RETURN(0); // Can't optimize this + goto end; if (!(res= value->val_str(&tmp))) - DBUG_RETURN(&null_element); + { + tree= &null_element; + goto end; + } /* TODO: @@ -3758,7 +3776,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, res= &tmp; } if (field->cmp_type() != STRING_RESULT) - DBUG_RETURN(0); // Can only optimize strings + goto end; // Can only optimize strings offset=maybe_null; length=key_part->store_length; @@ -3783,8 +3801,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, field_length= length; } length+=offset; - if (!(min_str= (char*) alloc_root(param->mem_root, length*2))) - DBUG_RETURN(0); + if (!(min_str= (char*) alloc_root(alloc, length*2))) + goto end; max_str=min_str+length; if (maybe_null) @@ -3799,20 +3817,21 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, min_str+offset, max_str+offset, &min_length, &max_length); if (like_error) // Can't optimize with LIKE - DBUG_RETURN(0); + goto end; if (offset != maybe_null) // BLOB or VARCHAR { int2store(min_str+maybe_null,min_length); int2store(max_str+maybe_null,max_length); } - DBUG_RETURN(new SEL_ARG(field,min_str,max_str)); + tree= new (alloc) SEL_ARG(field, min_str, max_str); + goto end; } if (!optimize_range && type != Item_func::EQ_FUNC && type != Item_func::EQUAL_FUNC) - DBUG_RETURN(0); // Can't optimize this + goto end; // Can't optimize this /* We can't always use indexes when comparing a string index to a number @@ -3821,21 +3840,22 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, if (field->result_type() == STRING_RESULT && value->result_type() != STRING_RESULT && field->cmp_type() != value->result_type()) - DBUG_RETURN(0); + goto end; if (value->save_in_field_no_warnings(field, 1) < 0) { /* This happens when we try to insert a NULL field in a not null column */ - DBUG_RETURN(&null_element); // cmp with NULL is never TRUE + tree= &null_element; // cmp with NULL is never TRUE + goto end; } - str= (char*) alloc_root(param->mem_root, key_part->store_length+1); + str= (char*) alloc_root(alloc, key_part->store_length+1); if (!str) - DBUG_RETURN(0); + goto end; if (maybe_null) *str= (char) field->is_real_null(); // Set to 1 if null field->get_key_image(str+maybe_null, key_part->length, key_part->image_type); - if (!(tree=new SEL_ARG(field,str,str))) - DBUG_RETURN(0); // out of memory + if (!(tree= new (alloc) SEL_ARG(field, str, str))) + goto end; // out of memory /* Check if we are comparing an UNSIGNED integer with a negative constant. @@ -3848,9 +3868,8 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, negative integers (which otherwise fails because at query execution time negative integers are cast to unsigned if compared with unsigned). */ - Item_result field_result_type= field->result_type(); - Item_result value_result_type= value->result_type(); - if (field_result_type == INT_RESULT && value_result_type == INT_RESULT && + if (field->result_type() == INT_RESULT && + value->result_type() == INT_RESULT && ((Field_num*)field)->unsigned_flag && !((Item_int*)value)->unsigned_flag) { longlong item_val= value->val_int(); @@ -3859,10 +3878,13 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, if (type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) { tree->type= SEL_ARG::IMPOSSIBLE; - DBUG_RETURN(tree); + goto end; } if (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC) - DBUG_RETURN(0); + { + tree= 0; + goto end; + } } } @@ -3925,6 +3947,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, default: break; } + +end: + param->thd->mem_root= alloc; DBUG_RETURN(tree); } diff --git a/sql/protocol.cc b/sql/protocol.cc index 1c399a89a99..ade94a483a8 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -28,6 +28,7 @@ #include <stdarg.h> static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024; +static void write_eof_packet(THD *thd, NET *net); #ifndef EMBEDDED_LIBRARY bool Protocol::net_store_data(const char *from, uint length) @@ -362,43 +363,52 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ */ void -send_eof(THD *thd, bool no_flush) +send_eof(THD *thd) { NET *net= &thd->net; DBUG_ENTER("send_eof"); if (net->vio != 0 && !net->no_send_eof) { - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - uchar buff[5]; - /* Don't send warn count during SP execution, as the warn_list - is cleared between substatements, and mysqltest gets confused */ - uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); - buff[0]=254; - int2store(buff+1, tmp); - /* - The following test should never be true, but it's better to do it - because if 'is_fatal_error' is set the server is not going to execute - other queries (see the if test in dispatch_command / COM_QUERY) - */ - if (thd->is_fatal_error) - thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; - int2store(buff+3, thd->server_status); - VOID(my_net_write(net,(char*) buff,5)); - VOID(net_flush(net)); - } - else - { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) - VOID(net_flush(net)); - } + write_eof_packet(thd, net); + VOID(net_flush(net)); thd->net.no_send_error= 1; DBUG_PRINT("info", ("EOF sent, so no more error sending allowed")); } DBUG_VOID_RETURN; } + +/* + Format EOF packet according to the current protocol and + write it to the network output buffer. +*/ + +static void write_eof_packet(THD *thd, NET *net) +{ + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + uchar buff[5]; + /* + Don't send warn count during SP execution, as the warn_list + is cleared between substatements, and mysqltest gets confused + */ + uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535)); + buff[0]= 254; + int2store(buff+1, tmp); + /* + The following test should never be true, but it's better to do it + because if 'is_fatal_error' is set the server is not going to execute + other queries (see the if test in dispatch_command / COM_QUERY) + */ + if (thd->is_fatal_error) + thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; + int2store(buff+3, thd->server_status); + VOID(my_net_write(net, (char*) buff, 5)); + } + else + VOID(my_net_write(net, eof_buff, 1)); +} + /* Please client to send scrambled_password in old format. SYNOPSYS @@ -640,7 +650,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags) } if (flags & SEND_EOF) - my_net_write(&thd->net, eof_buff, 1); + write_eof_packet(thd, &thd->net); DBUG_RETURN(prepare_for_send(list)); err: diff --git a/sql/protocol.h b/sql/protocol.h index 5b402cb2669..2717d2258fa 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -179,7 +179,7 @@ void net_printf_error(THD *thd, uint sql_errno, ...); void net_send_error(THD *thd, uint sql_errno=0, const char *err=0); void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); -void send_eof(THD *thd, bool no_flush=0); +void send_eof(THD *thd); bool send_old_password_request(THD *thd); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); diff --git a/sql/set_var.cc b/sql/set_var.cc index 1c0de702e4e..3f991713eb7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1617,7 +1617,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { if (!(res= var->value->val_str(&str))) { - strmake(buff, "NULL", 4); + strmov(buff, "NULL"); goto err; } var->save_result.ulong_value= ((ulong) @@ -2983,7 +2983,7 @@ int set_var::check(THD *thd) } if ((!value->fixed && - value->fix_fields(thd, 0, &value)) || value->check_cols(1)) + value->fix_fields(thd, &value)) || value->check_cols(1)) return -1; if (var->check_update_type(value->result_type())) { @@ -3017,7 +3017,7 @@ int set_var::light_check(THD *thd) if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)) return 1; - if (value && ((!value->fixed && value->fix_fields(thd, 0, &value)) || + if (value && ((!value->fixed && value->fix_fields(thd, &value)) || value->check_cols(1))) return -1; return 0; @@ -3046,7 +3046,7 @@ int set_var_user::check(THD *thd) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - return (user_var_item->fix_fields(thd, 0, (Item**) 0) || + return (user_var_item->fix_fields(thd, (Item**) 0) || user_var_item->check()) ? -1 : 0; } @@ -3069,7 +3069,7 @@ int set_var_user::light_check(THD *thd) Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) */ - return (user_var_item->fix_fields(thd, 0, (Item**) 0)); + return (user_var_item->fix_fields(thd, (Item**) 0)); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 7ae5130764f..747e7031530 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5358,3 +5358,5 @@ ER_STMT_HAS_NO_OPEN_CURSOR eng "The statement (%lu) has no open cursor." ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG eng "Explicit or implicit commit is not allowed in stored function or trigger." +ER_NO_DEFAULT_FOR_VIEW_FIELD + eng "Field of view '%-.64s.%-.64s' underlying table doesn't have a default value" diff --git a/sql/sp.cc b/sql/sp.cc index 4f89d6ba6da..456248db66b 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -676,15 +676,20 @@ db_show_routine_status(THD *thd, int type, const char *wild) tables is not VIEW for sure => we can pass 0 as condition */ - setup_tables(thd, &tables, 0, &leaves, FALSE); + thd->lex->select_lex.context.resolve_in_table_list_only(&tables); + setup_tables(thd, &thd->lex->select_lex.context, + &tables, 0, &leaves, FALSE); for (used_field= &used_fields[0]; used_field->field_name; used_field++) { - Item_field *field= new Item_field("mysql", "proc", + Item_field *field= new Item_field(&thd->lex->select_lex.context, + "mysql", "proc", used_field->field_name); - if (!(used_field->field= find_field_in_tables(thd, field, &tables, - 0, REPORT_ALL_ERRORS, 1))) + if (!field || + !(used_field->field= find_field_in_tables(thd, field, &tables, + 0, REPORT_ALL_ERRORS, 1, + TRUE))) { res= SP_INTERNAL_ERROR; goto err_case1; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 825ec34e410..6be80568186 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -117,7 +117,7 @@ sp_prepare_func_item(THD* thd, Item **it_addr) DBUG_ENTER("sp_prepare_func_item"); it_addr= it->this_item_addr(thd, it_addr); - if (!it->fixed && (*it_addr)->fix_fields(thd, 0, it_addr)) + if (!it->fixed && (*it_addr)->fix_fields(thd, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); @@ -735,11 +735,10 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - thd->set_n_backup_item_arena(&call_arena, &backup_arena); // QQ Should have some error checking here? (types, etc...) nctx= new sp_rcontext(csize, hmax, cmax); - nctx->callers_mem_root= backup_arena.mem_root; + nctx->callers_mem_root= thd->mem_root; for (i= 0 ; i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); @@ -765,6 +764,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) } } thd->spcont= nctx; + thd->set_n_backup_item_arena(&call_arena, &backup_arena); + /* mem_root was moved to backup_arena */ + DBUG_ASSERT(nctx->callers_mem_root == backup_arena.mem_root); ret= execute(thd); @@ -834,7 +836,6 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } init_alloc_root(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); - thd->set_n_backup_item_arena(&call_arena, &backup_arena); if (csize > 0 || hmax > 0 || cmax > 0) { @@ -899,12 +900,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } if (! ret) + { + thd->set_n_backup_item_arena(&call_arena, &backup_arena); ret= execute(thd); - - // Partially restore context now. - // We still need the call mem root and free list for processing - // of out parameters. - thd->restore_backup_item_arena(&call_arena, &backup_arena); + thd->restore_backup_item_arena(&call_arena, &backup_arena); + } if (!ret && csize > 0) { @@ -962,7 +962,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) we do not check suv->fixed, because it can't be fixed after creation */ - suv->fix_fields(thd, NULL, &item); + suv->fix_fields(thd, &item); suv->fix_length_and_dec(); suv->check(); suv->update(); @@ -1474,13 +1474,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, they want to store some value in local variable, pass return value and etc... So their life time should be longer than one instruction. - Probably we can call destructors for most of them then we are leaving - routine. But this won't help much as they are allocated in main query - MEM_ROOT anyway. So they all go to global thd->free_list. - - May be we can use some other MEM_ROOT for this purprose ??? - - What else should we do for cleanup ? cleanup_items() is called in sp_head::execute() */ return res; @@ -1586,8 +1579,8 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) DBUG_ENTER("sp_instr_set_trigger_field::execute"); /* QQ: Still unsure what should we return in case of error 1 or -1 ? */ - if (!value->fixed && value->fix_fields(thd, 0, &value) || - trigger_field->fix_fields(thd, 0, 0) || + if (!value->fixed && value->fix_fields(thd, &value) || + trigger_field->fix_fields(thd, 0) || (value->save_in_field(trigger_field->field, 0) < 0)) res= -1; *nextp= m_ip + 1; @@ -1942,7 +1935,7 @@ int sp_instr_cpush::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_cpush::execute"); - thd->spcont->push_cursor(&m_lex_keeper); + thd->spcont->push_cursor(&m_lex_keeper, this); *nextp= m_ip+1; DBUG_RETURN(0); } @@ -2001,12 +1994,24 @@ sp_instr_copen::execute(THD *thd, uint *nextp) } else { + Query_arena *old_arena= thd->current_arena; + + /* + Get the Query_arena from the cpush instruction, which contains + the free_list of the query, so new items (if any) are stored in + the right free_list, and we can cleanup after each open. + */ + thd->current_arena= c->get_instr(); res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this); + /* Cleanup the query's items */ + if (thd->current_arena->free_list) + cleanup_items(thd->current_arena->free_list); + thd->current_arena= old_arena; /* Work around the fact that errors in selects are not returned properly (but instead converted into a warning), so if a condition handler caught, we have lost the result code. - */ + */ if (!res) { uint dummy1, dummy2; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index aacb9254753..d0817e43790 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -148,9 +148,9 @@ sp_rcontext::restore_variables(uint fp) } void -sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper) +sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) { - m_cstack[m_ccount++]= new sp_cursor(lex_keeper); + m_cstack[m_ccount++]= new sp_cursor(lex_keeper, i); } void @@ -169,8 +169,9 @@ sp_rcontext::pop_cursors(uint count) * */ -sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper) - :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL) +sp_cursor::sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i) + :m_lex_keeper(lex_keeper), m_prot(NULL), m_isopen(0), m_current_row(NULL), + m_i(i) { /* currsor can't be stored in QC, so we should prevent opening QC for diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index b188805435f..856beb13f6d 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -26,6 +26,7 @@ struct sp_cond_type; class sp_cursor; struct sp_pvar; class sp_lex_keeper; +class sp_instr_cpush; #define SP_HANDLER_NONE 0 #define SP_HANDLER_EXIT 1 @@ -161,7 +162,7 @@ class sp_rcontext : public Sql_alloc restore_variables(uint fp); void - push_cursor(sp_lex_keeper *lex_keeper); + push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); void pop_cursors(uint count); @@ -203,7 +204,7 @@ class sp_cursor : public Sql_alloc { public: - sp_cursor(sp_lex_keeper *lex_keeper); + sp_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); virtual ~sp_cursor() { @@ -229,6 +230,12 @@ public: int fetch(THD *, List<struct sp_pvar> *vars); + inline sp_instr_cpush * + get_instr() + { + return m_i; + } + private: MEM_ROOT m_mem_root; // My own mem_root @@ -238,6 +245,7 @@ private: my_bool m_nseof; // Original no_send_eof Protocol *m_oprot; // Original protcol MYSQL_ROWS *m_current_row; + sp_instr_cpush *m_i; // My push instruction void destroy(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d8bbb686ba2..383adcadc6a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2439,21 +2439,19 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, table_list->alias, name, item_name, (ulong) ref)); if (table_list->field_translation) { - uint num; - if (table_list->schema_table_reformed) + Field_iterator_view field_it; + field_it.set(table_list); + DBUG_ASSERT(table_list->schema_table_reformed || + (ref != 0 && table_list->view != 0)); + for (; !field_it.end_of_fields(); field_it.next()) { - num= thd->lex->current_select->item_list.elements; - } - else - { - DBUG_ASSERT(ref != 0 && table_list->view != 0); - num= table_list->view->select_lex.item_list.elements; - } - Field_translator *trans= table_list->field_translation; - for (uint i= 0; i < num; i ++) - { - if (!my_strcasecmp(system_charset_info, trans[i].name, name)) + if (!my_strcasecmp(system_charset_info, field_it.name(), name)) { + Item *item= field_it.create_item(thd); + if (!item) + { + DBUG_RETURN(0); + } if (table_list->schema_table_reformed) { /* @@ -2462,7 +2460,7 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, So we can return ->field. It is used only for 'show & where' commands. */ - DBUG_RETURN(((Item_field*) (trans[i].item))->field); + DBUG_RETURN(((Item_field*) (field_it.item()))->field); } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_grants_view && @@ -2472,26 +2470,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list, name, length)) DBUG_RETURN(WRONG_GRANT); #endif - if (thd->lex->current_select->no_wrap_view_item) - { - if (register_tree_change) - thd->change_item_tree(ref, trans[i].item); - else - *ref= trans[i].item; - } + if (register_tree_change) + thd->change_item_tree(ref, item); else - { - Item_ref *item_ref= new Item_ref(&trans[i].item, - table_list->view_name.str, - item_name); - /* as far as Item_ref have defined reference it do not need tables */ - if (register_tree_change && item_ref) - thd->change_item_tree(ref, item_ref); - else if (item_ref) - *ref= item_ref; - if (!(*ref)->fixed) - (*ref)->fix_fields(thd, 0, ref); - } + *ref= item; DBUG_RETURN((Field*) view_ref_found); } } @@ -2599,19 +2581,21 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, SYNOPSIS find_field_in_tables() - thd Pointer to current thread structure - item Field item that should be found - tables Tables to be searched for item - ref If 'item' is resolved to a view field, ref is set to - point to the found view field - report_error Degree of error reporting: - - IGNORE_ERRORS then do not report any error - - IGNORE_EXCEPT_NON_UNIQUE report only non-unique - fields, suppress all other errors - - REPORT_EXCEPT_NON_UNIQUE report all other errors - except when non-unique fields were found - - REPORT_ALL_ERRORS - check_privileges need to check privileges + thd Pointer to current thread structure + item Field item that should be found + tables Tables to be searched for item + ref If 'item' is resolved to a view field, ref is set to + point to the found view field + report_error Degree of error reporting: + - IGNORE_ERRORS then do not report any error + - IGNORE_EXCEPT_NON_UNIQUE report only non-unique + fields, suppress all other errors + - REPORT_EXCEPT_NON_UNIQUE report all other errors + except when non-unique fields were found + - REPORT_ALL_ERRORS + check_privileges need to check privileges + register_tree_change TRUE if ref is not stack variable and we + need register changes in item tree RETURN VALUES 0 If error: the found field is not unique, or there are @@ -2627,7 +2611,7 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, Field * find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, Item **ref, find_item_error_report_type report_error, - bool check_privileges) + bool check_privileges, bool register_tree_change) { Field *found=0; const char *db=item->db_name; @@ -2635,6 +2619,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, const char *name=item->field_name; uint length=(uint) strlen(name); char name_buff[NAME_LEN+1]; + bool allow_rowid; if (item->cached_table) { @@ -2669,7 +2654,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, (test(table->grant.want_privilege) && check_privileges), 1, &(item->cached_field_index), - TRUE); + register_tree_change); } if (found) { @@ -2702,13 +2687,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, db= name_buff; } - bool search_global= item->item_flags & MY_ITEM_PREFER_1ST_TABLE; if (table_name && table_name[0]) { /* Qualified field */ - bool found_table=0; - uint table_idx= 0; - for (; tables; tables= search_global?tables->next_global:tables->next_local, - table_idx++) + bool found_table= 0; + for (; tables; tables= tables->next_local) { /* TODO; Ensure that db and tables->db always points to something ! */ if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) && @@ -2725,7 +2707,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, (test(tables->grant.want_privilege) && check_privileges), 1, &(item->cached_field_index), - TRUE); + register_tree_change); if (find) { item->cached_table= tables; @@ -2744,8 +2726,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found=find; - if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) - break; } } } @@ -2770,11 +2750,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; return (Field*) 0; } - bool allow_rowid= tables && !tables->next_local; // Only one table - uint table_idx= 0; - for (; tables ; tables= search_global?tables->next_global:tables->next_local, - table_idx++) + allow_rowid= tables && !tables->next_local; // Only one table + for (; tables ; tables= tables->next_local) { + Field *field; if (!tables->table && !tables->ancestor) { if (report_error == REPORT_ALL_ERRORS || @@ -2783,17 +2762,17 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) not_found_field; } - Field *field= find_field_in_table(thd, tables, name, item->name, - length, ref, - (tables->table && - test(tables->table->grant. - want_privilege) && - check_privileges), - (test(tables->grant.want_privilege) && - check_privileges), - allow_rowid, - &(item->cached_field_index), - TRUE); + field= find_field_in_table(thd, tables, name, item->name, + length, ref, + (tables->table && + test(tables->table->grant. + want_privilege) && + check_privileges), + (test(tables->grant.want_privilege) && + check_privileges), + allow_rowid, + &(item->cached_field_index), + register_tree_change); if (field) { if (field == WRONG_GRANT) @@ -2809,8 +2788,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, return (Field*) 0; } found= field; - if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE) - break; } } if (found) @@ -3066,7 +3043,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, */ it.replace(new Item_int("Not_used", (longlong) 1, 21)); } - else if (insert_fields(thd,tables,((Item_field*) item)->db_name, + else if (insert_fields(thd, ((Item_field*) item)->context, + ((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it, any_privileges)) { @@ -3102,7 +3080,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ** Check that all given fields exists and fill struct with current data ****************************************************************************/ -bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +bool setup_fields(THD *thd, Item **ref_pointer_array, List<Item> &fields, bool set_query_id, List<Item> *sum_func_list, bool allow_sum_func) { @@ -3131,7 +3109,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, Item **ref= ref_pointer_array; while ((item= it++)) { - if (!item->fixed && item->fix_fields(thd, tables, it.ref()) || + if (!item->fixed && item->fix_fields(thd, it.ref()) || (item= *(it.ref()))->check_cols(1)) { DBUG_RETURN(TRUE); /* purecov: inspected */ @@ -3181,6 +3159,7 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) SYNOPSIS setup_tables() thd Thread handler + context name resolution contest to setup table list there tables Table list conds Condition of current SELECT (can be changed by VIEW) leaves List of join table leaves list @@ -3200,11 +3179,15 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) TRUE error */ -bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, +bool setup_tables(THD *thd, Name_resolution_context *context, + TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert) { uint tablenr= 0; DBUG_ENTER("setup_tables"); + + context->table_list= tables; + /* this is used for INSERT ... SELECT. For select we setup tables except first (and its underlying tables) @@ -3259,10 +3242,21 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, table_list; table_list= table_list->next_local) { - if (table_list->ancestor && - table_list->setup_ancestor(thd, conds, - table_list->effective_with_check)) - DBUG_RETURN(1); + if (table_list->ancestor) + { + DBUG_ASSERT(table_list->view); + Query_arena *arena= thd->current_arena, backup; + bool res; + if (arena->is_conventional()) + arena= 0; // For easier test + else + thd->set_n_backup_item_arena(arena, &backup); + res= table_list->setup_ancestor(thd); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + if (res) + DBUG_RETURN(1); + } } DBUG_RETURN(0); } @@ -3314,7 +3308,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, SYNOPSIS insert_fields() thd Thread handler - tables List of tables + context Context for name resolution db_name Database name in case of 'database_name.table_name.*' table_name Table name in case of 'table_name.*' it Pointer to '*' @@ -3328,7 +3322,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, */ bool -insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, +insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, bool any_privileges) { @@ -3352,7 +3346,9 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } found= 0; - for (; tables; tables= tables->next_local) + for (TABLE_LIST *tables= context->table_list; + tables; + tables= tables->next_local) { Field_iterator *iterator; TABLE_LIST *natural_join_table; @@ -3361,7 +3357,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, TABLE_LIST *last; TABLE_LIST *embedding; TABLE *table= tables->table; - bool alias_used= 0; if (!table_name || (!my_strcasecmp(table_alias_charset, table_name, tables->alias) && @@ -3395,16 +3390,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } } #endif - if (table) - thd->used_tables|= table->map; - else - { - view_iter.set(tables); - for (; !view_iter.end_of_fields(); view_iter.next()) - { - thd->used_tables|= view_iter.item(thd)->used_tables(); - } - } natural_join_table= 0; last= embedded= tables; @@ -3435,8 +3420,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, { iterator= &view_iter; view= 1; - alias_used= my_strcasecmp(table_alias_charset, - tables->table_name, tables->alias); } else { @@ -3445,6 +3428,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, } iterator->set(tables); + /* for view used tables will be collected in following loop */ + if (table) + thd->used_tables|= table->map; + for (; !iterator->end_of_fields(); iterator->next()) { Item *not_used_item; @@ -3457,16 +3444,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, strlen(field_name), ¬_used_item, 0, 0, 0, ¬_used_field_index, TRUE)) { - Item *item= iterator->item(thd); - if (view && !thd->lex->current_select->no_wrap_view_item) - { - /* - as far as we have view, then item point to view_iter, so we - can use it directly for this view specific operation - */ - item= new Item_ref(view_iter.item_ptr(), tables->view_name.str, - field_name); - } + Item *item= iterator->create_item(thd); + if (!item) + goto err; + thd->used_tables|= item->used_tables(); if (!found++) (void) it->replace(item); // Replace '*' else @@ -3537,9 +3518,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, my_message(ER_NO_TABLES_USED, ER(ER_NO_TABLES_USED), MYF(0)); else my_error(ER_BAD_TABLE_ERROR, MYF(0), table_name); -#ifndef NO_EMBEDDED_ACCESS_CHECKS err: -#endif DBUG_RETURN(1); } @@ -3550,16 +3529,25 @@ err: SYNOPSIS setup_conds() thd thread handler - tables list of tables for name resolving leaves list of leaves of join table tree */ -int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) +int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, + COND **conds) { SELECT_LEX *select_lex= thd->lex->current_select; Query_arena *arena= thd->current_arena, backup; - bool save_wrapper= thd->lex->current_select->no_wrap_view_item; TABLE_LIST *table= NULL; // For HP compilers + /* + it_is_update set to TRUE when tables of primary SELECT_LEX (SELECT_LEX + which belong to LEX, i.e. most up SELECT) will be updated by + INSERT/UPDATE/LOAD + NOTE: using this condition helps to prevent call of prepare_check_option() + from subquery of VIEW, because tables of subquery belongs to VIEW + (see condition before prepare_check_option() call) + */ + bool it_is_update= (select_lex == &thd->lex->select_lex) && + thd->lex->which_check_option_applicable(); DBUG_ENTER("setup_conds"); if (select_lex->conds_processed_with_permanent_arena || @@ -3568,12 +3556,17 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->set_query_id=1; - thd->lex->current_select->no_wrap_view_item= 0; + for (table= tables; table; table= table->next_local) + { + if (table->prepare_where(thd, conds, FALSE)) + goto err_no_arena; + } + select_lex->cond_count= 0; if (*conds) { thd->where="where clause"; - if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) || + if (!(*conds)->fixed && (*conds)->fix_fields(thd, conds) || (*conds)->check_cols(1)) goto err_no_arena; } @@ -3591,11 +3584,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) /* Make a join an a expression */ thd->where="on clause"; if (!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) || + embedded->on_expr->fix_fields(thd, &embedded->on_expr) || embedded->on_expr->check_cols(1)) goto err_no_arena; select_lex->cond_count++; } + if (embedded->natural_join) { /* Make a join of all fields wich have the same name */ @@ -3675,7 +3669,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { if (t2_field != view_ref_found) { - if (!(item_t2= new Item_field(thd, t2_field))) + if (!(item_t2= new Item_field(thd, &select_lex->context, + t2_field))) goto err; /* Mark field used for table cache */ t2_field->query_id= thd->query_id; @@ -3687,7 +3682,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) t1_field->query_id= thd->query_id; t1->used_keys.intersect(t1_field->part_of_key); } - Item_func_eq *tmp= new Item_func_eq(iterator->item(thd), + Item_func_eq *tmp= new Item_func_eq(iterator->create_item(thd), item_t2); if (!tmp) goto err; @@ -3703,7 +3698,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) { COND *on_expr= cond_and; if (!on_expr->fixed) - on_expr->fix_fields(thd, 0, &on_expr); + on_expr->fix_fields(thd, &on_expr); if (!embedded->outer_join) // Not left join { *conds= and_conds(*conds, cond_and); @@ -3712,7 +3707,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { - if ((*conds)->fix_fields(thd, tables, conds)) + if ((*conds)->fix_fields(thd, conds)) goto err_no_arena; } } @@ -3724,8 +3719,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) thd->restore_backup_item_arena(arena, &backup); if (embedded->on_expr && !embedded->on_expr->fixed) { - if (embedded->on_expr->fix_fields(thd, tables, - &embedded->on_expr)) + if (embedded->on_expr->fix_fields(thd, &embedded->on_expr)) goto err_no_arena; } } @@ -3737,6 +3731,20 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) } while (embedding && embedding->nested_join->join_list.head() == embedded); + + /* process CHECK OPTION */ + if (it_is_update) + { + TABLE_LIST *view= table->belong_to_view; + if (!view) + view= table; + if (view->effective_with_check) + { + if (view->prepare_check_option(thd)) + goto err_no_arena; + thd->change_item_tree(&table->check_option, view->check_option); + } + } } if (!thd->current_arena->is_conventional()) @@ -3750,14 +3758,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) select_lex->where= *conds; select_lex->conds_processed_with_permanent_arena= 1; } - thd->lex->current_select->no_wrap_view_item= save_wrapper; DBUG_RETURN(test(thd->net.report_error)); err: if (arena) thd->restore_backup_item_arena(arena, &backup); err_no_arena: - thd->lex->current_select->no_wrap_view_item= save_wrapper; DBUG_RETURN(1); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 20f48da9283..a941ba11943 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -784,7 +784,10 @@ void THD::nocheck_register_item_tree_change(Item **place, Item *old_value, void *change_mem= alloc_root(runtime_memroot, sizeof(*change)); if (change_mem == 0) { - fatal_error(); + /* + OOM, thd->fatal_error() is called by the error handler of the + memroot. Just return. + */ return; } change= new (change_mem) Item_change_record; @@ -1451,17 +1454,16 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) (void)local_vars.push_back(new Item_splocal(mv->s, mv->offset)); else { - Item_func_set_user_var *xx = new Item_func_set_user_var(mv->s, item); + Item_func_set_user_var *var= new Item_func_set_user_var(mv->s, item); /* Item_func_set_user_var can't substitute something else on its place => 0 can be passed as last argument (reference on item) Item_func_set_user_var can't be fixed after creation, so we do not - check xx->fixed + check var->fixed */ - xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first, - 0); - xx->fix_length_and_dec(); - vars.push_back(xx); + var->fix_fields(thd, 0); + var->fix_length_and_dec(); + vars.push_back(var); } } return 0; @@ -1538,15 +1540,19 @@ void Statement::set_statement(Statement *stmt) void Statement::set_n_backup_statement(Statement *stmt, Statement *backup) { + DBUG_ENTER("Statement::set_n_backup_statement"); backup->set_statement(this); set_statement(stmt); + DBUG_VOID_RETURN; } void Statement::restore_backup_statement(Statement *stmt, Statement *backup) { + DBUG_ENTER("Statement::restore_backup_statement"); stmt->set_statement(this); set_statement(backup); + DBUG_VOID_RETURN; } @@ -1569,6 +1575,7 @@ void Query_arena::set_n_backup_item_arena(Query_arena *set, Query_arena *backup) { DBUG_ENTER("Query_arena::set_n_backup_item_arena"); DBUG_ASSERT(backup->is_backup_arena == FALSE); + backup->set_item_arena(this); set_item_arena(set); #ifndef DBUG_OFF diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 25fef8b0ad6..d83937098e2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -300,7 +300,9 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_delete"); - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) || + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, conds, &select_lex->leaf_tables, + FALSE) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) || setup_ftfuncs(select_lex)) DBUG_RETURN(TRUE); @@ -356,7 +358,8 @@ bool mysql_multi_delete_prepare(THD *thd) lex->query_tables also point on local list of DELETE SELECT_LEX */ - if (setup_tables(thd, lex->query_tables, &lex->select_lex.where, + if (setup_tables(thd, &thd->lex->select_lex.context, + lex->query_tables, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index e1d701936cf..fc9d15e94c4 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -114,6 +114,10 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) bool is_union= first_select->next_select() && first_select->next_select()->linkage == UNION_TYPE; + /* prevent name resolving out of derived table */ + for (SELECT_LEX *sl= first_select; sl; sl= sl->next_select()) + sl->context.outer_context= 0; + if (!(derived_result= new select_union(0))) DBUG_RETURN(1); // out of memory diff --git a/sql/sql_do.cc b/sql/sql_do.cc index e37f3e86dda..08388dee516 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -24,7 +24,7 @@ bool mysql_do(THD *thd, List<Item> &values) List_iterator<Item> li(values); Item *value; DBUG_ENTER("mysql_do"); - if (setup_fields(thd, 0, 0, values, 0, 0, 0)) + if (setup_fields(thd, 0, values, 0, 0, 0)) DBUG_RETURN(TRUE); while ((value = li++)) value->val_int(); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e905f93b860..e109600bcd0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -353,7 +353,9 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, LINT_INIT(key); LINT_INIT(key_len); - list.push_front(new Item_field(NULL,NULL,"*")); + thd->lex->select_lex.context.resolve_in_table_list_only(tables); + list.push_front(new Item_field(&thd->lex->select_lex.context, + NULL, NULL, "*")); List_iterator<Item> it(list); it++; @@ -410,7 +412,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, tables->table=table; if (cond && ((!cond->fixed && - cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1))) + cond->fix_fields(thd, &cond)) || cond->check_cols(1))) goto err0; if (keyname) @@ -422,7 +424,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } } - if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0)) + if (insert_fields(thd, &thd->lex->select_lex.context, + tables->db, tables->alias, &it, 0)) goto err0; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); @@ -505,7 +508,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, { // 'item' can be changed by fix_fields() call if ((!item->fixed && - item->fix_fields(thd, tables, it_ke.ref())) || + item->fix_fields(thd, it_ke.ref())) || (item= *it_ke.ref())->check_cols(1)) goto err; if (item->used_tables() & ~RAND_TABLE_BIT) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 0cf8d1e93a7..6780beec258 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -81,14 +81,18 @@ enum enum_used_fields static bool init_fields(THD *thd, TABLE_LIST *tables, struct st_find_field *find_fields, uint count) { + Name_resolution_context *context= &thd->lex->select_lex.context; DBUG_ENTER("init_fields"); + context->resolve_in_table_list_only(tables); for (; count-- ; find_fields++) { /* We have to use 'new' here as field will be re_linked on free */ - Item_field *field= new Item_field("mysql", find_fields->table_name, + Item_field *field= new Item_field(context, + "mysql", find_fields->table_name, find_fields->field_name); if (!(find_fields->field= find_field_in_tables(thd, field, tables, - 0, REPORT_ALL_ERRORS, 1))) + 0, REPORT_ALL_ERRORS, 1, + TRUE))) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -544,7 +548,6 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, prepare_simple_select() thd Thread handler cond WHERE part of select - tables list of tables, used in WHERE table goal table error code of error (out) @@ -553,11 +556,11 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, # created SQL_SELECT */ -SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables, +SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE *table, int *error) { if (!cond->fixed) - cond->fix_fields(thd, tables, &cond); // can never fail + cond->fix_fields(thd, &cond); // can never fail /* Assume that no indexes cover all required fields */ table->used_keys.clear_all(); @@ -599,7 +602,7 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, new Item_string("\\",1,&my_charset_latin1)); if (thd->is_fatal_error) return 0; // OOM - return prepare_simple_select(thd,cond,tables,table,error); + return prepare_simple_select(thd, cond, table, error); } @@ -651,7 +654,8 @@ bool mysqld_help(THD *thd, const char *mask) tables do not contain VIEWs => we can pass 0 as conds */ - setup_tables(thd, tables, 0, &leaves, FALSE); + setup_tables(thd, &thd->lex->select_lex.context, + tables, 0, &leaves, FALSE); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); if (init_fields(thd, tables, used_fields, array_elements(used_fields))) goto error; @@ -718,15 +722,15 @@ bool mysqld_help(THD *thd, const char *mask) Item *cond_cat_by_cat= new Item_func_equal(new Item_field(cat_cat_id), new Item_int((int32)category_id)); - if (!(select= prepare_simple_select(thd,cond_topic_by_cat, - tables,tables[0].table,&error))) + if (!(select= prepare_simple_select(thd, cond_topic_by_cat, + tables[0].table, &error))) goto error; get_all_items_for_category(thd,tables[0].table, used_fields[help_topic_name].field, select,&topics_list); delete select; - if (!(select= prepare_simple_select(thd,cond_cat_by_cat,tables, - tables[1].table,&error))) + if (!(select= prepare_simple_select(thd, cond_cat_by_cat, + tables[1].table, &error))) goto error; get_all_items_for_category(thd,tables[1].table, used_fields[help_category_name].field, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2ce81d8815e..576866cb17d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -31,7 +31,7 @@ static void end_delayed_insert(THD *thd); extern "C" pthread_handler_decl(handle_delayed_insert,arg); static void unlink_blobs(register TABLE *table); #endif -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id); +static bool check_view_insertability(THD *thd, TABLE_LIST *view); /* Define to force use of my_malloc() if the allocated memory block is big */ @@ -106,7 +106,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } else { // Part field list - TABLE_LIST *save_next; + Name_resolution_context *context= &thd->lex->select_lex.context; + TABLE_LIST *save_next= table_list->next_local, + *save_context= context->table_list; + bool save_resolve_in_select_list= + thd->lex->select_lex.context.resolve_in_select_list; int res; if (fields.elements != values.elements) { @@ -115,12 +119,15 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } thd->dupp_field=0; - thd->lex->select_lex.no_wrap_view_item= 1; - save_next= table_list->next_local; // fields only from first table + thd->lex->select_lex.no_wrap_view_item= TRUE; + /* fields only from first table */ table_list->next_local= 0; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); + context->resolve_in_table_list_only(table_list); + res= setup_fields(thd, 0, fields, 1, 0, 0); table_list->next_local= save_next; - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= FALSE; + context->table_list= save_context; + context->resolve_in_select_list= save_resolve_in_select_list; if (res) return -1; if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) @@ -159,7 +166,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_key_in_view(thd, table_list) || (table_list->view && - check_view_insertability(table_list, thd->query_id))) + check_view_insertability(thd, table_list))) { my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT"); return -1; @@ -209,7 +216,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, Check the fields we are going to modify. This will set the query_id of all used fields to the threads query_id. */ - if (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0)) + if (setup_fields(thd, 0, update_fields, 1, 0, 0)) return -1; if (table->timestamp_field) @@ -247,6 +254,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ulonglong id; COPY_INFO info; TABLE *table= 0; + TABLE_LIST *next_local; List_iterator_fast<List_item> its(values_list); List_item *values; #ifndef EMBEDDED_LIBRARY @@ -327,7 +335,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, /* mysql_prepare_insert set table_list->table if it was not set */ table= table_list->table; - // is table which we are changing used somewhere in other parts of query + next_local= table_list->next_local; + table_list->next_local= 0; + thd->lex->select_lex.context.resolve_in_table_list_only(table_list); value_count= values->elements; while ((values= its++)) { @@ -337,10 +347,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto abort; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto abort; } its.rewind (); + table_list->next_local= next_local; /* Fill in the given fields and dump it to the table file */ @@ -387,12 +398,16 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, MODE_STRICT_ALL_TABLES))); if ((fields.elements || !value_count) && - check_that_all_fields_are_given_values(thd, table)) + check_that_all_fields_are_given_values(thd, table, table_list)) { /* thd->net.report_error is now set, which will abort the next loop */ error= 1; } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + error= 1; + while ((values= its++)) { if (fields.elements || !value_count) @@ -596,6 +611,7 @@ abort: SYNOPSIS check_view_insertability() + thd - thread handler view - reference on VIEW IMPLEMENTATION @@ -612,7 +628,7 @@ abort: TRUE - can't be used for insert */ -static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) +static bool check_view_insertability(THD * thd, TABLE_LIST *view) { uint num= view->view->select_lex.item_list.elements; TABLE *table= view->table; @@ -620,15 +636,25 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) *trans_end= trans_start + num; Field_translator *trans; Field **field_ptr= table->field; - query_id_t other_query_id= query_id - 1; + uint used_fields_buff_size= (table->s->fields + 7) / 8; + uchar *used_fields_buff= (uchar*)thd->alloc(used_fields_buff_size); + MY_BITMAP used_fields; DBUG_ENTER("check_key_in_view"); + if (!used_fields_buff) + DBUG_RETURN(TRUE); // EOM + DBUG_ASSERT(view->table != 0 && view->field_translation != 0); + bitmap_init(&used_fields, used_fields_buff, used_fields_buff_size * 8, 0); + bitmap_clear_all(&used_fields); + view->contain_auto_increment= 0; /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { + if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) + return TRUE; Item_field *field; /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->filed_for_view_update())) @@ -636,7 +662,6 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) if (field->field->unireg_check == Field::NEXT_NUMBER) view->contain_auto_increment= 1; /* prepare unique test */ - field->field->query_id= other_query_id; /* remove collation (or other transparent for update function) if we have it @@ -648,29 +673,12 @@ static bool check_view_insertability(TABLE_LIST *view, query_id_t query_id) { /* Thanks to test above, we know that all columns are of type Item_field */ Item_field *field= (Item_field *)trans->item; - if (field->field->query_id == query_id) + /* check fields belong to table in which we are inserting */ + if (field->field->table == table && + bitmap_fast_test_and_set(&used_fields, field->field->field_index)) DBUG_RETURN(TRUE); - field->field->query_id= query_id; } - /* VIEW contain all fields without default value */ - for (; *field_ptr; field_ptr++) - { - Field *field= *field_ptr; - /* field have not default value */ - if ((field->type() == FIELD_TYPE_BLOB) && - (table->timestamp_field != field || - field->unireg_check == Field::TIMESTAMP_UN_FIELD)) - { - for (trans= trans_start; ; trans++) - { - if (trans == trans_end) - DBUG_RETURN(TRUE); // Field was not part of view - if (((Item_field *)trans->item)->field == *field_ptr) - break; // ok - } - } - } DBUG_RETURN(FALSE); } @@ -698,7 +706,8 @@ 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, table_list, where, &thd->lex->select_lex.leaf_tables, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, where, &thd->lex->select_lex.leaf_tables, select_insert)) DBUG_RETURN(TRUE); @@ -711,7 +720,7 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); } - DBUG_RETURN(insert_view_fields(&fields, table_list)); + DBUG_RETURN(insert_view_fields(thd, &fields, table_list)); } DBUG_RETURN(FALSE); @@ -725,31 +734,63 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, mysql_prepare_insert() thd Thread handler table_list Global/local table list - table Table to insert into (can be NULL if table should be taken from - table_list->table) + table Table to insert into (can be NULL if table should + be taken from table_list->table) where Where clause (for insert ... select) select_insert TRUE if INSERT ... SELECT statement + TODO (in far future) + In cases of: + INSERT INTO t1 SELECT a, sum(a) as sum1 from t2 GROUP BY a + ON DUPLICATE KEY ... + we should be able to refer to sum1 in the ON DUPLICATE KEY part + + WARNING + You MUST set table->insert_values to 0 after calling this function + before releasing the table object. + RETURN VALUE FALSE OK TRUE error */ -bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, - List<Item> &fields, List_item *values, +bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, + TABLE *table, List<Item> &fields, List_item *values, List<Item> &update_fields, List<Item> &update_values, enum_duplicates duplic, COND **where, bool select_insert) { + SELECT_LEX *select_lex= &thd->lex->select_lex; + TABLE_LIST *save_table_list; + TABLE_LIST *save_next_local; bool insert_into_view= (table_list->view != 0); - /* TODO: use this condition for 'WITH CHECK OPTION' */ - bool res; - TABLE_LIST *next_local; + bool save_resolve_in_select_list; + bool res= 0; DBUG_ENTER("mysql_prepare_insert"); DBUG_PRINT("enter", ("table_list 0x%lx, table 0x%lx, view %d", (ulong)table_list, (ulong)table, (int)insert_into_view)); + /* + For subqueries in VALUES() we should not see the table in which we are + inserting (for INSERT ... SELECT this is done by changing table_list, + because INSERT ... SELECT share SELECT_LEX it with SELECT. + */ + if (!select_insert) + { + for (SELECT_LEX_UNIT *un= select_lex->first_inner_unit(); + un; + un= un->next_unit()) + { + for (SELECT_LEX *sl= un->first_select(); + sl; + sl= sl->next_select()) + { + sl->context.outer_context= 0; + } + } + } + if (duplic == DUP_UPDATE) { /* it should be allocated before Item::fix_fields() */ @@ -761,31 +802,54 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, select_insert)) DBUG_RETURN(TRUE); - next_local= table_list->next_local; + save_table_list= select_lex->context.table_list; + save_resolve_in_select_list= select_lex->context.resolve_in_select_list; + save_next_local= table_list->next_local; + table_list->next_local= 0; + select_lex->context.resolve_in_table_list_only(table_list); if ((values && check_insert_fields(thd, table_list, fields, *values, !insert_into_view)) || - (values && setup_fields(thd, 0, table_list, *values, 0, 0, 0)) || - (duplic == DUP_UPDATE && - ((thd->lex->select_lex.no_wrap_view_item= 1, - (res= check_update_fields(thd, table_list, update_fields)), - thd->lex->select_lex.no_wrap_view_item= 0, - res) || - setup_fields(thd, 0, table_list, update_values, 1, 0, 0)))) - DBUG_RETURN(TRUE); - table_list->next_local= next_local; + (values && setup_fields(thd, 0, *values, 0, 0, 0))) + res= TRUE; + else if (duplic == DUP_UPDATE) + { + select_lex->no_wrap_view_item= TRUE; + res= check_update_fields(thd, table_list, update_fields); + select_lex->no_wrap_view_item= FALSE; + if (select_lex->group_list.elements == 0) + { + /* + When we are not using GROUP BY we can refer to other tables in the + ON DUPLICATE KEY part + */ + table_list->next_local= save_next_local; + } + if (!res) + res= setup_fields(thd, 0, update_values, 1, 0, 0); + } + table_list->next_local= save_next_local; + select_lex->context.table_list= save_table_list; + select_lex->context.resolve_in_select_list= save_resolve_in_select_list; + if (res) + DBUG_RETURN(res); if (!table) table= table_list->table; - if (!select_insert && unique_table(table_list, table_list->next_global)) + if (!select_insert) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); - DBUG_RETURN(TRUE); + Item *fake_conds= 0; + if (unique_table(table_list, table_list->next_global)) + { + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + DBUG_RETURN(TRUE); + } + select_lex->fix_prepare_information(thd, &fake_conds); + select_lex->first_execution= 0; } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); - thd->lex->select_lex.first_execution= 0; DBUG_RETURN(FALSE); } @@ -1038,7 +1102,8 @@ before_trg_err: Check that all fields with arn't null_fields are used ******************************************************************************/ -int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) +int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, + TABLE_LIST *table_list) { int err= 0; for (Field **field=entry->field ; *field ; field++) @@ -1047,10 +1112,29 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry) ((*field)->flags & NO_DEFAULT_VALUE_FLAG) && ((*field)->real_type() != FIELD_TYPE_ENUM)) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_NO_DEFAULT_FOR_FIELD, - ER(ER_NO_DEFAULT_FOR_FIELD), - (*field)->field_name); + bool view= FALSE; + if (table_list) + { + table_list= (table_list->belong_to_view ? + table_list->belong_to_view : + table_list); + view= (table_list->view); + } + if (view) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_VIEW_FIELD, + ER(ER_NO_DEFAULT_FOR_VIEW_FIELD), + table_list->view_db.str, + table_list->view_name.str); + } + else + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_DEFAULT_FOR_FIELD, + ER(ER_NO_DEFAULT_FOR_FIELD), + (*field)->field_name); + } err= 1; } } @@ -1932,35 +2016,37 @@ bool delayed_insert::handle_inserts(void) bool mysql_insert_select_prepare(THD *thd) { LEX *lex= thd->lex; + SELECT_LEX *select_lex= &lex->select_lex; TABLE_LIST *first_select_leaf_table; DBUG_ENTER("mysql_insert_select_prepare"); + /* SELECT_LEX do not belong to INSERT statement, so we can't add WHERE clause if table is VIEW */ - lex->query_tables->no_where_clause= 1; + if (mysql_prepare_insert(thd, lex->query_tables, lex->query_tables->table, lex->field_list, 0, lex->update_list, lex->value_list, lex->duplicates, - &lex->select_lex.where, TRUE)) + &select_lex->where, TRUE)) DBUG_RETURN(TRUE); /* exclude first table from leaf tables list, because it belong to INSERT */ - DBUG_ASSERT(lex->select_lex.leaf_tables != 0); - lex->leaf_tables_insert= lex->select_lex.leaf_tables; + DBUG_ASSERT(select_lex->leaf_tables != 0); + lex->leaf_tables_insert= select_lex->leaf_tables; /* skip all leaf tables belonged to view where we are insert */ - for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf; + for (first_select_leaf_table= select_lex->leaf_tables->next_leaf; first_select_leaf_table && first_select_leaf_table->belong_to_view && first_select_leaf_table->belong_to_view == lex->leaf_tables_insert->belong_to_view; first_select_leaf_table= first_select_leaf_table->next_leaf) {} - lex->select_lex.leaf_tables= first_select_leaf_table; + select_lex->leaf_tables= first_select_leaf_table; DBUG_RETURN(FALSE); } @@ -1988,8 +2074,8 @@ select_insert::select_insert(TABLE_LIST *table_list_par, TABLE *table_par, int select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { - int res; LEX *lex= thd->lex; + int res; SELECT_LEX *lex_current_select_save= lex->current_select; DBUG_ENTER("select_insert::prepare"); @@ -2043,8 +2129,11 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(fields->elements && - check_that_all_fields_are_given_values(thd, table)); + res= ((fields->elements && + check_that_all_fields_are_given_values(thd, table, table_list)) || + table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)); + DBUG_RETURN(res); } @@ -2290,7 +2379,8 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(check_that_all_fields_are_given_values(thd, table)); + DBUG_RETURN(check_that_all_fields_are_given_values(thd, table, + table_list)); } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 08f0c3badf7..fe79b6dd035 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1104,7 +1104,8 @@ void st_select_lex::init_query() having= where= prep_where= 0; olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; - resolve_mode= NOMATTER_MODE; + context.select_lex= this; + context.init(); cond_count= with_wild= 0; conds_processed_with_permanent_arena= 0; ref_pointer_array= 0; @@ -1703,8 +1704,7 @@ bool st_lex::can_not_use_merged() bool st_lex::only_view_structure() { - switch(sql_command) - { + switch (sql_command) { case SQLCOM_SHOW_CREATE: case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_FIELDS: @@ -1744,6 +1744,31 @@ bool st_lex::need_correct_ident() } } +/* + Get effective type of CHECK OPTION for given view + + SYNOPSIS + get_effective_with_check() + view given view + + NOTE + It have not sense to set CHECK OPTION for SELECT satement or subqueries, + so we do not. + + RETURN + VIEW_CHECK_NONE no need CHECK OPTION + VIEW_CHECK_LOCAL CHECK OPTION LOCAL + VIEW_CHECK_CASCADED CHECK OPTION CASCADED +*/ + +uint8 st_lex::get_effective_with_check(st_table_list *view) +{ + if (view->select_lex->master_unit() == &unit && + which_check_option_applicable()) + return (uint8)view->with_check; + return VIEW_CHECK_NONE; +} + /* initialize limit counters @@ -1804,7 +1829,8 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local) */ if ((*link_to_local= test(select_lex.table_list.first))) { - select_lex.table_list.first= (byte*) first->next_local; + select_lex.table_list.first= (byte*) (select_lex.context.table_list= + first->next_local); select_lex.table_list.elements--; //safety first->next_local= 0; /* @@ -1909,7 +1935,8 @@ void st_lex::link_first_table_back(TABLE_LIST *first, if (link_to_local) { first->next_local= (TABLE_LIST*) select_lex.table_list.first; - select_lex.table_list.first= (byte*) first; + select_lex.table_list.first= + (byte*) (select_lex.context.table_list= first); select_lex.table_list.elements++; //safety } } @@ -1930,7 +1957,21 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) if (!thd->current_arena->is_conventional() && first_execution) { first_execution= 0; - prep_where= where; + if (*conds) + { + prep_where= *conds; + *conds= where= prep_where->copy_andor_structure(thd); + } + for (TABLE_LIST *tbl= (TABLE_LIST *)table_list.first; + tbl; + tbl= tbl->next_local) + { + if (tbl->on_expr) + { + tbl->prep_on_expr= tbl->on_expr; + tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); + } + } } } @@ -1945,3 +1986,4 @@ void st_select_lex::fix_prepare_information(THD *thd, Item **conds) st_select_lex_unit::change_result are in sql_union.cc */ + diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5cf0b66598f..8fde37b0126 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -470,6 +470,7 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; class st_select_lex: public st_select_lex_node { public: + Name_resolution_context context; char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ Item *where, *having; /* WHERE & HAVING clauses */ Item *prep_where; /* saved WHERE clause for prepared statement processing */ @@ -549,27 +550,6 @@ public: /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; - /* - SELECT for SELECT command st_select_lex. Used to privent scaning - item_list of non-SELECT st_select_lex (no sense find to finding - reference in it (all should be in tables, it is dangerouse due - to order of fix_fields calling for non-SELECTs commands (item list - can be not fix_fieldsd)). This value will be assigned for - primary select (sql_yac.yy) and for any subquery and - UNION SELECT (sql_parse.cc mysql_new_select()) - - - INSERT for primary st_select_lex structure of simple INSERT/REPLACE - (used for name resolution, see Item_fiels & Item_ref fix_fields, - FALSE for INSERT/REPLACE ... SELECT, because it's - st_select_lex->table_list will be preprocessed (first table removed) - before passing to handle_select) - - NOMATTER for other - */ - enum {NOMATTER_MODE, SELECT_MODE, INSERT_MODE} resolve_mode; - - void init_query(); void init_select(); st_select_lex_unit* master_unit(); @@ -903,7 +883,30 @@ typedef struct st_lex bool can_not_use_merged(); bool only_view_structure(); bool need_correct_ident(); + uint8 get_effective_with_check(st_table_list *view); + /* + Is this update command where 'WHITH CHECK OPTION' clause is important + SYNOPSIS + st_lex::which_check_option_applicable() + + RETURN + TRUE have to take 'WHITH CHECK OPTION' clause into account + FALSE 'WHITH CHECK OPTION' clause do not need + */ + inline bool which_check_option_applicable() + { + switch (sql_command) { + case SQLCOM_UPDATE: + case SQLCOM_UPDATE_MULTI: + case SQLCOM_INSERT: + case SQLCOM_INSERT_SELECT: + case SQLCOM_LOAD: + return TRUE; + default: + return FALSE; + } + } inline bool requires_prelocking() { return test(query_tables_own_last); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index cc25839bcc9..1ec209aba85 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -149,7 +149,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } if (open_and_lock_tables(thd, table_list)) DBUG_RETURN(TRUE); - if (setup_tables(thd, table_list, &unused_conds, + if (setup_tables(thd, &thd->lex->select_lex.context, + table_list, &unused_conds, &thd->lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(-1); if (!table_list->table || // do not suport join view @@ -159,6 +160,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD"); DBUG_RETURN(TRUE); } + if (table_list->prepare_where(thd, 0, TRUE) || + table_list->prepare_check_option(thd)) + { + DBUG_RETURN(TRUE); + } /* Let us emit an error if we are loading data to table which is used in subselect in SET clause like we do it for INSERT. @@ -186,16 +192,16 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, Let us also prepare SET clause, altough it is probably empty in this case. */ - if (setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) || - setup_fields(thd, 0, table_list, set_values, 1, 0, 0)) + if (setup_fields(thd, 0, set_fields, 1, 0, 0) || + setup_fields(thd, 0, set_values, 1, 0, 0)) DBUG_RETURN(TRUE); } else { // Part field list /* TODO: use this conds for 'WITH CHECK OPTIONS' */ - if (setup_fields(thd, 0, table_list, fields_vars, 1, 0, 0) || - setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) || - check_that_all_fields_are_given_values(thd, table)) + if (setup_fields(thd, 0, fields_vars, 1, 0, 0) || + setup_fields(thd, 0, set_fields, 1, 0, 0) || + check_that_all_fields_are_given_values(thd, table, table_list)) DBUG_RETURN(TRUE); /* Check whenever TIMESTAMP field with auto-set feature specified @@ -209,7 +215,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, check_that_all_fields_are_given_values() and setting use_timestamp since it may update query_id for some fields. */ - if (setup_fields(thd, 0, table_list, set_values, 1, 0, 0)) + if (setup_fields(thd, 0, set_values, 1, 0, 0)) DBUG_RETURN(TRUE); } diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index 831b15cf7ef..71e8fe4149f 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -77,7 +77,8 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new { not_found= 0; ((Item_field*)new_item)->db_name=iif->db_name; - Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name); + Item_field *new_one=new Item_field(&select_lex->context, + iif->db_name, iif->table_name, iif->field_name); privlist.push_back(new_one); if (add_to_list(new_select->group_list,new_one,1)) return 1; @@ -152,12 +153,11 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) List<Item> all_fields(select_lex->item_list); - if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first + if (setup_tables(lex->thd, &select_lex->context, + (TABLE_LIST *)select_lex->table_list.first &select_lex->where, &select_lex->leaf_tables, FALSE) || - setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, - select_lex->item_list, 1, &all_fields,1) || - setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, - item_list_copy, 1, &all_fields, 1)) + setup_fields(lex->thd, 0, select_lex->item_list, 1, &all_fields,1) || + setup_fields(lex->thd, 0, item_list_copy, 1, &all_fields, 1)) return -1; if (select_lex->olap == CUBE_TYPE) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6b65f24e289..a57ad84da5b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2289,6 +2289,10 @@ mysql_execute_command(THD *thd) lex->first_lists_tables_same(); /* should be assigned after making first tables same */ all_tables= lex->query_tables; + /* set context for commands which do not use setup_tables */ + select_lex-> + context.resolve_in_table_list_only((TABLE_LIST*)select_lex-> + table_list.first); /* Reset warning count for each query that uses tables @@ -2568,7 +2572,7 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) || + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); @@ -2877,9 +2881,7 @@ mysql_execute_command(THD *thd) CREATE from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; res= handle_select(thd, lex, result, 0); - select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE; delete result; } /* reset for PS */ @@ -3218,6 +3220,8 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; + /* Skip first table, which is the table we are inserting in */ + select_lex->context.table_list= first_table->next_local; res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, lex->update_list, lex->value_list, lex->duplicates, lex->ignore); @@ -3228,6 +3232,7 @@ end_with_restore_list: case SQLCOM_REPLACE_SELECT: case SQLCOM_INSERT_SELECT: { + select_result *result; DBUG_ASSERT(first_table == all_tables && first_table != 0); if ((res= insert_precheck(thd, all_tables))) break; @@ -3239,27 +3244,24 @@ end_with_restore_list: /* Don't unlock tables until command is written to binary log */ select_lex->options|= SELECT_NO_UNLOCK; - select_result *result; unit->set_limit(select_lex); - if (!(res= open_and_lock_tables(thd, all_tables))) { /* Skip first table, which is the table we are inserting in */ select_lex->table_list.first= (byte*)first_table->next_local; res= mysql_insert_select_prepare(thd); + lex->select_lex.context.table_list= first_table->next_local; if (!res && (result= new select_insert(first_table, first_table->table, &lex->field_list, - &lex->update_list, &lex->value_list, + &lex->update_list, + &lex->value_list, lex->duplicates, lex->ignore))) { - /* - insert/replace from SELECT give its SELECT_LEX for SELECT, - and item_list belong to SELECT - */ - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + /* Skip first table, which is the table we are inserting in */ + select_lex->context.table_list= first_table->next_local; + res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE); - select_lex->resolve_mode= SELECT_LEX::INSERT_MODE; delete result; } /* revert changes for SP */ @@ -3859,7 +3861,7 @@ end_with_restore_list: { Item *it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1)) + if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) { my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -5226,16 +5228,27 @@ mysql_new_select(LEX *lex, bool move_down) unit->link_prev= 0; unit->return_to= lex->current_select; select_lex->include_down(unit); - /* TODO: assign resolve_mode for fake subquery after merging with new tree */ + /* + By default we assume that it is usual subselect and we have outer name + resolution context, if no we will assign it to 0 later + */ + select_lex->context.outer_context= &select_lex->outer_select()->context; } else { + Name_resolution_context *outer_context; if (lex->current_select->order_list.first && !lex->current_select->braces) { my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY"); DBUG_RETURN(1); } select_lex->include_neighbour(lex->current_select); + /* + we are not sure that we have one level of SELECTs above, so we take + outer_context address from first select of unit + */ + outer_context= + select_lex->master_unit()->first_select()->context.outer_context; SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX *fake= unit->fake_select_lex; if (!fake) @@ -5252,13 +5265,23 @@ mysql_new_select(LEX *lex, bool move_down) fake->make_empty_select(); fake->linkage= GLOBAL_OPTIONS_TYPE; fake->select_limit= 0; + + fake->context.outer_context= outer_context; + /* allow item list resolving in fake select for ORDER BY */ + fake->context.resolve_in_select_list= TRUE; + fake->context.select_lex= fake; } + select_lex->context.outer_context= outer_context; } select_lex->master_unit()->global_parameters= select_lex; select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); lex->current_select= select_lex; - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + /* + in subquery is SELECT query and we allow resolution of names in SELECT + list + */ + select_lex->context.resolve_in_select_list= TRUE; DBUG_RETURN(0); } @@ -6377,9 +6400,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, */ /* - Writing this command to the binlog may result in infinite loops when doing - mysqlbinlog|mysql, and anyway it does not really make sense to log it - automatically (would cause more trouble to users than it would help them) + Writing this command to the binlog may result in infinite loops + when doing mysqlbinlog|mysql, and anyway it does not really make + sense to log it automatically (would cause more trouble to users + than it would help them) */ tmp_write_to_binlog= 0; mysql_log.new_file(1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c97cb037f15..53f706bd0f6 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -917,12 +917,12 @@ static bool mysql_test_insert(Prepared_statement *stmt, goto error; /* - open temporary memory pool for temporary data allocated by derived - tables & preparation procedure - Note that this is done without locks (should not be needed as we will not - access any data here) - If we would use locks, then we have to ensure we are not using - TL_WRITE_DELAYED as having two such locks can cause table corruption. + open temporary memory pool for temporary data allocated by derived + tables & preparation procedure + Note that this is done without locks (should not be needed as we will not + access any data here) + If we would use locks, then we have to ensure we are not using + TL_WRITE_DELAYED as having two such locks can cause table corruption. */ if (open_normal_and_derived_tables(thd, table_list)) goto error; @@ -939,9 +939,9 @@ static bool mysql_test_insert(Prepared_statement *stmt, table_list->table->insert_values=(byte *)1; } - if (mysql_prepare_insert(thd, table_list, table_list->table, fields, - values, update_fields, update_values, duplic, - &unused_conds, FALSE)) + if (mysql_prepare_insert(thd, table_list, table_list->table, + fields, values, update_fields, update_values, + duplic, &unused_conds, FALSE)) goto error; value_count= values->elements; @@ -963,7 +963,7 @@ static bool mysql_test_insert(Prepared_statement *stmt, my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto error; } - if (setup_fields(thd, 0, table_list, *values, 0, 0, 0)) + if (setup_fields(thd, 0, *values, 0, 0, 0)) goto error; } } @@ -1039,9 +1039,9 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->grant.want_privilege= want_privilege; table_list->table->grant.want_privilege= want_privilege; #endif - thd->lex->select_lex.no_wrap_view_item= 1; - res= setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0); - thd->lex->select_lex.no_wrap_view_item= 0; + thd->lex->select_lex.no_wrap_view_item= TRUE; + res= setup_fields(thd, 0, select->item_list, 1, 0, 0); + thd->lex->select_lex.no_wrap_view_item= FALSE; if (res) goto error; #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -1050,7 +1050,7 @@ static int mysql_test_update(Prepared_statement *stmt, table_list->table->grant.want_privilege= (SELECT_ACL & ~table_list->table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, stmt->lex->value_list, 0, 0, 0)) + if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0)) goto error; /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); @@ -1119,6 +1119,8 @@ static bool mysql_test_select(Prepared_statement *stmt, SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_test_select"); + lex->select_lex.context.resolve_in_select_list= TRUE; + #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) @@ -1207,7 +1209,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, if (open_and_lock_tables(thd, tables)) DBUG_RETURN(TRUE); - DBUG_RETURN(setup_fields(thd, 0, 0, *values, 0, 0, 0)); + DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0)); } @@ -1277,6 +1279,8 @@ static bool select_like_stmt_test(Prepared_statement *stmt, THD *thd= stmt->thd; LEX *lex= stmt->lex; + lex->select_lex.context.resolve_in_select_list= TRUE; + if (specific_prepare && (*specific_prepare)(thd)) DBUG_RETURN(TRUE); @@ -1354,9 +1358,8 @@ static bool mysql_test_create_table(Prepared_statement *stmt) if (select_lex->item_list.elements) { - select_lex->resolve_mode= SELECT_LEX::SELECT_MODE; + select_lex->context.resolve_in_select_list= TRUE; res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0); - select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE; } /* put tables back for PS rexecuting */ @@ -1446,16 +1449,21 @@ error: static bool mysql_insert_select_prepare_tester(THD *thd) { + TABLE_LIST *first; + bool res; SELECT_LEX *first_select= &thd->lex->select_lex; /* Skip first table, which is the table we are inserting in */ - first_select->table_list.first= (byte*)((TABLE_LIST*)first_select-> - table_list.first)->next_local; + first_select->table_list.first= (byte*)(first= + ((TABLE_LIST*)first_select-> + table_list.first)->next_local); + res= mysql_insert_select_prepare(thd); /* insert/replace from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - first_select->resolve_mode= SELECT_LEX::SELECT_MODE; - return mysql_insert_select_prepare(thd); + thd->lex->select_lex.context.resolve_in_select_list= TRUE; + thd->lex->select_lex.context.table_list= first; + return res; } @@ -1493,12 +1501,12 @@ static int mysql_test_insert_select(Prepared_statement *stmt, first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first; DBUG_ASSERT(first_local_table != 0); - res= select_like_stmt_test_with_open_n_lock(stmt, tables, - &mysql_insert_select_prepare_tester, - OPTION_SETUP_TABLES_DONE); + res= + select_like_stmt_test_with_open_n_lock(stmt, tables, + &mysql_insert_select_prepare_tester, + OPTION_SETUP_TABLES_DONE); /* revert changes made by mysql_insert_select_prepare_tester */ lex->select_lex.table_list.first= (byte*) first_local_table; - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; return res; } @@ -1538,6 +1546,10 @@ static bool check_prepared_statement(Prepared_statement *stmt, lex->first_lists_tables_same(); tables= lex->query_tables; + /* set context for commands which do not use setup_tables */ + lex->select_lex.context.resolve_in_table_list_only(select_lex-> + get_table_list()); + switch (sql_command) { case SQLCOM_REPLACE: case SQLCOM_INSERT: @@ -1813,18 +1825,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, void init_stmt_after_parse(THD *thd, LEX *lex) { SELECT_LEX *sl= lex->all_selects_list; - /* - Save WHERE clause pointers, because they may be changed during query - optimisation. - */ - for (; sl; sl= sl->next_select_in_list()) - { - sl->prep_where= sl->where; - sl->uncacheable&= ~UNCACHEABLE_PREPARE; - } - for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global) - table->prep_on_expr= table->on_expr; + for (; sl; sl= sl->next_select_in_list()) + sl->uncacheable&= ~UNCACHEABLE_PREPARE; } @@ -2203,13 +2206,15 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) ulong num_rows= uint4korr(packet+4); Prepared_statement *stmt; Statement stmt_backup; + Cursor *cursor; DBUG_ENTER("mysql_stmt_fetch"); statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) DBUG_VOID_RETURN; - if (!stmt->cursor || !stmt->cursor->is_open()) + cursor= stmt->cursor; + if (!cursor || !cursor->is_open()) { my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id); DBUG_VOID_RETURN; @@ -2222,22 +2227,27 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) my_pthread_setprio(pthread_self(), QUERY_PRIOR); thd->protocol= &thd->protocol_prep; // Switch to binary protocol - stmt->cursor->fetch(num_rows); + cursor->fetch(num_rows); thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - thd->restore_backup_statement(stmt, &stmt_backup); - thd->current_arena= thd; - - if (!stmt->cursor->is_open()) + if (!cursor->is_open()) { /* We're done with the fetch: reset PS for next execution */ cleanup_stmt_and_thd_after_use(stmt, thd); reset_stmt_params(stmt); + /* + Must be the last, as some momory is still needed for + the previous calls. + */ + free_root(cursor->mem_root, MYF(0)); } + thd->restore_backup_statement(stmt, &stmt_backup); + thd->current_arena= thd; + DBUG_VOID_RETURN; } @@ -2264,14 +2274,21 @@ void mysql_stmt_reset(THD *thd, char *packet) /* There is always space for 4 bytes in buffer */ ulong stmt_id= uint4korr(packet); Prepared_statement *stmt; + Cursor *cursor; DBUG_ENTER("mysql_stmt_reset"); statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; - if (stmt->cursor && stmt->cursor->is_open()) - stmt->cursor->close(); + cursor= stmt->cursor; + if (cursor && cursor->is_open()) + { + thd->change_list= cursor->change_list; + cursor->close(FALSE); + cleanup_stmt_and_thd_after_use(stmt, thd); + free_root(cursor->mem_root, MYF(0)); + } stmt->state= Query_arena::PREPARED; @@ -2430,6 +2447,8 @@ Prepared_statement::~Prepared_statement() if (cursor) cursor->Cursor::~Cursor(); free_items(); + if (cursor) + free_root(cursor->mem_root, MYF(0)); delete lex->result; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a31e4203a93..66e783a2103 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -28,8 +28,6 @@ #include <hash.h> #include <ft_global.h> -typedef uint32 cache_rec_length_type; - const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "MAYBE_REF","ALL","range","index","fulltext", "ref_or_null","unique_subquery","index_subquery", @@ -182,10 +180,10 @@ static void reset_cache_read(JOIN_CACHE *cache); static void reset_cache_write(JOIN_CACHE *cache); static void read_cached_record(JOIN_TAB *tab); static bool cmp_buffer_with_ref(JOIN_TAB *tab); -static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields,ORDER *new_order); -static ORDER *create_distinct_group(THD *thd, ORDER *order, - List<Item> &fields, +static bool setup_new_fields(THD *thd, List<Item> &fields, + List<Item> &all_fields, ORDER *new_order); +static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array, + ORDER *order, List<Item> &fields, bool *all_order_by_fields_used); static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); @@ -283,6 +281,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array, save_allow_sum_func= thd->allow_sum_func; thd->allow_sum_func= 0; res= setup_conds(thd, tables, leaves, conds); + thd->allow_sum_func= save_allow_sum_func; res= res || setup_order(thd, ref_pointer_array, tables, fields, all_fields, order); @@ -339,11 +338,12 @@ 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, tables_list, &conds, &select_lex->leaf_tables, + setup_tables(thd, &select_lex->context, + tables_list, &conds, &select_lex->leaf_tables, FALSE)) || 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), tables_list, fields_list, 1, + setup_fields(thd, (*rref_pointer_array), fields_list, 1, &all_fields, 1) || setup_without_group(thd, (*rref_pointer_array), tables_list, select_lex->leaf_tables, fields_list, @@ -359,7 +359,7 @@ JOIN::prepare(Item ***rref_pointer_array, thd->allow_sum_func=1; select_lex->having_fix_field= 1; bool having_fix_rc= (!having->fixed && - (having->fix_fields(thd, tables_list, &having) || + (having->fix_fields(thd, &having) || having->check_cols(1))); select_lex->having_fix_field= 0; if (having_fix_rc || thd->net.report_error) @@ -432,7 +432,7 @@ JOIN::prepare(Item ***rref_pointer_array, goto err; /* purecov: inspected */ if (procedure) { - if (setup_new_fields(thd, tables_list, fields_list, all_fields, + if (setup_new_fields(thd, fields_list, all_fields, procedure->param_fields)) goto err; /* purecov: inspected */ if (procedure->group) @@ -566,7 +566,7 @@ JOIN::optimize() Item_cond_and can't be fixed after creation, so we do not check conds->fixed */ - conds->fix_fields(thd, tables_list, &conds); + conds->fix_fields(thd, &conds); conds->change_ref_to_fields(thd, tables_list); conds->top_level_item(); having= 0; @@ -779,7 +779,8 @@ JOIN::optimize() bool all_order_fields_used; if (order) skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1); - if ((group_list=create_distinct_group(thd, order, fields_list, + if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, + order, fields_list, &all_order_fields_used))) { bool skip_group= (skip_sort_order && @@ -1117,7 +1118,6 @@ int JOIN::reinit() { DBUG_ENTER("JOIN::reinit"); - first_record= 0; if (exec_tmp_table1) @@ -1737,6 +1737,7 @@ Cursor::init_from_thd(THD *thd) lock= thd->lock; query_id= thd->query_id; free_list= thd->free_list; + change_list= thd->change_list; reset_thd(thd); /* XXX: thd->locked_tables is not changed. @@ -1753,6 +1754,7 @@ Cursor::reset_thd(THD *thd) thd->open_tables= 0; thd->lock= 0; thd->free_list= 0; + thd->change_list.empty(); } @@ -1826,6 +1828,7 @@ Cursor::fetch(ulong num_rows) thd->open_tables= open_tables; thd->lock= lock; thd->query_id= query_id; + thd->change_list= change_list; /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &backup_arena); @@ -1842,10 +1845,8 @@ Cursor::fetch(ulong num_rows) #ifdef USING_TRANSACTIONS ha_release_temporary_latches(thd); #endif - + /* Grab free_list here to correctly free it in close */ thd->restore_backup_item_arena(this, &backup_arena); - DBUG_ASSERT(thd->free_list == 0); - reset_thd(thd); if (error == NESTED_LOOP_CURSOR_LIMIT) { @@ -1853,10 +1854,12 @@ Cursor::fetch(ulong num_rows) thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; ::send_eof(thd); thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; + change_list= thd->change_list; + reset_thd(thd); } else { - close(); + close(TRUE); if (error == NESTED_LOOP_OK) { thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; @@ -1871,7 +1874,7 @@ Cursor::fetch(ulong num_rows) void -Cursor::close() +Cursor::close(bool is_active) { THD *thd= join->thd; DBUG_ENTER("Cursor::close"); @@ -1884,6 +1887,10 @@ Cursor::close() (void) unit->cleanup(); else (void) join->select_lex->cleanup(); + + if (is_active) + close_thread_tables(thd); + else { /* XXX: Another hack: closing tables used in the cursor */ DBUG_ASSERT(lock || open_tables || derived_tables); @@ -1903,11 +1910,7 @@ Cursor::close() join= 0; unit= 0; free_items(); - /* - Must be last, as some memory might be allocated for free purposes, - like in free_tmp_table() (TODO: fix this issue) - */ - free_root(mem_root, MYF(0)); + change_list.empty(); DBUG_VOID_RETURN; } @@ -1915,7 +1918,7 @@ Cursor::close() Cursor::~Cursor() { if (is_open()) - close(); + close(FALSE); } /*********************************************************************/ @@ -1977,6 +1980,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, bool free_join= 1; DBUG_ENTER("mysql_select"); + select_lex->context.resolve_in_select_list= TRUE; JOIN *join; if (select_lex->join != 0) { @@ -7445,7 +7449,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) conds->top_level_item(); /* conds is always a new item as both cond and on_expr existed */ DBUG_ASSERT(!conds->fixed); - conds->fix_fields(join->thd, 0, &conds); + conds->fix_fields(join->thd, &conds); } else conds= table->on_expr; @@ -7666,7 +7670,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond->fixed, also it do not need tables so we use 0 as second argument. */ - cond->fix_fields(thd, 0, &cond); + cond->fix_fields(thd, &cond); } thd->insert_id(0); // Clear for next request } @@ -7685,7 +7689,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value) cond->fixed, also it do not need tables so we use 0 as second argument. */ - cond->fix_fields(thd, 0, &cond); + cond->fix_fields(thd, &cond); } } } @@ -7957,7 +7961,9 @@ Field *create_tmp_field_for_schema(THD *thd, Item *item, TABLE *table) Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, - bool group, bool modify_item, uint convert_blob_length) + bool group, bool modify_item, + bool table_cant_handle_bit_fields, + uint convert_blob_length) { switch (type) { case Item::SUM_FUNC_ITEM: @@ -7972,6 +7978,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::DEFAULT_VALUE_ITEM: { Item_field *field= (Item_field*) item; + if (table_cant_handle_bit_fields && field->field->type() == FIELD_TYPE_BIT) + return create_tmp_field_from_item(thd, item, table, copy_func, + modify_item, convert_blob_length); return create_tmp_field_from_field(thd, (*from_field= field->field), item->name, table, modify_item ? (Item_field*) item : NULL, @@ -8195,6 +8204,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, Field *new_field= create_tmp_field(thd, table, arg, arg->type(), ©_func, tmp_from_field, group != 0,not_all_columns, + group || distinct, param->convert_blob_length); if (!new_field) goto err; // Should be OOM @@ -8205,6 +8215,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *blob_field++= (uint) (reg_field - table->field); blob_count++; } + new_field->field_index= (uint) (reg_field - table->field); *(reg_field++)= new_field; if (new_field->real_type() == MYSQL_TYPE_STRING || new_field->real_type() == MYSQL_TYPE_VARCHAR) @@ -8242,7 +8253,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, create_tmp_field_for_schema(thd, item, table) : create_tmp_field(thd, table, item, type, ©_func, tmp_from_field, group != 0, - not_all_columns || group !=0, + not_all_columns || group != 0, 0, param->convert_blob_length); if (!new_field) @@ -8270,6 +8281,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, new_field->flags|= GROUP_FLAG; } new_field->query_id= thd->query_id; + new_field->field_index= (uint) (reg_field - table->field); *(reg_field++) =new_field; } if (!--hidden_field_count) @@ -8380,6 +8392,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, } else field->move_field((char*) pos,(uchar*) 0,0); + if (field->type() == FIELD_TYPE_BIT) + { + /* We have to reserve place for extra bits among null bits */ + ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8, + null_count & 7); + null_count+= (field->field_length & 7); + } field->reset(); if (from_field[i]) { /* Not a table Item */ @@ -11171,8 +11190,7 @@ static bool fix_having(JOIN *join, Item **having) else // This should never happen if (!(table->select->cond= new Item_cond_and(table->select->cond, sort_table_cond)) || - table->select->cond->fix_fields(join->thd, join->tables_list, - &table->select->cond)) + table->select->cond->fix_fields(join->thd, &table->select->cond)) return 1; table->select_cond=table->select->cond; table->select_cond->top_level_item(); @@ -11622,7 +11640,7 @@ used_blob_length(CACHE_FIELD **ptr) static bool store_record_in_cache(JOIN_CACHE *cache) { - cache_rec_length_type length; + uint length; uchar *pos; CACHE_FIELD *copy,*end_field; bool last_record; @@ -11667,9 +11685,9 @@ store_record_in_cache(JOIN_CACHE *cache) end > str && end[-1] == ' ' ; end--) ; length=(uint) (end-str); - memcpy(pos+sizeof(length), str, length); - memcpy_fixed(pos, &length, sizeof(length)); - pos+= length+sizeof(length); + memcpy(pos+2, str, length); + int2store(pos, length); + pos+= length+2; } else { @@ -11703,7 +11721,7 @@ static void read_cached_record(JOIN_TAB *tab) { uchar *pos; - cache_rec_length_type length; + uint length; bool last_record; CACHE_FIELD *copy,*end_field; @@ -11732,10 +11750,10 @@ read_cached_record(JOIN_TAB *tab) { if (copy->strip) { - memcpy_fixed(&length, pos, sizeof(length)); - memcpy(copy->str, pos+sizeof(length), length); + length= uint2korr(pos); + memcpy(copy->str, pos+2, length); memset(copy->str+length, ' ', copy->length-length); - pos+= sizeof(length)+length; + pos+= 2 + length; } else { @@ -11772,12 +11790,10 @@ cp_buffer_from_ref(THD *thd, TABLE_REF *ref) thd->count_cuted_fields= CHECK_FIELD_IGNORE; for (store_key **copy=ref->key_copy ; *copy ; copy++) { - int res; - if ((res= (*copy)->copy())) + if ((*copy)->copy() & 1) { thd->count_cuted_fields= save_count_cuted_fields; - if ((res= res & 1)) - return res; // Something went wrong + return 1; // Something went wrong } } thd->count_cuted_fields= save_count_cuted_fields; @@ -11864,8 +11880,8 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, original field name, we should additionaly check if we have conflict for this name (in case if we would perform lookup in all tables). */ - if (unaliased && !order_item->fixed && order_item->fix_fields(thd, tables, - order->item)) + if (unaliased && !order_item->fixed && + order_item->fix_fields(thd, order->item)) return TRUE; /* Lookup the current GROUP field in the FROM clause. */ @@ -11876,7 +11892,8 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, order_item_type == Item::REF_ITEM) { from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables, - &view_ref, IGNORE_ERRORS, TRUE); + &view_ref, IGNORE_ERRORS, TRUE, + FALSE); if (!from_field) from_field= (Field*) not_found_field; } @@ -11933,7 +11950,7 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, arguments for which fix_fields already was called. */ if (!order_item->fixed && - (order_item->fix_fields(thd, tables, order->item) || + (order_item->fix_fields(thd, order->item) || (order_item= *order->item)->check_cols(1) || thd->is_fatal_error)) return TRUE; /* Wrong field. */ @@ -12045,7 +12062,7 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, */ static bool -setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, +setup_new_fields(THD *thd, List<Item> &fields, List<Item> &all_fields, ORDER *new_field) { Item **item; @@ -12062,7 +12079,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, else { thd->where="procedure list"; - if ((*new_field->item)->fix_fields(thd, tables, new_field->item)) + if ((*new_field->item)->fix_fields(thd, new_field->item)) DBUG_RETURN(1); /* purecov: inspected */ all_fields.push_front(*new_field->item); new_field->item=all_fields.head_ref(); @@ -12078,12 +12095,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, */ static ORDER * -create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields, +create_distinct_group(THD *thd, Item **ref_pointer_array, + ORDER *order_list, List<Item> &fields, bool *all_order_by_fields_used) { List_iterator<Item> li(fields); Item *item; ORDER *order,*group,**prev; + uint index= 0; *all_order_by_fields_used= 1; while ((item=li++)) @@ -12115,11 +12134,17 @@ create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields, ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) return 0; - ord->item=li.ref(); + /* + We have here only field_list (not all_field_list), so we can use + simple indexing of ref_pointer_array (order in the array and in the + list are same) + */ + ord->item= ref_pointer_array + index; ord->asc=1; *prev=ord; prev= &ord->next; } + index++; } *prev=0; return group; @@ -12142,7 +12167,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, param->quick_group=1; while ((field=li++)) { - Item::Type type=field->type(); + Item::Type type=field->real_item()->type(); if (type == Item::FIELD_ITEM) param->field_count++; else if (type == Item::SUM_FUNC_ITEM) @@ -12156,7 +12181,7 @@ count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, for (uint i=0 ; i < sum_item->arg_count ; i++) { - if (sum_item->args[0]->type() == Item::FIELD_ITEM) + if (sum_item->args[0]->real_item()->type() == Item::FIELD_ITEM) param->field_count++; else param->func_count++; @@ -12403,9 +12428,10 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, param->copy_funcs.empty(); for (i= 0; (pos= li++); i++) { - if (pos->type() == Item::FIELD_ITEM) + if (pos->real_item()->type() == Item::FIELD_ITEM) { Item_field *item; + pos= pos->real_item(); if (!(item= new Item_field(thd, ((Item_field*) pos)))) goto err; pos= item; @@ -12860,7 +12886,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) DBUG_RETURN(TRUE); if (!cond->fixed) - cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond); + cond->fix_fields(thd, (Item**)&cond); if (join_tab->select) { error=(int) cond->add(join_tab->select->cond); @@ -12902,8 +12928,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) thd reference to the context expr expression to make replacement group_list list of references to group by items - changed out: returns 1 if item contains a replaced field item - + changed out: returns 1 if item contains a replaced field item + DESCRIPTION The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate @@ -12932,6 +12958,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { if (expr->arg_count) { + Name_resolution_context *context= &thd->lex->current_select->context; Item **arg,**arg_end; for (arg= expr->arguments(), arg_end= expr->arguments()+expr->arg_count; @@ -12945,8 +12972,9 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, { if (item->eq(*group_tmp->item,0)) { - Item *new_item; - if(!(new_item= new Item_ref(group_tmp->item, 0, item->name))) + Item *new_item; + if(!(new_item= new Item_ref(context, group_tmp->item, 0, + item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); *changed= TRUE; diff --git a/sql/sql_select.h b/sql/sql_select.h index 6d33ae2f978..ac3e8898cc6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -390,6 +390,7 @@ class Cursor: public Sql_alloc, public Query_arena /* List of items created during execution */ query_id_t query_id; public: + Item_change_list change_list; select_send result; /* Temporary implementation as now we replace THD state by value */ @@ -402,7 +403,8 @@ public: void fetch(ulong num_rows); void reset() { join= 0; } bool is_open() const { return join != 0; } - void close(); + + void close(bool is_active); void set_unit(SELECT_LEX_UNIT *unit_arg) { unit= unit_arg; } Cursor(THD *thd); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 12025c82da6..72092db400d 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3240,11 +3240,13 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { ST_FIELD_INFO *field_info= schema_table->fields_info; + Name_resolution_context *context= &thd->lex->select_lex.context; for ( ; field_info->field_name; field_info++) { if (field_info->old_name) { - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3264,12 +3266,14 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; LEX *lex= thd->lex; SELECT_LEX *sel= lex->current_select; + Name_resolution_context *context= &sel->context; if (!sel->item_list.elements) { ST_FIELD_INFO *field_info= &schema_table->fields_info[1]; String buffer(tmp,sizeof(tmp), system_charset_info); - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (!field || add_item_to_list(thd, field)) return 1; buffer.length(0); @@ -3291,6 +3295,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) char tmp[128]; String buffer(tmp,sizeof(tmp), thd->charset()); LEX *lex= thd->lex; + Name_resolution_context *context= &lex->select_lex.context; ST_FIELD_INFO *field_info= &schema_table->fields_info[2]; buffer.length(0); @@ -3302,7 +3307,8 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) buffer.append(lex->wild->ptr()); buffer.append(")"); } - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (add_item_to_list(thd, field)) return 1; field->set_name(buffer.ptr(), buffer.length(), system_charset_info); @@ -3310,7 +3316,7 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) { field->set_name(buffer.ptr(), buffer.length(), system_charset_info); field_info= &schema_table->fields_info[3]; - field= new Item_field(NullS, NullS, field_info->field_name); + field= new Item_field(context, NullS, NullS, field_info->field_name); if (add_item_to_list(thd, field)) return 1; field->set_name(field_info->old_name, strlen(field_info->old_name), @@ -3325,6 +3331,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {3, 14, 13, 6, 15, 5, 16, 17, 18, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; @@ -3332,7 +3340,8 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) *field_num == 17 || *field_num == 18)) continue; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3351,10 +3360,13 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {0, 2, 1, 3, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3373,10 +3385,13 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table) int fields_arr[]= {2, 3, 4, 19, 16, 15, 14, 18, -1}; int *field_num= fields_arr; ST_FIELD_INFO *field_info; + Name_resolution_context *context= &thd->lex->select_lex.context; + for (; *field_num >= 0; field_num++) { field_info= &schema_table->fields_info[*field_num]; - Item_field *field= new Item_field(NullS, NullS, field_info->field_name); + Item_field *field= new Item_field(context, + NullS, NullS, field_info->field_name); if (field) { field->set_name(field_info->old_name, @@ -3442,12 +3457,11 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) if (table_list->field_translation) { - Field_translator *end= table_list->field_translation + - sel->item_list.elements; + Field_translator *end= table_list->field_translation_end; for (transl= table_list->field_translation; transl < end; transl++) { if (!transl->item->fixed && - transl->item->fix_fields(thd, table_list, &transl->item)) + transl->item->fix_fields(thd, &transl->item)) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -3464,11 +3478,12 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { char *name= item->name; transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item)) + if (!item->fixed && item->fix_fields(thd, &transl[i].item)) DBUG_RETURN(1); transl[i++].name= name; } table_list->field_translation= transl; + table_list->field_translation_end= transl + sel->item_list.elements; } DBUG_RETURN(0); @@ -3495,7 +3510,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx); LEX_STRING db, table; DBUG_ENTER("mysql_schema_select"); - /* + /* We have to make non const db_name & table_name because of lower_case_table_names */ @@ -3503,7 +3518,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, information_schema_name.length, 0); make_lex_string(thd, &table, schema_table->table_name, strlen(schema_table->table_name), 0); - if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ + if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */ !sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0), 0, 0, TL_READ, (List<String> *) 0, (List<String> *) 0)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e03a6c24d42..b050d46f358 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -267,7 +267,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->table_name); else error= 1; - } else { @@ -1734,7 +1733,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, field=item->tmp_table_field(&tmp_table); else field=create_tmp_field(thd, &tmp_table, item, item->type(), - (Item ***) 0, &tmp_field,0,0,0); + (Item ***) 0, &tmp_field, 0, 0, 0, 0); if (!field || !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ? ((Item_field *)item)->field : @@ -3400,7 +3399,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, */ if (!Field::type_can_have_key_part(cfield->field->type()) || !Field::type_can_have_key_part(cfield->sql_type) || - cfield->field->field_length == key_part_length || + (cfield->field->field_length == key_part_length && + !f_is_blob(key_part->key_type)) || (cfield->length && (cfield->length < key_part_length / key_part->field->charset()->mbmaxlen))) key_part_length= 0; // Use whole field diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 95524a6dfbf..1272d38f729 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -201,7 +201,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables) { trg_field->setup_field(thd, table); if (!trg_field->fixed && - trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0)) + trg_field->fix_fields(thd, (Item **)0)) return 1; } diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 4df3fe0949d..d588572a762 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -65,8 +65,8 @@ class udf_handler :public Sql_alloc Item_result result_type () const { return u_d ? u_d->returns : STRING_RESULT;} bool get_arguments(); - bool fix_fields(THD *thd,struct st_table_list *tlist,Item_result_field *item, - uint arg_count,Item **args); + bool fix_fields(THD *thd, Item_result_field *item, + uint arg_count, Item **args); void cleanup(); double val(my_bool *null_value) { diff --git a/sql/sql_union.cc b/sql/sql_union.cc index bf657ce5396..c23f14e980b 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -124,6 +124,13 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd) fake_select_lex->table_list.link_in_list((byte *)&result_table_list, (byte **) &result_table_list.next_local); + for (ORDER *order= (ORDER *)global_parameters->order_list.first; + order; + order=order->next) + { + (*order->item)->walk(&Item::change_context_processor, + (byte *) &fake_select_lex->context); + } } @@ -187,6 +194,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, else tmp_result= sel_result; + sl->context.resolve_in_select_list= TRUE; + for (;sl; sl= sl->next_select()) { bool can_skip_order_by; @@ -646,6 +655,7 @@ bool st_select_lex::cleanup() if (join) { + DBUG_ASSERT((st_select_lex*)join->select_lex == this); error= join->destroy(); delete join; join= 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 6b9a8ddfcb6..ce4a7d6394e 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -67,6 +67,8 @@ static bool check_fields(THD *thd, List<Item> &items) List_iterator<Item> it(items); Item *item; Item_field *field; + Name_resolution_context *context= &thd->lex->select_lex.context; + while ((item= it++)) { if (!(field= item->filed_for_view_update())) @@ -185,14 +187,8 @@ int mysql_update(THD *thd, #ifndef NO_EMBEDDED_ACCESS_CHECKS table_list->grant.want_privilege= table->grant.want_privilege= want_privilege; #endif - { - bool res; - select_lex->no_wrap_view_item= 1; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); - select_lex->no_wrap_view_item= 0; - if (res) - DBUG_RETURN(1); /* purecov: inspected */ - } + if (setup_fields_with_no_wrap(thd, 0, fields, 1, 0, 0)) + DBUG_RETURN(1); /* purecov: inspected */ if (table_list->view && check_fields(thd, fields)) { DBUG_RETURN(1); @@ -216,7 +212,7 @@ int mysql_update(THD *thd, table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); #endif - if (setup_fields(thd, 0, table_list, values, 1, 0, 0)) + if (setup_fields(thd, 0, values, 1, 0, 0)) { free_underlaid_joins(thd, select_lex); DBUG_RETURN(1); /* purecov: inspected */ @@ -557,7 +553,9 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, tables.table= table; tables.alias= table_list->alias; - if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, FALSE) || + if (setup_tables(thd, &select_lex->context, + table_list, conds, &select_lex->leaf_tables, + FALSE) || 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, @@ -617,7 +615,6 @@ bool mysql_multi_update_prepare(THD *thd) TABLE_LIST *tl, *leaves; List<Item> *fields= &lex->select_lex.item_list; table_map tables_for_update; - int res; bool update_view= 0; /* if this multi-update was converted from usual update, here is table @@ -642,15 +639,12 @@ bool mysql_multi_update_prepare(THD *thd) call in setup_tables()). */ - if (setup_tables(thd, table_list, &lex->select_lex.where, + if (setup_tables(thd, &lex->select_lex.context, + table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE)) DBUG_RETURN(TRUE); - leaves= lex->select_lex.leaf_tables; - if ((lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), - lex->select_lex.no_wrap_view_item= 0, - res)) + if (setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) DBUG_RETURN(TRUE); for (tl= table_list; tl ; tl= tl->next_local) @@ -672,6 +666,7 @@ bool mysql_multi_update_prepare(THD *thd) /* Setup timestamp handling and locking mode */ + leaves= lex->select_lex.leaf_tables; for (tl= leaves; tl; tl= tl->next_leaf) { TABLE *table= tl->table; @@ -762,12 +757,10 @@ bool mysql_multi_update_prepare(THD *thd) for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) tbl->cleanup_items(); - if (setup_tables(thd, table_list, &lex->select_lex.where, + if (setup_tables(thd, &lex->select_lex.context, + table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE) || - (lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), - lex->select_lex.no_wrap_view_item= 0, - res)) + setup_fields_with_no_wrap(thd, 0, *fields, 1, 0, 0)) DBUG_RETURN(TRUE); } @@ -897,7 +890,7 @@ int multi_update::prepare(List<Item> ¬_used_values, reference tables */ - if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0)) + if (setup_fields(thd, 0, *values, 1, 0, 0)) DBUG_RETURN(1); /* diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 25610f8749b..c8abee1e7dc 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -831,10 +831,23 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->effective_algorithm= VIEW_ALGORITHM_MERGE; DBUG_PRINT("info", ("algorithm: MERGE")); table->updatable= (table->updatable_view != 0); - table->effective_with_check= (uint8)table->with_check; - - table->ancestor= view_tables; - + table->effective_with_check= + old_lex->get_effective_with_check(table); + + /* prepare view context */ + lex->select_lex.context.resolve_in_table_list_only(table->ancestor= + view_tables); + lex->select_lex.context.outer_context= 0; + lex->select_lex.context.select_lex= table->select_lex; + /* do not check privileges & hide errors for view underlyings */ + for (SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + { + sl->context.check_privileges= FALSE; + sl->context.error_processor= &view_error_processor; + sl->context.error_processor_data= (void *)table; + } /* Tables of the main select of the view should be marked as belonging to the same select as original view (again we can use LEX::select_lex @@ -867,13 +880,12 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) table->where= view_select->where; /* Add subqueries units to SELECT into which we merging current view. - unit(->next)* chain starts with subqueries that are used by this view and continues with subqueries that are used by other views. We must not add any subquery twice (otherwise we'll form a loop), - to do this we remember in end_unit the first subquery that has + to do this we remember in end_unit the first subquery that has been already added. - + NOTE: we do not support UNION here, so we take only one select */ SELECT_LEX_NODE *end_unit= table->select_lex->slave; @@ -1059,9 +1071,9 @@ frm_type_enum mysql_frm_type(char *path) bool check_key_in_view(THD *thd, TABLE_LIST *view) { TABLE *table; - Field_translator *trans; + Field_translator *trans, *end_of_trans; KEY *key_info, *key_info_end; - uint i, elements_in_view; + uint i; DBUG_ENTER("check_key_in_view"); /* @@ -1078,9 +1090,24 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) trans= view->field_translation; key_info_end= (key_info= table->key_info)+ table->s->keys; - elements_in_view= view->view->select_lex.item_list.elements; + end_of_trans= view->field_translation_end; DBUG_ASSERT(table != 0 && view->field_translation != 0); + { + /* + We should be sure that all fields are ready to get keys from them, but + this operation should not have influence on Field::query_id, to avoid + marking as used fields which are not used + */ + bool save_set_query_id= thd->set_query_id; + thd->set_query_id= 0; + for (Field_translator *fld= trans; fld < end_of_trans; fld++) + { + if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item)) + return TRUE; + } + thd->set_query_id= save_set_query_id; + } /* Loop over all keys to see if a unique-not-null key is used */ for (;key_info != key_info_end ; key_info++) { @@ -1092,15 +1119,15 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) /* check that all key parts are used */ for (;;) { - uint k; - for (k= 0; k < elements_in_view; k++) + Field_translator *k; + for (k= trans; k < end_of_trans; k++) { Item_field *field; - if ((field= trans[k].item->filed_for_view_update()) && + if ((field= k->item->filed_for_view_update()) && field->field == key_part->field) break; } - if (k == elements_in_view) + if (k == end_of_trans) break; // Key is not possible if (++key_part == key_part_end) DBUG_RETURN(FALSE); // Found usable key @@ -1112,19 +1139,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) /* check all fields presence */ { Field **field_ptr; + Field_translator *fld; for (field_ptr= table->field; *field_ptr; field_ptr++) { - for (i= 0; i < elements_in_view; i++) + for (fld= trans; fld < end_of_trans; fld++) { Item_field *field; - if ((field= trans[i].item->filed_for_view_update()) && + if ((field= fld->item->filed_for_view_update()) && field->field == *field_ptr) break; } - if (i == elements_in_view) // If field didn't exists + if (fld == end_of_trans) // If field didn't exists { /* - Keys or all fields of underlying tables are not foud => we have + Keys or all fields of underlying tables are not found => we have to check variable updatable_views_with_limit to decide should we issue an error or just a warning */ @@ -1149,6 +1177,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) SYNOPSIS insert_view_fields() + thd thread handler list list for insertion view view for processing @@ -1157,19 +1186,20 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) TRUE error (is not sent to cliet) */ -bool insert_view_fields(List<Item> *list, TABLE_LIST *view) +bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view) { - uint elements_in_view= view->view->select_lex.item_list.elements; + Field_translator *trans_end; Field_translator *trans; DBUG_ENTER("insert_view_fields"); if (!(trans= view->field_translation)) DBUG_RETURN(FALSE); + trans_end= view->field_translation_end; - for (uint i= 0; i < elements_in_view; i++) + for (Field_translator *entry= trans; entry < trans_end; entry++) { Item_field *fld; - if ((fld= trans[i].item->filed_for_view_update())) + if ((fld= entry->item->filed_for_view_update())) list->push_back(fld); else { diff --git a/sql/sql_view.h b/sql/sql_view.h index 4e6aaf7f477..3246dbae383 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -25,7 +25,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode); bool check_key_in_view(THD *thd, TABLE_LIST * view); -bool insert_view_fields(List<Item> *list, TABLE_LIST *view); +bool insert_view_fields(THD *thd, List<Item> *list, TABLE_LIST *view); frm_type_enum mysql_frm_type(char *path); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 360bc421965..4fc9819d0e1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1259,7 +1259,6 @@ create: THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; /* first table in list is target VIEW name */ if (!lex->select_lex.add_table_to_list(thd, $5, NULL, 0)) YYABORT; @@ -2114,6 +2113,7 @@ sp_proc_stmt: } | LABEL_SYM IDENT { +#ifdef SP_GOTO LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -2131,9 +2131,14 @@ sp_proc_stmt: lab->ctx= ctx; sp->backpatch(lab); } +#else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#endif } | GOTO_SYM IDENT { +#ifdef SP_GOTO LEX *lex= Lex; sp_head *sp= lex->sphead; sp_pcontext *ctx= lex->spcont; @@ -2186,6 +2191,10 @@ sp_proc_stmt: i= new sp_instr_jump(ip, ctx, lab->ip); /* Jump back */ sp->add_instr(i); } +#else + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; +#endif } | OPEN_SYM ident { @@ -3383,7 +3392,6 @@ alter: LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; lex->create_view_mode= VIEW_ALTER; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; /* first table in list is target VIEW name */ lex->select_lex.add_table_to_list(thd, $4, NULL, 0); } @@ -3941,7 +3949,6 @@ select: { LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; - lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; } ; @@ -4095,7 +4102,10 @@ select_item_list: | '*' { THD *thd= YYTHD; - if (add_item_to_list(thd, new Item_field(NULL, NULL, "*"))) + if (add_item_to_list(thd, + new Item_field(&thd->lex->current_select-> + context, + NULL, NULL, "*"))) YYABORT; (thd->lex->current_select->with_wild)++; }; @@ -4393,10 +4403,10 @@ simple_expr: my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str); YYABORT; } - $$= new Item_default_value($3); + $$= new Item_default_value(&Select->context, $3); } | VALUES '(' simple_ident ')' - { $$= new Item_insert_value($3); } + { $$= new Item_insert_value(&Select->context, $3); } | FUNC_ARG0 '(' ')' { if (!$1.symbol->create_func) @@ -4687,15 +4697,16 @@ simple_expr: name->init_qname(YYTHD); sp_add_to_hash(&lex->spfuns, name); if ($5) - $$= new Item_func_sp(name, *$5); + $$= new Item_func_sp(&lex->current_select->context, name, *$5); else - $$= new Item_func_sp(name); + $$= new Item_func_sp(&lex->current_select->context, name); lex->safe_to_cache_query=0; } | IDENT_sys '(' udf_expr_list ')' { #ifdef HAVE_DLOPEN udf_func *udf; + SELECT_LEX *sel= Select; if (using_udf_functions && (udf=find_udf($1.str, $1.length))) { @@ -4776,9 +4787,9 @@ simple_expr: sp_add_to_hash(&lex->spfuns, name); if ($3) - $$= new Item_func_sp(name, *$3); + $$= new Item_func_sp(&lex->current_select->context, name, *$3); else - $$= new Item_func_sp(name); + $$= new Item_func_sp(&lex->current_select->context, name); lex->safe_to_cache_query=0; } } @@ -4980,8 +4991,10 @@ sum_expr: opt_gconcat_separator ')' { - Select->in_sum_expr--; - $$=new Item_func_group_concat($3,$5,Select->gorder_list,$7); + SELECT_LEX *sel= Select; + sel->in_sum_expr--; + $$=new Item_func_group_concat(&sel->context, $3, $5, + sel->gorder_list, $7); $5->empty(); }; @@ -5400,16 +5413,30 @@ using_list: ident { SELECT_LEX *sel= Select; - if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1, + if (!($$= new Item_func_eq(new Item_field(&sel->context, + sel->db1, sel->table1, $1.str), - new Item_field(sel->db2, sel->table2, + new Item_field(&sel->context, + sel->db2, sel->table2, $1.str)))) YYABORT; } | using_list ',' ident { SELECT_LEX *sel= Select; - if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1))) + if (!($$= + new Item_cond_and(new + Item_func_eq(new + Item_field(&sel->context, + sel->db1, + sel->table1, + $3.str), + new + Item_field(&sel->context, + sel->db2, + sel->table2, + $3.str)), + $1))) YYABORT; }; @@ -5675,7 +5702,10 @@ procedure_clause: lex->proc_list.elements=0; lex->proc_list.first=0; lex->proc_list.next= (byte**) &lex->proc_list.first; - if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str))) + if (add_proc_to_list(lex->thd, new Item_field(&lex-> + current_select-> + context, + NULL,NULL,$2.str))) YYABORT; Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); } @@ -5922,7 +5952,6 @@ insert: mysql_init_select(lex); /* for subselects */ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; } insert_lock_option opt_ignore insert2 { @@ -5940,7 +5969,6 @@ replace: lex->sql_command = SQLCOM_REPLACE; lex->duplicates= DUP_REPLACE; mysql_init_select(lex); - lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; } replace_lock_option insert2 { @@ -6058,7 +6086,7 @@ values: expr_or_default: expr { $$= $1;} - | DEFAULT {$$= new Item_default_value(); } + | DEFAULT {$$= new Item_default_value(&Select->context); } ; opt_insert_update: @@ -6120,24 +6148,9 @@ insert_update_elem: simple_ident_nospvar equal expr_or_default { LEX *lex= Lex; - uint8 tmp= MY_ITEM_PREFER_1ST_TABLE; if (lex->update_list.push_back($1) || lex->value_list.push_back($3)) YYABORT; - /* - INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY - UPDATE a= a + b1.b - - Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items - to prevent find_field_in_tables() doing further item searching - if it finds item occurence in first table in insert_table_list. - This allows to avoid ambiguity in resolving 'a' field in - example above. - */ - $1->walk(&Item::set_flags_processor, - (byte *) &tmp); - $3->walk(&Item::set_flags_processor, - (byte *) &tmp); }; opt_low_priority: @@ -7027,15 +7040,17 @@ insert_ident: table_wild: ident '.' '*' { - $$ = new Item_field(NullS,$1.str,"*"); - Lex->current_select->with_wild++; + SELECT_LEX *sel= Select; + $$ = new Item_field(&sel->context, NullS, $1.str, "*"); + sel->with_wild++; } | ident '.' ident '.' '*' { - $$ = new Item_field((YYTHD->client_capabilities & + SELECT_LEX *sel= Select; + $$ = new Item_field(&sel->context, (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str,"*"); - Lex->current_select->with_wild++; + sel->with_wild++; } ; @@ -7060,8 +7075,8 @@ simple_ident: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : + (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); } } | simple_ident_q { $$= $1; } @@ -7073,8 +7088,8 @@ simple_ident_nospvar: SELECT_LEX *sel=Select; $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,NullS,$1.str) : - (Item*) new Item_ref(NullS,NullS,$1.str); + (Item*) new Item_field(&sel->context, NullS, NullS, $1.str) : + (Item*) new Item_ref(&sel->context, NullS, NullS, $1.str); } | simple_ident_q { $$= $1; } ; @@ -7111,7 +7126,8 @@ simple_ident_q: YYABORT; } - if (!(trg_fld= new Item_trigger_field(new_row ? + if (!(trg_fld= new Item_trigger_field(&lex->current_select->context, + new_row ? Item_trigger_field::NEW_ROW: Item_trigger_field::OLD_ROW, $3.str))) @@ -7136,8 +7152,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,$1.str,$3.str) : - (Item*) new Item_ref(NullS,$1.str,$3.str); + (Item*) new Item_field(&sel->context, NullS, $1.str, $3.str) : + (Item*) new Item_ref(&sel->context, NullS, $1.str, $3.str); } } | '.' ident '.' ident @@ -7152,8 +7168,8 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field(NullS,$2.str,$4.str) : - (Item*) new Item_ref(NullS, $2.str, $4.str); + (Item*) new Item_field(&sel->context, NullS, $2.str, $4.str) : + (Item*) new Item_ref(&sel->context, NullS, $2.str, $4.str); } | ident '.' ident '.' ident { @@ -7167,10 +7183,12 @@ simple_ident_q: } $$= (sel->parsing_place != IN_HAVING || sel->get_in_sum_expr() > 0) ? - (Item*) new Item_field((YYTHD->client_capabilities & + (Item*) new Item_field(&sel->context, + (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str) : - (Item*) new Item_ref((YYTHD->client_capabilities & + (Item*) new Item_ref(&sel->context, + (YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str, $5.str); }; @@ -7414,7 +7432,6 @@ keyword: | INNOBASE_SYM {} | INSERT_METHOD {} | RELAY_THREAD {} - | LABEL_SYM {} | LANGUAGE_SYM {} | LAST_SYM {} | LEAVES {} @@ -7720,11 +7737,13 @@ sys_option_value: it= new Item_null(); } - if (!(trg_fld= new Item_trigger_field(Item_trigger_field::NEW_ROW, + if (!(trg_fld= new Item_trigger_field(&lex->current_select-> + context, + Item_trigger_field::NEW_ROW, $2.base_name.str)) || - !(i= new sp_instr_set_trigger_field( - lex->sphead->instructions(), lex->spcont, - trg_fld, it))) + !(i= new sp_instr_set_trigger_field(lex->sphead-> + instructions(), + lex->spcont, trg_fld, it))) YYABORT; /* diff --git a/sql/table.cc b/sql/table.cc index 6677453969b..fec74c570f3 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -594,6 +594,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, goto err; /* purecov: inspected */ } + reg_field->field_index= i; reg_field->comment=comment; if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) { @@ -1713,8 +1714,6 @@ void st_table_list::set_ancestor() } if (tbl->multitable_view) multitable_view= TRUE; - if (tbl->table) - tbl->table->grant= grant; } while ((tbl= tbl->next_local)); if (!multitable_view) @@ -1727,68 +1726,18 @@ void st_table_list::set_ancestor() /* - Save old want_privilege and clear want_privilege - - SYNOPSIS - save_and_clear_want_privilege() -*/ - -void st_table_list::save_and_clear_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - { - privilege_backup= tbl->table->grant.want_privilege; - tbl->table->grant.want_privilege= 0; - } - else - { - tbl->save_and_clear_want_privilege(); - } - } -} - - -/* - restore want_privilege saved by save_and_clear_want_privilege - - SYNOPSIS - restore_want_privilege() -*/ - -void st_table_list::restore_want_privilege() -{ - for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) - { - if (tbl->table) - tbl->table->grant.want_privilege= privilege_backup; - else - { - tbl->restore_want_privilege(); - } - } -} - - -/* setup fields of placeholder of merged VIEW SYNOPSIS st_table_list::setup_ancestor() thd - thread handler - conds - condition of this JOIN - check_opt_type - WHITH CHECK OPTION type (VIEW_CHECK_NONE, - VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + NOTES ancestor is list of tables and views used by view (underlying tables/views) DESCRIPTION It is: - - preparing translation table for view columns (fix_fields() for every - call and creation for first call) - - preparing WHERE, ON and CHECK OPTION condition (fix_fields() for every - call and merging for first call). + - preparing translation table for view columns If there are underlying view(s) procedure first will be called for them. RETURN @@ -1796,163 +1745,114 @@ void st_table_list::restore_want_privilege() TRUE - error */ -bool st_table_list::setup_ancestor(THD *thd, Item **conds, - uint8 check_opt_type) +bool st_table_list::setup_ancestor(THD *thd) { - Field_translator *transl; - SELECT_LEX *select= &view->select_lex; - SELECT_LEX *current_select_save= thd->lex->current_select; - byte *main_table_list_save= select_lex->table_list.first; - Item *item; - TABLE_LIST *tbl; - List_iterator_fast<Item> it(select->item_list); - uint i= 0; - enum sub_select_type linkage_save= - select_lex->master_unit()->first_select()->linkage; - bool save_set_query_id= thd->set_query_id; - bool save_wrapper= select_lex->no_wrap_view_item; - bool save_allow_sum_func= thd->allow_sum_func; - bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - - if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&res)) - return TRUE; - - for (tbl= ancestor; tbl; tbl= tbl->next_local) + if (!field_translation) { - if (tbl->ancestor && - tbl->setup_ancestor(thd, conds, - (check_opt_type == VIEW_CHECK_CASCADED ? - VIEW_CHECK_CASCADED : - VIEW_CHECK_NONE))) + Field_translator *transl; + SELECT_LEX *select= &view->select_lex; + Item *item; + TABLE_LIST *tbl; + List_iterator_fast<Item> it(select->item_list); + uint field_count= 0; + + if (check_stack_overrun(thd, STACK_MIN_SIZE, (char *)&field_count)) + { DBUG_RETURN(TRUE); - } + } - /* - We have to ensure that inside the view we are not referring to any - table outside of the view. We do it by changing the pointers used - by fix_fields to look up tables so that only tables and views in - view are seen. We also set linkage to DERIVED_TABLE_TYPE as a barrier - so that we stop resolving fields as this level. - */ - thd->lex->current_select= select_lex; - select_lex->table_list.first= (byte *)ancestor; - select_lex->master_unit()->first_select()->linkage= DERIVED_TABLE_TYPE; + for (tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->ancestor && + tbl->setup_ancestor(thd)) + { + DBUG_RETURN(TRUE); + } + } - if (field_translation) - { - DBUG_PRINT("info", ("there are already translation table")); - - select_lex->no_wrap_view_item= 1; - - thd->set_query_id= 1; - /* this view was prepared already on previous PS/SP execution */ - Field_translator *end= field_translation + select->item_list.elements; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - for (transl= field_translation; transl < end; transl++) + /* Create view fields translation table */ + + if (!(transl= + (Field_translator*)(thd->current_arena-> + alloc(select->item_list.elements * + sizeof(Field_translator))))) { - if (!transl->item->fixed && - transl->item->fix_fields(thd, ancestor, &transl->item)) - goto err; + DBUG_RETURN(TRUE); } - for (tbl= ancestor; tbl; tbl= tbl->next_local) + + while ((item= it++)) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + transl[field_count].name= item->name; + transl[field_count++].item= item; } - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, ancestor, &check_option)) - goto err; - restore_want_privilege(); + field_translation= transl; + field_translation_end= transl + field_count; + /* TODO: use hash for big number of fields */ - /* WHERE/ON resolved => we can rename fields */ - for (transl= field_translation; transl < end; transl++) + /* full text function moving to current select */ + if (view->select_lex.ftfunc_list->elements) { - transl->item->rename((char *)transl->name); + Item_func_match *ifm; + SELECT_LEX *current_select= thd->lex->current_select; + List_iterator_fast<Item_func_match> + li(*(view->select_lex.ftfunc_list)); + while ((ifm= li++)) + current_select->ftfunc_list->push_front(ifm); } - goto ok; } + DBUG_RETURN(FALSE); +} - /* Create view fields translation table */ - if (!(transl= - (Field_translator*)(thd->current_arena-> - alloc(select->item_list.elements * - sizeof(Field_translator))))) - { - res= TRUE; - goto ok; // Restore thd - } +/* + Prepare where expression of view - select_lex->no_wrap_view_item= 1; + SYNOPSIS + st_table_list::prep_where() + thd - thread handler + conds - condition of this JOIN + no_where_clause - do not build WHERE or ON outer qwery do not need it + (it is INSERT), we do not need conds if this flag is set - /* - Resolve all view items against ancestor table. + NOTE: have to be called befor CHECK OPTION preparation, because it makes + fix_fields for view WHERE clause - TODO: do it only for real used fields "on demand" to mark really - used fields correctly. - */ - thd->set_query_id= 1; - /* real rights will be checked in VIEW field */ - save_and_clear_want_privilege(); - /* aggregate function are allowed */ - thd->allow_sum_func= 1; - while ((item= it++)) - { - /* save original name of view column */ - char *name= item->name; - transl[i].item= item; - if (!item->fixed && item->fix_fields(thd, ancestor, &transl[i].item)) - goto err; - /* set new item get in fix fields and original column name */ - transl[i++].name= name; - } - field_translation= transl; - /* TODO: sort this list? Use hash for big number of fields */ + RETURN + FALSE - OK + TRUE - error +*/ - for (tbl= ancestor; tbl; tbl= tbl->next_local) +bool st_table_list::prep_where(THD *thd, Item **conds, + bool no_where_clause) +{ + DBUG_ENTER("st_table_list::prep_where"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - if (tbl->on_expr && !tbl->on_expr->fixed && - tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr)) - goto err; + if (tbl->view && tbl->prep_where(thd, conds, no_where_clause)) + { + DBUG_RETURN(TRUE); + } } - if (where || - (check_opt_type == VIEW_CHECK_CASCADED && - ancestor->check_option)) - { - Query_arena *arena= thd->current_arena, backup; - TABLE_LIST *tbl= this; - if (arena->is_conventional()) - arena= 0; // For easier test - - if (where && !where->fixed && where->fix_fields(thd, ancestor, &where)) - goto err; - - if (arena) - thd->set_n_backup_item_arena(arena, &backup); - if (check_opt_type) + if (where) + { + if (!where->fixed && where->fix_fields(thd, &where)) { - if (where) - check_option= where->copy_andor_structure(thd); - if (check_opt_type == VIEW_CHECK_CASCADED) - { - check_option= and_conds(check_option, ancestor->check_option); - } + DBUG_RETURN(TRUE); } /* check that it is not VIEW in which we insert with INSERT SELECT (in this case we can't add view WHERE condition to main SELECT_LEX) */ - if (where && !no_where_clause) + if (!no_where_clause && !where_processed) { + TABLE_LIST *tbl= this; + Query_arena *arena= thd->current_arena, backup; + arena= thd->change_arena_if_needed(&backup); // For easier test + /* Go up to join tree and try to find left join */ for (; tbl; tbl= tbl->embedding) { @@ -1969,72 +1869,107 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, } } if (tbl == 0) - { - if (outer_join) - { - /* - Store WHERE condition to ON expression for outer join, because - we can't use WHERE to correctly execute left joins on VIEWs and - this expression will not be moved to WHERE condition (i.e. will - be clean correctly for PS/SP) - */ - on_expr= and_conds(on_expr, where); - } - else - { - /* - It is conds of JOIN, but it will be stored in - st_select_lex::prep_where for next reexecution - */ - *conds= and_conds(*conds, where); - } - } + *conds= and_conds(*conds, where); + if (arena) + thd->restore_backup_item_arena(arena, &backup); + where_processed= TRUE; } - - if (arena) - thd->restore_backup_item_arena(arena, &backup); } - restore_want_privilege(); - /* - fix_fields do not need tables, because new are only AND operation and we - just need recollect statistics - */ - if (check_option && !check_option->fixed && - check_option->fix_fields(thd, 0, &check_option)) - goto err; + DBUG_RETURN(FALSE); +} + + +/* + Prepare check option expression of table + + SYNOPSIS + st_table_list::prep_check_option() + thd - thread handler + check_opt_type - WITH CHECK OPTION type (VIEW_CHECK_NONE, + VIEW_CHECK_LOCAL, VIEW_CHECK_CASCADED) + we use this parameter instead of direct check of + effective_with_check to change type of underlying + views to VIEW_CHECK_CASCADED if outer view have + such option and prevent processing of underlying + view check options if outer view have just + VIEW_CHECK_LOCAL option. + + NOTE + This method build check options for every call + (usual execution or every SP/PS call) + This method have to be called after WHERE preparation + (st_table_list::prep_where) - /* WHERE/ON resolved => we can rename fields */ + RETURN + FALSE - OK + TRUE - error +*/ + +bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type) +{ + DBUG_ENTER("st_table_list::prep_check_option"); + + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { - Field_translator *end= field_translation + select->item_list.elements; - for (transl= field_translation; transl < end; transl++) + /* see comment of check_opt_type parameter */ + if (tbl->view && + tbl->prep_check_option(thd, + ((check_opt_type == VIEW_CHECK_CASCADED) ? + VIEW_CHECK_CASCADED : + VIEW_CHECK_NONE))) { - transl->item->rename((char *)transl->name); + DBUG_RETURN(TRUE); } } - /* full text function moving to current select */ - if (view->select_lex.ftfunc_list->elements) + if (check_opt_type) { - Query_arena *arena= thd->current_arena, backup; - if (arena->is_conventional()) - arena= 0; // For easier test - else - thd->set_n_backup_item_arena(arena, &backup); - - Item_func_match *ifm; - List_iterator_fast<Item_func_match> - li(*(view->select_lex.ftfunc_list)); - while ((ifm= li++)) - current_select_save->ftfunc_list->push_front(ifm); - if (arena) - thd->restore_backup_item_arena(arena, &backup); + Item *item= 0; + if (where) + { + DBUG_ASSERT(where->fixed); + item= where->copy_andor_structure(thd); + } + if (check_opt_type == VIEW_CHECK_CASCADED) + { + for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) + { + if (tbl->check_option) + item= and_conds(item, tbl->check_option); + } + } + if (item) + thd->change_item_tree(&check_option, item); + } + + if (check_option) + { + const char *save_where= thd->where; + thd->where= "check option"; + if (!check_option->fixed && + check_option->fix_fields(thd, &check_option) || + check_option->check_cols(1)) + { + DBUG_RETURN(TRUE); + } + thd->where= save_where; } + DBUG_RETURN(FALSE); +} + - goto ok; +/* + Hide errors which show view underlying table information + + SYNOPSIS + st_table_list::hide_view_error() + thd thread handler -err: - res= TRUE; +*/ + +void st_table_list::hide_view_error(THD *thd) +{ /* Hide "Unknown column" or "Unknown function" error */ if (thd->net.last_errno == ER_BAD_FIELD_ERROR || thd->net.last_errno == ER_SP_DOES_NOT_EXIST) @@ -2042,15 +1977,12 @@ err: thd->clear_error(); my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str); } - -ok: - select_lex->no_wrap_view_item= save_wrapper; - thd->lex->current_select= current_select_save; - select_lex->table_list.first= main_table_list_save; - select_lex->master_unit()->first_select()->linkage= linkage_save; - thd->set_query_id= save_set_query_id; - thd->allow_sum_func= save_allow_sum_func; - DBUG_RETURN(res); + else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD) + { + thd->clear_error(); + // TODO: make correct error message + my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str); + } } @@ -2094,9 +2026,9 @@ void st_table_list::cleanup_items() if (!field_translation) return; - Field_translator *end= (field_translation + - view->select_lex.item_list.elements); - for (Field_translator *transl= field_translation; transl < end; transl++) + for (Field_translator *transl= field_translation; + transl < field_translation_end; + transl++) transl->item->walk(&Item::cleanup_processor, 0); } @@ -2209,8 +2141,9 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) void Field_iterator_view::set(TABLE_LIST *table) { + view= table; ptr= table->field_translation; - array_end= ptr + table->view->select_lex.item_list.elements; + array_end= table->field_translation_end; } @@ -2220,9 +2153,9 @@ const char *Field_iterator_table::name() } -Item *Field_iterator_table::item(THD *thd) +Item *Field_iterator_table::create_item(THD *thd) { - return new Item_field(thd, *ptr); + return new Item_field(thd, &thd->lex->current_select->context, *ptr); } @@ -2232,6 +2165,51 @@ const char *Field_iterator_view::name() } +Item *Field_iterator_view::create_item(THD *thd) +{ + return create_view_field(thd, view, &ptr->item, ptr->name); +} + +Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, + const char *name) +{ + bool save_wrapper= thd->lex->select_lex.no_wrap_view_item; + Item *field= *field_ref; + DBUG_ENTER("create_view_field"); + + if (view->schema_table_reformed) + { + /* + In case of SHOW command (schema_table_reformed set) all items are + fixed + */ + DBUG_ASSERT(field && field->fixed); + DBUG_RETURN(field); + } + + DBUG_ASSERT(field); + thd->lex->current_select->no_wrap_view_item= TRUE; + if (!field->fixed) + { + if (field->fix_fields(thd, field_ref)) + { + thd->lex->current_select->no_wrap_view_item= save_wrapper; + DBUG_RETURN(0); + } + field= *field_ref; + } + thd->lex->current_select->no_wrap_view_item= save_wrapper; + if (thd->lex->current_select->no_wrap_view_item) + { + DBUG_RETURN(field); + } + Item *item= new Item_direct_view_ref(&view->view->select_lex.context, + field_ref, view->view_name.str, + name); + DBUG_RETURN(item); +} + + /***************************************************************************** ** Instansiate templates *****************************************************************************/ diff --git a/sql/table.h b/sql/table.h index 8bc4e01852f..d0c998c4c10 100644 --- a/sql/table.h +++ b/sql/table.h @@ -314,9 +314,9 @@ typedef struct st_schema_table #define JOIN_TYPE_LEFT 1 #define JOIN_TYPE_RIGHT 2 -#define VIEW_ALGORITHM_UNDEFINED 0 -#define VIEW_ALGORITHM_TMPTABLE 1 -#define VIEW_ALGORITHM_MERGE 2 +#define VIEW_ALGORITHM_UNDEFINED 0 +#define VIEW_ALGORITHM_TMPTABLE 1 +#define VIEW_ALGORITHM_MERGE 2 /* view WITH CHECK OPTION parameter options */ #define VIEW_CHECK_NONE 0 @@ -329,9 +329,13 @@ typedef struct st_schema_table #define VIEW_CHECK_SKIP 2 struct st_lex; +struct st_table_list; class select_union; class TMP_TABLE_PARAM; +Item *create_view_field(THD *thd, st_table_list *view, Item **field_ref, + const char *name); + struct Field_translator { Item *item; @@ -384,6 +388,8 @@ typedef struct st_table_list st_select_lex *select_lex; st_lex *view; /* link on VIEW lex for merging */ Field_translator *field_translation; /* array of VIEW fields */ + /* pointer to element after last one in translation table above */ + Field_translator *field_translation_end; /* list of ancestor(s) of this table (underlying table(s)/view(s) */ st_table_list *ancestor; /* most upper view this table belongs to */ @@ -408,8 +414,7 @@ typedef struct st_table_list algorithm) */ uint8 effective_with_check; - uint effective_algorithm; /* which algorithm was really used */ - uint privilege_backup; /* place for saving privileges */ + uint8 effective_algorithm; /* which algorithm was really used */ GRANT_INFO grant; /* data need by some engines in query cache*/ ulonglong engine_data; @@ -424,7 +429,6 @@ typedef struct st_table_list bool updating; /* for replicate-do/ignore table */ bool force_index; /* prefer index over table scan */ bool ignore_leaves; /* preload only non-leaf nodes */ - bool no_where_clause; /* do not attach WHERE to SELECT */ table_map dep_tables; /* tables the table depends on */ table_map on_expr_dep_tables; /* tables on expression depends on */ struct st_nested_join *nested_join; /* if the element is a nested join */ @@ -437,6 +441,8 @@ typedef struct st_table_list /* TRUE if this merged view contain auto_increment field */ bool contain_auto_increment; bool multitable_view; /* TRUE iff this is multitable view */ + /* view where processed */ + bool where_processed; /* FRMTYPE_ERROR if any type is acceptable */ enum frm_type_enum required_type; char timestamp_buffer[20]; /* buffer for timestamp (19+1) */ @@ -449,16 +455,32 @@ typedef struct st_table_list void calc_md5(char *buffer); void set_ancestor(); int view_check_option(THD *thd, bool ignore_failure); - bool setup_ancestor(THD *thd, Item **conds, uint8 check_option); + bool setup_ancestor(THD *thd); void cleanup_items(); bool placeholder() {return derived || view; } void print(THD *thd, String *str); - void save_and_clear_want_privilege(); - void restore_want_privilege(); bool check_single_table(st_table_list **table, table_map map, st_table_list *view); bool set_insert_values(MEM_ROOT *mem_root); + void hide_view_error(THD *thd); st_table_list *find_underlying_table(TABLE *table); + inline bool prepare_check_option(THD *thd) + { + bool res= FALSE; + if (effective_with_check) + res= prep_check_option(thd, effective_with_check); + return res; + } + inline bool prepare_where(THD *thd, Item **conds, + bool no_where_clause) + { + if (effective_algorithm == VIEW_ALGORITHM_MERGE) + return prep_where(thd, conds, no_where_clause); + return FALSE; + } +private: + bool prep_check_option(THD *thd, uint8 check_opt_type); + bool prep_where(THD *thd, Item **conds, bool no_where_clause); } TABLE_LIST; class Item; @@ -471,7 +493,7 @@ public: virtual void next()= 0; virtual bool end_of_fields()= 0; /* Return 1 at end of list */ virtual const char *name()= 0; - virtual Item *item(THD *)= 0; + virtual Item *create_item(THD *)= 0; virtual Field *field()= 0; }; @@ -486,7 +508,7 @@ public: void next() { ptr++; } bool end_of_fields() { return *ptr == 0; } const char *name(); - Item *item(THD *thd); + Item *create_item(THD *thd); Field *field() { return *ptr; } }; @@ -494,15 +516,18 @@ public: class Field_iterator_view: public Field_iterator { Field_translator *ptr, *array_end; + TABLE_LIST *view; public: Field_iterator_view() :ptr(0), array_end(0) {} void set(TABLE_LIST *table); void next() { ptr++; } bool end_of_fields() { return ptr == array_end; } const char *name(); - Item *item(THD *thd) { return ptr->item; } + Item *create_item(THD *thd); Item **item_ptr() {return &ptr->item; } Field *field() { return 0; } + + inline Item *item() { return ptr->item; } }; diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index 5844a6e688b..408e511d2e8 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -223,7 +223,7 @@ static int my_strnncoll_ucs2(CHARSET_INFO *cs, t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc; if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; @@ -284,7 +284,7 @@ static int my_strnncollsp_ucs2(CHARSET_INFO *cs __attribute__((unused)), int t_wc = uni_plane[t[0]] ? (int) uni_plane[t[0]][t[1]].sort : (((int) t[0]) << 8) + (int) t[1]; if ( s_wc != t_wc ) - return s_wc - t_wc; + return s_wc > t_wc ? 1 : -1; s+= 2; t+= 2; @@ -1364,7 +1364,7 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs, } if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index c991953f206..de08c080b3b 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -2204,7 +2204,7 @@ static int my_strnncoll_utf8(CHARSET_INFO *cs, t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc; if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; @@ -2277,7 +2277,7 @@ static int my_strnncollsp_utf8(CHARSET_INFO *cs, t_wc = uni_plane[plane] ? uni_plane[plane][t_wc & 0xFF].sort : t_wc; if ( s_wc != t_wc ) { - return ((int) s_wc) - ((int) t_wc); + return s_wc > t_wc ? 1 : -1; } s+=s_res; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 8debf7614a3..a80d5e1d1be 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13332,6 +13332,274 @@ static void test_bug9992() mysql_close(mysql1); } + +/* Bug#10736: cursors and subqueries, memroot management */ + +static void test_bug10736() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[21]; + int rc; + const char *stmt_text; + int i= 0; + ulong type; + + myheader("test_bug10736"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name VARCHAR(20) NOT NULL)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + "(1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= mysql_stmt_init(mysql); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + rc= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type); + check_execute(stmt, rc); + stmt_text= "select name from t1 where name=(select name from t1 where id=2)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void*) a; + bind[0].buffer_length= sizeof(a); + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 3; i++) + { + int row_no= 0; + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + printf("%d: %s\n", row_no, a); + ++row_no; + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + +/* Bug#10794: cursors, packets out of order */ + +static void test_bug10794() +{ + MYSQL_STMT *stmt, *stmt1; + MYSQL_BIND bind[2]; + char a[21]; + int id_val; + ulong a_len; + int rc; + const char *stmt_text; + int i= 0; + ulong type; + + myheader("test_bug10794"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "name varchar(20) not null)"); + stmt= mysql_stmt_init(mysql); + stmt_text= "insert into t1 (id, name) values (?, ?)"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= (void*) &id_val; + bind[1].buffer_type= MYSQL_TYPE_STRING; + bind[1].buffer= (void*) a; + bind[1].length= &a_len; + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + for (i= 0; i < 34; i++) + { + id_val= (i+1)*10; + sprintf(a, "a%d", i); + a_len= strlen(a); /* safety against broken sprintf */ + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + } + stmt_text= "select name from t1"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + stmt1= mysql_stmt_init(mysql); + mysql_stmt_attr_set(stmt1, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (void*) a; + bind[0].buffer_length= sizeof(a); + bind[0].length= &a_len; + rc= mysql_stmt_bind_result(stmt, bind); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent) + printf("Fetched row from stmt: %s\n", a); + /* Don't optimize: an attribute of the original test case */ + mysql_stmt_free_result(stmt); + mysql_stmt_reset(stmt); + stmt_text= "select name from t1 where id=10"; + rc= mysql_stmt_prepare(stmt1, stmt_text, strlen(stmt_text)); + check_execute(stmt1, rc); + rc= mysql_stmt_bind_result(stmt1, bind); + check_execute(stmt1, rc); + rc= mysql_stmt_execute(stmt1); + while (1) + { + rc= mysql_stmt_fetch(stmt1); + if (rc == MYSQL_NO_DATA) + { + if (!opt_silent) + printf("End of data in stmt1\n"); + break; + } + check_execute(stmt1, rc); + if (!opt_silent) + printf("Fetched row from stmt1: %s\n", a); + } + mysql_stmt_close(stmt); + mysql_stmt_close(stmt1); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11172: cursors, crash on a fetch from a datetime column */ + +static void test_bug11172() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind_in[1], bind_out[2]; + MYSQL_TIME hired; + int rc; + const char *stmt_text; + int i= 0, id; + ulong type; + + myheader("test_bug11172"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key," + "hired date not null)"); + rc= mysql_query(mysql, + "insert into t1 (id, hired) values (1, '1933-08-24'), " + "(2, '1965-01-01'), (3, '1949-08-17'), (4, '1945-07-07'), " + "(5, '1941-05-15'), (6, '1978-09-15'), (7, '1936-03-28')"); + myquery(rc); + stmt= mysql_stmt_init(mysql); + stmt_text= "SELECT id, hired FROM t1 WHERE hired=?"; + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + bzero(bind_in, sizeof(bind_in)); + bzero(bind_out, sizeof(bind_out)); + bzero(&hired, sizeof(hired)); + hired.year= 1965; + hired.month= 1; + hired.day= 1; + bind_in[0].buffer_type= MYSQL_TYPE_DATE; + bind_in[0].buffer= (void*) &hired; + bind_in[0].buffer_length= sizeof(hired); + bind_out[0].buffer_type= MYSQL_TYPE_LONG; + bind_out[0].buffer= (void*) &id; + bind_out[1]= bind_in[0]; + + for (i= 0; i < 3; i++) + { + rc= mysql_stmt_bind_param(stmt, bind_in); + check_execute(stmt, rc); + rc= mysql_stmt_bind_result(stmt, bind_out); + check_execute(stmt, rc); + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + while ((rc= mysql_stmt_fetch(stmt)) == 0) + { + if (!opt_silent) + printf("fetched data %d:%d-%d-%d\n", id, + hired.year, hired.month, hired.day); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + mysql_stmt_free_result(stmt) || mysql_stmt_reset(stmt); + } + mysql_stmt_close(stmt); + mysql_rollback(mysql); + mysql_rollback(mysql); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Bug#11656: cursors, crash on a fetch from a query with distinct. */ + +static void test_bug11656() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[2]; + int rc; + const char *stmt_text; + char buf[2][20]; + int i= 0; + ulong type; + + myheader("test_bug11656"); + + mysql_query(mysql, "drop table if exists t1"); + + rc= mysql_query(mysql, "create table t1 (" + "server varchar(40) not null, " + "test_kind varchar(1) not null, " + "test_id varchar(30) not null , " + "primary key (server,test_kind,test_id))"); + myquery(rc); + + stmt_text= "select distinct test_kind, test_id from t1 " + "where server in (?, ?)"; + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text)); + check_execute(stmt, rc); + type= (ulong) CURSOR_TYPE_READ_ONLY; + mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (const void*) &type); + + bzero(bind, sizeof(bind)); + strcpy(buf[0], "pcint502_MY2"); + strcpy(buf[1], "*"); + for (i=0; i < 2; i++) + { + bind[i].buffer_type= MYSQL_TYPE_STRING; + bind[i].buffer= (gptr *)&buf[i]; + bind[i].buffer_length= strlen(buf[i]); + } + mysql_stmt_bind_param(stmt, bind); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + mysql_stmt_close(stmt); + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -13567,6 +13835,10 @@ static struct my_tests_st my_tests[]= { { "test_bug10729", test_bug10729 }, { "test_bug11111", test_bug11111 }, { "test_bug9992", test_bug9992 }, + { "test_bug10736", test_bug10736 }, + { "test_bug10794", test_bug10794 }, + { "test_bug11172", test_bug11172 }, + { "test_bug11656", test_bug11656 }, { 0, 0 } }; |