From e41788d2b286bb9d76e972e57d2b476abd5efc86 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 27 Dec 2013 13:00:14 +0200 Subject: Increased back_log to 150, but not more than max_connections. - This was done to get better performance when doing a lot of connections. Ensure that thread_cache_size is not larger than max_connections (trivial optimizations). Fixed that the --host_cache_size=# startup option works mysql-test/r/variables.result: Increase back_log to 150 sql/hostname.cc: Fixed that the --host_cache_size=# startup option works sql/mysqld.cc: Ensure that back_log and thread_cache_size is not set higher than max_connections (as this would not make any sense). sql/sys_vars.cc: Increased back_log to 150 --- mysql-test/r/variables.result | 4 ++-- mysql-test/suite/sys_vars/r/back_log_basic.result | 10 +++++----- sql/hostname.cc | 2 +- sql/mysqld.cc | 7 +++++++ sql/sys_vars.cc | 2 +- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 9b1c1b6955e..eb896082810 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -1137,12 +1137,12 @@ ERROR HY000: Variable 'ft_stopword_file' is a read only variable # SHOW VARIABLES like 'back_log'; Variable_name Value -back_log 50 +back_log 150 SELECT @@session.back_log; ERROR HY000: Variable 'back_log' is a GLOBAL variable SELECT @@global.back_log; @@global.back_log -50 +150 SET @@session.back_log= 7; ERROR HY000: Variable 'back_log' is a read only variable SET @@global.back_log= 7; diff --git a/mysql-test/suite/sys_vars/r/back_log_basic.result b/mysql-test/suite/sys_vars/r/back_log_basic.result index 5cfb0da65d6..d68e72a8a4a 100644 --- a/mysql-test/suite/sys_vars/r/back_log_basic.result +++ b/mysql-test/suite/sys_vars/r/back_log_basic.result @@ -1,20 +1,20 @@ select @@global.back_log; @@global.back_log -50 +150 select @@session.back_log; ERROR HY000: Variable 'back_log' is a GLOBAL variable show global variables like 'back_log'; Variable_name Value -back_log 50 +back_log 150 show session variables like 'back_log'; Variable_name Value -back_log 50 +back_log 150 select * from information_schema.global_variables where variable_name='back_log'; VARIABLE_NAME VARIABLE_VALUE -BACK_LOG 50 +BACK_LOG 150 select * from information_schema.session_variables where variable_name='back_log'; VARIABLE_NAME VARIABLE_VALUE -BACK_LOG 50 +BACK_LOG 150 set global back_log=1; ERROR HY000: Variable 'back_log' is a read only variable set session back_log=1; diff --git a/sql/hostname.cc b/sql/hostname.cc index 1200dd2c185..21e652a346f 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -149,7 +149,7 @@ bool hostname_cache_init() Host_entry tmp; uint key_offset= (uint) ((char*) (&tmp.ip_key) - (char*) &tmp); - if (!(hostname_cache= new hash_filo(HOST_CACHE_SIZE, + if (!(hostname_cache= new hash_filo(host_cache_size, key_offset, HOST_ENTRY_KEY_SIZE, NULL, (my_hash_free_key) free, &my_charset_bin))) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5dbb3407428..b5e22c874f2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8943,6 +8943,13 @@ static int get_options(int *argc_ptr, char ***argv_ptr) max_binlog_size_var->option.def_value; } } + + /* Ensure that some variables are not set higher than needed */ + if (back_log > max_connections) + back_log= max_connections; + if (thread_cache_size > max_connections) + thread_cache_size= max_connections; + return 0; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index edd6e7b12a4..a1fa9a45e99 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -364,7 +364,7 @@ static Sys_var_ulong Sys_back_log( "MySQL can have. This comes into play when the main MySQL thread " "gets very many connection requests in a very short time", READ_ONLY GLOBAL_VAR(back_log), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, 65535), DEFAULT(50), BLOCK_SIZE(1)); + VALID_RANGE(1, 65535), DEFAULT(150), BLOCK_SIZE(1)); static Sys_var_charptr Sys_basedir( "basedir", "Path to installation directory. All paths are " -- cgit v1.2.1 From 273078c5faa19b60e2cc93330d18534fae221487 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 2 Jan 2014 11:19:19 +0200 Subject: Fixes to get valgrind to work with jemalloc - Added MALLOC_LIBRARY variable to hold name of malloc library - Back ported valgrind related fixes from jemalloc 3.4.1 to the included jemalloc 3.3.1 - Renamed bitmap_init() and bitmap_free() to my_bitmap_init() and my_bitmap_free() to avoid clash with jemalloc 3.4.1 - Use option --soname-synonyms=somalloc=NON to valgrind when using jemalloc - Show version related variables in mysqld --help -- Added SHOW_VALUE_IN_HELP marker Increased back_log to 150 as the original value was a bit too small CMakeLists.txt: Added MALLOC_LIBRARY variable to hold name of malloc library cmake/jemalloc.cmake: Added MALLOC_LIBRARY variable to hold name of malloc library config.h.cmake: Added MALLOC_LIBRARY variable to hold name of malloc library extra/jemalloc/ChangeLog: Updates changelog extra/jemalloc/include/jemalloc/internal/arena.h: Backported valgrind fixes from jemalloc 3.4.1 extra/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in: Backported valgrind fixes from jemalloc 3.4.1 extra/jemalloc/include/jemalloc/internal/private_namespace.h: Backported valgrind fixes from jemalloc 3.4.1 extra/jemalloc/include/jemalloc/internal/tcache.h: Backported valgrind fixes from jemalloc 3.4.1 extra/jemalloc/src/arena.c: Backported valgrind fixes from jemalloc 3.4.1 include/my_bitmap.h: Renamed bitmap_init() and bitmap_free() to my_bitmap_init() and my_bitmap_free() to avoid clash with jemalloc 3.4.1 mysql-test/mysql-test-run.pl: Use option --soname-synonyms=somalloc=NON to valgrind when using jemalloc mysql-test/valgrind.supp: Supression of memory leak in OpenSuse 12.3 mysys/my_bitmap.c: Renamed bitmap_init() and bitmap_free() to my_bitmap_init() and my_bitmap_free() sql/ha_ndbcluster_binlog.cc: Renames sql/ha_ndbcluster_cond.h: Renames sql/ha_partition.cc: Renames sql/handler.cc: Renames sql/item_subselect.cc: Renames sql/log_event.cc: Renames sql/log_event_old.cc: Renames sql/mysqld.cc: Renames Show version related variables in mysqld --help sql/opt_range.cc: Renames sql/opt_table_elimination.cc: Renames sql/partition_info.cc: Renames sql/rpl_injector.h: Renames sql/set_var.h: Renames sql/slave.cc: Renames sql/sql_bitmap.h: Renames sql/sql_insert.cc: Renames sql/sql_lex.h: Renames sql/sql_parse.cc: Renames sql/sql_partition.cc: Renames sql/sql_select.cc: Renames sql/sql_show.cc: Renames sql/sql_update.cc: Renames sql/sys_vars.cc: Show version related variables in mysqld --help sql/sys_vars.h: Added SHOW_VALUE_IN_HELP marker for variables that should be shown in --help sql/table.cc: Renames sql/table.h: Removed not used bitmap_init_value storage/connect/ha_connect.cc: Removed compiler warning storage/maria/ma_open.c: Renames unittest/mysys/bitmap-t.c: Renames --- CMakeLists.txt | 1 + cmake/jemalloc.cmake | 2 + config.h.cmake | 1 + extra/jemalloc/ChangeLog | 9 +++ extra/jemalloc/include/jemalloc/internal/arena.h | 66 ++++++++++++++-------- .../jemalloc/internal/jemalloc_internal.h.in | 4 ++ .../include/jemalloc/internal/private_namespace.h | 2 + extra/jemalloc/include/jemalloc/internal/tcache.h | 4 +- extra/jemalloc/src/arena.c | 44 +++++++++++---- include/my_bitmap.h | 11 +++- mysql-test/mysql-test-run.pl | 7 +++ mysql-test/r/mysqld--help.result | 3 +- mysql-test/t/mysqld--help.test | 4 +- mysql-test/valgrind.supp | 9 +++ mysys/my_bitmap.c | 10 ++-- sql/ha_ndbcluster_binlog.cc | 12 ++-- sql/ha_ndbcluster_cond.h | 12 ++-- sql/ha_partition.cc | 28 ++++----- sql/handler.cc | 4 +- sql/item_subselect.cc | 16 +++--- sql/log_event.cc | 30 +++++----- sql/log_event_old.cc | 16 +++--- sql/mysqld.cc | 17 ++++-- sql/opt_range.cc | 16 +++--- sql/opt_table_elimination.cc | 2 +- sql/partition_info.cc | 2 +- sql/rpl_injector.h | 4 +- sql/set_var.h | 7 ++- sql/slave.cc | 2 +- sql/sql_bitmap.h | 4 +- sql/sql_insert.cc | 2 +- sql/sql_lex.h | 1 + sql/sql_parse.cc | 13 ++++- sql/sql_partition.cc | 6 +- sql/sql_select.cc | 10 ++-- sql/sql_show.cc | 2 +- sql/sql_update.cc | 2 +- sql/sys_vars.cc | 30 +++++++--- sql/sys_vars.h | 1 + sql/table.cc | 14 ++--- sql/table.h | 1 - storage/connect/ha_connect.cc | 2 + storage/maria/ma_open.c | 4 +- unittest/mysys/bitmap-t.c | 10 ++-- 44 files changed, 279 insertions(+), 168 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47c92d27eb1..c02a6e29390 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,7 @@ MYSQL_CHECK_SSL() # Add readline or libedit. MYSQL_CHECK_READLINE() +SET(MALLOC_LIBRARY "system") CHECK_JEMALLOC() # diff --git a/cmake/jemalloc.cmake b/cmake/jemalloc.cmake index bc6bf60781d..3df17f362bc 100644 --- a/cmake/jemalloc.cmake +++ b/cmake/jemalloc.cmake @@ -53,6 +53,7 @@ MACRO (CHECK_JEMALLOC) CHECK_LIBRARY_EXISTS(jemalloc malloc_stats_print "" HAVE_JEMALLOC) IF (HAVE_JEMALLOC) SET(LIBJEMALLOC jemalloc) + SET(MALLOC_LIBRARY "system jemalloc") ELSEIF (WITH_JEMALLOC STREQUAL "system") MESSAGE(FATAL_ERROR "system jemalloc is not found") ELSEIF (WITH_JEMALLOC STREQUAL "yes") @@ -61,5 +62,6 @@ MACRO (CHECK_JEMALLOC) ENDIF() IF(WITH_JEMALLOC STREQUAL "bundled" OR trybundled) USE_BUNDLED_JEMALLOC() + SET(MALLOC_LIBRARY "bundled jemalloc") ENDIF() ENDMACRO() diff --git a/config.h.cmake b/config.h.cmake index d09be63894e..916ec34669a 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -636,6 +636,7 @@ #define VERSION "@VERSION@" #define PROTOCOL_VERSION 10 +#define MALLOC_LIBRARY "@MALLOC_LIBRARY@" /* time_t related defines */ diff --git a/extra/jemalloc/ChangeLog b/extra/jemalloc/ChangeLog index fc096d8f42f..4f03fc141cb 100644 --- a/extra/jemalloc/ChangeLog +++ b/extra/jemalloc/ChangeLog @@ -6,6 +6,15 @@ found in the git revision history: http://www.canonware.com/cgi-bin/gitweb.cgi?p=jemalloc.git git://canonware.com/jemalloc.git +* 3.3.1a (December 27, 2013) + + Bug fixes from 3.4.1 + - Fix Valgrind integration flaws that caused Valgrind warnings about reads of + uninitialized memory in: + + arena chunk headers + + internal zero-initialized data structures (relevant to tcache and prof + code) + * 3.3.1 (March 6, 2013) This version fixes bugs that are typically encountered only when utilizing diff --git a/extra/jemalloc/include/jemalloc/internal/arena.h b/extra/jemalloc/include/jemalloc/internal/arena.h index f2c18f43543..bbcfedacead 100644 --- a/extra/jemalloc/include/jemalloc/internal/arena.h +++ b/extra/jemalloc/include/jemalloc/internal/arena.h @@ -441,6 +441,7 @@ void arena_postfork_child(arena_t *arena); #ifndef JEMALLOC_ENABLE_INLINE arena_chunk_map_t *arena_mapp_get(arena_chunk_t *chunk, size_t pageind); size_t *arena_mapbitsp_get(arena_chunk_t *chunk, size_t pageind); +size_t arena_mapbitsp_read(size_t *mapbitsp); size_t arena_mapbits_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_unallocated_size_get(arena_chunk_t *chunk, size_t pageind); @@ -451,6 +452,7 @@ size_t arena_mapbits_dirty_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_unzeroed_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_large_get(arena_chunk_t *chunk, size_t pageind); size_t arena_mapbits_allocated_get(arena_chunk_t *chunk, size_t pageind); +void arena_mapbitsp_write(size_t *mapbitsp, size_t mapbits); void arena_mapbits_unallocated_set(arena_chunk_t *chunk, size_t pageind, size_t size, size_t flags); void arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind, @@ -497,11 +499,18 @@ arena_mapbitsp_get(arena_chunk_t *chunk, size_t pageind) return (&arena_mapp_get(chunk, pageind)->bits); } +JEMALLOC_ALWAYS_INLINE size_t +arena_mapbitsp_read(size_t *mapbitsp) +{ + + return (*mapbitsp); +} + JEMALLOC_ALWAYS_INLINE size_t arena_mapbits_get(arena_chunk_t *chunk, size_t pageind) { - return (*arena_mapbitsp_get(chunk, pageind)); + return (arena_mapbitsp_read(arena_mapbitsp_get(chunk, pageind))); } JEMALLOC_ALWAYS_INLINE size_t @@ -584,83 +593,90 @@ arena_mapbits_allocated_get(arena_chunk_t *chunk, size_t pageind) return (mapbits & CHUNK_MAP_ALLOCATED); } +JEMALLOC_ALWAYS_INLINE void +arena_mapbitsp_write(size_t *mapbitsp, size_t mapbits) +{ + + *mapbitsp = mapbits; +} + JEMALLOC_ALWAYS_INLINE void arena_mapbits_unallocated_set(arena_chunk_t *chunk, size_t pageind, size_t size, size_t flags) { - size_t *mapbitsp; + size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); - mapbitsp = arena_mapbitsp_get(chunk, pageind); assert((size & PAGE_MASK) == 0); assert((flags & ~CHUNK_MAP_FLAGS_MASK) == 0); assert((flags & (CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == flags); - *mapbitsp = size | CHUNK_MAP_BININD_INVALID | flags; + arena_mapbitsp_write(mapbitsp, size | CHUNK_MAP_BININD_INVALID | flags); } JEMALLOC_ALWAYS_INLINE void arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind, size_t size) { - size_t *mapbitsp; + size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); + size_t mapbits = arena_mapbitsp_read(mapbitsp); - mapbitsp = arena_mapbitsp_get(chunk, pageind); assert((size & PAGE_MASK) == 0); - assert((*mapbitsp & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == 0); - *mapbitsp = size | (*mapbitsp & PAGE_MASK); + assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == 0); + arena_mapbitsp_write(mapbitsp, size | (mapbits & PAGE_MASK)); } JEMALLOC_ALWAYS_INLINE void arena_mapbits_large_set(arena_chunk_t *chunk, size_t pageind, size_t size, size_t flags) { - size_t *mapbitsp; + size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); + size_t mapbits = arena_mapbitsp_read(mapbitsp); size_t unzeroed; - mapbitsp = arena_mapbitsp_get(chunk, pageind); assert((size & PAGE_MASK) == 0); assert((flags & CHUNK_MAP_DIRTY) == flags); - unzeroed = *mapbitsp & CHUNK_MAP_UNZEROED; /* Preserve unzeroed. */ - *mapbitsp = size | CHUNK_MAP_BININD_INVALID | flags | unzeroed | - CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED; + unzeroed = mapbits & CHUNK_MAP_UNZEROED; /* Preserve unzeroed. */ + arena_mapbitsp_write(mapbitsp, size | CHUNK_MAP_BININD_INVALID | flags + | unzeroed | CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED); } JEMALLOC_ALWAYS_INLINE void arena_mapbits_large_binind_set(arena_chunk_t *chunk, size_t pageind, size_t binind) { - size_t *mapbitsp; + size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); + size_t mapbits = arena_mapbitsp_read(mapbitsp); assert(binind <= BININD_INVALID); - mapbitsp = arena_mapbitsp_get(chunk, pageind); assert(arena_mapbits_large_size_get(chunk, pageind) == PAGE); - *mapbitsp = (*mapbitsp & ~CHUNK_MAP_BININD_MASK) | (binind << - CHUNK_MAP_BININD_SHIFT); + arena_mapbitsp_write(mapbitsp, (mapbits & ~CHUNK_MAP_BININD_MASK) | + (binind << CHUNK_MAP_BININD_SHIFT)); } JEMALLOC_ALWAYS_INLINE void arena_mapbits_small_set(arena_chunk_t *chunk, size_t pageind, size_t runind, size_t binind, size_t flags) { - size_t *mapbitsp; + size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); + size_t mapbits = arena_mapbitsp_read(mapbitsp); size_t unzeroed; assert(binind < BININD_INVALID); - mapbitsp = arena_mapbitsp_get(chunk, pageind); assert(pageind - runind >= map_bias); assert((flags & CHUNK_MAP_DIRTY) == flags); - unzeroed = *mapbitsp & CHUNK_MAP_UNZEROED; /* Preserve unzeroed. */ - *mapbitsp = (runind << LG_PAGE) | (binind << CHUNK_MAP_BININD_SHIFT) | - flags | unzeroed | CHUNK_MAP_ALLOCATED; + unzeroed = mapbits & CHUNK_MAP_UNZEROED; /* Preserve unzeroed. */ + arena_mapbitsp_write(mapbitsp, (runind << LG_PAGE) | (binind << + CHUNK_MAP_BININD_SHIFT) | flags | unzeroed | CHUNK_MAP_ALLOCATED); } JEMALLOC_ALWAYS_INLINE void arena_mapbits_unzeroed_set(arena_chunk_t *chunk, size_t pageind, size_t unzeroed) { - size_t *mapbitsp; + size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind); + size_t mapbits = arena_mapbitsp_read(mapbitsp); - mapbitsp = arena_mapbitsp_get(chunk, pageind); - *mapbitsp = (*mapbitsp & ~CHUNK_MAP_UNZEROED) | unzeroed; + arena_mapbitsp_write(mapbitsp, (mapbits & ~CHUNK_MAP_UNZEROED) | + unzeroed); } JEMALLOC_INLINE bool diff --git a/extra/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in b/extra/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in index 50d84cabf69..124ec34bddf 100644 --- a/extra/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in +++ b/extra/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in @@ -235,6 +235,7 @@ static const bool config_ivsalloc = #ifdef JEMALLOC_DEBUG /* Disable inlining to make debugging easier. */ # define JEMALLOC_ALWAYS_INLINE +# define JEMALLOC_ALWAYS_INLINE_C static # define JEMALLOC_INLINE # define inline #else @@ -242,8 +243,11 @@ static const bool config_ivsalloc = # ifdef JEMALLOC_HAVE_ATTR # define JEMALLOC_ALWAYS_INLINE \ static inline JEMALLOC_ATTR(unused) JEMALLOC_ATTR(always_inline) +# define JEMALLOC_ALWAYS_INLINE_C \ + static inline JEMALLOC_ATTR(always_inline) # else # define JEMALLOC_ALWAYS_INLINE static inline +# define JEMALLOC_ALWAYS_INLINE_C static inline # endif # define JEMALLOC_INLINE static inline # ifdef _MSC_VER diff --git a/extra/jemalloc/include/jemalloc/internal/private_namespace.h b/extra/jemalloc/include/jemalloc/internal/private_namespace.h index 65de3163fd3..cdb0b0eb1c4 100644 --- a/extra/jemalloc/include/jemalloc/internal/private_namespace.h +++ b/extra/jemalloc/include/jemalloc/internal/private_namespace.h @@ -33,6 +33,8 @@ #define arena_mapbits_unzeroed_get JEMALLOC_N(arena_mapbits_unzeroed_get) #define arena_mapbits_unzeroed_set JEMALLOC_N(arena_mapbits_unzeroed_set) #define arena_mapbitsp_get JEMALLOC_N(arena_mapbitsp_get) +#define arena_mapbitsp_read JEMALLOC_N(arena_mapbitsp_read) +#define arena_mapbitsp_write JEMALLOC_N(arena_mapbitsp_write) #define arena_mapp_get JEMALLOC_N(arena_mapp_get) #define arena_maxclass JEMALLOC_N(arena_maxclass) #define arena_new JEMALLOC_N(arena_new) diff --git a/extra/jemalloc/include/jemalloc/internal/tcache.h b/extra/jemalloc/include/jemalloc/internal/tcache.h index ba36204ff21..d4eecdee0dc 100644 --- a/extra/jemalloc/include/jemalloc/internal/tcache.h +++ b/extra/jemalloc/include/jemalloc/internal/tcache.h @@ -313,6 +313,7 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero) } else if (opt_zero) memset(ret, 0, size); } + VALGRIND_MAKE_MEM_UNDEFINED(ret, size); } else { if (config_fill && opt_junk) { arena_alloc_junk_small(ret, &arena_bin_info[binind], @@ -321,7 +322,6 @@ tcache_alloc_small(tcache_t *tcache, size_t size, bool zero) VALGRIND_MAKE_MEM_UNDEFINED(ret, size); memset(ret, 0, size); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); if (config_stats) tbin->tstats.nrequests++; @@ -368,11 +368,11 @@ tcache_alloc_large(tcache_t *tcache, size_t size, bool zero) else if (opt_zero) memset(ret, 0, size); } + VALGRIND_MAKE_MEM_UNDEFINED(ret, size); } else { VALGRIND_MAKE_MEM_UNDEFINED(ret, size); memset(ret, 0, size); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); if (config_stats) tbin->tstats.nrequests++; diff --git a/extra/jemalloc/src/arena.c b/extra/jemalloc/src/arena.c index 05a787f89d9..d28b629a1e1 100644 --- a/extra/jemalloc/src/arena.c +++ b/extra/jemalloc/src/arena.c @@ -368,14 +368,21 @@ arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages) (npages << LG_PAGE)); } +static inline void +arena_run_page_mark_zeroed(arena_chunk_t *chunk, size_t run_ind) +{ + + VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind << + LG_PAGE)), PAGE); +} + static inline void arena_run_page_validate_zeroed(arena_chunk_t *chunk, size_t run_ind) { size_t i; UNUSED size_t *p = (size_t *)((uintptr_t)chunk + (run_ind << LG_PAGE)); - VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind << - LG_PAGE)), PAGE); + arena_run_page_mark_zeroed(chunk, run_ind); for (i = 0; i < PAGE / sizeof(size_t); i++) assert(p[i] == 0); } @@ -458,6 +465,9 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, } else if (config_debug) { arena_run_page_validate_zeroed( chunk, run_ind+i); + } else { + arena_run_page_mark_zeroed( + chunk, run_ind+i); } } } else { @@ -467,6 +477,9 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, */ arena_run_zero(chunk, run_ind, need_pages); } + } else { + VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + + (run_ind << LG_PAGE)), (need_pages << LG_PAGE)); } /* @@ -508,9 +521,9 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool large, arena_run_page_validate_zeroed(chunk, run_ind+need_pages-1); } + VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + + (run_ind << LG_PAGE)), (need_pages << LG_PAGE)); } - VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + (run_ind << - LG_PAGE)), (need_pages << LG_PAGE)); } static arena_chunk_t * @@ -569,17 +582,24 @@ arena_chunk_alloc(arena_t *arena) * unless the chunk is not zeroed. */ if (zero == false) { + VALGRIND_MAKE_MEM_UNDEFINED( + (void *)arena_mapp_get(chunk, map_bias+1), + (size_t)((uintptr_t) arena_mapp_get(chunk, + chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk, + map_bias+1))); for (i = map_bias+1; i < chunk_npages-1; i++) arena_mapbits_unzeroed_set(chunk, i, unzeroed); - } else if (config_debug) { + } else { VALGRIND_MAKE_MEM_DEFINED( (void *)arena_mapp_get(chunk, map_bias+1), - (void *)((uintptr_t) - arena_mapp_get(chunk, chunk_npages-1) - - (uintptr_t)arena_mapp_get(chunk, map_bias+1))); - for (i = map_bias+1; i < chunk_npages-1; i++) { - assert(arena_mapbits_unzeroed_get(chunk, i) == - unzeroed); + (size_t)((uintptr_t) arena_mapp_get(chunk, + chunk_npages-1) - (uintptr_t)arena_mapp_get(chunk, + map_bias+1))); + if (config_debug) { + for (i = map_bias+1; i < chunk_npages-1; i++) { + assert(arena_mapbits_unzeroed_get(chunk, + i) == unzeroed); + } } } arena_mapbits_unallocated_set(chunk, chunk_npages-1, @@ -1458,6 +1478,7 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) } else if (opt_zero) memset(ret, 0, size); } + VALGRIND_MAKE_MEM_UNDEFINED(ret, size); } else { if (config_fill && opt_junk) { arena_alloc_junk_small(ret, &arena_bin_info[binind], @@ -1466,7 +1487,6 @@ arena_malloc_small(arena_t *arena, size_t size, bool zero) VALGRIND_MAKE_MEM_UNDEFINED(ret, size); memset(ret, 0, size); } - VALGRIND_MAKE_MEM_UNDEFINED(ret, size); return (ret); } diff --git a/include/my_bitmap.h b/include/my_bitmap.h index ef3274a8269..9c9550e3141 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -41,9 +41,14 @@ typedef struct st_bitmap #ifdef __cplusplus extern "C" { #endif + +/* compatibility functions */ +#define bitmap_init(A,B,C,D) my_bitmap_init(A,B,C,D) +#define bitmap_free(A) my_bitmap_free(A) + extern void create_last_word_mask(MY_BITMAP *map); -extern my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, - my_bool thread_safe); +extern my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, + my_bool thread_safe); extern my_bool bitmap_is_clear_all(const MY_BITMAP *map); extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); extern my_bool bitmap_is_set_all(const MY_BITMAP *map); @@ -64,7 +69,7 @@ extern uint bitmap_get_first(const MY_BITMAP *map); extern uint bitmap_get_first_set(const MY_BITMAP *map); extern uint bitmap_bits_set(const MY_BITMAP *map); extern uint bitmap_get_next_set(const MY_BITMAP *map, uint bitmap_bit); -extern void bitmap_free(MY_BITMAP *map); +extern void my_bitmap_free(MY_BITMAP *map); extern void bitmap_set_above(MY_BITMAP *map, uint from_byte, uint use_bit); extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size); extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index b00ddd5f2fc..5ca0a5bbe8d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -6181,6 +6181,13 @@ sub valgrind_arguments { mtr_add_arg($args, "--num-callers=16"); mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) if -f "$glob_mysql_test_dir/valgrind.supp"; + + # Ensure the jemalloc works with mysqld + if ($mysqld_variables{'version-malloc-library'} ne "system" && + $$exe =~ /mysqld/) + { + mtr_add_arg($args, "--soname-synonyms=somalloc=NONE" ); + } } # Add valgrind options, can be overriden by user diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 421afbbf1ba..c74b263c5e9 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1019,7 +1019,7 @@ auto-increment-increment 1 auto-increment-offset 1 autocommit TRUE automatic-sp-privileges TRUE -back-log 50 +back-log 150 big-tables FALSE bind-address (No default value) binlog-annotate-row-events FALSE @@ -1221,6 +1221,7 @@ port-open-timeout 0 preload-buffer-size 32768 profiling-history-size 15 progress-report-time 56 +protocol-version 10 query-alloc-block-size 8192 query-cache-limit 1048576 query-cache-min-res-unit 4096 diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test index 1b119ca7ea6..c27fa58f935 100644 --- a/mysql-test/t/mysqld--help.test +++ b/mysql-test/t/mysqld--help.test @@ -20,7 +20,9 @@ perl; # their paths may vary: @skipvars=qw/basedir open-files-limit general-log-file log plugin-dir log-slow-queries pid-file slow-query-log-file log-basename - datadir slave-load-tmpdir tmpdir socket thread-pool-size/; + datadir slave-load-tmpdir tmpdir socket thread-pool-size + large-files-support lower-case-file-system system-time-zone + version.*/; # Plugins which may or may not be there: @plugins=qw/innodb ndb archive blackhole federated partition ndbcluster diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 754991e9014..fa9e37022d4 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -117,6 +117,15 @@ fun:pthread_create } +{ + pthread memalign memory loss2 + Memcheck:Leak + fun:memalign + fun:tls_get_addr_tail + ... + fun:*ha_initialize_handlerton* +} + { pthread pthread_key_create Memcheck:Leak diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 3105f4b1daf..67c478659b5 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -167,10 +167,10 @@ static inline uint get_first_set(my_bitmap_map value, uint word_pos) } -my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, - my_bool thread_safe __attribute__((unused))) +my_bool my_bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, + my_bool thread_safe __attribute__((unused))) { - DBUG_ENTER("bitmap_init"); + DBUG_ENTER("my_bitmap_init"); if (!buf) { uint size_in_bytes= bitmap_buffer_size(n_bits); @@ -202,9 +202,9 @@ my_bool bitmap_init(MY_BITMAP *map, my_bitmap_map *buf, uint n_bits, } -void bitmap_free(MY_BITMAP *map) +void my_bitmap_free(MY_BITMAP *map) { - DBUG_ENTER("bitmap_free"); + DBUG_ENTER("my_bitmap_free"); if (map->bitmap) { if (map->mutex) diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index fc53183ca7a..531211eb175 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -446,7 +446,7 @@ int ndbcluster_binlog_init_share(NDB_SHARE *share, TABLE *_table) alloc_root(mem_root, no_nodes * sizeof(MY_BITMAP)); for (i= 0; i < no_nodes; i++) { - bitmap_init(&share->subscriber_bitmap[i], + my_bitmap_init(&share->subscriber_bitmap[i], (Uint32*)alloc_root(mem_root, max_ndb_nodes/8), max_ndb_nodes, FALSE); bitmap_clear_all(&share->subscriber_bitmap[i]); @@ -1119,7 +1119,7 @@ ndbcluster_update_slock(THD *thd, MY_BITMAP slock; uint32 bitbuf[SCHEMA_SLOCK_SIZE/4]; - bitmap_init(&slock, bitbuf, sizeof(bitbuf)*8, false); + my_bitmap_init(&slock, bitbuf, sizeof(bitbuf)*8, false); if (ndbtab == 0) { @@ -1370,7 +1370,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, { int i, updated= 0; int no_storage_nodes= g_ndb_cluster_connection->no_db_nodes(); - bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, FALSE); + my_bitmap_init(&schema_subscribers, bitbuf, sizeof(bitbuf)*8, FALSE); bitmap_set_all(&schema_subscribers); /* begin protect ndb_schema_share */ @@ -1908,7 +1908,7 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, Cluster_schema *schema= (Cluster_schema *) sql_alloc(sizeof(Cluster_schema)); MY_BITMAP slock; - bitmap_init(&slock, schema->slock, 8*SCHEMA_SLOCK_SIZE, FALSE); + my_bitmap_init(&slock, schema->slock, 8*SCHEMA_SLOCK_SIZE, FALSE); uint node_id= g_ndb_cluster_connection->node_id(); { ndbcluster_get_schema(tmp_share, schema); @@ -3353,7 +3353,7 @@ ndb_binlog_thread_handle_data_event(Ndb *ndb, NdbEventOperation *pOp, MY_BITMAP b; /* Potential buffer for the bitmap */ uint32 bitbuf[128 / (sizeof(uint32) * 8)]; - bitmap_init(&b, n_fields <= sizeof(bitbuf) * 8 ? bitbuf : NULL, + my_bitmap_init(&b, n_fields <= sizeof(bitbuf) * 8 ? bitbuf : NULL, n_fields, FALSE); bitmap_set_all(&b); @@ -3573,7 +3573,7 @@ static NDB_SCHEMA_OBJECT *ndb_get_schema_object(const char *key, break; } mysql_mutex_init(key_ndb_schema_object_mutex, &ndb_schema_object->mutex, MY_MUTEX_INIT_FAST); - bitmap_init(&ndb_schema_object->slock_bitmap, ndb_schema_object->slock, + my_bitmap_init(&ndb_schema_object->slock_bitmap, ndb_schema_object->slock, sizeof(ndb_schema_object->slock)*8, FALSE); bitmap_clear_all(&ndb_schema_object->slock_bitmap); break; diff --git a/sql/ha_ndbcluster_cond.h b/sql/ha_ndbcluster_cond.h index 27675588ed7..9ea0438a348 100644 --- a/sql/ha_ndbcluster_cond.h +++ b/sql/ha_ndbcluster_cond.h @@ -350,18 +350,18 @@ class Ndb_cond_traverse_context : public Sql_alloc skip(0), collation(NULL), rewrite_stack(NULL) { // Allocate type checking bitmaps - bitmap_init(&expect_mask, 0, 512, FALSE); - bitmap_init(&expect_field_type_mask, 0, 512, FALSE); - bitmap_init(&expect_field_result_mask, 0, 512, FALSE); + my_bitmap_init(&expect_mask, 0, 512, FALSE); + my_bitmap_init(&expect_field_type_mask, 0, 512, FALSE); + my_bitmap_init(&expect_field_result_mask, 0, 512, FALSE); if (stack) cond_ptr= stack->ndb_cond; }; ~Ndb_cond_traverse_context() { - bitmap_free(&expect_mask); - bitmap_free(&expect_field_type_mask); - bitmap_free(&expect_field_result_mask); + my_bitmap_free(&expect_mask); + my_bitmap_free(&expect_field_type_mask); + my_bitmap_free(&expect_field_result_mask); if (rewrite_stack) delete rewrite_stack; } void expect(Item::Type type) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 603e0bf59dc..0d16107bdd8 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -3301,10 +3301,10 @@ err: void ha_partition::free_partition_bitmaps() { /* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */ - bitmap_free(&m_bulk_insert_started); - bitmap_free(&m_locked_partitions); - bitmap_free(&m_partitions_to_reset); - bitmap_free(&m_key_not_found_partitions); + my_bitmap_free(&m_bulk_insert_started); + my_bitmap_free(&m_locked_partitions); + my_bitmap_free(&m_partitions_to_reset); + my_bitmap_free(&m_key_not_found_partitions); } @@ -3316,14 +3316,14 @@ bool ha_partition::init_partition_bitmaps() { DBUG_ENTER("ha_partition::init_partition_bitmaps"); /* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */ - if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE)) + if (my_bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE)) DBUG_RETURN(true); bitmap_clear_all(&m_bulk_insert_started); /* Initialize the bitmap we use to keep track of locked partitions */ - if (bitmap_init(&m_locked_partitions, NULL, m_tot_parts, FALSE)) + if (my_bitmap_init(&m_locked_partitions, NULL, m_tot_parts, FALSE)) { - bitmap_free(&m_bulk_insert_started); + my_bitmap_free(&m_bulk_insert_started); DBUG_RETURN(true); } bitmap_clear_all(&m_locked_partitions); @@ -3332,10 +3332,10 @@ bool ha_partition::init_partition_bitmaps() Initialize the bitmap we use to keep track of partitions which may have something to reset in ha_reset(). */ - if (bitmap_init(&m_partitions_to_reset, NULL, m_tot_parts, FALSE)) + if (my_bitmap_init(&m_partitions_to_reset, NULL, m_tot_parts, FALSE)) { - bitmap_free(&m_bulk_insert_started); - bitmap_free(&m_locked_partitions); + my_bitmap_free(&m_bulk_insert_started); + my_bitmap_free(&m_locked_partitions); DBUG_RETURN(true); } bitmap_clear_all(&m_partitions_to_reset); @@ -3344,11 +3344,11 @@ bool ha_partition::init_partition_bitmaps() Initialize the bitmap we use to keep track of partitions which returned HA_ERR_KEY_NOT_FOUND from index_read_map. */ - if (bitmap_init(&m_key_not_found_partitions, NULL, m_tot_parts, FALSE)) + if (my_bitmap_init(&m_key_not_found_partitions, NULL, m_tot_parts, FALSE)) { - bitmap_free(&m_bulk_insert_started); - bitmap_free(&m_locked_partitions); - bitmap_free(&m_partitions_to_reset); + my_bitmap_free(&m_bulk_insert_started); + my_bitmap_free(&m_locked_partitions); + my_bitmap_free(&m_partitions_to_reset); DBUG_RETURN(true); } bitmap_clear_all(&m_key_not_found_partitions); diff --git a/sql/handler.cc b/sql/handler.cc index ae337f4a153..6af1682e080 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5719,7 +5719,7 @@ static int binlog_log_row(TABLE* table, the first row handled in this statement. In that case, we need to write table maps for all locked tables to the binary log. */ - if (likely(!(error= bitmap_init(&cols, + if (likely(!(error= my_bitmap_init(&cols, use_bitbuf ? bitbuf : NULL, (n_fields + 7) & ~7UL, FALSE)))) @@ -5741,7 +5741,7 @@ static int binlog_log_row(TABLE* table, before_record, after_record); } if (!use_bitbuf) - bitmap_free(&cols); + my_bitmap_free(&cols); } } return error ? HA_ERR_RBR_LOGGING_FAILED : 0; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 81c4f0f51e5..88cae108039 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -4685,13 +4685,13 @@ ulonglong subselect_hash_sj_engine::rowid_merge_buff_size( */ static my_bool -bitmap_init_memroot(MY_BITMAP *map, uint n_bits, MEM_ROOT *mem_root) +my_bitmap_init_memroot(MY_BITMAP *map, uint n_bits, MEM_ROOT *mem_root) { my_bitmap_map *bitmap_buf; if (!(bitmap_buf= (my_bitmap_map*) alloc_root(mem_root, bitmap_buffer_size(n_bits))) || - bitmap_init(map, bitmap_buf, n_bits, FALSE)) + my_bitmap_init(map, bitmap_buf, n_bits, FALSE)) return TRUE; bitmap_clear_all(map); return FALSE; @@ -4729,9 +4729,9 @@ bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) DBUG_ENTER("subselect_hash_sj_engine::init"); - if (bitmap_init_memroot(&non_null_key_parts, tmp_columns->elements, + if (my_bitmap_init_memroot(&non_null_key_parts, tmp_columns->elements, thd->mem_root) || - bitmap_init_memroot(&partial_match_key_parts, tmp_columns->elements, + my_bitmap_init_memroot(&partial_match_key_parts, tmp_columns->elements, thd->mem_root)) DBUG_RETURN(TRUE); @@ -5453,7 +5453,7 @@ Ordered_key::Ordered_key(uint keyid_arg, TABLE *tbl_arg, Item *search_key_arg, Ordered_key::~Ordered_key() { my_free(key_buff); - bitmap_free(&null_key); + my_bitmap_free(&null_key); } @@ -5563,7 +5563,7 @@ bool Ordered_key::alloc_keys_buffers() lookup offset. */ /* Notice that max_null_row is max array index, we need count, so +1. */ - if (bitmap_init(&null_key, NULL, (uint)(max_null_row + 1), FALSE)) + if (my_bitmap_init(&null_key, NULL, (uint)(max_null_row + 1), FALSE)) return TRUE; cur_key_idx= HA_POS_ERROR; @@ -6002,8 +6002,8 @@ subselect_rowid_merge_engine::init(MY_BITMAP *non_null_key_parts, */ if (!has_covering_null_columns) { - if (bitmap_init_memroot(&matching_keys, merge_keys_count, thd->mem_root) || - bitmap_init_memroot(&matching_outer_cols, merge_keys_count, thd->mem_root)) + if (my_bitmap_init_memroot(&matching_keys, merge_keys_count, thd->mem_root) || + my_bitmap_init_memroot(&matching_outer_cols, merge_keys_count, thd->mem_root)) return TRUE; /* diff --git a/sql/log_event.cc b/sql/log_event.cc index f24e85eff70..7f0933792be 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -9114,8 +9114,8 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, set_flags(NO_FOREIGN_KEY_CHECKS_F); if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS) set_flags(RELAXED_UNIQUE_CHECKS_F); - /* if bitmap_init fails, caught in is_valid() */ - if (likely(!bitmap_init(&m_cols, + /* if my_bitmap_init fails, caught in is_valid() */ + if (likely(!my_bitmap_init(&m_cols, m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL, m_width, false))) @@ -9129,7 +9129,7 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, } else { - // Needed because bitmap_init() does not set it to null on failure + // Needed because my_bitmap_init() does not set it to null on failure m_cols.bitmap= 0; } } @@ -9230,8 +9230,8 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, DBUG_PRINT("debug", ("Reading from %p", ptr_after_width)); m_width = net_field_length(&ptr_after_width); DBUG_PRINT("debug", ("m_width=%lu", m_width)); - /* if bitmap_init fails, catched in is_valid() */ - if (likely(!bitmap_init(&m_cols, + /* if my_bitmap_init fails, catched in is_valid() */ + if (likely(!my_bitmap_init(&m_cols, m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL, m_width, false))) @@ -9244,7 +9244,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, } else { - // Needed because bitmap_init() does not set it to null on failure + // Needed because my_bitmap_init() does not set it to null on failure m_cols.bitmap= NULL; DBUG_VOID_RETURN; } @@ -9256,8 +9256,8 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, { DBUG_PRINT("debug", ("Reading from %p", ptr_after_width)); - /* if bitmap_init fails, caught in is_valid() */ - if (likely(!bitmap_init(&m_cols_ai, + /* if my_bitmap_init fails, caught in is_valid() */ + if (likely(!my_bitmap_init(&m_cols_ai, m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL, m_width, false))) @@ -9271,7 +9271,7 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, } else { - // Needed because bitmap_init() does not set it to null on failure + // Needed because my_bitmap_init() does not set it to null on failure m_cols_ai.bitmap= 0; DBUG_VOID_RETURN; } @@ -9302,8 +9302,8 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, Rows_log_event::~Rows_log_event() { if (m_cols.bitmap == m_bitbuf) // no my_malloc happened - m_cols.bitmap= 0; // so no my_free in bitmap_free - bitmap_free(&m_cols); // To pair with bitmap_init(). + m_cols.bitmap= 0; // so no my_free in my_bitmap_free + my_bitmap_free(&m_cols); // To pair with my_bitmap_init(). my_free(m_rows_buf); my_free(m_extra_row_data); } @@ -11962,8 +11962,8 @@ Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg, void Update_rows_log_event::init(MY_BITMAP const *cols) { - /* if bitmap_init fails, caught in is_valid() */ - if (likely(!bitmap_init(&m_cols_ai, + /* if my_bitmap_init fails, caught in is_valid() */ + if (likely(!my_bitmap_init(&m_cols_ai, m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL, m_width, false))) @@ -11982,8 +11982,8 @@ void Update_rows_log_event::init(MY_BITMAP const *cols) Update_rows_log_event::~Update_rows_log_event() { if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened - m_cols_ai.bitmap= 0; // so no my_free in bitmap_free - bitmap_free(&m_cols_ai); // To pair with bitmap_init(). + m_cols_ai.bitmap= 0; // so no my_free in my_bitmap_free + my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init(). } diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 7b89d5bdf08..0cb78686243 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1244,8 +1244,8 @@ Old_rows_log_event::Old_rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, set_flags(NO_FOREIGN_KEY_CHECKS_F); if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS) set_flags(RELAXED_UNIQUE_CHECKS_F); - /* if bitmap_init fails, caught in is_valid() */ - if (likely(!bitmap_init(&m_cols, + /* if my_bitmap_init fails, caught in is_valid() */ + if (likely(!my_bitmap_init(&m_cols, m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL, m_width, false))) @@ -1259,7 +1259,7 @@ Old_rows_log_event::Old_rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, } else { - // Needed because bitmap_init() does not set it to null on failure + // Needed because my_bitmap_init() does not set it to null on failure m_cols.bitmap= 0; } } @@ -1313,8 +1313,8 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len, DBUG_PRINT("debug", ("Reading from %p", ptr_after_width)); m_width = net_field_length(&ptr_after_width); DBUG_PRINT("debug", ("m_width=%lu", m_width)); - /* if bitmap_init fails, catched in is_valid() */ - if (likely(!bitmap_init(&m_cols, + /* if my_bitmap_init fails, catched in is_valid() */ + if (likely(!my_bitmap_init(&m_cols, m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL, m_width, false))) @@ -1327,7 +1327,7 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len, } else { - // Needed because bitmap_init() does not set it to null on failure + // Needed because my_bitmap_init() does not set it to null on failure m_cols.bitmap= NULL; DBUG_VOID_RETURN; } @@ -1358,8 +1358,8 @@ Old_rows_log_event::Old_rows_log_event(const char *buf, uint event_len, Old_rows_log_event::~Old_rows_log_event() { if (m_cols.bitmap == m_bitbuf) // no my_malloc happened - m_cols.bitmap= 0; // so no my_free in bitmap_free - bitmap_free(&m_cols); // To pair with bitmap_init(). + m_cols.bitmap= 0; // so no my_free in my_bitmap_free + my_bitmap_free(&m_cols); // To pair with my_bitmap_init(). my_free(m_rows_buf); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b5e22c874f2..a52251462b1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -366,7 +366,8 @@ static DYNAMIC_ARRAY all_options; /* Global variables */ bool opt_bin_log, opt_bin_log_used=0, opt_ignore_builtin_innodb= 0; -my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0, opt_abort; +my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table= 0, opt_help= 0; +static my_bool opt_abort; ulonglong log_output_options; my_bool opt_userstat_running; my_bool opt_log_queries_not_using_indexes= 0; @@ -1964,7 +1965,7 @@ void clean_up(bool print_message) // We must call end_slave() as clean_up may have been called during startup end_slave(); if (use_slave_mask) - bitmap_free(&slave_error_mask); + my_bitmap_free(&slave_error_mask); #endif stop_handle_manager(); release_ddl_log(); @@ -2018,7 +2019,7 @@ void clean_up(bool print_message) if (defaults_argv) free_defaults(defaults_argv); free_tmpdir(&mysql_tmpdir_list); - bitmap_free(&temp_pool); + my_bitmap_free(&temp_pool); free_max_user_conn(); free_global_user_stats(); free_global_client_stats(); @@ -4251,7 +4252,7 @@ static int init_common_variables() #endif /* defined(ENABLED_DEBUG_SYNC) */ #if (ENABLE_TEMP_POOL) - if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) + if (use_temp_pool && my_bitmap_init(&temp_pool,0,1024,1)) return 1; #else use_temp_pool= 0; @@ -7965,7 +7966,6 @@ static int option_cmp(my_option *a, my_option *b) return 1; } } - DBUG_ASSERT(a->name == b->name); return 0; } @@ -7980,9 +7980,16 @@ static void print_help() sys_var_add_options(&all_options, sys_var::PARSE_EARLY); add_plugin_options(&all_options, &mem_root); sort_dynamic(&all_options, (qsort_cmp) option_cmp); + sort_dynamic(&all_options, (qsort_cmp) option_cmp); add_terminator(&all_options); my_print_help((my_option*) all_options.buffer); + + /* Add variables that can be shown but not changed, like version numbers */ + pop_dynamic(&all_options); + sys_var_add_options(&all_options, sys_var::SHOW_VALUE_IN_HELP); + sort_dynamic(&all_options, (qsort_cmp) option_cmp); + add_terminator(&all_options); my_print_variables((my_option*) all_options.buffer); free_root(&mem_root, MYF(0)); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6982db898fb..4766934845f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1823,7 +1823,7 @@ QUICK_RANGE_SELECT::QUICK_RANGE_SELECT(THD *thd, TABLE *table, uint key_nr, *create_error= 1; } else - bitmap_init(&column_bitmap, bitmap, head->s->fields, FALSE); + my_bitmap_init(&column_bitmap, bitmap, head->s->fields, FALSE); DBUG_VOID_RETURN; } @@ -2847,7 +2847,7 @@ static int fill_used_fields_bitmap(PARAM *param) param->fields_bitmap_size= table->s->column_bitmap_size; if (!(tmp= (my_bitmap_map*) alloc_root(param->mem_root, param->fields_bitmap_size)) || - bitmap_init(¶m->needed_fields, tmp, table->s->fields, FALSE)) + my_bitmap_init(¶m->needed_fields, tmp, table->s->fields, FALSE)) return 1; bitmap_copy(¶m->needed_fields, table->read_set); @@ -4104,7 +4104,7 @@ static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar, */ return find_used_partitions_imerge(ppar, merges.head()); } - bitmap_init(&all_merges, bitmap_buf, n_bits, FALSE); + my_bitmap_init(&all_merges, bitmap_buf, n_bits, FALSE); bitmap_set_prefix(&all_merges, n_bits); List_iterator it(merges); @@ -4751,7 +4751,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts); if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize))) return TRUE; - bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts, + my_bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts, FALSE); } range_par->key_parts= key_part; @@ -5511,7 +5511,7 @@ bool create_fields_bitmap(PARAM *param, MY_BITMAP *fields_bitmap) if (!(bitmap_buf= (my_bitmap_map *) alloc_root(param->mem_root, param->fields_bitmap_size))) return TRUE; - if (bitmap_init(fields_bitmap, bitmap_buf, param->table->s->fields, FALSE)) + if (my_bitmap_init(fields_bitmap, bitmap_buf, param->table->s->fields, FALSE)) return TRUE; return FALSE; @@ -6329,7 +6329,7 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg) param->fields_bitmap_size))) DBUG_RETURN(NULL); - if (bitmap_init(&ror_scan->covered_fields, bitmap_buf, + if (my_bitmap_init(&ror_scan->covered_fields, bitmap_buf, param->table->s->fields, FALSE)) DBUG_RETURN(NULL); bitmap_clear_all(&ror_scan->covered_fields); @@ -6447,7 +6447,7 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param) if (!(buf= (my_bitmap_map*) alloc_root(param->mem_root, param->fields_bitmap_size))) return NULL; - if (bitmap_init(&info->covered_fields, buf, param->table->s->fields, + if (my_bitmap_init(&info->covered_fields, buf, param->table->s->fields, FALSE)) return NULL; info->is_covering= FALSE; @@ -7024,7 +7024,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, covered_fields->bitmap= (my_bitmap_map*)alloc_root(param->mem_root, param->fields_bitmap_size); if (!covered_fields->bitmap || - bitmap_init(covered_fields, covered_fields->bitmap, + my_bitmap_init(covered_fields, covered_fields->bitmap, param->table->s->fields, FALSE)) DBUG_RETURN(0); bitmap_clear_all(covered_fields); diff --git a/sql/opt_table_elimination.cc b/sql/opt_table_elimination.cc index 46bed0e60e7..9b58f5f3126 100644 --- a/sql/opt_table_elimination.cc +++ b/sql/opt_table_elimination.cc @@ -1042,7 +1042,7 @@ bool Dep_analysis_context::setup_equality_modules_deps(List void *buf; if (!(buf= current_thd->alloc(bitmap_buffer_size(offset))) || - bitmap_init(&expr_deps, (my_bitmap_map*)buf, offset, FALSE)) + my_bitmap_init(&expr_deps, (my_bitmap_map*)buf, offset, FALSE)) { DBUG_RETURN(TRUE); /* purecov: inspected */ } diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 44407bd737f..09f1c2986df 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -385,7 +385,7 @@ bool partition_info::can_prune_insert(THD* thd, DBUG_RETURN(true); } /* Also clears all bits. */ - if (bitmap_init(used_partitions, bitmap_buf, num_partitions, false)) + if (my_bitmap_init(used_partitions, bitmap_buf, num_partitions, false)) { /* purecov: begin deadcode */ /* Cannot happen, due to pre-alloc. */ diff --git a/sql/rpl_injector.h b/sql/rpl_injector.h index f4790cc963a..98788955e24 100644 --- a/sql/rpl_injector.h +++ b/sql/rpl_injector.h @@ -94,13 +94,13 @@ public: injector::transaction::table tbl(share->table, true); MY_BITMAP cols; - bitmap_init(&cols, NULL, (i + 7) / 8, false); + my_bitmap_init(&cols, NULL, (i + 7) / 8, false); inj->write_row(::server_id, tbl, &cols, row_data); or MY_BITMAP cols; - bitmap_init(&cols, NULL, (i + 7) / 8, false); + my_bitmap_init(&cols, NULL, (i + 7) / 8, false); inj->write_row(::server_id, injector::transaction::table(share->table, true), &cols, row_data); diff --git a/sql/set_var.h b/sql/set_var.h index 11501c4212a..b5005874d8f 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -60,7 +60,7 @@ public: sys_var *next; LEX_CSTRING name; enum flag_enum { GLOBAL, SESSION, ONLY_SESSION, SCOPE_MASK=1023, - READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096 }; + READONLY=1024, ALLOCATED=2048, PARSE_EARLY=4096, SHOW_VALUE_IN_HELP=8192 }; /** Enumeration type to indicate for a system variable whether it will be written to the binlog or not. @@ -142,8 +142,9 @@ public: } bool register_option(DYNAMIC_ARRAY *array, int parse_flags) { - return (option.id != -1) && ((flags & PARSE_EARLY) == parse_flags) && - insert_dynamic(array, (uchar*)&option); + return ((((option.id != -1) && ((flags & PARSE_EARLY) == parse_flags)) || + (flags & parse_flags)) && + insert_dynamic(array, (uchar*)&option)); } private: diff --git a/sql/slave.cc b/sql/slave.cc index 835b0d9b15a..f6665a6a436 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -573,7 +573,7 @@ void init_slave_skip_errors(const char* arg) const char *p; DBUG_ENTER("init_slave_skip_errors"); - if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0)) + if (my_bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0)) { fprintf(stderr, "Badly out of memory, please check your system status\n"); exit(1); diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index 7e163b0dbcc..2e07695f605 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -34,7 +34,7 @@ public: Bitmap() { init(); } Bitmap(const Bitmap& from) { *this=from; } explicit Bitmap(uint prefix_to_set) { init(prefix_to_set); } - void init() { bitmap_init(&map, buffer, default_width, 0); } + void init() { my_bitmap_init(&map, buffer, default_width, 0); } void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); } uint length() const { return default_width; } Bitmap& operator=(const Bitmap& map2) @@ -52,7 +52,7 @@ public: void intersect(ulonglong map2buff) { MY_BITMAP map2; - bitmap_init(&map2, (uint32 *)&map2buff, sizeof(ulonglong)*8, 0); + my_bitmap_init(&map2, (uint32 *)&map2buff, sizeof(ulonglong)*8, 0); bitmap_intersect(&map, &map2); } /* Use highest bit for all bits above sizeof(ulonglong)*8. */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0acb7e747ad..8e3826eff48 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1229,7 +1229,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) DBUG_ASSERT(view->table != 0 && view->field_translation != 0); - (void) bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0); + (void) my_bitmap_init(&used_fields, used_fields_buff, table->s->fields, 0); bitmap_clear_all(&used_fields); view->contain_auto_increment= 0; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 479fa81edd7..06c78ba81a8 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2470,6 +2470,7 @@ struct LEX: public Query_tables_list uint8 context_analysis_only; bool drop_temporary, local_file, one_shot_set; bool check_exists; + bool replace; bool autocommit; bool verbose, no_write_to_binlog; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f9bfa6d120b..f8af7873a50 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2828,11 +2828,16 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } + /* Check privileges */ if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; +#ifndef QQ /* Might have been updated in create_table_precheck */ create_info.alias= create_table->alias; +#else + create_table->alias= (char*) create_info.alias; +#endif #ifdef HAVE_READLINK /* Fix names if symlinked tables */ @@ -7954,6 +7959,10 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, want_priv= lex->create_info.tmp_table() ? CREATE_TMP_ACL : (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0)); + /* CREATE OR REPLACE on not temporary tables require DROP_ACL */ + if (lex->replace && !lex->create_info.tmp_table()) + want_priv= DROP_ACL; + if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, &create_table->grant.m_internal, @@ -7990,8 +7999,8 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, - For temporary MERGE tables we do not track if their child tables are base or temporary. As result we can't guarantee that privilege check - which was done in presence of temporary child will stay relevant later - as this temporary table might be removed. + which was done in presence of temporary child will stay relevant + later as this temporary table might be removed. If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for the underlying *base* tables, it would create a security breach as in diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 3e19a33ee32..2e8a6efe8e4 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -651,7 +651,7 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, result= TRUE; goto end; } - if (bitmap_init(&part_info->full_part_field_set, bitmap_buf, + if (my_bitmap_init(&part_info->full_part_field_set, bitmap_buf, table->s->fields, FALSE)) { mem_alloc_error(table->s->fields); @@ -1230,9 +1230,9 @@ static bool set_up_partition_bitmaps(THD *thd, partition_info *part_info) mem_alloc_error(bitmap_bytes * 2); DBUG_RETURN(TRUE); } - bitmap_init(&part_info->read_partitions, bitmap_buf, bitmap_bits, FALSE); + my_bitmap_init(&part_info->read_partitions, bitmap_buf, bitmap_bits, FALSE); /* Use the second half of the allocated buffer for lock_partitions */ - bitmap_init(&part_info->lock_partitions, bitmap_buf + (bitmap_bytes / 4), + my_bitmap_init(&part_info->lock_partitions, bitmap_buf + (bitmap_bytes / 4), bitmap_bits, FALSE); part_info->bitmaps_are_initialized= TRUE; part_info->set_partition_bitmaps(NULL); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c109ee10877..307cf99b61f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15333,18 +15333,18 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps) { uint field_count= table->s->fields; - bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, + my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, FALSE); - bitmap_init(&table->def_vcol_set, + my_bitmap_init(&table->def_vcol_set, (my_bitmap_map*) (bitmaps+ bitmap_buffer_size(field_count)), field_count, FALSE); - bitmap_init(&table->tmp_set, + my_bitmap_init(&table->tmp_set, (my_bitmap_map*) (bitmaps+ 2*bitmap_buffer_size(field_count)), field_count, FALSE); - bitmap_init(&table->eq_join_set, + my_bitmap_init(&table->eq_join_set, (my_bitmap_map*) (bitmaps+ 3*bitmap_buffer_size(field_count)), field_count, FALSE); - bitmap_init(&table->cond_set, + my_bitmap_init(&table->cond_set, (my_bitmap_map*) (bitmaps+ 4*bitmap_buffer_size(field_count)), field_count, FALSE); /* write_set and all_set are copies of read_set */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 17767a2afb3..bcbe544b99c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7678,7 +7678,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(0); my_bitmap_map* bitmaps= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count)); - bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, + my_bitmap_init(&table->def_read_set, (my_bitmap_map*) bitmaps, field_count, FALSE); table->read_set= &table->def_read_set; bitmap_clear_all(table->read_set); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 889eaf5fceb..ccdc91e10df 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -191,7 +191,7 @@ static void prepare_record_for_error_message(int error, TABLE *table) DBUG_VOID_RETURN; /* Create unique_map with all fields used by that index. */ - bitmap_init(&unique_map, unique_map_buf, table->s->fields, FALSE); + my_bitmap_init(&unique_map, unique_map_buf, table->s->fields, FALSE); table->mark_columns_used_by_index_no_reset(keynr, &unique_map); /* Subtract read_set and write_set. */ diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index a1fa9a45e99..864808cff32 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -593,7 +593,7 @@ static bool check_charset_db(sys_var *self, THD *thd, set_var *var) } static Sys_var_struct Sys_character_set_database( "character_set_database", - " The character set used by the default database", + "The character set used by the default database", SESSION_VAR(collation_database), NO_CMD_LINE, offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info), NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_charset_db)); @@ -1062,7 +1062,7 @@ static Sys_var_keycache Sys_key_cache_age_threshold( static Sys_var_mybool Sys_large_files_support( "large_files_support", "Whether mysqld was compiled with options for large file support", - READ_ONLY GLOBAL_VAR(opt_large_files), + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(opt_large_files), NO_CMD_LINE, DEFAULT(sizeof(my_off_t) > 4)); static Sys_var_uint Sys_large_page_size( @@ -1184,7 +1184,8 @@ static Sys_var_mybool Sys_lower_case_file_system( "lower_case_file_system", "Case sensitivity of file names on the file system where the " "data directory is located", - READ_ONLY GLOBAL_VAR(lower_case_file_system), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(lower_case_file_system), + NO_CMD_LINE, DEFAULT(FALSE)); static Sys_var_uint Sys_lower_case_table_names( @@ -2145,7 +2146,7 @@ static Sys_var_ulong Sys_preload_buff_size( static Sys_var_uint Sys_protocol_version( "protocol_version", "The version of the client/server protocol used by the MySQL server", - READ_ONLY GLOBAL_VAR(protocol_version), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(protocol_version), NO_CMD_LINE, VALID_RANGE(0, ~0), DEFAULT(PROTOCOL_VERSION), BLOCK_SIZE(1)); static Sys_var_proxy_user Sys_proxy_user( @@ -2853,7 +2854,8 @@ static Sys_var_mybool Sys_sync_frm( static char *system_time_zone_ptr; static Sys_var_charptr Sys_system_time_zone( "system_time_zone", "The server system time zone", - READ_ONLY GLOBAL_VAR(system_time_zone_ptr), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(system_time_zone_ptr), + NO_CMD_LINE, IN_SYSTEM_CHARSET, DEFAULT(system_time_zone)); static Sys_var_ulong Sys_table_def_size( @@ -3063,27 +3065,37 @@ static Sys_var_mybool Sys_timed_mutexes( static char *server_version_ptr; static Sys_var_charptr Sys_version( "version", "Server version", - READ_ONLY GLOBAL_VAR(server_version_ptr), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(server_version_ptr), + NO_CMD_LINE, IN_SYSTEM_CHARSET, DEFAULT(server_version)); static char *server_version_comment_ptr; static Sys_var_charptr Sys_version_comment( "version_comment", "version_comment", - READ_ONLY GLOBAL_VAR(server_version_comment_ptr), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(server_version_comment_ptr), + NO_CMD_LINE, IN_SYSTEM_CHARSET, DEFAULT(MYSQL_COMPILATION_COMMENT)); static char *server_version_compile_machine_ptr; static Sys_var_charptr Sys_version_compile_machine( "version_compile_machine", "version_compile_machine", - READ_ONLY GLOBAL_VAR(server_version_compile_machine_ptr), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP + GLOBAL_VAR(server_version_compile_machine_ptr), NO_CMD_LINE, IN_SYSTEM_CHARSET, DEFAULT(MACHINE_TYPE)); static char *server_version_compile_os_ptr; static Sys_var_charptr Sys_version_compile_os( "version_compile_os", "version_compile_os", - READ_ONLY GLOBAL_VAR(server_version_compile_os_ptr), NO_CMD_LINE, + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(server_version_compile_os_ptr), + NO_CMD_LINE, IN_SYSTEM_CHARSET, DEFAULT(SYSTEM_TYPE)); +static char *malloc_library; +static Sys_var_charptr Sys_malloc_library( + "version_malloc_library", "Version of the used malloc library", + READ_ONLY SHOW_VALUE_IN_HELP GLOBAL_VAR(malloc_library), NO_CMD_LINE, + IN_SYSTEM_CHARSET, DEFAULT(MALLOC_LIBRARY)); + static Sys_var_ulong Sys_net_wait_timeout( "wait_timeout", "The number of seconds the server waits for activity on a " diff --git a/sql/sys_vars.h b/sql/sys_vars.h index bef5fbdd126..6c0228fd6a0 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -56,6 +56,7 @@ // this means that Sys_var_charptr initial value was malloc()ed #define PREALLOCATED sys_var::ALLOCATED+ #define PARSED_EARLY sys_var::PARSE_EARLY+ +#define SHOW_VALUE_IN_HELP sys_var::SHOW_VALUE_IN_HELP+ /* Sys_var_bit meaning is reversed, like in diff --git a/sql/table.cc b/sql/table.cc index ecab578d97d..954383e231b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2013,7 +2013,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (!(bitmaps= (my_bitmap_map*) alloc_root(&share->mem_root, share->column_bitmap_size))) goto err; - bitmap_init(&share->all_set, bitmaps, share->fields, FALSE); + my_bitmap_init(&share->all_set, bitmaps, share->fields, FALSE); bitmap_set_all(&share->all_set); delete handler_file; @@ -2821,17 +2821,17 @@ partititon_err: bitmap_size= share->column_bitmap_size; if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*6))) goto err; - bitmap_init(&outparam->def_read_set, + my_bitmap_init(&outparam->def_read_set, (my_bitmap_map*) bitmaps, share->fields, FALSE); - bitmap_init(&outparam->def_write_set, + my_bitmap_init(&outparam->def_write_set, (my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE); - bitmap_init(&outparam->def_vcol_set, + my_bitmap_init(&outparam->def_vcol_set, (my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE); - bitmap_init(&outparam->tmp_set, + my_bitmap_init(&outparam->tmp_set, (my_bitmap_map*) (bitmaps+bitmap_size*3), share->fields, FALSE); - bitmap_init(&outparam->eq_join_set, + my_bitmap_init(&outparam->eq_join_set, (my_bitmap_map*) (bitmaps+bitmap_size*4), share->fields, FALSE); - bitmap_init(&outparam->cond_set, + my_bitmap_init(&outparam->cond_set, (my_bitmap_map*) (bitmaps+bitmap_size*5), share->fields, FALSE); outparam->default_column_bitmaps(); diff --git a/sql/table.h b/sql/table.h index c25e2c8a83a..0d0f8c49f21 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1067,7 +1067,6 @@ public: ORDER *group; String alias; /* alias or table name */ uchar *null_flags; - my_bitmap_map *bitmap_init_value; MY_BITMAP def_read_set, def_write_set, def_vcol_set, tmp_set; MY_BITMAP eq_join_set; /* used to mark equi-joined fields */ MY_BITMAP cond_set; /* used to mark fields from sargable conditions*/ diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 706f29175d6..ad146ce282d 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -3938,7 +3938,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd, cls= GetListOption(g, "class", topt->oplist); #endif // WIN32 port= atoi(GetListOption(g, "port", topt->oplist, "0")); +#if defined(ODBC_SUPPORT) mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); +#endif mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); #if defined(PROMPT_OK) cop= atoi(GetListOption(g, "checkdsn", topt->oplist, "0")); diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index eb0dc5f9def..a1d4e215118 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -153,8 +153,8 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, const char *name, info.lock_type= F_WRLCK; _ma_set_data_pagecache_callbacks(&info.dfile, share); - bitmap_init(&info.changed_fields, changed_fields_bitmap, - share->base.fields, 0); + my_bitmap_init(&info.changed_fields, changed_fields_bitmap, + share->base.fields, 0); if ((*share->init)(&info)) goto err; diff --git a/unittest/mysys/bitmap-t.c b/unittest/mysys/bitmap-t.c index 0666f4eaa15..c4588779c9b 100644 --- a/unittest/mysys/bitmap-t.c +++ b/unittest/mysys/bitmap-t.c @@ -129,8 +129,8 @@ my_bool test_compare_operators(MY_BITMAP *map, uint bitsize) MY_BITMAP *map2= &map2_obj, *map3= &map3_obj; my_bitmap_map map2buf[MAX_TESTED_BITMAP_SIZE]; my_bitmap_map map3buf[MAX_TESTED_BITMAP_SIZE]; - bitmap_init(&map2_obj, map2buf, bitsize, FALSE); - bitmap_init(&map3_obj, map3buf, bitsize, FALSE); + my_bitmap_init(&map2_obj, map2buf, bitsize, FALSE); + my_bitmap_init(&map3_obj, map3buf, bitsize, FALSE); bitmap_clear_all(map2); bitmap_clear_all(map3); for (i=0; i < no_loops; i++) @@ -374,7 +374,7 @@ my_bool test_compare(MY_BITMAP *map, uint bitsize) uint32 map2buf[MAX_TESTED_BITMAP_SIZE]; uint i, test_bit; uint no_loops= bitsize > 128 ? 128 : bitsize; - if (bitmap_init(&map2, map2buf, bitsize, FALSE)) + if (my_bitmap_init(&map2, map2buf, bitsize, FALSE)) { diag("init error for bitsize %d", bitsize); return TRUE; @@ -433,7 +433,7 @@ my_bool test_intersect(MY_BITMAP *map, uint bitsize) MY_BITMAP map2; uint32 map2buf[MAX_TESTED_BITMAP_SIZE]; uint i, test_bit1, test_bit2, test_bit3; - if (bitmap_init(&map2, map2buf, bitsize2, FALSE)) + if (my_bitmap_init(&map2, map2buf, bitsize2, FALSE)) { diag("init error for bitsize %d", bitsize2); return TRUE; @@ -481,7 +481,7 @@ my_bool do_test(uint bitsize) { MY_BITMAP map; my_bitmap_map buf[MAX_TESTED_BITMAP_SIZE]; - if (bitmap_init(&map, buf, bitsize, FALSE)) + if (my_bitmap_init(&map, buf, bitsize, FALSE)) { diag("init error for bitsize %d", bitsize); goto error; -- cgit v1.2.1 From 659304d410dc56103a9045e1e3476bc530f35398 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Thu, 9 Jan 2014 22:01:12 +0200 Subject: Cleanups: - Updated help for mysql-test-run - Added OQGraph to all cmake error output regarding OQGraph to make it easier to spot problems - Suppressed warning messages from OQGraph - Added test for version_malloc_library variable mysql-test/mysql-test-run.pl: Updated help mysql-test/suite/sys_vars/r/version_malloc_library_basic.result: Added test for version_malloc_library variable mysql-test/suite/sys_vars/t/version_malloc_library_basic.test: Added test for version_malloc_library variable storage/oqgraph/CMakeLists.txt: Added OQGraph to all cmake error output regarding OQGraph to make it easier to spot problems storage/oqgraph/mysql-test/oqgraph/boundary_conditions.result: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/boundary_conditions.test: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/invalid_operations.result: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/invalid_operations.test: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/isnull.result: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/isnull.test: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/regression_1233113.result: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/regression_1233113.test: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/regression_drop_after.result: Suppressed warning messages storage/oqgraph/mysql-test/oqgraph/regression_drop_after.test: Suppressed warning messages --- mysql-test/mysql-test-run.pl | 15 +++- .../sys_vars/r/version_malloc_library_basic.result | 53 +++++++++++++ .../sys_vars/t/version_malloc_library_basic.test | 90 ++++++++++++++++++++++ storage/oqgraph/CMakeLists.txt | 7 +- .../mysql-test/oqgraph/boundary_conditions.result | 1 + .../mysql-test/oqgraph/boundary_conditions.test | 2 + .../mysql-test/oqgraph/invalid_operations.result | 1 + .../mysql-test/oqgraph/invalid_operations.test | 2 + storage/oqgraph/mysql-test/oqgraph/isnull.result | 2 +- storage/oqgraph/mysql-test/oqgraph/isnull.test | 3 +- .../mysql-test/oqgraph/regression_1233113.result | 1 + .../mysql-test/oqgraph/regression_1233113.test | 2 + .../oqgraph/regression_drop_after.result | 1 + .../mysql-test/oqgraph/regression_drop_after.test | 2 + 14 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/version_malloc_library_basic.result create mode 100644 mysql-test/suite/sys_vars/t/version_malloc_library_basic.test diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 5ca0a5bbe8d..4d494bc4c57 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -6318,7 +6318,20 @@ sub usage ($) { $0 [ OPTIONS ] [ TESTCASE ] -Options to control what engine/variation to run +Where test case can be specified as: + +testcase[.test] Runs the test case named 'testcase' from all suits +path-to-testcase +[suite.]testcase[,combination] + +Examples: + +alias +main.alias 'main' is the name of the suite for the 't' directory. +rpl.rpl_invoked_features,mix,xtradb_plugin +suite/rpl/t/rpl.rpl_invoked_features + +Options to control what engine/variation to run: embedded-server Use the embedded server, i.e. no mysqld daemons ps-protocol Use the binary protocol between client and server diff --git a/mysql-test/suite/sys_vars/r/version_malloc_library_basic.result b/mysql-test/suite/sys_vars/r/version_malloc_library_basic.result new file mode 100644 index 00000000000..5895b8122d9 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/version_malloc_library_basic.result @@ -0,0 +1,53 @@ +'#---------------------BS_STVARS_053_01----------------------#' +SELECT COUNT(@@GLOBAL.version_malloc_library); +COUNT(@@GLOBAL.version_malloc_library) +1 +1 Expected +'#---------------------BS_STVARS_053_02----------------------#' +SET @@GLOBAL.version_malloc_library=1; +ERROR HY000: Variable 'version_malloc_library' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.version_malloc_library); +COUNT(@@GLOBAL.version_malloc_library) +1 +1 Expected +'#---------------------BS_STVARS_053_03----------------------#' +SELECT @@GLOBAL.version_malloc_library = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='version_malloc_library'; +@@GLOBAL.version_malloc_library = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.version_malloc_library); +COUNT(@@GLOBAL.version_malloc_library) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='version_malloc_library'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +'#---------------------BS_STVARS_053_04----------------------#' +SELECT @@version_malloc_library = @@GLOBAL.version_malloc_library; +@@version_malloc_library = @@GLOBAL.version_malloc_library +1 +1 Expected +'#---------------------BS_STVARS_053_05----------------------#' +SELECT COUNT(@@version_malloc_library); +COUNT(@@version_malloc_library) +1 +1 Expected +SELECT COUNT(@@local.version_malloc_library); +ERROR HY000: Variable 'version_malloc_library' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.version_malloc_library); +ERROR HY000: Variable 'version_malloc_library' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.version_malloc_library); +COUNT(@@GLOBAL.version_malloc_library) +1 +1 Expected +SELECT version_malloc_library = @@SESSION.version; +ERROR 42S22: Unknown column 'version_malloc_library' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/t/version_malloc_library_basic.test b/mysql-test/suite/sys_vars/t/version_malloc_library_basic.test new file mode 100644 index 00000000000..6318ca4abd5 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/version_malloc_library_basic.test @@ -0,0 +1,90 @@ +################## mysql-test\t\version_malloc_library.test ################### +# # +# Variable Name: version_malloc_library # +# Scope: Global # +# Access Type: Static # +# Data Type: String # +# # +# Description:Test Cases of Dynamic System Variable version # +# that checks the behavior of this variable in the following ways # +# * Value Check # +# * Scope Check # +# # +############################################################################### + +--echo '#---------------------BS_STVARS_053_01----------------------#' +#################################################################### +# Displaying default value # +#################################################################### +SELECT COUNT(@@GLOBAL.version_malloc_library); +--echo 1 Expected + + +--echo '#---------------------BS_STVARS_053_02----------------------#' +#################################################################### +# Check if Value can set # +#################################################################### + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.version_malloc_library=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.version_malloc_library); +--echo 1 Expected + + + + +--echo '#---------------------BS_STVARS_053_03----------------------#' +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# + +SELECT @@GLOBAL.version_malloc_library = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='version_malloc_library'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.version_malloc_library); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='version_malloc_library'; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_053_04----------------------#' +############################################################################### +# Check if accessing variable with and without GLOBAL point to same variable # +############################################################################### +SELECT @@version_malloc_library = @@GLOBAL.version_malloc_library; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_053_05----------------------#' +############################################################################### +# Check if version_malloc_library can be accessed with and without @@ sign # +############################################################################### + +SELECT COUNT(@@version_malloc_library); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.version_malloc_library); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.version_malloc_library); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.version_malloc_library); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT version_malloc_library = @@SESSION.version; +--echo Expected error 'Readonly variable' + + diff --git a/storage/oqgraph/CMakeLists.txt b/storage/oqgraph/CMakeLists.txt index 74d05873f6f..3f592133969 100644 --- a/storage/oqgraph/CMakeLists.txt +++ b/storage/oqgraph/CMakeLists.txt @@ -3,14 +3,14 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") MESSAGE(STATUS "Configuring OQGraph") FIND_PACKAGE(Boost) IF(NOT Boost_FOUND) - MESSAGE(STATUS "Boost not found") + MESSAGE(STATUS "Boost not found. OQGraph will not be compiled") RETURN() ENDIF() INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS}) FIND_PACKAGE(Judy) IF(NOT Judy_FOUND) - MESSAGE(STATUS "Judy not found") + MESSAGE(STATUS "Judy not found. OQGraph will not be compiled") RETURN() ENDIF() INCLUDE_DIRECTORIES(${Judy_INCLUDE_DIR}) @@ -53,6 +53,7 @@ IF(BOOST_OK) MODULE_ONLY COMPONENT oqgraph-engine LINK_LIBRARIES ${Judy_LIBRARIES}) + MESSAGE(STATUS "OQGraph OK") ELSE(BOOST_OK) - MESSAGE(STATUS "Requisites for OQGraph not met") + MESSAGE(STATUS "Requisites for OQGraph not met. OQGraph will not be compiled") ENDIF(BOOST_OK) diff --git a/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.result b/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.result index 9aa806eace9..7cb65bc07ea 100644 --- a/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.result +++ b/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.result @@ -1,6 +1,7 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; DROP TABLE IF EXISTS graph2; +call mtr.add_suppression("graph_base is open on delete"); CREATE TABLE graph2 ( latch VARCHAR(32) NULL, origid BIGINT UNSIGNED NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.test b/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.test index 869994aa208..a6dae0e2678 100644 --- a/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.test +++ b/storage/oqgraph/mysql-test/oqgraph/boundary_conditions.test @@ -4,6 +4,8 @@ DROP TABLE IF EXISTS graph; DROP TABLE IF EXISTS graph2; --enable_warnings +call mtr.add_suppression("graph_base is open on delete"); + CREATE TABLE graph2 ( latch VARCHAR(32) NULL, origid BIGINT UNSIGNED NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/invalid_operations.result b/storage/oqgraph/mysql-test/oqgraph/invalid_operations.result index 046c468b768..49639c278d0 100644 --- a/storage/oqgraph/mysql-test/oqgraph/invalid_operations.result +++ b/storage/oqgraph/mysql-test/oqgraph/invalid_operations.result @@ -1,5 +1,6 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; +call mtr.add_suppression("graph_base is open on delete"); CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, to_id INT UNSIGNED NOT NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/invalid_operations.test b/storage/oqgraph/mysql-test/oqgraph/invalid_operations.test index 8f79b23ed43..cab99ec5018 100644 --- a/storage/oqgraph/mysql-test/oqgraph/invalid_operations.test +++ b/storage/oqgraph/mysql-test/oqgraph/invalid_operations.test @@ -3,6 +3,8 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; --enable_warnings +call mtr.add_suppression("graph_base is open on delete"); + # Create the backing store CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/isnull.result b/storage/oqgraph/mysql-test/oqgraph/isnull.result index 38ebf12413c..d9af33222dc 100644 --- a/storage/oqgraph/mysql-test/oqgraph/isnull.result +++ b/storage/oqgraph/mysql-test/oqgraph/isnull.result @@ -38,5 +38,5 @@ NULL 1 NULL 1 1 2 select * from graph where latch is null and destid=2; latch origid destid weight seq linkid NULL NULL 2 1 1 1 -DROP TABLE graph_base; DROP TABLE graph; +DROP TABLE graph_base; diff --git a/storage/oqgraph/mysql-test/oqgraph/isnull.test b/storage/oqgraph/mysql-test/oqgraph/isnull.test index 93105887834..dc7622daa0d 100644 --- a/storage/oqgraph/mysql-test/oqgraph/isnull.test +++ b/storage/oqgraph/mysql-test/oqgraph/isnull.test @@ -34,6 +34,5 @@ select * from graph where latch is null; select * from graph where latch is null and origid=1; select * from graph where latch is null and destid=2; -DROP TABLE graph_base; DROP TABLE graph; - +DROP TABLE graph_base; diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_1233113.result b/storage/oqgraph/mysql-test/oqgraph/regression_1233113.result index 415b2181bbb..2b0ea4b2acb 100644 --- a/storage/oqgraph/mysql-test/oqgraph/regression_1233113.result +++ b/storage/oqgraph/mysql-test/oqgraph/regression_1233113.result @@ -1,5 +1,6 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; +call mtr.add_suppression("graph_base is open on delete"); CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, to_id INT UNSIGNED NOT NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_1233113.test b/storage/oqgraph/mysql-test/oqgraph/regression_1233113.test index 26e6656eea5..db53b2b39ae 100644 --- a/storage/oqgraph/mysql-test/oqgraph/regression_1233113.test +++ b/storage/oqgraph/mysql-test/oqgraph/regression_1233113.test @@ -3,6 +3,8 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; --enable_warnings +call mtr.add_suppression("graph_base is open on delete"); + # Create the backing store CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.result b/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.result index 84902676ef2..cace2c40564 100644 --- a/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.result +++ b/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.result @@ -1,5 +1,6 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; +call mtr.add_suppression("graph_base is open on delete"); CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, to_id INT UNSIGNED NOT NULL, diff --git a/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.test b/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.test index b6f4418112c..673eb867032 100644 --- a/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.test +++ b/storage/oqgraph/mysql-test/oqgraph/regression_drop_after.test @@ -3,6 +3,8 @@ DROP TABLE IF EXISTS graph_base; DROP TABLE IF EXISTS graph; --enable_warnings +call mtr.add_suppression("graph_base is open on delete"); + # Create the backing store CREATE TABLE graph_base ( from_id INT UNSIGNED NOT NULL, -- cgit v1.2.1 From 7ffc9da093bf34cf0f524fcf39be9af2a149ce19 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 29 Jan 2014 15:37:17 +0200 Subject: Implementation of MDEV-5491: CREATE OR REPLACE TABLE Using CREATE OR REPLACE TABLE is be identical to DROP TABLE IF EXISTS table_name; CREATE TABLE ...; Except that: * CREATE OR REPLACE is be atomic (now one can create the same table between drop and create). * Temporary tables will not shadow the table name for the DROP as the CREATE TABLE tells us already if we are using a temporary table or not. * If the table was locked with LOCK TABLES, the new table will be locked with the same lock after it's created. Implementation details: - We don't anymore open the to-be-created table during CREATE TABLE, which the original code did. - There is no need to open a table we are planning to create. It's enough to check if the table exists or not. - Removed some of duplicated code for CREATE IF NOT EXISTS. - Give an error when using CREATE OR REPLACE with IF NOT EXISTS (conflicting options). - As a side effect of the code changes, we don't anymore have to internally re-prepare prepared statements with CREATE TABLE if the table exists. - Made one code path for all testing if log table are in use. - Better error message if one tries to create/drop/alter a log table in use - Added back disabled rpl_row_create_table test as it now seams to work and includes a lot of interesting tests. - Added HA_LEX_CREATE_REPLACE to mark if we are using CREATE OR REPLACE - Aligned CREATE OR REPLACE parsing code in sql_yacc.yy for TABLE and VIEW - Changed interface for drop_temporary_table() to make it more reusable - Changed Locked_tables_list::init_locked_tables() to work on the table object instead of the table list object. Before this it used a mix of both, which was not good. - Locked_tables_list::unlock_locked_tables(THD *thd) now requires a valid thd argument. Old usage of calling this with 0 i changed to instead call Locked_tables_list::reset() - Added functions Locked_tables_list:restore_lock() and Locked_tables_list::add_back_last_deleted_lock() to be able to easily add back a locked table to the lock list. - Added restart_trans_for_tables() to be able to restart a transaction. - DROP_ACL is required if one uses CREATE TABLE OR REPLACE. - Added drop of normal and temporary tables in create_table_imp() if CREATE OR REPLACE was used. - Added reacquiring of table locks in mysql_create_table() and mysql_create_like_table() mysql-test/include/commit.inc: With new code we get fewer status increments mysql-test/r/commit_1innodb.result: With new code we get fewer status increments mysql-test/r/create.result: Added testing of create or replace with timeout mysql-test/r/create_or_replace.result: Basic testing of CREATE OR REPLACE TABLE mysql-test/r/partition_exchange.result: New error message mysql-test/r/ps_ddl.result: Fewer reprepares with new code mysql-test/suite/archive/discover.result: Don't rediscover archive tables if the .frm file exists (Sergei will look at this if there is a better way...) mysql-test/suite/archive/discover.test: Don't rediscover archive tables if the .frm file exists (Sergei will look at this if there is a better way...) mysql-test/suite/funcs_1/r/innodb_views.result: New error message mysql-test/suite/funcs_1/r/memory_views.result: New error message mysql-test/suite/rpl/disabled.def: rpl_row_create_table should now be safe to use mysql-test/suite/rpl/r/rpl_row_create_table.result: Updated results after adding back disabled test mysql-test/suite/rpl/t/rpl_create_if_not_exists.test: Added comment mysql-test/suite/rpl/t/rpl_row_create_table.test: Added CREATE OR REPLACE TABLE test mysql-test/t/create.test: Added CREATE OR REPLACE TABLE test mysql-test/t/create_or_replace-master.opt: Create logs mysql-test/t/create_or_replace.test: Basic testing of CREATE OR REPLACE TABLE mysql-test/t/partition_exchange.test: Error number changed as we are now using same code for all log table change issues mysql-test/t/ps_ddl.test: Fewer reprepares with new code sql/handler.h: Moved things around a bit in a structure to get better alignment. Added HA_LEX_CREATE_REPLACE to mark if we are using CREATE OR REPLACE Added 3 elements to end of HA_CREATE_INFO to be able to store state to add backs locks in case of LOCK TABLES. sql/log.cc: Reimplemented check_if_log_table(): - Simpler and faster usage - Can give error messages This gives us one code path for allmost all error messages if log tables are in use sql/log.h: New interface for check_if_log_table() sql/slave.cc: More logging sql/sql_alter.cc: New interface for check_if_log_table() sql/sql_base.cc: More documentation Changed interface for drop_temporary_table() to make it more reusable Changed Locked_tables_list::init_locked_tables() to work on the table object instead of the table list object. Before this it used a mix of both, which was not good. Locked_tables_list::unlock_locked_tables(THD *thd) now requires a valid thd argument. Old usage of calling this with 0 i changed to instead call Locked_tables_list::reset() Added functions Locked_tables_list:restore_lock() and Locked_tables_list::add_back_last_deleted_lock() to be able to easily add back a locked table to the lock list. Check for command number instead of open_strategy of CREATE TABLE was used. Added restart_trans_for_tables() to be able to restart a transaction. This was needed in "create or replace ... select" between the drop table and the select. sql/sql_base.h: Added and updated function prototypes sql/sql_class.h: Added new prototypes to Locked_tables_list class Added extra argument to select_create to avoid double call to eof() or send_error() - I needed this in some edge case where the table was not created against expections. sql/sql_db.cc: New interface for check_if_log_table() sql/sql_insert.cc: Remember position to lock information so that we can reaquire table lock for LOCK TABLES + CREATE OR REPLACE TABLE SELECT. Later add back the lock by calling restore_lock(). Removed one not needed indentation level in create_table_from_items() Ensure we don't call send_eof() or abort_result_set() twice. sql/sql_lex.h: Removed variable that I temporarly added in an earlier changeset sql/sql_parse.cc: Removed old test code (marked with QQ) Ensure that we have open_strategy set as TABLE_LIST::OPEN_STUB in CREATE TABLE Removed some IF NOT EXISTS code as this is now handled in create_table_table_impl(). Set OPTION_KEEP_LOGS later. This code had to be moved as the test for IF EXISTS has changed place. DROP_ACL is required if one uses CREATE TABLE OR REPLACE. sql/sql_partition_admin.cc: New interface for check_if_log_table() sql/sql_rename.cc: New interface for check_if_log_table() sql/sql_table.cc: New interface for check_if_log_table() Moved some code in mysql_rm_table() under a common test. - Safe as temporary tables doesn't have statistics. - !is_temporary_table(table) test was moved out from drop_temporary_table() and merged with upper level code. - Added drop of normal and temporary tables in create_table_imp() if CREATE OR REPLACE was used. - Added reacquiring of table locks in mysql_create_table() and mysql_create_like_table() - In mysql_create_like_table(), restore table->open_strategy() if it was changed. - Re-test if table was a view after opening it. sql/sql_table.h: New prototype for mysql_create_table_no_lock() sql/sql_yacc.yy: Added syntax for CREATE OR REPLACE TABLE Reuse new code for CREATE OR REPLACE VIEW sql/table.h: Added name for enum type sql/table_cache.cc: More DBUG --- mysql-test/include/commit.inc | 2 +- mysql-test/r/commit_1innodb.result | 2 +- mysql-test/r/create.result | 2 + mysql-test/r/create_or_replace.result | 293 +++++++++++++++++++++ mysql-test/r/partition_exchange.result | 2 +- mysql-test/r/ps_ddl.result | 6 +- mysql-test/suite/archive/discover.result | 3 + mysql-test/suite/archive/discover.test | 4 + mysql-test/suite/funcs_1/r/innodb_views.result | 2 +- mysql-test/suite/funcs_1/r/memory_views.result | 2 +- mysql-test/suite/rpl/disabled.def | 1 - mysql-test/suite/rpl/r/rpl_row_create_table.result | 156 +++++------ .../suite/rpl/t/rpl_create_if_not_exists.test | 4 +- mysql-test/suite/rpl/t/rpl_row_create_table.test | 3 +- mysql-test/t/create.test | 2 + mysql-test/t/create_or_replace-master.opt | 1 + mysql-test/t/create_or_replace.test | 234 ++++++++++++++++ mysql-test/t/partition_exchange.test | 2 +- mysql-test/t/ps_ddl.test | 6 +- sql/handler.h | 26 +- sql/log.cc | 56 ++-- sql/log.h | 4 +- sql/slave.cc | 3 +- sql/sql_alter.cc | 15 +- sql/sql_base.cc | 217 ++++++++++----- sql/sql_base.h | 4 +- sql/sql_class.h | 10 +- sql/sql_db.cc | 8 +- sql/sql_insert.cc | 165 +++++++----- sql/sql_lex.h | 1 - sql/sql_parse.cc | 60 ++--- sql/sql_partition_admin.cc | 7 +- sql/sql_rename.cc | 8 +- sql/sql_table.cc | 214 +++++++++++---- sql/sql_table.h | 10 +- sql/sql_yacc.yy | 64 +++-- sql/table.h | 2 +- sql/table_cache.cc | 2 + 38 files changed, 1195 insertions(+), 408 deletions(-) create mode 100644 mysql-test/r/create_or_replace.result create mode 100644 mysql-test/t/create_or_replace-master.opt create mode 100644 mysql-test/t/create_or_replace.test diff --git a/mysql-test/include/commit.inc b/mysql-test/include/commit.inc index bdb6f48f095..e72ebba8527 100644 --- a/mysql-test/include/commit.inc +++ b/mysql-test/include/commit.inc @@ -751,7 +751,7 @@ call p_verify_status_increment(4, 4, 4, 4); --echo # Sic: no table is created. create table if not exists t2 (a int) select 6 union select 7; --echo # Sic: first commits the statement, and then the transaction. -call p_verify_status_increment(2, 0, 2, 0); +call p_verify_status_increment(0, 0, 0, 0); create table t3 select a from t2; call p_verify_status_increment(2, 0, 4, 4); alter table t3 add column (b int); diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result index 3583e8ed396..1e173221b15 100644 --- a/mysql-test/r/commit_1innodb.result +++ b/mysql-test/r/commit_1innodb.result @@ -830,7 +830,7 @@ create table if not exists t2 (a int) select 6 union select 7; Warnings: Note 1050 Table 't2' already exists # Sic: first commits the statement, and then the transaction. -call p_verify_status_increment(2, 0, 2, 0); +call p_verify_status_increment(0, 0, 0, 0); SUCCESS create table t3 select a from t2; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 7eba25d8ea3..41a2200c13f 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -2602,6 +2602,8 @@ create table t1 (a int, b int) select 2,2; ERROR 42S01: Table 't1' already exists create table t1 like t2; ERROR 42S01: Table 't1' already exists +create or replace table t1 (a int, b int) select 2,2; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction select * from t1; a b 1 1 diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result new file mode 100644 index 00000000000..42a3d1fe17c --- /dev/null +++ b/mysql-test/r/create_or_replace.result @@ -0,0 +1,293 @@ +drop table if exists t1,t2; +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES(1),(2),(3); +# +# Check first syntax and wrong usage +# +CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int); +ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS +create or replace trigger trg before insert on t1 for each row set @a:=1; +ERROR HY000: Incorrect usage of OR REPLACE and TRIGGERS / SP / EVENT +create or replace table mysql.general_log (a int); +ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled +create or replace table mysql.slow_log (a int); +ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled +# +# Usage when table doesn't exist +# +CREATE OR REPLACE TABLE t1 (a int); +CREATE TABLE t1 (a int); +ERROR 42S01: Table 't1' already exists +DROP TABLE t1; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int); +CREATE TEMPORARY TABLE t1 (a int, b int, c int); +ERROR 42S01: Table 't1' already exists +DROP TEMPORARY TABLE t1; +# +# Testing with temporary tables +# +CREATE OR REPLACE TABLE t1 (a int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TEMPORARY TABLE t1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +create temporary table t1 (i int) engine=InnoDB; +create or replace temporary table t1 (a int, b int) engine=InnoDB; +create or replace temporary table t1 (j int); +show create table t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `j` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine= innodb; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int) engine= innodb; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine=myisam; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TEMPORARY TABLE t1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +CREATE OR REPLACE TABLE t2 (a int); +ERROR HY000: Table 't2' was not locked with LOCK TABLES +DROP TABLE t1; +UNLOCK TABLES; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int) SELECT * from t2; +SELECT * FROM t1; +a +1 +2 +3 +CREATE OR REPLACE TEMPORARY TABLE t1 (b int) SELECT * from t2; +SELECT * FROM t1; +b a +NULL 1 +NULL 2 +NULL 3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `b` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TEMPORARY TABLE t1 AS SELECT a FROM t2; +CREATE TEMPORARY TABLE IF NOT EXISTS t1(a int, b int) SELECT 1,2 FROM t2; +Warnings: +Note 1050 Table 't1' already exists +create or replace table t1 as select 1; +show create table t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# +# Testing with normal tables +# +CREATE OR REPLACE TABLE t1 (a int); +CREATE OR REPLACE TABLE t1 (a int, b int); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (a int) SELECT * from t2; +SELECT * FROM t1; +a +1 +2 +3 +TRUNCATE TABLE t1; +CREATE TABLE IF NOT EXISTS t1 (a int) SELECT * from t2; +Warnings: +Note 1050 Table 't1' already exists +SELECT * FROM t1; +a +DROP TABLE t1; +CREATE TABLE t1 (i int); +CREATE OR REPLACE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `1` int(1) NOT NULL DEFAULT '0' +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write,t2 write; +CREATE OR REPLACE TABLE t1 (a int, b int); +SELECT * FROM t1; +a b +INSERT INTO t1 values(1,1); +CREATE OR REPLACE TABLE t1 (a int, b int, c int); +INSERT INTO t1 values(1,1,1); +CREATE OR REPLACE TABLE t3 (a int); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +UNLOCK TABLES; +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write,t2 write; +CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2; +SELECT * FROM t2; +a +1 +2 +3 +SELECT * FROM t1; +b a 1 +NULL 1 1 +NULL 2 1 +NULL 3 1 +SELECT * FROM t1; +b a 1 +NULL 1 1 +NULL 2 1 +NULL 3 1 +INSERT INTO t1 values(1,1,1); +CREATE OR REPLACE TABLE t1 (a int, b int, c int, d int); +INSERT INTO t1 values(1,1,1,1); +CREATE OR REPLACE TABLE t3 (a int); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +UNLOCK TABLES; +DROP TABLE t1; +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write,t2 write, t1 as t1_read read; +CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2; +SELECT * FROM t1; +b a 1 +NULL 1 1 +NULL 2 1 +NULL 3 1 +SELECT * FROM t2; +a +1 +2 +3 +SELECT * FROM t1 as t1_read; +ERROR HY000: Table 't1_read' was not locked with LOCK TABLES +DROP TABLE t1; +UNLOCK TABLES; +# +# Test also with InnoDB (transactional engine) +# +create table t1 (i int) engine=innodb; +lock table t1 write; +create or replace table t1 (j int); +unlock tables; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `j` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (i int) engine=InnoDB; +lock table t1 write, t2 write; +create or replace table t1 (j int) engine=innodb; +unlock tables; +drop table t1; +create table t1 (i int) engine=InnoDB; +create table t3 (i int) engine=InnoDB; +insert into t3 values(1),(2),(3); +lock table t1 write, t2 write, t3 write; +create or replace table t1 (a int, i int) engine=innodb select t2.a,t3.i from t2,t3; +unlock tables; +select * from t1 order by a,i; +a i +1 1 +1 2 +1 3 +2 1 +2 2 +2 3 +3 1 +3 2 +3 3 +drop table t1,t3; +# +# Testing CREATE .. LIKE +# +create or replace table t1 like t2; +create or replace table t1 like t2; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 (b int); +lock tables t1 write, t2 read; +create or replace table t1 like t2; +SELECT * FROM t1; +a +INSERT INTO t1 values(1); +CREATE OR REPLACE TABLE t1 like t2; +INSERT INTO t1 values(2); +unlock tables; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# +# Test with prepared statements +# +prepare stmt1 from 'create or replace table t1 select * from t2'; +execute stmt1; +select * from t1; +a +1 +2 +3 +execute stmt1; +select * from t1; +a +1 +2 +3 +drop table t1; +execute stmt1; +select * from t1; +a +1 +2 +3 +deallocate prepare stmt1; +drop table t1; +# +# Test with views +# +create view t1 as select 1; +create table if not exists t1 (a int); +Warnings: +Note 1050 Table 't1' already exists +create or replace table t1 (a int); +ERROR 42S02: Unknown table 'test.t1' +drop table t1; +ERROR 42S02: Unknown table 'test.t1' +drop view t1; +DROP TABLE t2; diff --git a/mysql-test/r/partition_exchange.result b/mysql-test/r/partition_exchange.result index 36499004869..fec08e99c72 100644 --- a/mysql-test/r/partition_exchange.result +++ b/mysql-test/r/partition_exchange.result @@ -1088,7 +1088,7 @@ ALTER TABLE t PARTITION BY RANGE (UNIX_TIMESTAMP(event_time) DIV 1) (PARTITION p0 VALUES LESS THAN (123456789), PARTITION pMAX VALUES LESS THAN MAXVALUE); ALTER TABLE t EXCHANGE PARTITION p0 WITH TABLE general_log; -ERROR HY000: Incorrect usage of PARTITION and log table +ERROR HY000: You cannot 'ALTER PARTITION' a log table if logging is enabled ALTER TABLE general_log ENGINE = CSV; SET @@global.general_log = @old_general_log_state; DROP TABLE t; diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result index 8284e974574..dec0d12c455 100644 --- a/mysql-test/r/ps_ddl.result +++ b/mysql-test/r/ps_ddl.result @@ -1930,7 +1930,7 @@ SUCCESS execute stmt; ERROR 42S01: Table 't2' already exists -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); SUCCESS execute stmt; @@ -1946,7 +1946,7 @@ SUCCESS execute stmt; ERROR 42S01: Table 't2' already exists -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); SUCCESS drop temporary table t2; @@ -1964,7 +1964,7 @@ drop table t2; create view t2 as select 1; execute stmt; Got one of the listed errors -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); SUCCESS execute stmt; diff --git a/mysql-test/suite/archive/discover.result b/mysql-test/suite/archive/discover.result index c4f4bb4104f..726c8712917 100644 --- a/mysql-test/suite/archive/discover.result +++ b/mysql-test/suite/archive/discover.result @@ -135,4 +135,7 @@ select * from t1; a flush tables; create table t1 (a int) engine=archive; +ERROR 42S01: Table 't1' already exists +flush tables; +create table t1 (a int) engine=archive; drop table t1; diff --git a/mysql-test/suite/archive/discover.test b/mysql-test/suite/archive/discover.test index 8dfe09f7b33..144a5dbdcf9 100644 --- a/mysql-test/suite/archive/discover.test +++ b/mysql-test/suite/archive/discover.test @@ -125,6 +125,10 @@ create table t1 (a int) engine=archive; select * from t1; flush tables; remove_file $mysqld_datadir/test/t1.ARZ; +--error ER_TABLE_EXISTS_ERROR +create table t1 (a int) engine=archive; +remove_file $mysqld_datadir/test/t1.frm; +flush tables; create table t1 (a int) engine=archive; drop table t1; diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index 96b6d3171f0..e6d98159b39 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -7579,7 +7579,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp SELECT * FROM test.tb2 limit 2' at line 1 CREATE OR REPLACE TEMPORARY VIEW test.v1 AS SELECT * FROM test.tb2 limit 2 ; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TEMPORARY VIEW test.v1 AS +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'VIEW test.v1 AS SELECT * FROM test.tb2 limit 2' at line 1 Drop view if exists test.v1 ; Use test; diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index ddde31b76d1..21990c2bd9d 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -7580,7 +7580,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp SELECT * FROM test.tb2 limit 2' at line 1 CREATE OR REPLACE TEMPORARY VIEW test.v1 AS SELECT * FROM test.tb2 limit 2 ; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TEMPORARY VIEW test.v1 AS +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'VIEW test.v1 AS SELECT * FROM test.tb2 limit 2' at line 1 Drop view if exists test.v1 ; Use test; diff --git a/mysql-test/suite/rpl/disabled.def b/mysql-test/suite/rpl/disabled.def index 5cc3916b614..de3091a56e5 100644 --- a/mysql-test/suite/rpl/disabled.def +++ b/mysql-test/suite/rpl/disabled.def @@ -10,7 +10,6 @@ # ############################################################################## -rpl_row_create_table : Bug#11759274 2010-02-27 andrei failed different way than earlier with bug#45576 rpl_spec_variables : BUG#11755836 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux rpl_get_master_version_and_clock : Bug#11766137 Jan 05 2011 joro Valgrind warnings rpl_get_master_version_and_clock rpl_partition_archive : MDEV-5077 2013-09-27 svoj Cannot exchange partition with archive table diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result index 393e2fdb851..07822a39b46 100644 --- a/mysql-test/suite/rpl/r/rpl_row_create_table.result +++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result @@ -1,23 +1,24 @@ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; -**** Resetting master and slave **** -include/stop_slave.inc -RESET SLAVE; -RESET MASTER; -include/start_slave.inc -CREATE TABLE t1 (a INT, b INT); +include/master-slave.inc +[connection master] +include/wait_for_slave_to_stop.inc +include/wait_for_slave_to_start.inc +include/rpl_reset.inc +CREATE TABLE t1 (a INT); +CREATE OR REPLACE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE t1 (a INT, b INT) +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT, b INT) ENGINE=Merge +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8 +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8 **** On Master **** SHOW CREATE TABLE t1; @@ -111,15 +112,10 @@ NULL 3 6 NULL 4 2 NULL 5 10 NULL 6 12 -**** Resetting master and slave **** -include/stop_slave.inc -RESET SLAVE; -RESET MASTER; -include/start_slave.inc +include/rpl_reset.inc CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; ERROR 23000: Duplicate entry '2' for key 'b' -show binlog events from ; -Log_name Pos Event_type Server_id End_log_pos Info +include/show_binlog_events.inc CREATE TABLE t7 (a INT, b INT UNIQUE); INSERT INTO t7 SELECT a,b FROM tt3; ERROR 23000: Duplicate entry '2' for key 'b' @@ -128,23 +124,20 @@ a b 1 2 2 4 3 6 -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE) -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Table_map # # table_id: # (test.t7) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT SELECT * FROM t7 ORDER BY a,b; a b 1 2 2 4 3 6 -**** Resetting master and slave **** -include/stop_slave.inc -RESET SLAVE; -RESET MASTER; -include/start_slave.inc +include/rpl_reset.inc CREATE TEMPORARY TABLE tt4 (a INT, b INT); INSERT INTO tt4 VALUES (4,8), (5,10), (6,12); BEGIN; @@ -152,11 +145,11 @@ INSERT INTO t7 SELECT a,b FROM tt4; ROLLBACK; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Table_map # # table_id: # (test.t7) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT SELECT * FROM t7 ORDER BY a,b; a b @@ -174,11 +167,7 @@ a b 4 8 5 10 6 12 -**** Resetting master and slave **** -include/stop_slave.inc -RESET SLAVE; -RESET MASTER; -include/start_slave.inc +include/rpl_reset.inc CREATE TABLE t8 LIKE t4; CREATE TABLE t9 LIKE tt4; CREATE TEMPORARY TABLE tt5 LIKE t4; @@ -197,9 +186,11 @@ Create Table CREATE TABLE `t9` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t8 LIKE t4 +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE `t9` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL @@ -219,15 +210,12 @@ Create Table CREATE TABLE `t9` ( ) ENGINE=MEMORY DEFAULT CHARSET=latin1 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; STOP SLAVE; +include/wait_for_slave_to_stop.inc SET GLOBAL storage_engine=@storage_engine; START SLAVE; +include/wait_for_slave_to_start.inc ================ BUG#22864 ================ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; +include/rpl_reset.inc SET AUTOCOMMIT=0; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); @@ -270,37 +258,38 @@ a 1 2 3 -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE `t4` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 # Table_map # # table_id: # (test.t4) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT SHOW TABLES; Tables_in_test @@ -333,10 +322,7 @@ a 3 DROP TABLE IF EXISTS t1,t2,t3,t4; SET AUTOCOMMIT=1; -STOP SLAVE; -RESET SLAVE; -RESET MASTER; -START SLAVE; +include/rpl_reset.inc CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a INT) ENGINE=INNODB; @@ -355,19 +341,21 @@ a 4 6 9 -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ SELECT * FROM t2 ORDER BY a; a @@ -377,11 +365,7 @@ a 6 9 TRUNCATE TABLE t2; -**** Resetting master and slave **** -include/stop_slave.inc -RESET SLAVE; -RESET MASTER; -include/start_slave.inc +include/rpl_reset.inc BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt2 @@ -394,8 +378,14 @@ Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back SELECT * FROM t2 ORDER BY a; a -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK SELECT * FROM t2 ORDER BY a; a DROP TABLE t1,t2; @@ -412,35 +402,28 @@ a 1 2 DROP TABLE t1; -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; +include/rpl_reset.inc DROP DATABASE IF EXISTS mysqltest1; CREATE DATABASE mysqltest1; CREATE TABLE mysqltest1.without_select (f1 BIGINT); CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1; -show binlog events from ; +include/show_binlog_events.inc Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # DROP DATABASE IF EXISTS mysqltest1 +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # CREATE DATABASE mysqltest1 +master-bin.000001 # Gtid # # GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE mysqltest1.without_select (f1 BIGINT) -master-bin.000001 # Query # # BEGIN +master-bin.000001 # Gtid # # BEGIN GTID #-#-# master-bin.000001 # Query # # use `test`; CREATE TABLE `mysqltest1`.`with_select` ( `f1` int(1) NOT NULL DEFAULT '0' ) master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT DROP DATABASE mysqltest1; -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; +include/rpl_reset.inc CREATE TEMPORARY TABLE t7(c1 INT); CREATE TABLE t5(c1 INT); CREATE TABLE t4(c1 INT); @@ -461,4 +444,5 @@ DROP VIEW IF EXISTS bug48506_t1, bug48506_t2, bug48506_t3; DROP TEMPORARY TABLES t7; DROP TABLES t4, t5; DROP TABLES IF EXISTS bug48506_t4; +include/rpl_end.inc end of the tests diff --git a/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test index 72f1201c93c..b27250f908f 100644 --- a/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test +++ b/mysql-test/suite/rpl/t/rpl_create_if_not_exists.test @@ -52,6 +52,8 @@ CREATE DATABASE IF NOT EXISTS mysqltest; USE mysqltest; CREATE TABLE IF NOT EXISTS t(c1 int); CREATE TABLE IF NOT EXISTS t1 LIKE t; +# The following will not be logged because t2 existed and we will not +# put the data of SELECT into the binary log CREATE TABLE IF NOT EXISTS t2 SELECT * FROM t; CREATE EVENT IF NOT EXISTS e ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR @@ -104,7 +106,7 @@ SELECT * FROM t1; SELECT * FROM t2; sync_slave_with_master; -# In these two statements, t1 and t2 are the base table. The recoreds of t2 +# In these two statements, t1 and t2 are the base table. The records of t2 # are inserted into it when CREATE TABLE ... SELECT was executed. SELECT * FROM t1; SELECT * FROM t2; diff --git a/mysql-test/suite/rpl/t/rpl_row_create_table.test b/mysql-test/suite/rpl/t/rpl_row_create_table.test index ef3c0758643..da73d753dcd 100644 --- a/mysql-test/suite/rpl/t/rpl_row_create_table.test +++ b/mysql-test/suite/rpl/t/rpl_row_create_table.test @@ -28,7 +28,8 @@ START SLAVE; --source include/rpl_reset.inc connection master; -CREATE TABLE t1 (a INT, b INT); +CREATE TABLE t1 (a INT); +CREATE OR REPLACE TABLE t1 (a INT, b INT); CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index ebcad5f4af4..8bb7339ce83 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -2014,6 +2014,8 @@ create table t1 (a int, b int); create table t1 (a int, b int) select 2,2; --error ER_TABLE_EXISTS_ERROR create table t1 like t2; +--error ER_LOCK_WAIT_TIMEOUT +create or replace table t1 (a int, b int) select 2,2; disconnect user1; connection default; select * from t1; diff --git a/mysql-test/t/create_or_replace-master.opt b/mysql-test/t/create_or_replace-master.opt new file mode 100644 index 00000000000..e94228f2f33 --- /dev/null +++ b/mysql-test/t/create_or_replace-master.opt @@ -0,0 +1 @@ +--log-output=TABLE,FILE --general-log=1 --slow-query-log=1 diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test new file mode 100644 index 00000000000..b776be23b08 --- /dev/null +++ b/mysql-test/t/create_or_replace.test @@ -0,0 +1,234 @@ +# +# Check CREATE OR REPLACE ALTER TABLE +# + +--source include/have_innodb.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + +# +# Create help table +# + +CREATE TABLE t2 (a int); +INSERT INTO t2 VALUES(1),(2),(3); + +--echo # +--echo # Check first syntax and wrong usage +--echo # + +--error ER_WRONG_USAGE +CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int); +--error ER_WRONG_USAGE +create or replace trigger trg before insert on t1 for each row set @a:=1; + +# check that we don't try to create a log table in use +--error ER_BAD_LOG_STATEMENT +create or replace table mysql.general_log (a int); +--error ER_BAD_LOG_STATEMENT +create or replace table mysql.slow_log (a int); + +--echo # +--echo # Usage when table doesn't exist +--echo # + +CREATE OR REPLACE TABLE t1 (a int); +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t1 (a int); +DROP TABLE t1; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int); +--error ER_TABLE_EXISTS_ERROR +CREATE TEMPORARY TABLE t1 (a int, b int, c int); +DROP TEMPORARY TABLE t1; + +--echo # +--echo # Testing with temporary tables +--echo # + +CREATE OR REPLACE TABLE t1 (a int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int); +SHOW CREATE TABLE t1; +DROP TEMPORARY TABLE t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# Test also with InnoDB +create temporary table t1 (i int) engine=InnoDB; +create or replace temporary table t1 (a int, b int) engine=InnoDB; +create or replace temporary table t1 (j int); +show create table t1; +drop table t1; + +# Using lock tables on normal tables with create or replace on temp tables +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int); +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine= innodb; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int) engine= innodb; +CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine=myisam; +SHOW CREATE TABLE t1; +DROP TEMPORARY TABLE t1; +SHOW CREATE TABLE t1; +# Verify that table is still locked +--error ER_TABLE_NOT_LOCKED +CREATE OR REPLACE TABLE t2 (a int); +DROP TABLE t1; +UNLOCK TABLES; + +# +# Using CREATE SELECT +# + +CREATE OR REPLACE TEMPORARY TABLE t1 (a int) SELECT * from t2; +SELECT * FROM t1; +CREATE OR REPLACE TEMPORARY TABLE t1 (b int) SELECT * from t2; +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TEMPORARY TABLE t1 AS SELECT a FROM t2; +CREATE TEMPORARY TABLE IF NOT EXISTS t1(a int, b int) SELECT 1,2 FROM t2; +create or replace table t1 as select 1; +show create table t1; +DROP TABLE t1; + + +--echo # +--echo # Testing with normal tables +--echo # + +CREATE OR REPLACE TABLE t1 (a int); +CREATE OR REPLACE TABLE t1 (a int, b int); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 (a int) SELECT * from t2; +SELECT * FROM t1; +TRUNCATE TABLE t1; +CREATE TABLE IF NOT EXISTS t1 (a int) SELECT * from t2; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (i int); +CREATE OR REPLACE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# Using lock tables with CREATE OR REPLACE +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write,t2 write; +CREATE OR REPLACE TABLE t1 (a int, b int); +# Verify if table is still locked +SELECT * FROM t1; +INSERT INTO t1 values(1,1); +CREATE OR REPLACE TABLE t1 (a int, b int, c int); +INSERT INTO t1 values(1,1,1); +--error ER_TABLE_NOT_LOCKED +CREATE OR REPLACE TABLE t3 (a int); +UNLOCK TABLES; +DROP TABLE t1; + +# Using lock tables with CREATE OR REPLACE ... SELECT +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write,t2 write; +CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2; +# Verify if table is still locked +SELECT * FROM t2; +SELECT * FROM t1; +SELECT * FROM t1; +INSERT INTO t1 values(1,1,1); +CREATE OR REPLACE TABLE t1 (a int, b int, c int, d int); +INSERT INTO t1 values(1,1,1,1); +--error ER_TABLE_NOT_LOCKED +CREATE OR REPLACE TABLE t3 (a int); +UNLOCK TABLES; +DROP TABLE t1; + +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLES t1 write,t2 write, t1 as t1_read read; +CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2; +SELECT * FROM t1; +SELECT * FROM t2; +--error ER_TABLE_NOT_LOCKED +SELECT * FROM t1 as t1_read; +DROP TABLE t1; +UNLOCK TABLES; + +--echo # +--echo # Test also with InnoDB (transactional engine) +--echo # + +create table t1 (i int) engine=innodb; +lock table t1 write; +create or replace table t1 (j int); +unlock tables; +show create table t1; +drop table t1; + +create table t1 (i int) engine=InnoDB; +lock table t1 write, t2 write; +create or replace table t1 (j int) engine=innodb; +unlock tables; +drop table t1; + +create table t1 (i int) engine=InnoDB; +create table t3 (i int) engine=InnoDB; +insert into t3 values(1),(2),(3); +lock table t1 write, t2 write, t3 write; +create or replace table t1 (a int, i int) engine=innodb select t2.a,t3.i from t2,t3; +unlock tables; +select * from t1 order by a,i; +drop table t1,t3; + +--echo # +--echo # Testing CREATE .. LIKE +--echo # + +create or replace table t1 like t2; +create or replace table t1 like t2; +show create table t1; +drop table t1; +create table t1 (b int); +lock tables t1 write, t2 read; +create or replace table t1 like t2; +SELECT * FROM t1; +INSERT INTO t1 values(1); +CREATE OR REPLACE TABLE t1 like t2; +INSERT INTO t1 values(2); +unlock tables; +show create table t1; +drop table t1; + +--echo # +--echo # Test with prepared statements +--echo # + +prepare stmt1 from 'create or replace table t1 select * from t2'; +execute stmt1; +select * from t1; +execute stmt1; +select * from t1; +drop table t1; +execute stmt1; +select * from t1; +deallocate prepare stmt1; +drop table t1; + +--echo # +--echo # Test with views +--echo # + +create view t1 as select 1; +create table if not exists t1 (a int); +--error ER_BAD_TABLE_ERROR +create or replace table t1 (a int); +--error ER_BAD_TABLE_ERROR +drop table t1; +drop view t1; + +# +# Cleanup +# +DROP TABLE t2; diff --git a/mysql-test/t/partition_exchange.test b/mysql-test/t/partition_exchange.test index d7dfd6f543e..e538bee16cd 100644 --- a/mysql-test/t/partition_exchange.test +++ b/mysql-test/t/partition_exchange.test @@ -439,7 +439,7 @@ CREATE TABLE t LIKE general_log; ALTER TABLE t PARTITION BY RANGE (UNIX_TIMESTAMP(event_time) DIV 1) (PARTITION p0 VALUES LESS THAN (123456789), PARTITION pMAX VALUES LESS THAN MAXVALUE); ---error ER_WRONG_USAGE +--error ER_BAD_LOG_STATEMENT ALTER TABLE t EXCHANGE PARTITION p0 WITH TABLE general_log; ALTER TABLE general_log ENGINE = CSV; SET @@global.general_log = @old_general_log_state; diff --git a/mysql-test/t/ps_ddl.test b/mysql-test/t/ps_ddl.test index c34800976c7..21355ca42b7 100644 --- a/mysql-test/t/ps_ddl.test +++ b/mysql-test/t/ps_ddl.test @@ -1610,7 +1610,7 @@ call p_verify_reprepare_count(0); # Base table with name of table to be created exists --error ER_TABLE_EXISTS_ERROR execute stmt; -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); --error ER_TABLE_EXISTS_ERROR execute stmt; call p_verify_reprepare_count(0); @@ -1622,7 +1622,7 @@ execute stmt; call p_verify_reprepare_count(0); --error ER_TABLE_EXISTS_ERROR execute stmt; -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); drop temporary table t2; --error ER_TABLE_EXISTS_ERROR execute stmt; @@ -1641,7 +1641,7 @@ drop table t2; create view t2 as select 1; --error ER_TABLE_EXISTS_ERROR,9999 execute stmt; -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); --error ER_TABLE_EXISTS_ERROR,9999 execute stmt; call p_verify_reprepare_count(0); diff --git a/sql/handler.h b/sql/handler.h index 69b9c3e071e..1e22bf05aba 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -32,6 +32,7 @@ #include "sql_cache.h" #include "structs.h" /* SHOW_COMP_OPTION */ #include "sql_array.h" /* Dynamic_array<> */ +#include "mdl.h" #include #include @@ -378,6 +379,7 @@ enum enum_alter_inplace_result { #define HA_LEX_CREATE_IF_NOT_EXISTS 2 #define HA_LEX_CREATE_TABLE_LIKE 4 #define HA_CREATE_TMP_ALTER 8 +#define HA_LEX_CREATE_REPLACE 16 #define HA_MAX_REC_LENGTH 65535 /* Table caching type */ @@ -1573,9 +1575,15 @@ struct HA_CREATE_INFO ulong avg_row_length; ulong used_fields; ulong key_block_size; - uint stats_sample_pages; /* number of pages to sample during - stats estimation, if used, otherwise 0. */ - enum_stats_auto_recalc stats_auto_recalc; + /* + number of pages to sample during + stats estimation, if used, otherwise 0. + */ + uint stats_sample_pages; + uint null_bits; /* NULL bits at start of record */ + uint options; /* OR of HA_CREATE_ options */ + uint merge_insert_method; + uint extra_size; /* length of extra data segment */ SQL_I_List merge_list; handlerton *db_type; /** @@ -1588,21 +1596,23 @@ struct HA_CREATE_INFO If nothing speficied inherits the value of the original table (if present). */ enum row_type row_type; - uint null_bits; /* NULL bits at start of record */ - uint options; /* OR of HA_CREATE_ options */ - uint merge_insert_method; - uint extra_size; /* length of extra data segment */ enum ha_choice transactional; - bool varchar; ///< 1 if table has a VARCHAR enum ha_storage_media storage_media; ///< DEFAULT, DISK or MEMORY enum ha_choice page_checksum; ///< If we have page_checksums engine_option_value *option_list; ///< list of table create options + enum_stats_auto_recalc stats_auto_recalc; + bool varchar; ///< 1 if table has a VARCHAR /* the following three are only for ALTER TABLE, check_if_incompatible_data() */ ha_table_option_struct *option_struct; ///< structure with parsed table options ha_field_option_struct **fields_option_struct; ///< array of field option structures ha_index_option_struct **indexes_option_struct; ///< array of index option structures + /* The following is used to remember the old state for CREATE OR REPLACE */ + TABLE *table; + TABLE_LIST *pos_in_locked_tables; + MDL_ticket *mdl_ticket; + bool tmp_table() { return options & HA_LEX_CREATE_TMP_TABLE; } }; diff --git a/sql/log.cc b/sql/log.cc index 90305ec227e..9ea1514ef77 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -525,35 +525,57 @@ bool LOGGER::is_log_table_enabled(uint log_table_type) } -/* Check if a given table is opened log table */ -int check_if_log_table(size_t db_len, const char *db, size_t table_name_len, - const char *table_name, bool check_if_opened) +/** + Check if a given table is opened log table + + @param table Table to check + @param check_if_opened Only fail if it's a log table in use + @param error_msg String to put in error message if not ok. + No error message if 0 + @return 0 ok + @return # Type of log file + */ + +int check_if_log_table(const TABLE_LIST *table, + bool check_if_opened, + const char *error_msg) { - if (db_len == 5 && + int result= 0; + if (table->db_length == 5 && !(lower_case_table_names ? - my_strcasecmp(system_charset_info, db, "mysql") : - strcmp(db, "mysql"))) + my_strcasecmp(system_charset_info, table->db, "mysql") : + strcmp(table->db, "mysql"))) { - if (table_name_len == 11 && !(lower_case_table_names ? - my_strcasecmp(system_charset_info, - table_name, "general_log") : - strcmp(table_name, "general_log"))) + const char *table_name= table->table_name; + + if (table->table_name_length == 11 && + !(lower_case_table_names ? + my_strcasecmp(system_charset_info, + table_name, "general_log") : + strcmp(table_name, "general_log"))) { - if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL)) - return QUERY_LOG_GENERAL; - return 0; + result= QUERY_LOG_GENERAL; + goto end; } - if (table_name_len == 8 && !(lower_case_table_names ? + if (table->table_name_length == 8 && !(lower_case_table_names ? my_strcasecmp(system_charset_info, table_name, "slow_log") : strcmp(table_name, "slow_log"))) { - if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_SLOW)) - return QUERY_LOG_SLOW; - return 0; + result= QUERY_LOG_SLOW; + goto end; } } return 0; + +end: + if (!check_if_opened || logger.is_log_table_enabled(result)) + { + if (error_msg) + my_error(ER_BAD_LOG_STATEMENT, MYF(0), error_msg); + return result; + } + return 0; } diff --git a/sql/log.h b/sql/log.h index 73518d2594f..18e86d9d0f8 100644 --- a/sql/log.h +++ b/sql/log.h @@ -833,8 +833,8 @@ public: }; -int check_if_log_table(size_t db_len, const char *db, size_t table_name_len, - const char *table_name, bool check_if_opened); +int check_if_log_table(const TABLE_LIST *table, bool check_if_opened, + const char *errmsg); class Log_to_csv_event_handler: public Log_event_handler { diff --git a/sql/slave.cc b/sql/slave.cc index f6665a6a436..6886a6345ab 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1047,9 +1047,10 @@ static bool sql_slave_killed(rpl_group_info *rgi) "documentation for details)."; DBUG_PRINT("info", ("modified_non_trans_table: %d OPTION_BEGIN: %d " - "is_in_group: %d", + "OPTION_KEEP_LOG: %d is_in_group: %d", thd->transaction.all.modified_non_trans_table, test(thd->variables.option_bits & OPTION_BEGIN), + test(thd->variables.option_bits & OPTION_KEEP_LOG), rli->is_in_group())); if (rli->abort_slave) diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc index 01bffaf132f..97b9c127c22 100644 --- a/sql/sql_alter.cc +++ b/sql/sql_alter.cc @@ -338,19 +338,8 @@ bool Sql_cmd_discard_import_tablespace::execute(THD *thd) it is the case. TODO: this design is obsolete and will be removed. */ - int table_kind= check_if_log_table(table_list->db_length, table_list->db, - table_list->table_name_length, - table_list->table_name, false); - - if (table_kind) - { - /* Disable alter of enabled log tables */ - if (logger.is_log_table_enabled(table_kind)) - { - my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER"); - return true; - } - } + if (check_if_log_table(table_list, TRUE, "ALTER")) + return true; return mysql_discard_or_import_tablespace(thd, table_list, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e3ce2adf862..0a38cbbeb1a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -784,12 +784,18 @@ static void close_open_tables(THD *thd) access the table cache key @param[in] extra - HA_EXTRA_PREPRE_FOR_DROP if the table is being dropped - HA_EXTRA_PREPARE_FOR_REANME if the table is being renamed - HA_EXTRA_NOT_USED no drop/rename - In case of drop/reanme the documented behaviour is to + HA_EXTRA_PREPARE_FOR_DROP + - The table is dropped + HA_EXTRA_PREPARE_FOR_RENAME + - The table is renamed + HA_EXTRA_NOT_USED + - The table is marked as closed in the + locked_table_list but kept there so one can call + locked_table_list->reopen_tables() to put it back. + + In case of drop/rename the documented behavior is to implicitly remove the table from LOCK TABLES - list. + list. @pre Must be called with an X MDL lock on the table. */ @@ -1588,26 +1594,21 @@ TABLE *find_temporary_table(THD *thd, thd->temporary_tables list, it's impossible to tell here whether we're dealing with an internal or a user temporary table. - If is_trans is not null, we return the type of the table: - either transactional (e.g. innodb) as TRUE or non-transactional - (e.g. myisam) as FALSE. + @param thd Thread handler + @param table Temporary table to be deleted + @param is_trans Is set to the type of the table: + transactional (e.g. innodb) as TRUE or non-transactional + (e.g. myisam) as FALSE. @retval 0 the table was found and dropped successfully. - @retval 1 the table was not found in the list of temporary tables - of this thread @retval -1 the table is in use by a outer query */ -int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans) +int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans) { DBUG_ENTER("drop_temporary_table"); DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'", - table_list->db, table_list->table_name)); - - if (!is_temporary_table(table_list)) - DBUG_RETURN(1); - - TABLE *table= table_list->table; + table->s->db.str, table->s->table_name.str)); /* Table might be in use by some outer statement. */ if (table->query_id && table->query_id != thd->query_id) @@ -1627,10 +1628,10 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans) */ mysql_lock_remove(thd, thd->lock, table); close_temporary_table(thd, table, 1, 1); - table_list->table= NULL; DBUG_RETURN(0); } + /* unlink from thd->temporary tables and close temporary table */ @@ -2611,9 +2612,9 @@ Locked_tables_list::init_locked_tables(THD *thd) { TABLE_LIST *src_table_list= table->pos_in_table_list; char *db, *table_name, *alias; - size_t db_len= src_table_list->db_length; - size_t table_name_len= src_table_list->table_name_length; - size_t alias_len= strlen(src_table_list->alias); + size_t db_len= table->s->db.length; + size_t table_name_len= table->s->table_name.length; + size_t alias_len= table->alias.length(); TABLE_LIST *dst_table_list; if (! multi_alloc_root(&m_locked_tables_root, @@ -2623,23 +2624,15 @@ Locked_tables_list::init_locked_tables(THD *thd) &alias, alias_len + 1, NullS)) { - unlock_locked_tables(0); + reset(); return TRUE; } - memcpy(db, src_table_list->db, db_len + 1); - memcpy(table_name, src_table_list->table_name, table_name_len + 1); - memcpy(alias, src_table_list->alias, alias_len + 1); - /** - Sic: remember the *actual* table level lock type taken, to - acquire the exact same type in reopen_tables(). - E.g. if the table was locked for write, src_table_list->lock_type is - TL_WRITE_DEFAULT, whereas reginfo.lock_type has been updated from - thd->update_lock_default. - */ + memcpy(db, table->s->db.str, db_len + 1); + memcpy(table_name, table->s->table_name.str, table_name_len + 1); + strmake(alias, table->alias.ptr(), alias_len); dst_table_list->init_one_table(db, db_len, table_name, table_name_len, - alias, - src_table_list->table->reginfo.lock_type); + alias, table->reginfo.lock_type); dst_table_list->table= table; dst_table_list->mdl_request.ticket= src_table_list->mdl_request.ticket; @@ -2660,7 +2653,7 @@ Locked_tables_list::init_locked_tables(THD *thd) (m_locked_tables_count+1)); if (m_reopen_array == NULL) { - unlock_locked_tables(0); + reset(); return TRUE; } } @@ -2681,42 +2674,50 @@ Locked_tables_list::init_locked_tables(THD *thd) void Locked_tables_list::unlock_locked_tables(THD *thd) { - if (thd) + DBUG_ASSERT(!thd->in_sub_stmt && + !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); + /* + Sic: we must be careful to not close open tables if + we're not in LOCK TABLES mode: unlock_locked_tables() is + sometimes called implicitly, expecting no effect on + open tables, e.g. from begin_trans(). + */ + if (thd->locked_tables_mode != LTM_LOCK_TABLES) + return; + + for (TABLE_LIST *table_list= m_locked_tables; + table_list; table_list= table_list->next_global) { - DBUG_ASSERT(!thd->in_sub_stmt && - !(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); /* - Sic: we must be careful to not close open tables if - we're not in LOCK TABLES mode: unlock_locked_tables() is - sometimes called implicitly, expecting no effect on - open tables, e.g. from begin_trans(). + Clear the position in the list, the TABLE object will be + returned to the table cache. */ - if (thd->locked_tables_mode != LTM_LOCK_TABLES) - return; + if (table_list->table) // If not closed + table_list->table->pos_in_locked_tables= NULL; + } + thd->leave_locked_tables_mode(); - for (TABLE_LIST *table_list= m_locked_tables; - table_list; table_list= table_list->next_global) - { - /* - Clear the position in the list, the TABLE object will be - returned to the table cache. - */ - if (table_list->table) // If not closed - table_list->table->pos_in_locked_tables= NULL; - } - thd->leave_locked_tables_mode(); + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + + /* + We rely on the caller to implicitly commit the + transaction and release transactional locks. + */ - DBUG_ASSERT(thd->transaction.stmt.is_empty()); - close_thread_tables(thd); - /* - We rely on the caller to implicitly commit the - transaction and release transactional locks. - */ - } /* After closing tables we can free memory used for storing lock request for metadata locks and TABLE_LIST elements. */ + reset(); +} + +/* + Free memory allocated for storing locks +*/ + +void Locked_tables_list::reset() +{ free_root(&m_locked_tables_root, MYF(0)); m_locked_tables= NULL; m_locked_tables_last= &m_locked_tables; @@ -2781,6 +2782,7 @@ void Locked_tables_list::unlink_from_list(THD *thd, m_locked_tables_last= table_list->prev_global; else table_list->next_global->prev_global= table_list->prev_global; + m_locked_tables_count--; } } @@ -2834,6 +2836,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) m_locked_tables_last= table_list->prev_global; else table_list->next_global->prev_global= table_list->prev_global; + m_locked_tables_count--; } } } @@ -2908,6 +2911,57 @@ Locked_tables_list::reopen_tables(THD *thd) return FALSE; } +/** + Add back a locked table to the locked list that we just removed from it. + This is needed in CREATE OR REPLACE TABLE where we are dropping, creating + and re-opening a locked table. + + @return 0 0k + @return 1 error +*/ + +bool Locked_tables_list::restore_lock(THD *thd, TABLE_LIST *dst_table_list, + TABLE *table, MYSQL_LOCK *lock) +{ + MYSQL_LOCK *merged_lock; + DBUG_ENTER("restore_lock"); + DBUG_ASSERT(!strcmp(dst_table_list->table_name, table->s->table_name.str)); + + /* Ensure we have the memory to add the table back */ + if (!(merged_lock= mysql_lock_merge(thd->lock, lock))) + DBUG_RETURN(1); + thd->lock= merged_lock; + + /* Link to the new table */ + dst_table_list->table= table; + /* + The lock type may have changed (normally it should not as create + table will lock the table in write mode + */ + dst_table_list->lock_type= table->reginfo.lock_type; + table->pos_in_locked_tables= dst_table_list; + + add_back_last_deleted_lock(dst_table_list); + + DBUG_RETURN(0); +} + +/* + Add back the last deleted lock structure. + This should be followed by a call to reopen_tables() to + open the table. +*/ + +void Locked_tables_list::add_back_last_deleted_lock(TABLE_LIST *dst_table_list) +{ + /* Link the lock back in the locked tables list */ + dst_table_list->prev_global= m_locked_tables_last; + *m_locked_tables_last= dst_table_list; + m_locked_tables_last= &dst_table_list->next_global; + dst_table_list->next_global= 0; + m_locked_tables_count++; +} + #ifndef DBUG_OFF /* Cause a spurious statement reprepare for debug purposes. */ @@ -4045,9 +4099,9 @@ lock_table_names(THD *thd, if (mdl_requests.is_empty()) DBUG_RETURN(FALSE); - /* Check if CREATE TABLE was used */ - create_table= (tables_start && tables_start->open_strategy == - TABLE_LIST::OPEN_IF_EXISTS); + /* Check if CREATE TABLE without REPLACE was used */ + create_table= (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + !(thd->lex->create_info.options & HA_LEX_CREATE_REPLACE)); if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) { @@ -5293,6 +5347,39 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, } +/* + Restart transaction for tables + + This is used when we had to do an implicit commit after tables are opened + and want to restart transactions on tables. + + This is used in case of: + LOCK TABLES xx + CREATE OR REPLACE TABLE xx; +*/ + +bool restart_trans_for_tables(THD *thd, TABLE_LIST *table) +{ + DBUG_ENTER("restart_trans_for_tables"); + + if (!thd->locked_tables_mode) + DBUG_RETURN(FALSE); + + for (; table; table= table->next_global) + { + if (table->placeholder()) + continue; + + if (check_lock_and_start_stmt(thd, thd->lex, table)) + { + DBUG_ASSERT(0); // Should never happen + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + + /** Prepare statement for reopening of tables and recalculation of set of prelocked tables. diff --git a/sql/sql_base.h b/sql/sql_base.h index 3e633fad084..61442843a39 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -248,7 +248,7 @@ void close_thread_table(THD *thd, TABLE **table_ptr); bool close_temporary_tables(THD *thd); TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, bool check_alias); -int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans); +int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans); void close_temporary_table(THD *thd, TABLE *table, bool free_share, bool delete_table); void close_temporary(TABLE *table, bool free_share, bool delete_table); @@ -486,6 +486,8 @@ inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, } +bool restart_trans_for_tables(THD *thd, TABLE_LIST *table); + /** A context of open_tables() function, used to recover from a failed open_table() or open_routine() attempt. diff --git a/sql/sql_class.h b/sql/sql_class.h index 19c1ac8f4b6..14f58b30f3c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1513,8 +1513,9 @@ public: void unlock_locked_tables(THD *thd); ~Locked_tables_list() { - unlock_locked_tables(0); + reset(); } + void reset(); bool init_locked_tables(THD *thd); TABLE_LIST *locked_tables() { return m_locked_tables; } void unlink_from_list(THD *thd, TABLE_LIST *table_list, @@ -1523,6 +1524,9 @@ public: MYSQL_LOCK *lock, size_t reopen_count); bool reopen_tables(THD *thd); + bool restore_lock(THD *thd, TABLE_LIST *dst_table_list, TABLE *table, + MYSQL_LOCK *lock); + void add_back_last_deleted_lock(TABLE_LIST *dst_table_list); }; @@ -3995,6 +3999,8 @@ class select_create: public select_insert { MYSQL_LOCK *m_lock; /* m_lock or thd->extra_lock */ MYSQL_LOCK **m_plock; + bool exit_done; + public: select_create (TABLE_LIST *table_arg, HA_CREATE_INFO *create_info_par, @@ -4006,7 +4012,7 @@ public: create_info(create_info_par), select_tables(select_tables_arg), alter_info(alter_info_arg), - m_plock(NULL) + m_plock(NULL), exit_done(0) {} int prepare(List &list, SELECT_LEX_UNIT *u); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 8068901ebec..85e9b1aa852 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -798,14 +798,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0)) { for (table= tables; table; table= table->next_local) - { - if (check_if_log_table(table->db_length, table->db, - table->table_name_length, table->table_name, true)) - { - my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); + if (check_if_log_table(table, TRUE, "DROP")) goto exit; - } - } } /* Lock all tables and stored routines about to be dropped. */ diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8e3826eff48..719e0bae4ff 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3916,6 +3916,16 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, DEBUG_SYNC(thd,"create_table_select_before_create"); + /* Check if LOCK TABLES + CREATE OR REPLACE of existing normal table*/ + if (thd->locked_tables_mode && create_table->table && + !create_info->tmp_table()) + { + /* Remember information about the locked table */ + create_info->pos_in_locked_tables= + create_table->table->pos_in_locked_tables; + create_info->mdl_ticket= create_table->table->mdl_ticket; + } + /* Create and lock table. @@ -3932,52 +3942,63 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, TABLE, which is a wrong order. So we keep binary logging disabled when we open_table(). */ + + if (!mysql_create_table_no_lock(thd, create_table->db, + create_table->table_name, + create_info, alter_info, NULL, + select_field_count)) { - if (!mysql_create_table_no_lock(thd, create_table->db, - create_table->table_name, - create_info, alter_info, NULL, - select_field_count)) + DEBUG_SYNC(thd,"create_table_select_before_open"); + + /* + If we had a temporary table or a table used with LOCK TABLES, + it was closed by mysql_create() + */ + create_table->table= 0; + + if (!create_info->tmp_table()) { - DEBUG_SYNC(thd,"create_table_select_before_open"); + Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); + TABLE_LIST::enum_open_strategy save_open_strategy; - if (!create_info->tmp_table()) - { - Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); - /* - Here we open the destination table, on which we already have - an exclusive metadata lock. - */ - if (open_table(thd, create_table, thd->mem_root, &ot_ctx)) - { - quick_rm_table(thd, create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name), - 0); - } - else - table= create_table->table; - } - else + /* Force the newly created table to be opened */ + save_open_strategy= create_table->open_strategy; + create_table->open_strategy= TABLE_LIST::OPEN_NORMAL; + /* + Here we open the destination table, on which we already have + an exclusive metadata lock. + */ + if (open_table(thd, create_table, thd->mem_root, &ot_ctx)) { - if (open_temporary_table(thd, create_table)) - { - /* - This shouldn't happen as creation of temporary table should make - it preparable for open. Anyway we can't drop temporary table if - we are unable to find it. - */ - DBUG_ASSERT(0); - } - else - table= create_table->table; + quick_rm_table(thd, create_info->db_type, create_table->db, + table_case_name(create_info, create_table->table_name), + 0); } + /* Restore */ + create_table->open_strategy= save_open_strategy; } - if (!table) // open failed + else { - if (!thd->is_error()) // CREATE ... IF NOT EXISTS - my_ok(thd); // succeed, but did nothing - DBUG_RETURN(0); + if (open_temporary_table(thd, create_table)) + { + /* + This shouldn't happen as creation of temporary table should make + it preparable for open. Anyway we can't drop temporary table if + we are unable to find it. + */ + DBUG_ASSERT(0); + } } } + else + create_table->table= 0; // Create failed + + if (!(table= create_table->table)) + { + if (!thd->is_error()) // CREATE ... IF NOT EXISTS + my_ok(thd); // succeed, but did nothing + DBUG_RETURN(0); + } DEBUG_SYNC(thd,"create_table_select_before_lock"); @@ -3994,7 +4015,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, /* purecov: begin tested */ /* This can happen in innodb when you get a deadlock when using same table - in insert and select + in insert and select or when you run out of memory. */ my_error(ER_CANT_LOCK, MYF(0), my_errno); if (*lock) @@ -4092,8 +4113,6 @@ select_create::prepare(List &values, SELECT_LEX_UNIT *u) thd->binlog_start_trans_and_stmt(); } - DBUG_ASSERT(create_table->table == NULL); - DEBUG_SYNC(thd,"create_table_select_before_check_if_exists"); if (!(table= create_table_from_items(thd, create_info, create_table, @@ -4236,32 +4255,53 @@ void select_create::send_error(uint errcode,const char *err) bool select_create::send_eof() { - bool tmp=select_insert::send_eof(); - if (tmp) + if (select_insert::send_eof()) + { abort_result_set(); - else + return 1; + } + + exit_done= 1; // Avoid double calls + /* + Do an implicit commit at end of statement for non-temporary + tables. This can fail, but we should unlock the table + nevertheless. + */ + if (!table->s->tmp_table) { - /* - Do an implicit commit at end of statement for non-temporary - tables. This can fail, but we should unlock the table - nevertheless. - */ - if (!table->s->tmp_table) - { - trans_commit_stmt(thd); - trans_commit_implicit(thd); - } + trans_commit_stmt(thd); + trans_commit_implicit(thd); + } - table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); - table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); - if (m_plock) + table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); + + if (m_plock) + { + MYSQL_LOCK *lock= *m_plock; + *m_plock= NULL; + m_plock= NULL; + + if (create_info->pos_in_locked_tables) { - mysql_unlock_tables(thd, *m_plock); - *m_plock= NULL; - m_plock= NULL; + /* + If we are under lock tables, we have created a table that was + originally locked. We should add back the lock to ensure that + all tables in the thd->open_list are locked! + */ + table->mdl_ticket= create_info->mdl_ticket; + + /* The following should never fail, except if out of memory */ + if (!thd->locked_tables_list.restore_lock(thd, + create_info-> + pos_in_locked_tables, + table, lock)) + return 0; // ok + /* Fail. Continue without locking the table */ } + mysql_unlock_tables(thd, lock); } - return tmp; + return 0; } @@ -4269,6 +4309,11 @@ void select_create::abort_result_set() { DBUG_ENTER("select_create::abort_result_set"); + /* Avoid double calls, could happen in case of out of memory on cleanup */ + if (exit_done) + DBUG_VOID_RETURN; + exit_done= 1; + /* In select_insert::abort_result_set() we roll back the statement, including truncating the transaction cache of the binary log. To do this, we diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 06c78ba81a8..479fa81edd7 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2470,7 +2470,6 @@ struct LEX: public Query_tables_list uint8 context_analysis_only; bool drop_temporary, local_file, one_shot_set; bool check_exists; - bool replace; bool autocommit; bool verbose, no_write_to_binlog; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f8af7873a50..706e9e1a3a6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2832,12 +2832,8 @@ case SQLCOM_PREPARE: if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; -#ifndef QQ /* Might have been updated in create_table_precheck */ create_info.alias= create_table->alias; -#else - create_table->alias= (char*) create_info.alias; -#endif #ifdef HAVE_READLINK /* Fix names if symlinked tables */ @@ -2867,6 +2863,12 @@ case SQLCOM_PREPARE: create_info.table_charset= 0; } + /* + For CREATE TABLE we should not open the table even if it exists. + If the table exists, we should either not create it or replace it + */ + lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + #ifdef WITH_PARTITION_STORAGE_ENGINE { partition_info *part_info= thd->lex->part_info; @@ -2958,25 +2960,6 @@ case SQLCOM_PREPARE: } else { - /* The table already exists */ - if (create_table->table) - { - if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, - ER_TABLE_EXISTS_ERROR, - ER(ER_TABLE_EXISTS_ERROR), - create_info.alias); - my_ok(thd); - } - else - { - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias); - res= 1; - } - goto end_with_restore_list; - } - /* Remove target table from main select and name resolution context. This can't be done earlier as it will break view merging in @@ -2984,9 +2967,8 @@ case SQLCOM_PREPARE: */ lex->unlink_first_table(&link_to_local); - /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ - if (create_info.tmp_table()) - thd->variables.option_bits|= OPTION_KEEP_LOG; + /* Store reference to table in case of LOCK TABLES */ + create_info.table= create_table->table; /* select_create is currently not re-execution friendly and @@ -3004,18 +2986,18 @@ case SQLCOM_PREPARE: CREATE from SELECT give its SELECT_LEX for SELECT, and item_list belong to SELECT */ - res= handle_select(thd, lex, result, 0); + if (!(res= handle_select(thd, lex, result, 0))) + { + if (create_info.tmp_table()) + thd->variables.option_bits|= OPTION_KEEP_LOG; + } delete result; } - lex->link_first_table_back(create_table, link_to_local); } } else { - /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ - if (create_info.tmp_table()) - thd->variables.option_bits|= OPTION_KEEP_LOG; /* regular create */ if (create_info.options & HA_LEX_CREATE_TABLE_LIKE) { @@ -3030,7 +3012,12 @@ case SQLCOM_PREPARE: &create_info, &alter_info); } if (!res) + { + /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ + if (create_info.tmp_table()) + thd->variables.option_bits|= OPTION_KEEP_LOG; my_ok(thd); + } } end_with_restore_list: @@ -7960,8 +7947,9 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0)); /* CREATE OR REPLACE on not temporary tables require DROP_ACL */ - if (lex->replace && !lex->create_info.tmp_table()) - want_priv= DROP_ACL; + if ((lex->create_info.options & HA_LEX_CREATE_REPLACE) && + !lex->create_info.tmp_table()) + want_priv|= DROP_ACL; if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, @@ -8031,6 +8019,12 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, } error= FALSE; + /* + For CREATE TABLE we should not open the table even if it exists. + If the table exists, we should either not create it or replace it + */ + lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + err: DBUG_RETURN(error); } diff --git a/sql/sql_partition_admin.cc b/sql/sql_partition_admin.cc index 29ca86fa274..b2a8bca72db 100644 --- a/sql/sql_partition_admin.cc +++ b/sql/sql_partition_admin.cc @@ -506,13 +506,8 @@ bool Sql_cmd_alter_table_exchange_partition:: /* Don't allow to exchange with log table */ swap_table_list= table_list->next_local; - if (check_if_log_table(swap_table_list->db_length, swap_table_list->db, - swap_table_list->table_name_length, - swap_table_list->table_name, 0)) - { - my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table"); + if (check_if_log_table(swap_table_list, FALSE, "ALTER PARTITION")) DBUG_RETURN(TRUE); - } /* Currently no MDL lock that allows both read and write and is upgradeable diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 6babdd7c636..897aa183b60 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -84,12 +84,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) for (to_table= 0, ren_table= table_list; ren_table; to_table= 1 - to_table, ren_table= ren_table->next_local) { - int log_table_rename= 0; - - if ((log_table_rename= - check_if_log_table(ren_table->db_length, ren_table->db, - ren_table->table_name_length, - ren_table->table_name, 1))) + int log_table_rename; + if ((log_table_rename= check_if_log_table(ren_table, TRUE, NullS))) { /* as we use log_table_rename as an array index, we need it to start diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 45d9c5dc091..32e4fdc18a1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2031,33 +2031,29 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, bool error; Drop_table_error_handler err_handler; TABLE_LIST *table; - DBUG_ENTER("mysql_rm_table"); /* Disable drop of enabled log tables, must be done before name locking */ for (table= tables; table; table= table->next_local) { - if (check_if_log_table(table->db_length, table->db, - table->table_name_length, table->table_name, true)) - { - my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); + if (check_if_log_table(table, TRUE, "DROP")) DBUG_RETURN(true); - } } - if (!in_bootstrap) + if (!drop_temporary) { - for (table= tables; table; table= table->next_local) + if (!in_bootstrap) { - LEX_STRING db_name= { table->db, table->db_length }; - LEX_STRING table_name= { table->table_name, table->table_name_length }; - if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table)) - (void) delete_statistics_for_table(thd, &db_name, &table_name); + for (table= tables; table; table= table->next_local) + { + LEX_STRING db_name= { table->db, table->db_length }; + LEX_STRING table_name= { table->table_name, table->table_name_length }; + if (table->open_type == OT_BASE_ONLY || + !find_temporary_table(thd, table)) + (void) delete_statistics_for_table(thd, &db_name, &table_name); + } } - } - if (!drop_temporary) - { if (!thd->locked_tables_mode) { if (lock_table_names(thd, tables, NULL, @@ -2286,7 +2282,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, for (table= tables; table; table= table->next_local) { - bool is_trans; + bool is_trans= 0; char *db=table->db; size_t db_length= table->db_length; handlerton *table_type= 0; @@ -2311,12 +2307,16 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, . 1 - a temporary table was not found. . -1 - a temporary table is used by an outer statement. */ - if (table->open_type == OT_BASE_ONLY) + if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table)) error= 1; - else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1) + else { - DBUG_ASSERT(thd->in_sub_stmt); - goto err; + if ((error= drop_temporary_table(thd, table->table, &is_trans)) == -1) + { + DBUG_ASSERT(thd->in_sub_stmt); + goto err; + } + table->table= 0; } if ((drop_temporary && if_exists) || !error) @@ -4517,12 +4517,13 @@ err: way to ensure that concurrent operations won't intervene. mysql_create_table() is a wrapper that can be used for this. - @retval false OK - @retval true error + @retval 0 OK + @retval 1 error + @retval -1 table existed but IF EXISTS was used */ static -bool create_table_impl(THD *thd, +int create_table_impl(THD *thd, const char *db, const char *table_name, const char *path, HA_CREATE_INFO *create_info, @@ -4535,7 +4536,7 @@ bool create_table_impl(THD *thd, { const char *alias; handler *file= 0; - bool error= TRUE; + int error= 1; bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY; bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only; DBUG_ENTER("mysql_create_table_no_lock"); @@ -4565,22 +4566,66 @@ bool create_table_impl(THD *thd, /* Check if table exists */ if (create_info->tmp_table()) { - if (find_temporary_table(thd, db, table_name)) + TABLE *tmp_table; + if ((tmp_table= find_temporary_table(thd, db, table_name))) { - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + if (create_info->options & HA_LEX_CREATE_REPLACE) + { + bool is_trans; + /* + We are using CREATE OR REPLACE on an existing temporary table + Remove the old table so that we can re-create it. + */ + if (drop_temporary_table(thd, tmp_table, &is_trans)) + goto err; + } + else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) goto warn; - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); - goto err; + else + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); + goto err; + } } } - else + else { if (!internal_tmp_table && ha_table_exists(thd, db, table_name)) { - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + if (create_info->options & HA_LEX_CREATE_REPLACE) + { + TABLE_LIST table_list; + table_list.init_one_table(db, strlen(db), table_name, + strlen(table_name), table_name, + TL_WRITE_ALLOW_WRITE); + table_list.table= create_info->table; + + if (check_if_log_table(&table_list, TRUE, "CREATE OR REPLACE")) + goto err; + + /* + Rollback the empty transaction started in mysql_create_table() + call to open_and_lock_tables() when we are using LOCK TABLES. + */ + (void) trans_rollback_stmt(thd); + /* Remove normal table without logging */ + if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1)) + goto err; + /* + The test of query_tables is to ensure we have any tables in the + select part + */ + if (thd->lex->query_tables && + restart_trans_for_tables(thd, thd->lex->query_tables->next_global)) + goto err; + } + else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) goto warn; - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); - goto err; + else + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + goto err; + } } } @@ -4702,14 +4747,14 @@ bool create_table_impl(THD *thd, } #endif - error= FALSE; + error= 0; err: THD_STAGE_INFO(thd, stage_after_create); delete file; DBUG_RETURN(error); warn: - error= FALSE; + error= -1; push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), alias); @@ -4720,7 +4765,8 @@ warn: Simple wrapper around create_table_impl() to be used in various version of CREATE TABLE statement. */ -bool mysql_create_table_no_lock(THD *thd, + +int mysql_create_table_no_lock(THD *thd, const char *db, const char *table_name, HA_CREATE_INFO *create_info, Alter_info *alter_info, bool *is_trans, @@ -4728,6 +4774,7 @@ bool mysql_create_table_no_lock(THD *thd, { KEY *not_used_1; uint not_used_2; + int res; char path[FN_REFLEN + 1]; LEX_CUSTRING frm= {0,0}; @@ -4747,9 +4794,9 @@ bool mysql_create_table_no_lock(THD *thd, } } - bool res= create_table_impl(thd, db, table_name, path, create_info, - alter_info, create_table_mode, is_trans, - ¬_used_1, ¬_used_2, &frm); + res= create_table_impl(thd, db, table_name, path, create_info, + alter_info, create_table_mode, is_trans, + ¬_used_1, ¬_used_2, &frm); my_free(const_cast(frm.str)); return res; } @@ -4772,15 +4819,21 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, const char *table_name= create_table->table_name; bool is_trans= FALSE; int create_table_mode; + TABLE_LIST *pos_in_locked_tables= 0; DBUG_ENTER("mysql_create_table"); + DBUG_ASSERT(create_table == thd->lex->query_tables); + /* Open or obtain an exclusive metadata lock on table being created */ if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { /* is_error() may be 0 if table existed and we generated a warning */ DBUG_RETURN(thd->is_error()); } - + /* The following is needed only in case of lock tables */ + if ((create_info->table= thd->lex->query_tables->table)) + pos_in_locked_tables= create_info->table->pos_in_locked_tables; + /* Got lock. */ DEBUG_SYNC(thd, "locked_table_name"); @@ -4791,9 +4844,25 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, promote_first_timestamp_column(&alter_info->create_list); if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info, - &is_trans, create_table_mode)) + &is_trans, create_table_mode) > 0) DBUG_RETURN(1); + /* + Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES + on a non temporary table + */ + if (thd->locked_tables_mode && pos_in_locked_tables && + (create_info->options & HA_LEX_CREATE_REPLACE)) + { + /* + Add back the deleted table and re-created table as a locked table + This should always work as we have a meta lock on the table. + */ + thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); + if (thd->locked_tables_list.reopen_tables(thd)) + thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + } + /* In RBR we don't need to log CREATE TEMPORARY TABLE */ if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) DBUG_RETURN(0); @@ -4986,10 +5055,12 @@ mysql_rename_table(handlerton *base, const char *old_db, TRUE error */ -bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, +bool mysql_create_like_table(THD* thd, TABLE_LIST* table, + TABLE_LIST* src_table, HA_CREATE_INFO *create_info) { HA_CREATE_INFO local_create_info; + TABLE_LIST *pos_in_locked_tables= 0; Alter_info local_alter_info; Alter_table_ctx local_alter_ctx; // Not used bool res= TRUE; @@ -4997,7 +5068,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, uint not_used; DBUG_ENTER("mysql_create_like_table"); - /* We the open source table to get its description in HA_CREATE_INFO and Alter_info objects. This also acquires a shared metadata lock @@ -5041,7 +5111,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, if (src_table->schema_table) local_create_info.max_rows= 0; /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */ - local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS; + local_create_info.options|= (create_info->options & + (HA_LEX_CREATE_IF_NOT_EXISTS | + HA_LEX_CREATE_REPLACE)); /* Replace type of source table with one specified in the statement. */ local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE; local_create_info.options|= create_info->tmp_table(); @@ -5053,11 +5125,39 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, */ local_create_info.data_file_name= local_create_info.index_file_name= NULL; - if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name, - &local_create_info, &local_alter_info, - &is_trans, C_ORDINARY_CREATE))) + /* The following is needed only in case of lock tables */ + if ((local_create_info.table= thd->lex->query_tables->table)) + pos_in_locked_tables= local_create_info.table->pos_in_locked_tables; + + if ((res= (mysql_create_table_no_lock(thd, table->db, table->table_name, + &local_create_info, &local_alter_info, + &is_trans, C_ORDINARY_CREATE) > 0))) goto err; + /* + Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES + on a non temporary table + */ + if (thd->locked_tables_mode && pos_in_locked_tables && + (create_info->options & HA_LEX_CREATE_REPLACE)) + { + /* + Add back the deleted table and re-created table as a locked table + This should always work as we have a meta lock on the table. + */ + thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables); + if (thd->locked_tables_list.reopen_tables(thd)) + thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + else + { + /* + Get pointer to the newly opened table. We need this to ensure we + don't reopen the table when doing statment logging below. + */ + table->table= pos_in_locked_tables->table; + } + } + /* Ensure that we have an exclusive lock on target table if we are creating non-temporary table. @@ -5108,6 +5208,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, { if (!table->table) { + TABLE_LIST::enum_open_strategy save_open_strategy; + int open_res; + /* Force the newly created table to be opened */ + save_open_strategy= table->open_strategy; + table->open_strategy= TABLE_LIST::OPEN_NORMAL; /* In order for store_create_info() to work we need to open @@ -5117,11 +5222,20 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, lock on this table. The table will be closed by close_thread_table() at the end of this branch. */ - if (open_table(thd, table, thd->mem_root, &ot_ctx)) + open_res= open_table(thd, table, thd->mem_root, &ot_ctx); + /* Restore */ + table->open_strategy= save_open_strategy; + if (open_res) goto err; new_table= TRUE; } - + } + /* + We have to re-test if the table was a view as the view may not + have been opened until just above. + */ + if (!table->view) + { int result __attribute__((unused))= store_create_info(thd, table, &query, create_info, FALSE /* show_database */); @@ -7726,9 +7840,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, it is the case. TODO: this design is obsolete and will be removed. */ - int table_kind= check_if_log_table(table_list->db_length, table_list->db, - table_list->table_name_length, - table_list->table_name, false); + int table_kind= check_if_log_table(table_list, FALSE, NullS); if (table_kind) { diff --git a/sql/sql_table.h b/sql/sql_table.h index c42f8aaa39e..c6ba7a581ec 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -187,11 +187,11 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, #define C_ALTER_TABLE_FRM_ONLY -2 #define C_ASSISTED_DISCOVERY -3 -bool mysql_create_table_no_lock(THD *thd, const char *db, - const char *table_name, - HA_CREATE_INFO *create_info, - Alter_info *alter_info, bool *is_trans, - int create_table_mode); +int mysql_create_table_no_lock(THD *thd, const char *db, + const char *table_name, + HA_CREATE_INFO *create_info, + Alter_info *alter_info, bool *is_trans, + int create_table_mode); handler *mysql_create_frm_image(THD *thd, const char *db, const char *table_name, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7514b7bec63..f25d3be4d1f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1664,7 +1664,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type type type_with_opt_collate int_type real_type order_dir lock_option udf_type opt_if_exists opt_local opt_table_options table_options - table_option opt_if_not_exists opt_no_write_to_binlog + table_option opt_if_not_exists create_or_replace opt_no_write_to_binlog opt_temporary all_or_any opt_distinct opt_ignore_leaves fulltext_options spatial_type union_option field_def @@ -1843,7 +1843,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); statement sp_suid sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa opt_field_or_var_spec fields_or_vars opt_load_data_set_spec - view_replace_or_algorithm view_replace view_algorithm view_or_trigger_or_sp_or_event definer_tail no_definer_tail view_suid view_tail view_list_opt view_list view_select @@ -2341,25 +2340,29 @@ connection_name: /* create a table */ create: - CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident + create_or_replace opt_table_options TABLE_SYM opt_if_not_exists table_ident { LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_TABLE; + if ($1 && $4) + { + my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE", "IF NOT EXISTS"); + MYSQL_YYABORT; + } if (!lex->select_lex.add_table_to_list(thd, $5, NULL, TL_OPTION_UPDATING, TL_WRITE, MDL_EXCLUSIVE)) MYSQL_YYABORT; - /* - For CREATE TABLE, an non-existing table is not an error. - Instruct open_tables() to just take an MDL lock if the - table does not exist. - */ - lex->query_tables->open_strategy= TABLE_LIST::OPEN_IF_EXISTS; lex->alter_info.reset(); lex->col_list.empty(); lex->change=NullS; bzero((char*) &lex->create_info,sizeof(lex->create_info)); - lex->create_info.options=$2 | $4; + /* + For CREATE TABLE we should not open the table even if it exists. + If the table exists, we should either not create it or replace it + */ + lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + lex->create_info.options= ($1 | $2 | $4); lex->create_info.default_table_charset= NULL; lex->name.str= 0; lex->name.length= 0; @@ -2428,14 +2431,22 @@ create: lex->name= $4; lex->create_info.options=$3; } - | CREATE + | create_or_replace { - Lex->create_view_mode= VIEW_CREATE_NEW; + Lex->create_view_mode= ($1 == 0 ? VIEW_CREATE_NEW : + VIEW_CREATE_OR_REPLACE); Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; Lex->create_view_suid= TRUE; } view_or_trigger_or_sp_or_event - {} + { + if ($1 && Lex->sql_command != SQLCOM_CREATE_VIEW) + { + my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE", + "TRIGGERS / SP / EVENT"); + MYSQL_YYABORT; + } + } | CREATE USER clear_privileges grant_list { Lex->sql_command = SQLCOM_CREATE_USER; @@ -5515,6 +5526,17 @@ opt_if_not_exists: } ; +create_or_replace: + CREATE /* empty */ + { + $$= 0; + } + | CREATE OR_SYM REPLACE + { + $$= HA_LEX_CREATE_REPLACE; + } + ; + opt_create_table_options: /* empty */ | create_table_options @@ -15799,7 +15821,7 @@ view_or_trigger_or_sp_or_event: {} | no_definer no_definer_tail {} - | view_replace_or_algorithm definer_opt view_tail + | view_algorithm definer_opt view_tail {} ; @@ -15858,20 +15880,6 @@ definer: **************************************************************************/ -view_replace_or_algorithm: - view_replace - {} - | view_replace view_algorithm - {} - | view_algorithm - {} - ; - -view_replace: - OR_SYM REPLACE - { Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; } - ; - view_algorithm: ALGORITHM_SYM EQ UNDEFINED_SYM { Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; } diff --git a/sql/table.h b/sql/table.h index 0d0f8c49f21..565f4c5ddad 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1951,7 +1951,7 @@ struct TABLE_LIST Indicates that if TABLE_LIST object corresponds to the table/view which requires special handling. */ - enum + enum enum_open_strategy { /* Normal open. */ OPEN_NORMAL= 0, diff --git a/sql/table_cache.cc b/sql/table_cache.cc index 6f51ac8276c..6b24f4348ee 100644 --- a/sql/table_cache.cc +++ b/sql/table_cache.cc @@ -196,6 +196,7 @@ static void check_unused(THD *thd) TABLE *entry; TABLE_SHARE *share; TDC_iterator tdc_it; + DBUG_ENTER("check_unused"); tdc_it.init(); mysql_mutex_lock(&LOCK_open); @@ -221,6 +222,7 @@ static void check_unused(THD *thd) } mysql_mutex_unlock(&LOCK_open); tdc_it.deinit(); + DBUG_VOID_RETURN; } #else #define check_unused(A) -- cgit v1.2.1 From 2410ecac602254a1fa4eaaa3812d782eaf7f7e32 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 29 Jan 2014 15:41:10 +0200 Subject: Fixed compiler warnings Made stopping of slave more robust Fixed tokudb test cases that gave different results between runs Speed up some slow tokudb tests by adding begin ... commit mysql-test/extra/rpl_tests/rpl_stop_slave.test: Ensure that slaves are properly synced before they are stopped. (Otherwise some tests results will be different between runs) storage/innobase/buf/buf0buf.cc: Fixed compiler warning storage/tokudb/mysql-test/tokudb/r/cluster_filter_unpack_varchar_and_int_hidden.result: Test case could be solved with index or range scan. storage/tokudb/mysql-test/tokudb/t/cluster_filter_unpack_varchar_and_int_hidden.test: Test case could be solved with index or range scan. storage/tokudb/mysql-test/tokudb_bugs/r/5733_innodb.result: Speed up test by adding begin...commit storage/tokudb/mysql-test/tokudb_bugs/r/5733_tokudb.result: Speed up test by adding begin...commit storage/tokudb/mysql-test/tokudb_bugs/t/5733_innodb.test: Speed up test by adding begin...commit storage/tokudb/mysql-test/tokudb_bugs/t/5733_tokudb.test: Speed up test by adding begin...commit storage/tokudb/mysql-test/tokudb_mariadb/r/compression.result: Added drop table (safety) storage/tokudb/mysql-test/tokudb_mariadb/t/compression.test: Added drop table (safety) --- mysql-test/extra/rpl_tests/rpl_stop_slave.test | 3 +++ storage/innobase/buf/buf0buf.cc | 2 +- .../tokudb/r/cluster_filter_unpack_varchar_and_int_hidden.result | 4 ++-- .../tokudb/t/cluster_filter_unpack_varchar_and_int_hidden.test | 2 ++ storage/tokudb/mysql-test/tokudb_bugs/r/5733_innodb.result | 2 ++ storage/tokudb/mysql-test/tokudb_bugs/r/5733_tokudb.result | 4 +++- storage/tokudb/mysql-test/tokudb_bugs/t/5733_innodb.test | 2 ++ storage/tokudb/mysql-test/tokudb_bugs/t/5733_tokudb.test | 4 ++++ storage/tokudb/mysql-test/tokudb_mariadb/r/compression.result | 1 + storage/tokudb/mysql-test/tokudb_mariadb/t/compression.test | 7 +++++++ 10 files changed, 27 insertions(+), 4 deletions(-) diff --git a/mysql-test/extra/rpl_tests/rpl_stop_slave.test b/mysql-test/extra/rpl_tests/rpl_stop_slave.test index b226f4f22f1..0f09faa0301 100644 --- a/mysql-test/extra/rpl_tests/rpl_stop_slave.test +++ b/mysql-test/extra/rpl_tests/rpl_stop_slave.test @@ -59,3 +59,6 @@ source include/wait_for_slave_sql_to_stop.inc; connection slave; START SLAVE SQL_THREAD; source include/wait_for_slave_sql_to_start.inc; + +connection master; +sync_slave_with_master; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 913f0a40ef4..c9d93b635e2 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2436,7 +2436,7 @@ buf_page_get_gen( ibool must_read; rw_lock_t* hash_lock; ib_mutex_t* block_mutex; - buf_page_t* hash_bpage; + buf_page_t* hash_bpage __attribute__((unused)); ulint retries = 0; buf_pool_t* buf_pool = buf_pool_get(space, offset); diff --git a/storage/tokudb/mysql-test/tokudb/r/cluster_filter_unpack_varchar_and_int_hidden.result b/storage/tokudb/mysql-test/tokudb/r/cluster_filter_unpack_varchar_and_int_hidden.result index cf70de29376..f67c5bccd6b 100644 --- a/storage/tokudb/mysql-test/tokudb/r/cluster_filter_unpack_varchar_and_int_hidden.result +++ b/storage/tokudb/mysql-test/tokudb/r/cluster_filter_unpack_varchar_and_int_hidden.result @@ -182,14 +182,14 @@ a b c d e f 3 30 200 2000 20000 200000 explain select * from t1 where b > 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index b b NULL NULL NULL; Using where; Using index +1 SIMPLE t1 index_or_range b b NULL NULL NULL; Using where; Using index_or_range select * from t1 where b > 0; a b c d e f 2 20 100 1000 10000 100000 3 30 200 2000 20000 200000 explain select * from t1 where d > "0"; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index d d NULL NULL NULL; Using where; Using index +1 SIMPLE t1 index_or_range d d NULL NULL NULL; Using where; Using index_or_range select * from t1 where d > "0"; a b c d e f 2 20 100 1000 10000 100000 diff --git a/storage/tokudb/mysql-test/tokudb/t/cluster_filter_unpack_varchar_and_int_hidden.test b/storage/tokudb/mysql-test/tokudb/t/cluster_filter_unpack_varchar_and_int_hidden.test index c90994f325a..f5b600e501a 100644 --- a/storage/tokudb/mysql-test/tokudb/t/cluster_filter_unpack_varchar_and_int_hidden.test +++ b/storage/tokudb/mysql-test/tokudb/t/cluster_filter_unpack_varchar_and_int_hidden.test @@ -83,10 +83,12 @@ explain select * from t1; select * from t1; --replace_column 7 NULL 9 NULL; +--replace_result index index_or_range range index_or_range explain select * from t1 where b > 0; select * from t1 where b > 0; --replace_column 7 NULL 9 NULL; +--replace_result index index_or_range range index_or_range explain select * from t1 where d > "0"; select * from t1 where d > "0"; diff --git a/storage/tokudb/mysql-test/tokudb_bugs/r/5733_innodb.result b/storage/tokudb/mysql-test/tokudb_bugs/r/5733_innodb.result index 10cdb4767f6..c850de928b9 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/r/5733_innodb.result +++ b/storage/tokudb/mysql-test/tokudb_bugs/r/5733_innodb.result @@ -1,6 +1,7 @@ drop table if exists t; set default_storage_engine='innodb'; create table t (id bigint primary key, x bigint not null); +begin; insert into t values (0,0); insert into t values (1,0); insert into t values (2,0); @@ -10001,6 +10002,7 @@ insert into t values (9996,0); insert into t values (9997,0); insert into t values (9998,0); insert into t values (9999,0); +commit; explain select id from t where id>0 limit 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t range PRIMARY PRIMARY 8 NULL # Using where; Using index diff --git a/storage/tokudb/mysql-test/tokudb_bugs/r/5733_tokudb.result b/storage/tokudb/mysql-test/tokudb_bugs/r/5733_tokudb.result index b642c8d6963..07e8b37c263 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/r/5733_tokudb.result +++ b/storage/tokudb/mysql-test/tokudb_bugs/r/5733_tokudb.result @@ -1,6 +1,7 @@ drop table if exists t; set default_storage_engine='tokudb'; create table t (id bigint primary key, x bigint not null); +begin; insert into t values (0,0); insert into t values (1,0); insert into t values (2,0); @@ -10001,9 +10002,10 @@ insert into t values (9996,0); insert into t values (9997,0); insert into t values (9998,0); insert into t values (9999,0); +commit; explain select id from t where id>0 limit 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t range PRIMARY PRIMARY 8 NULL # Using where; Using index +1 SIMPLE t index_or_range PRIMARY PRIMARY 8 NULL # Using where; Using index_or_range explain select * from t where id>0 limit 10; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t range PRIMARY PRIMARY 8 NULL # Using where diff --git a/storage/tokudb/mysql-test/tokudb_bugs/t/5733_innodb.test b/storage/tokudb/mysql-test/tokudb_bugs/t/5733_innodb.test index dec1f39eb97..d629c2cfe1c 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/t/5733_innodb.test +++ b/storage/tokudb/mysql-test/tokudb_bugs/t/5733_innodb.test @@ -11,12 +11,14 @@ set default_storage_engine='innodb'; create table t (id bigint primary key, x bigint not null); +begin; let $i=0; let $n=10000; while ($i < $n) { eval insert into t values ($i,0); inc $i; } +commit; replace_column 9 #; explain select id from t where id>0 limit 10; diff --git a/storage/tokudb/mysql-test/tokudb_bugs/t/5733_tokudb.test b/storage/tokudb/mysql-test/tokudb_bugs/t/5733_tokudb.test index e0e0fc886fd..2e30c839905 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/t/5733_tokudb.test +++ b/storage/tokudb/mysql-test/tokudb_bugs/t/5733_tokudb.test @@ -11,14 +11,18 @@ set default_storage_engine='tokudb'; create table t (id bigint primary key, x bigint not null); +begin; let $i=0; let $n=10000; while ($i < $n) { eval insert into t values ($i,0); inc $i; } +commit; +# TokuDB may do index or range scan on this. Both are ok replace_column 9 #; +--replace_result index index_or_range range index_or_range explain select id from t where id>0 limit 10; replace_column 9 #; diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/r/compression.result b/storage/tokudb/mysql-test/tokudb_mariadb/r/compression.result index f465fe5df65..ea8a0b521b9 100644 --- a/storage/tokudb/mysql-test/tokudb_mariadb/r/compression.result +++ b/storage/tokudb/mysql-test/tokudb_mariadb/r/compression.result @@ -1,3 +1,4 @@ +drop table if exists t1,t2,t3,t4,t5,t6; create table t1 (a text) engine=tokudb compression=tokudb_uncompressed; create table t2 (a text) engine=tokudb compression=tokudb_zlib; create table t3 (a text) engine=tokudb compression=tokudb_quicklz; diff --git a/storage/tokudb/mysql-test/tokudb_mariadb/t/compression.test b/storage/tokudb/mysql-test/tokudb_mariadb/t/compression.test index 1bac772437d..00478aed1c7 100644 --- a/storage/tokudb/mysql-test/tokudb_mariadb/t/compression.test +++ b/storage/tokudb/mysql-test/tokudb_mariadb/t/compression.test @@ -1,3 +1,10 @@ +# +# Initial cleanup from previous tests +# +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6; +--enable_warnings + create table t1 (a text) engine=tokudb compression=tokudb_uncompressed; create table t2 (a text) engine=tokudb compression=tokudb_zlib; create table t3 (a text) engine=tokudb compression=tokudb_quicklz; -- cgit v1.2.1 From 43f6e118fef843dd02821da3a24089b679fd30a3 Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Fri, 31 Jan 2014 12:06:28 +0200 Subject: Fixes for CREATE_OR_REPLACE - MDEV-5587 Server crashes in Locked_tables_list::restore_lock on CREATE OR REPLACE .. SELECT under LOCK - MDEV-5586 Assertion `share->tdc.all_tables.is_empty() || remove_type != TDC_RT_REMOVE_ALL' fails in tdc_remove_table - MDEV-5588 Strange error on CREATE OR REPLACE table over an existing view mysql-test/r/create_or_replace.result: Added test cases mysql-test/r/lowercase_view.result: New error message mysql-test/r/merge.result: New error message mysql-test/r/multi_update.result: New error message mysql-test/r/subselect.result: New error message mysql-test/r/subselect_exists_to_in.result: New error message mysql-test/r/subselect_no_mat.result: New error message mysql-test/r/subselect_no_opts.result: New error message mysql-test/r/subselect_no_scache.result: New error message mysql-test/r/subselect_no_semijoin.result: New error message mysql-test/r/view.result: New error message mysql-test/suite/funcs_1/r/myisam_views-big.result: New error message mysql-test/t/create_or_replace.test: New tests mysql-test/t/view.test: New error message sql/share/errmsg-utf8.txt: Added new error message sql/sql_base.cc: Updated error message Do an automatic UNLOCK TABLES if we don't have any locked tables (safety fix) sql/sql_db.cc: Updated arguments sql/sql_load.cc: New error message sql/sql_parse.cc: Check that we are not using a table we are dropping and re-creating sql/sql_table.cc: Added parameter to mysql_rm_table_no_locks() to not automaticly do UNLOCK TABLES Added better error message if trying to drop a view with DROP TABLE Don't try to create something we select from sql/sql_table.h: Updated prototypes --- mysql-test/r/create_or_replace.result | 48 ++++++++++++--- mysql-test/r/lowercase_view.result | 30 ++++----- mysql-test/r/merge.result | 72 +++++++++++----------- mysql-test/r/multi_update.result | 6 +- mysql-test/r/subselect.result | 14 ++--- mysql-test/r/subselect_exists_to_in.result | 14 ++--- mysql-test/r/subselect_no_mat.result | 14 ++--- mysql-test/r/subselect_no_opts.result | 14 ++--- mysql-test/r/subselect_no_scache.result | 14 ++--- mysql-test/r/subselect_no_semijoin.result | 14 ++--- mysql-test/r/view.result | 32 +++++----- mysql-test/suite/funcs_1/r/myisam_views-big.result | 2 +- mysql-test/t/create_or_replace.test | 47 ++++++++++++-- mysql-test/t/view.test | 2 +- sql/share/errmsg-utf8.txt | 12 ++-- sql/sql_base.cc | 6 +- sql/sql_db.cc | 2 +- sql/sql_load.cc | 3 +- sql/sql_parse.cc | 18 +++++- sql/sql_table.cc | 40 +++++++++--- sql/sql_table.h | 2 +- 21 files changed, 261 insertions(+), 145 deletions(-) diff --git a/mysql-test/r/create_or_replace.result b/mysql-test/r/create_or_replace.result index 42a3d1fe17c..e1586ff211c 100644 --- a/mysql-test/r/create_or_replace.result +++ b/mysql-test/r/create_or_replace.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2; +drop table if exists t1,t2,t3; CREATE TABLE t2 (a int); INSERT INTO t2 VALUES(1),(2),(3); # @@ -97,13 +97,23 @@ CREATE TEMPORARY TABLE t1 AS SELECT a FROM t2; CREATE TEMPORARY TABLE IF NOT EXISTS t1(a int, b int) SELECT 1,2 FROM t2; Warnings: Note 1050 Table 't1' already exists -create or replace table t1 as select 1; -show create table t1; +DROP TABLE t1; +CREATE TABLE t1 (a int); +CREATE OR REPLACE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; Table Create Table -t1 CREATE TEMPORARY TABLE `t1` ( - `a` int(11) DEFAULT NULL +t1 CREATE TABLE `t1` ( + `1` int(1) NOT NULL DEFAULT '0' ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; +create table t1 (a int); +create or replace table t1 as select * from t1; +ERROR HY000: Table 't1' is specified twice, both as a target for 'CREATE' and as a separate source for data +create or replace table t1 as select a from (select a from t1) as t3; +ERROR HY000: Table 't1' is specified twice, both as a target for 'CREATE' and as a separate source for data +create or replace table t1 as select a from t2 where t2.a in (select a from t1); +ERROR HY000: Table 't1' is specified twice, both as a target for 'CREATE' and as a separate source for data +drop table t1; # # Testing with normal tables # @@ -191,6 +201,15 @@ SELECT * FROM t1 as t1_read; ERROR HY000: Table 't1_read' was not locked with LOCK TABLES DROP TABLE t1; UNLOCK TABLES; +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLE t1 WRITE; +CREATE OR REPLACE TABLE t1 AS SELECT 1; +SELECT * from t1; +1 +1 +SELECT * from t2; +ERROR HY000: Table 't2' was not locked with LOCK TABLES +DROP TABLE t1; # # Test also with InnoDB (transactional engine) # @@ -253,6 +272,21 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create or replace table t1 like t2; +create or replace table t1 like t1; +ERROR 42000: Not unique table/alias: 't1' +drop table t1; +CREATE TEMPORARY TABLE t1 like t2; +CREATE OR REPLACE TABLE t1 like t1; +ERROR 42000: Not unique table/alias: 't1' +CREATE OR REPLACE TABLE t1 like t1; +ERROR 42000: Not unique table/alias: 't1' +drop table t1; +CREATE TEMPORARY TABLE t1 like t2; +CREATE OR REPLACE TEMPORARY TABLE t3 like t1; +CREATE OR REPLACE TEMPORARY TABLE t3 like t3; +ERROR 42000: Not unique table/alias: 't3' +drop table t1,t3; # # Test with prepared statements # @@ -286,8 +320,8 @@ create table if not exists t1 (a int); Warnings: Note 1050 Table 't1' already exists create or replace table t1 (a int); -ERROR 42S02: Unknown table 'test.t1' +ERROR 42S02: 'test.t1' is a view drop table t1; -ERROR 42S02: Unknown table 'test.t1' +ERROR 42S02: 'test.t1' is a view drop view t1; DROP TABLE t2; diff --git a/mysql-test/r/lowercase_view.result b/mysql-test/r/lowercase_view.result index 33c87ec101c..f43c39c4fc1 100644 --- a/mysql-test/r/lowercase_view.result +++ b/mysql-test/r/lowercase_view.result @@ -20,13 +20,13 @@ ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table ' update v2Aa set col1 = (select max(col1) from t1Aa); ERROR HY000: The definition of table 'v2Aa' prevents operation UPDATE on table 'v2Aa'. update v2aA set col1 = (select max(col1) from v2Aa); -ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +ERROR HY000: Table 'v2aA' is specified twice, both as a target for 'UPDATE' and as a separate source for data update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v2aA'. update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v1Aa) where t1aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1Aa' prevents operation UPDATE on table 't1aA'. update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v1aA) where v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1aA' for update in FROM clause +ERROR HY000: Table 'v1aA' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from v1aA) where v2Aa.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 't2Aa'. update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from v1Aa) where t1Aa.col1 = t2aA.col1; @@ -36,17 +36,17 @@ ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table ' update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from t1aA) where v2aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 'v2aA'. update t1Aa,t2Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1Aa' for update in FROM clause +ERROR HY000: Table 't1Aa' is specified twice, both as a target for 'UPDATE' and as a separate source for data update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from t1Aa) where v1aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1aA' prevents operation UPDATE on table 'v1aA'. update t2Aa,v2Aa set v2aA.col1 = (select max(col1) from t1aA) where v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause +ERROR HY000: Table 't2Aa' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t2Aa,t1Aa set t1aA.col1 = (select max(col1) from t1Aa) where t1aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause +ERROR HY000: Table 't2Aa' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t2Aa,v1Aa set v1aA.col1 = (select max(col1) from t1Aa) where v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't2Aa' for update in FROM clause +ERROR HY000: Table 't2Aa' is specified twice, both as a target for 'UPDATE' and as a separate source for data update v2aA,t2Aa set v2Aa.col1 = (select max(col1) from v2aA) where v2Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +ERROR HY000: Table 'v2aA' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1aA,t2Aa set t1Aa.col1 = (select max(col1) from v2aA) where t1aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 't1aA'. update v1aA,t2Aa set v1Aa.col1 = (select max(col1) from v2Aa) where v1aA.col1 = t2aA.col1; @@ -64,27 +64,27 @@ ERROR HY000: The definition of table 'v3aA' prevents operation UPDATE on table ' update v3aA set v3Aa.col1 = (select max(col1) from v2aA); ERROR HY000: The definition of table 'v2aA' prevents operation UPDATE on table 'v3aA'. update v3aA set v3Aa.col1 = (select max(col1) from v3aA); -ERROR HY000: You can't specify target table 'v3aA' for update in FROM clause +ERROR HY000: Table 'v3aA' is specified twice, both as a target for 'UPDATE' and as a separate source for data delete from v2Aa where col1 = (select max(col1) from v1Aa); ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 'v2Aa'. delete from v2aA where col1 = (select max(col1) from t1Aa); ERROR HY000: The definition of table 'v2aA' prevents operation DELETE on table 'v2aA'. delete from v2Aa where col1 = (select max(col1) from v2aA); -ERROR HY000: You can't specify target table 'v2Aa' for update in FROM clause +ERROR HY000: Table 'v2Aa' is specified twice, both as a target for 'DELETE' and as a separate source for data delete v2Aa from v2aA,t2Aa where (select max(col1) from v1aA) > 0 and v2Aa.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1aA' prevents operation DELETE on table 'v2aA'. delete t1aA from t1Aa,t2Aa where (select max(col1) from v1Aa) > 0 and t1aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 't1Aa'. delete v1aA from v1Aa,t2Aa where (select max(col1) from v1aA) > 0 and v1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v1Aa' for update in FROM clause +ERROR HY000: Table 'v1Aa' is specified twice, both as a target for 'DELETE' and as a separate source for data delete v2aA from v2Aa,t2Aa where (select max(col1) from t1Aa) > 0 and v2aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v2Aa' prevents operation DELETE on table 'v2Aa'. delete t1aA from t1Aa,t2Aa where (select max(col1) from t1aA) > 0 and t1Aa.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 't1Aa' for update in FROM clause +ERROR HY000: Table 't1Aa' is specified twice, both as a target for 'DELETE' and as a separate source for data delete v1aA from v1Aa,t2Aa where (select max(col1) from t1aA) > 0 and v1aA.col1 = t2aA.col1; ERROR HY000: The definition of table 'v1Aa' prevents operation DELETE on table 'v1Aa'. delete v2Aa from v2aA,t2Aa where (select max(col1) from v2Aa) > 0 and v2aA.col1 = t2aA.col1; -ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +ERROR HY000: Table 'v2aA' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t1Aa from t1aA,t2Aa where (select max(col1) from v2Aa) > 0 and t1Aa.col1 = t2aA.col1; ERROR HY000: The definition of table 'v2Aa' prevents operation DELETE on table 't1aA'. delete v1Aa from v1aA,t2Aa where (select max(col1) from v2aA) > 0 and v1Aa.col1 = t2aA.col1; @@ -98,15 +98,15 @@ ERROR HY000: The definition of table 'v1aA' prevents operation INSERT on table ' insert into v2Aa values ((select max(col1) from t1Aa)); ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 'v2Aa'. insert into t1aA values ((select max(col1) from t1Aa)); -ERROR HY000: You can't specify target table 't1aA' for update in FROM clause +ERROR HY000: Table 't1aA' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into v2aA values ((select max(col1) from t1aA)); ERROR HY000: The definition of table 'v2aA' prevents operation INSERT on table 'v2aA'. insert into v2Aa values ((select max(col1) from v2aA)); -ERROR HY000: You can't specify target table 'v2Aa' for update in FROM clause +ERROR HY000: Table 'v2Aa' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into t1Aa values ((select max(col1) from v2Aa)); ERROR HY000: The definition of table 'v2Aa' prevents operation INSERT on table 't1Aa'. insert into v2aA values ((select max(col1) from v2Aa)); -ERROR HY000: You can't specify target table 'v2aA' for update in FROM clause +ERROR HY000: Table 'v2aA' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into v3Aa (col1) values ((select max(col1) from v1Aa)); ERROR HY000: The definition of table 'v1Aa' prevents operation INSERT on table 'v3Aa'. insert into v3aA (col1) values ((select max(col1) from t1aA)); diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 0feb1cdce98..89aaf48219e 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -3657,85 +3657,85 @@ insert into tmp (b) values (1); insert into t1 (a) values (1); insert into t3 (b) values (1); insert into m1 (a) values ((select max(a) from m1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from m2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from t1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from t2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from t3, m1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from t3, m2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from t3, t1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from t3, t2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from tmp, m1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from tmp, m2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from tmp, t1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from tmp, t2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into m1 (a) values ((select max(a) from v1)); ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'm1'. insert into m1 (a) values ((select max(a) from tmp, v1)); ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'm1'. update m1 set a = ((select max(a) from m1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from m2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from t1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from t2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from t3, m1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from t3, m2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from t3, t1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from t3, t2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from tmp, m1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from tmp, m2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from tmp, t1)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from tmp, t2)); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update m1 set a = ((select max(a) from v1)); ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'm1'. update m1 set a = ((select max(a) from tmp, v1)); ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'm1'. delete from m1 where a = (select max(a) from m1); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from m2); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from t1); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from t2); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from t3, m1); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from t3, m2); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from t3, t1); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from t3, t2); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from tmp, m1); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from tmp, m2); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from tmp, t1); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from tmp, t2); -ERROR HY000: You can't specify target table 'm1' for update in FROM clause +ERROR HY000: Table 'm1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from m1 where a = (select max(a) from v1); ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'm1'. delete from m1 where a = (select max(a) from tmp, v1); diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index f49998da5f4..ff0aa828636 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -439,9 +439,9 @@ drop table t1, t2, t3; create table t1 (col1 int); create table t2 (col1 int); update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data drop table t1,t2; create table t1 ( aclid bigint not null primary key, @@ -457,7 +457,7 @@ drop table t1, t2; create table t1(a int); create table t2(a int); delete from t1,t2 using t1,t2 where t1.a=(select a from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data drop table t1, t2; create table t1 ( c char(8) not null ) engine=innodb; insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index fc98607e38a..effa77a5eb4 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -579,7 +579,7 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1 set b= (select b from t2); ERROR 21000: Subquery returns more than 1 row update t1 set b= (select b from t2 where t1.a = t2.a); @@ -602,7 +602,7 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b in (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from t1 where b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete from t1 where b = (select b from t2 where t1.a = t2.a); @@ -628,7 +628,7 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -ERROR HY000: You can't specify target table 't12' for update in FROM clause +ERROR HY000: Table 't12' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); @@ -647,7 +647,7 @@ create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); ERROR 21000: Subquery returns more than 1 row INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); @@ -697,7 +697,7 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); ERROR 21000: Subquery returns more than 1 row replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); @@ -765,9 +765,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t2 VALUES ((SELECT id FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data SELECT * FROM t2; id 1 diff --git a/mysql-test/r/subselect_exists_to_in.result b/mysql-test/r/subselect_exists_to_in.result index a70e6df3d00..bc9db36c8ce 100644 --- a/mysql-test/r/subselect_exists_to_in.result +++ b/mysql-test/r/subselect_exists_to_in.result @@ -583,7 +583,7 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1 set b= (select b from t2); ERROR 21000: Subquery returns more than 1 row update t1 set b= (select b from t2 where t1.a = t2.a); @@ -606,7 +606,7 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b in (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from t1 where b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete from t1 where b = (select b from t2 where t1.a = t2.a); @@ -632,7 +632,7 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -ERROR HY000: You can't specify target table 't12' for update in FROM clause +ERROR HY000: Table 't12' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); @@ -651,7 +651,7 @@ create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); ERROR 21000: Subquery returns more than 1 row INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); @@ -701,7 +701,7 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); ERROR 21000: Subquery returns more than 1 row replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); @@ -769,9 +769,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t2 VALUES ((SELECT id FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data SELECT * FROM t2; id 1 diff --git a/mysql-test/r/subselect_no_mat.result b/mysql-test/r/subselect_no_mat.result index 16f67820e0e..975d90b8358 100644 --- a/mysql-test/r/subselect_no_mat.result +++ b/mysql-test/r/subselect_no_mat.result @@ -586,7 +586,7 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1 set b= (select b from t2); ERROR 21000: Subquery returns more than 1 row update t1 set b= (select b from t2 where t1.a = t2.a); @@ -609,7 +609,7 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b in (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from t1 where b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete from t1 where b = (select b from t2 where t1.a = t2.a); @@ -635,7 +635,7 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -ERROR HY000: You can't specify target table 't12' for update in FROM clause +ERROR HY000: Table 't12' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); @@ -654,7 +654,7 @@ create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); ERROR 21000: Subquery returns more than 1 row INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); @@ -704,7 +704,7 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); ERROR 21000: Subquery returns more than 1 row replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); @@ -772,9 +772,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t2 VALUES ((SELECT id FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data SELECT * FROM t2; id 1 diff --git a/mysql-test/r/subselect_no_opts.result b/mysql-test/r/subselect_no_opts.result index bc2cc71b0fa..f9ea3c45ee3 100644 --- a/mysql-test/r/subselect_no_opts.result +++ b/mysql-test/r/subselect_no_opts.result @@ -582,7 +582,7 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1 set b= (select b from t2); ERROR 21000: Subquery returns more than 1 row update t1 set b= (select b from t2 where t1.a = t2.a); @@ -605,7 +605,7 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b in (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from t1 where b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete from t1 where b = (select b from t2 where t1.a = t2.a); @@ -631,7 +631,7 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -ERROR HY000: You can't specify target table 't12' for update in FROM clause +ERROR HY000: Table 't12' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); @@ -650,7 +650,7 @@ create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); ERROR 21000: Subquery returns more than 1 row INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); @@ -700,7 +700,7 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); ERROR 21000: Subquery returns more than 1 row replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); @@ -768,9 +768,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t2 VALUES ((SELECT id FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data SELECT * FROM t2; id 1 diff --git a/mysql-test/r/subselect_no_scache.result b/mysql-test/r/subselect_no_scache.result index 40a63afb1c6..2bc182ac6e9 100644 --- a/mysql-test/r/subselect_no_scache.result +++ b/mysql-test/r/subselect_no_scache.result @@ -585,7 +585,7 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1 set b= (select b from t2); ERROR 21000: Subquery returns more than 1 row update t1 set b= (select b from t2 where t1.a = t2.a); @@ -608,7 +608,7 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b in (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from t1 where b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete from t1 where b = (select b from t2 where t1.a = t2.a); @@ -634,7 +634,7 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -ERROR HY000: You can't specify target table 't12' for update in FROM clause +ERROR HY000: Table 't12' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); @@ -653,7 +653,7 @@ create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); ERROR 21000: Subquery returns more than 1 row INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); @@ -703,7 +703,7 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); ERROR 21000: Subquery returns more than 1 row replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); @@ -771,9 +771,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t2 VALUES ((SELECT id FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data SELECT * FROM t2; id 1 diff --git a/mysql-test/r/subselect_no_semijoin.result b/mysql-test/r/subselect_no_semijoin.result index 1fc2d98c0e8..a41c7636038 100644 --- a/mysql-test/r/subselect_no_semijoin.result +++ b/mysql-test/r/subselect_no_semijoin.result @@ -582,7 +582,7 @@ a b 1 11 2 12 update t1 set b= (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1 set b= (select b from t2); ERROR 21000: Subquery returns more than 1 row update t1 set b= (select b from t2 where t1.a = t2.a); @@ -605,7 +605,7 @@ select * from t1 where b = (select b from t2 where t1.a = t2.a); a b 2 12 delete from t1 where b in (select b from t1); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete from t1 where b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete from t1 where b = (select b from t2 where t1.a = t2.a); @@ -631,7 +631,7 @@ a b 22 11 2 12 delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t12 where t11.a = t12.a); -ERROR HY000: You can't specify target table 't12' for update in FROM clause +ERROR HY000: Table 't12' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2); ERROR 21000: Subquery returns more than 1 row delete t11.*, t12.* from t11,t12 where t11.a = t12.a and t11.b = (select b from t2 where t11.a = t2.a); @@ -650,7 +650,7 @@ create table t3 (b int); insert into t2 values (1); insert into t3 values (1),(2); INSERT INTO t1 (x) VALUES ((SELECT x FROM t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t1 (x) VALUES ((SELECT b FROM t3)); ERROR 21000: Subquery returns more than 1 row INSERT INTO t1 (x) VALUES ((SELECT a FROM t2)); @@ -700,7 +700,7 @@ insert into t3 values (1),(2); select * from t1; x y replace into t1 (x, y) VALUES ((SELECT x FROM t1), (SELECT a+1 FROM t2)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data replace into t1 (x, y) VALUES ((SELECT a FROM t3), (SELECT a+1 FROM t2)); ERROR 21000: Subquery returns more than 1 row replace into t1 (x, y) VALUES ((SELECT a FROM t2), (SELECT a+1 FROM t2)); @@ -768,9 +768,9 @@ SELECT * FROM t2 WHERE id IN (SELECT 5 UNION SELECT 2); id 2 INSERT INTO t2 VALUES ((SELECT * FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data INSERT INTO t2 VALUES ((SELECT id FROM t2)); -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'INSERT' and as a separate source for data SELECT * FROM t2; id 1 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index a926f975009..046c0056de3 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -205,7 +205,7 @@ ERROR 42S02: Unknown table 'v100' drop view t1; ERROR HY000: 'test.t1' is not VIEW drop table v1; -ERROR 42S02: Unknown table 'test.v1' +ERROR 42S02: 'test.v1' is a view drop view v1,v2; drop table t1; create table t1 (a int); @@ -931,13 +931,13 @@ ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v2 update v2 set col1 = (select max(col1) from t1); ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v2'. update v2 set col1 = (select max(col1) from v2); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: Table 'v2' is specified twice, both as a target for 'UPDATE' and as a separate source for data update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v2'. update t1,t2 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't1'. update v1,t2 set v1.col1 = (select max(col1) from v1) where v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v1' for update in FROM clause +ERROR HY000: Table 'v1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t2,v2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't2'. update t2,t1 set t1.col1 = (select max(col1) from v1) where t1.col1 = t2.col1; @@ -947,17 +947,17 @@ ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 't2 update v2,t2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1; ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v2'. update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'UPDATE' and as a separate source for data update v1,t2 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'v1'. update t2,v2 set v2.col1 = (select max(col1) from t1) where v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t2,t1 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t2,v1 set v1.col1 = (select max(col1) from t1) where v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't2' for update in FROM clause +ERROR HY000: Table 't2' is specified twice, both as a target for 'UPDATE' and as a separate source for data update v2,t2 set v2.col1 = (select max(col1) from v2) where v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: Table 'v2' is specified twice, both as a target for 'UPDATE' and as a separate source for data update t1,t2 set t1.col1 = (select max(col1) from v2) where t1.col1 = t2.col1; ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 't1'. update v1,t2 set v1.col1 = (select max(col1) from v2) where v1.col1 = t2.col1; @@ -975,27 +975,27 @@ ERROR HY000: The definition of table 'v3' prevents operation UPDATE on table 'v3 update v3 set v3.col1 = (select max(col1) from v2); ERROR HY000: The definition of table 'v2' prevents operation UPDATE on table 'v3'. update v3 set v3.col1 = (select max(col1) from v3); -ERROR HY000: You can't specify target table 'v3' for update in FROM clause +ERROR HY000: Table 'v3' is specified twice, both as a target for 'UPDATE' and as a separate source for data delete from v2 where col1 = (select max(col1) from v1); ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'v2'. delete from v2 where col1 = (select max(col1) from t1); ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 'v2'. delete from v2 where col1 = (select max(col1) from v2); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: Table 'v2' is specified twice, both as a target for 'DELETE' and as a separate source for data delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'v2'. delete t1 from t1,t2 where (select max(col1) from v1) > 0 and t1.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 't1'. delete v1 from v1,t2 where (select max(col1) from v1) > 0 and v1.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v1' for update in FROM clause +ERROR HY000: Table 'v1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete v2 from v2,t2 where (select max(col1) from t1) > 0 and v2.col1 = t2.col1; ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 'v2'. delete t1 from t1,t2 where (select max(col1) from t1) > 0 and t1.col1 = t2.col1; -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data delete v1 from v1,t2 where (select max(col1) from t1) > 0 and v1.col1 = t2.col1; ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'v1'. delete v2 from v2,t2 where (select max(col1) from v2) > 0 and v2.col1 = t2.col1; -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: Table 'v2' is specified twice, both as a target for 'DELETE' and as a separate source for data delete t1 from t1,t2 where (select max(col1) from v2) > 0 and t1.col1 = t2.col1; ERROR HY000: The definition of table 'v2' prevents operation DELETE on table 't1'. delete v1 from v1,t2 where (select max(col1) from v2) > 0 and v1.col1 = t2.col1; @@ -1009,15 +1009,15 @@ ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v2 insert into v2 values ((select max(col1) from t1)); ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v2'. insert into t1 values ((select max(col1) from t1)); -ERROR HY000: You can't specify target table 't1' for update in FROM clause +ERROR HY000: Table 't1' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into v2 values ((select max(col1) from t1)); ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v2'. insert into v2 values ((select max(col1) from v2)); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: Table 'v2' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into t1 values ((select max(col1) from v2)); ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 't1'. insert into v2 values ((select max(col1) from v2)); -ERROR HY000: You can't specify target table 'v2' for update in FROM clause +ERROR HY000: Table 'v2' is specified twice, both as a target for 'INSERT' and as a separate source for data insert into v3 (col1) values ((select max(col1) from v1)); ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'v3'. insert into v3 (col1) values ((select max(col1) from t1)); diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index 39782f8d2c5..55704135530 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -8400,7 +8400,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp SELECT * FROM test.tb2 limit 2' at line 1 CREATE OR REPLACE TEMPORARY VIEW test.v1 AS SELECT * FROM test.tb2 limit 2 ; -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TEMPORARY VIEW test.v1 AS +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'VIEW test.v1 AS SELECT * FROM test.tb2 limit 2' at line 1 Drop view if exists test.v1 ; Use test; diff --git a/mysql-test/t/create_or_replace.test b/mysql-test/t/create_or_replace.test index b776be23b08..7d6841ab9d2 100644 --- a/mysql-test/t/create_or_replace.test +++ b/mysql-test/t/create_or_replace.test @@ -4,7 +4,7 @@ --source include/have_innodb.inc --disable_warnings -drop table if exists t1,t2; +drop table if exists t1,t2,t3; --enable_warnings # @@ -90,10 +90,21 @@ SHOW CREATE TABLE t1; DROP TABLE t1; CREATE TEMPORARY TABLE t1 AS SELECT a FROM t2; CREATE TEMPORARY TABLE IF NOT EXISTS t1(a int, b int) SELECT 1,2 FROM t2; -create or replace table t1 as select 1; -show create table t1; DROP TABLE t1; +CREATE TABLE t1 (a int); +CREATE OR REPLACE TABLE t1 AS SELECT 1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +create table t1 (a int); +--error ER_UPDATE_TABLE_USED +create or replace table t1 as select * from t1; +--error ER_UPDATE_TABLE_USED +create or replace table t1 as select a from (select a from t1) as t3; +--error ER_UPDATE_TABLE_USED +create or replace table t1 as select a from t2 where t2.a in (select a from t1); +drop table t1; --echo # --echo # Testing with normal tables @@ -156,6 +167,14 @@ SELECT * FROM t1 as t1_read; DROP TABLE t1; UNLOCK TABLES; +CREATE OR REPLACE TABLE t1 (a int); +LOCK TABLE t1 WRITE; +CREATE OR REPLACE TABLE t1 AS SELECT 1; +SELECT * from t1; +--error ER_TABLE_NOT_LOCKED +SELECT * from t2; +DROP TABLE t1; + --echo # --echo # Test also with InnoDB (transactional engine) --echo # @@ -201,6 +220,24 @@ unlock tables; show create table t1; drop table t1; +create or replace table t1 like t2; +--error ER_NONUNIQ_TABLE +create or replace table t1 like t1; +drop table t1; + +CREATE TEMPORARY TABLE t1 like t2; +--error ER_NONUNIQ_TABLE +CREATE OR REPLACE TABLE t1 like t1; +--error ER_NONUNIQ_TABLE +CREATE OR REPLACE TABLE t1 like t1; +drop table t1; + +CREATE TEMPORARY TABLE t1 like t2; +CREATE OR REPLACE TEMPORARY TABLE t3 like t1; +--error ER_NONUNIQ_TABLE +CREATE OR REPLACE TEMPORARY TABLE t3 like t3; +drop table t1,t3; + --echo # --echo # Test with prepared statements --echo # @@ -222,9 +259,9 @@ drop table t1; create view t1 as select 1; create table if not exists t1 (a int); ---error ER_BAD_TABLE_ERROR +--error ER_IT_IS_A_VIEW create or replace table t1 (a int); ---error ER_BAD_TABLE_ERROR +--error ER_IT_IS_A_VIEW drop table t1; drop view t1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 5cb9d920c0c..ae8a8e11f79 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -141,7 +141,7 @@ drop view v100; drop view t1; # try to drop VIEW with DROP TABLE --- error ER_BAD_TABLE_ERROR +-- error ER_IT_IS_A_VIEW drop table v1; # try to drop table with DROP VIEW diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 2d061fc314c..cc231599037 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -2140,13 +2140,9 @@ ER_INSERT_INFO spa "Registros: %ld Duplicados: %ld Peligros: %ld" swe "Rader: %ld Dubletter: %ld Varningar: %ld" ukr "Записів: %ld Дублікатів: %ld Застережень: %ld" -ER_UPDATE_TABLE_USED - eng "You can't specify target table '%-.192s' for update in FROM clause" - ger "Die Verwendung der zu aktualisierenden Zieltabelle '%-.192s' ist in der FROM-Klausel nicht zulässig." - jpn "FROM句にある表 '%-.192s' はUPDATEの対象にできません。" - rus "Не допускается указание таблицы '%-.192s' в списке таблиц FROM для внесения в нее изменений" - swe "INSERT-table '%-.192s' får inte finnas i FROM tabell-listan" - ukr "Таблиця '%-.192s' що змінюється не дозволена у переліку таблиць FROM" +ER_UPDATE_TABLE_USED + eng "Table '%-.192s' is specified twice, both as a target for '%s' and as a separate source for data" + swe "Table '%-.192s' är använd två gånger. Både för '%s' och för att hämta data" ER_NO_SUCH_THREAD cze "Neznámá identifikace threadu: %lu" dan "Ukendt tråd id: %lu" @@ -7089,3 +7085,5 @@ ER_CHANGE_SLAVE_PARALLEL_THREADS_ACTIVE eng "Cannot change @@slave_parallel_threads while another change is in progress" ER_PRIOR_COMMIT_FAILED eng "Commit failed due to failure of an earlier commit on which this one depends" +ER_IT_IS_A_VIEW 42S02 + eng "'%-.192s' is a view" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0a38cbbeb1a..e5105b03614 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1483,7 +1483,7 @@ void update_non_unique_table_error(TABLE_LIST *update, return; } } - my_error(ER_UPDATE_TABLE_USED, MYF(0), update->alias); + my_error(ER_UPDATE_TABLE_USED, MYF(0), update->alias, operation); } @@ -2839,6 +2839,10 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count) m_locked_tables_count--; } } + + /* If no tables left, do an automatic UNLOCK TABLES */ + if (thd->lock && thd->lock->table_count == 0) + unlock_locked_tables(thd); } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 85e9b1aa852..fcde2b4acbd 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -829,7 +829,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) thd->push_internal_handler(&err_handler); if (!thd->killed && !(tables && - mysql_rm_table_no_locks(thd, tables, true, false, true, true))) + mysql_rm_table_no_locks(thd, tables, true, false, true, true, false))) { /* We temporarily disable the binary log while dropping the objects diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 281d1de7877..a0959bdd278 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -258,7 +258,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, */ if (unique_table(thd, table_list, table_list->next_global, 0)) { - my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name); + my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->table_name, + "LOAD DATA"); DBUG_RETURN(TRUE); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 706e9e1a3a6..0d0f1a2634f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2957,8 +2957,24 @@ case SQLCOM_PREPARE: /* Got error or warning. Set res to 1 if error */ if (!(res= thd->is_error())) my_ok(thd); // CREATE ... IF NOT EXISTS + goto end_with_restore_list; + } + + /* Ensure we don't try to create something from which we select from */ + if ((create_info.options & HA_LEX_CREATE_REPLACE) && + !create_info.tmp_table()) + { + TABLE_LIST *duplicate; + if ((duplicate= unique_table(thd, lex->query_tables, + lex->query_tables->next_global, + 0))) + { + update_non_unique_table_error(lex->query_tables, "CREATE", + duplicate); + res= TRUE; + goto end_with_restore_list; + } } - else { /* Remove target table from main select and name resolution diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 32e4fdc18a1..817823063eb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2103,7 +2103,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, /* mark for close and remove all cached entries */ thd->push_internal_handler(&err_handler); error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary, - false, false); + false, false, false); thd->pop_internal_handler(); if (error) @@ -2168,6 +2168,8 @@ static uint32 comment_length(THD *thd, uint32 comment_pos, @param drop_view Allow to delete VIEW .frm @param dont_log_query Don't write query to log files. This will also not generate warnings if the handler files doesn't exists + @param dont_free_locks Don't do automatic UNLOCK TABLE if no more locked + tables @retval 0 ok @retval 1 Error @@ -2190,7 +2192,8 @@ static uint32 comment_length(THD *thd, uint32 comment_pos, int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool drop_view, - bool dont_log_query) + bool dont_log_query, + bool dont_free_locks) { TABLE_LIST *table; char path[FN_REFLEN + 1], wrong_tables_buff[160], *alias= NULL; @@ -2204,6 +2207,8 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0; bool non_tmp_table_deleted= 0; bool is_drop_tmp_if_exists_added= 0; + bool one_table= tables->next_local == 0; + bool was_view= 0; String built_query; String built_trans_tmp_query, built_non_trans_tmp_query; DBUG_ENTER("mysql_rm_table_no_locks"); @@ -2413,7 +2418,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table"); error= 0; if ((drop_temporary || !ha_table_exists(thd, db, alias, &table_type) || - (!drop_view && table_type == view_pseudo_hton))) + (!drop_view && (was_view= (table_type == view_pseudo_hton))))) { /* One of the following cases happened: @@ -2544,7 +2549,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, err: if (wrong_tables.length()) { - if (!foreign_key_error) + if (one_table && was_view) + my_printf_error(ER_IT_IS_A_VIEW, ER(ER_IT_IS_A_VIEW), MYF(0), + wrong_tables.c_ptr_safe()); + else if (!foreign_key_error) my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0), wrong_tables.c_ptr_safe()); else @@ -2610,7 +2618,8 @@ err: */ if (thd->locked_tables_mode) { - if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0) + if (thd->lock && thd->lock->table_count == 0 && + non_temp_tables_count > 0 && !dont_free_locks) { thd->locked_tables_list.unlock_locked_tables(thd); goto end; @@ -4608,8 +4617,8 @@ int create_table_impl(THD *thd, call to open_and_lock_tables() when we are using LOCK TABLES. */ (void) trans_rollback_stmt(thd); - /* Remove normal table without logging */ - if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1)) + /* Remove normal table without logging. Keep tables locked */ + if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1, 1)) goto err; /* The test of query_tables is to ensure we have any tables in the @@ -4618,6 +4627,11 @@ int create_table_impl(THD *thd, if (thd->lex->query_tables && restart_trans_for_tables(thd, thd->lex->query_tables->next_global)) goto err; + /* + We have to log this query, even if it failed later to ensure the + drop is done. + */ + thd->variables.option_bits|= OPTION_KEEP_LOG; } else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) goto warn; @@ -5084,6 +5098,18 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, res= thd->is_error(); goto err; } + /* Ensure we don't try to create something from which we select from */ + if ((create_info->options & HA_LEX_CREATE_REPLACE) && + !create_info->tmp_table()) + { + TABLE_LIST *duplicate; + if ((duplicate= unique_table(thd, table, src_table, 0))) + { + update_non_unique_table_error(src_table, "CREATE", duplicate); + goto err; + } + } + src_table->table->use_all_columns(); DEBUG_SYNC(thd, "create_table_like_after_open"); diff --git a/sql/sql_table.h b/sql/sql_table.h index c6ba7a581ec..fc7eb775bef 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -238,7 +238,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, my_bool drop_temporary); int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool drop_view, - bool log_query); + bool log_query, bool dont_free_locks); bool quick_rm_table(THD *thd, handlerton *base, const char *db, const char *table_name, uint flags); void close_cached_table(THD *thd, TABLE *table); -- cgit v1.2.1 From 5426facdcbfba2d78dab3c709cbf278073383b7c Mon Sep 17 00:00:00 2001 From: Michael Widenius Date: Wed, 5 Feb 2014 19:01:59 +0200 Subject: Replication changes for CREATE OR REPLACE TABLE - CREATE TABLE is by default executed on the slave as CREATE OR REPLACE - DROP TABLE is by default executed on the slave as DROP TABLE IF NOT EXISTS This means that a slave will by default continue even if we try to create a table that existed on the slave (the table will be deleted and re-created) or if we try to drop a table that didn't exist on the slave. This should be safe as instead of having the slave stop because of an inconsistency between master and slave, it will fix the inconsistency. Those that would prefer to get a stopped slave instead for the above cases can set slave_ddl_exec_mode to STRICT. - Ensure that a CREATE OR REPLACE TABLE which dropped a table is replicated - DROP TABLE that generated an error on master is handled as an identical DROP TABLE on the slave (IF NOT EXISTS is not added in this case) - Added slave_ddl_exec_mode variable to decide how DDL's are replicated New logic for handling BEGIN GTID ... COMMIT from the binary log: - When we find a BEGIN GTID, we start a transaction and set OPTION_GTID_BEGIN - When we find COMMIT, we reset OPTION_GTID_BEGIN and execute the normal COMMIT code. - While OPTION_GTID_BEGIN is set: - We don't generate implict commits before or after statements - All tables are regarded as transactional tables in the binary log (to ensure things are executed exactly as on the master) - We reset OPTION_GTID_BEGIN also on rollback This will help ensuring that we don't get any sporadic commits (and thus new GTID's) on the slave and will help keep the GTID's between master and slave in sync. mysql-test/extra/rpl_tests/rpl_log.test: Added testing of mode slave_ddl_exec_mode=STRICT mysql-test/r/mysqld--help.result: New help messages mysql-test/suite/rpl/r/create_or_replace_mix.result: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/r/create_or_replace_row.result: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/r/create_or_replace_statement.result: Testing replication of create or replace mysql-test/suite/rpl/r/rpl_gtid_startpos.result: Test must be run in slave_ddl_exec_mode=STRICT as part of the test depends on that DROP TABLE should fail on slave. mysql-test/suite/rpl/r/rpl_row_log.result: Updated result mysql-test/suite/rpl/r/rpl_row_log_innodb.result: Updated result mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result: Updated result mysql-test/suite/rpl/r/rpl_stm_log.result: Updated result mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result: Updated result mysql-test/suite/rpl/r/rpl_temp_table_mix_row.result: Updated result mysql-test/suite/rpl/t/create_or_replace.inc: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/create_or_replace_mix.cnf: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/create_or_replace_mix.test: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/create_or_replace_row.cnf: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/create_or_replace_row.test: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/create_or_replace_statement.cnf: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/create_or_replace_statement.test: Testing of CREATE OR REPLACE TABLE with replication mysql-test/suite/rpl/t/rpl_gtid_startpos.test: Test must be run in slave_ddl_exec_mode=STRICT as part of the test depends on that DROP TABLE should fail on slave. mysql-test/suite/rpl/t/rpl_stm_log.test: Removed some lines mysql-test/suite/sys_vars/r/slave_ddl_exec_mode_basic.result: Testing of slave_ddl_exec_mode mysql-test/suite/sys_vars/t/slave_ddl_exec_mode_basic.test: Testing of slave_ddl_exec_mode sql/handler.cc: Regard all tables as transactional in commit if OPTION_GTID_BEGIN is set. This is to ensure that statments are not commited too early if non transactional tables are used. sql/log.cc: Regard all tables as transactional in commit if OPTION_GTID_BEGIN is set. Also treat 'direct' log events as transactional (to get them logged as they where on the master) sql/log_event.cc: Ensure that the new error from DROP TABLE when trying to drop a view is treated same as the old one. Store error code that slave expects in THD. Set OPTION_GTID_BEGIN if we find a BEGIN. Reset OPTION_GTID_BEGIN if we find a COMMIT. sql/mysqld.cc: Added slave_ddl_exec_mode_options sql/mysqld.h: Added slave_ddl_exec_mode_options sql/rpl_gtid.cc: Reset OPTION_GTID_BEGIN if we record a gtid (safety) sql/sql_class.cc: Regard all tables as transactional in commit if OPTION_GTID_BEGIN is set. sql/sql_class.h: Added to THD: log_current_statement and slave_expected_error sql/sql_insert.cc: Ensure that CREATE OR REPLACE is logged if table was deleted. Don't do implicit commit for CREATE if we are under OPTION_GTID_BEGIN sql/sql_parse.cc: Change CREATE TABLE -> CREATE OR REPLACE TABLE for slaves Change DROP TABLE -> DROP TABLE IF EXISTS for slaves CREATE TABLE doesn't force implicit commit in case of OPTION_GTID_BEGIN Don't do commits before or after any statement if OPTION_GTID_BEGIN was set. sql/sql_priv.h: Added OPTION_GTID_BEGIN sql/sql_show.cc: Enhanced store_create_info() to also be able to handle CREATE OR REPLACE sql/sql_show.h: Updated prototype sql/sql_table.cc: Ensure that CREATE OR REPLACE is logged if table was deleted. sql/sys_vars.cc: Added slave_ddl_exec_mode sql/transaction.cc: Added warning if we got a GTID under OPTION_GTID_BEGIN --- mysql-test/extra/rpl_tests/rpl_log.test | 8 +- mysql-test/r/mysqld--help.result | 16 +- .../suite/rpl/r/create_or_replace_mix.result | 162 ++++++++++++++++++ .../suite/rpl/r/create_or_replace_row.result | 184 +++++++++++++++++++++ .../suite/rpl/r/create_or_replace_statement.result | 144 ++++++++++++++++ mysql-test/suite/rpl/r/rpl_gtid_startpos.result | 3 + mysql-test/suite/rpl/r/rpl_row_log.result | 3 + mysql-test/suite/rpl/r/rpl_row_log_innodb.result | 3 + .../rpl/r/rpl_row_show_relaylog_events.result | 4 +- mysql-test/suite/rpl/r/rpl_stm_log.result | 3 + .../rpl/r/rpl_stm_mix_show_relaylog_events.result | 4 +- .../suite/rpl/r/rpl_temp_table_mix_row.result | 4 +- mysql-test/suite/rpl/t/create_or_replace.inc | 137 +++++++++++++++ mysql-test/suite/rpl/t/create_or_replace_mix.cnf | 9 + mysql-test/suite/rpl/t/create_or_replace_mix.test | 4 + mysql-test/suite/rpl/t/create_or_replace_row.cnf | 9 + mysql-test/suite/rpl/t/create_or_replace_row.test | 4 + .../suite/rpl/t/create_or_replace_statement.cnf | 9 + .../suite/rpl/t/create_or_replace_statement.test | 4 + mysql-test/suite/rpl/t/rpl_gtid_startpos.test | 8 +- mysql-test/suite/rpl/t/rpl_stm_log.test | 2 - .../sys_vars/r/slave_ddl_exec_mode_basic.result | 39 +++++ .../sys_vars/t/slave_ddl_exec_mode_basic.test | 67 ++++++++ plugin/metadata_lock_info/metadata_lock_info.cc | 1 + sql/handler.cc | 8 +- sql/log.cc | 59 +++++-- sql/log_event.cc | 39 +++-- sql/mysqld.cc | 1 + sql/mysqld.h | 2 +- sql/rpl_gtid.cc | 3 +- sql/rpl_rli.cc | 1 + sql/slave.cc | 3 +- sql/sql_class.cc | 32 ++++ sql/sql_class.h | 30 ++-- sql/sql_insert.cc | 22 ++- sql/sql_parse.cc | 70 ++++++-- sql/sql_priv.h | 2 + sql/sql_show.cc | 15 +- sql/sql_show.h | 3 +- sql/sql_table.cc | 62 +++++-- sql/sys_vars.cc | 32 +++- sql/transaction.cc | 6 + 42 files changed, 1112 insertions(+), 109 deletions(-) create mode 100644 mysql-test/suite/rpl/r/create_or_replace_mix.result create mode 100644 mysql-test/suite/rpl/r/create_or_replace_row.result create mode 100644 mysql-test/suite/rpl/r/create_or_replace_statement.result create mode 100644 mysql-test/suite/rpl/t/create_or_replace.inc create mode 100644 mysql-test/suite/rpl/t/create_or_replace_mix.cnf create mode 100644 mysql-test/suite/rpl/t/create_or_replace_mix.test create mode 100644 mysql-test/suite/rpl/t/create_or_replace_row.cnf create mode 100644 mysql-test/suite/rpl/t/create_or_replace_row.test create mode 100644 mysql-test/suite/rpl/t/create_or_replace_statement.cnf create mode 100644 mysql-test/suite/rpl/t/create_or_replace_statement.test create mode 100644 mysql-test/suite/sys_vars/r/slave_ddl_exec_mode_basic.result create mode 100644 mysql-test/suite/sys_vars/t/slave_ddl_exec_mode_basic.test diff --git a/mysql-test/extra/rpl_tests/rpl_log.test b/mysql-test/extra/rpl_tests/rpl_log.test index deff9d653e0..01e8497e4de 100644 --- a/mysql-test/extra/rpl_tests/rpl_log.test +++ b/mysql-test/extra/rpl_tests/rpl_log.test @@ -18,8 +18,12 @@ start slave; --source include/wait_for_slave_to_start.inc let $VERSION=`select version()`; - +# Lets run this test in STRICT MODE (DROP TABLE is not DROP TABLE IF EXISTS) +connection slave; +set @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +set @@global.slave_ddl_exec_mode=STRICT; connection master; + eval create table t1(n int not null auto_increment primary key)ENGINE=$engine_type; insert into t1 values (NULL); drop table t1; @@ -141,3 +145,5 @@ drop table t1; # End of 4.1 tests sync_slave_with_master; +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; +connection master; diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index c74b263c5e9..ce7cf8740d4 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -856,13 +856,22 @@ The following options may be given as the first argument: --skip-slave-start If set, slave is not autostarted. --slave-compressed-protocol Use compression on master/slave protocol + --slave-ddl-exec-mode=name + Modes for how replication events should be executed. + Legal values are STRICT and IDEMPOTENT (default). In + IDEMPOTENT mode, replication will not stop for DDL + operations that are idempotent. This means that CREATE + TABLE is treated CREATE TABLE OR REPLACE and DROP TABLE + is threated as DROP TABLE IF EXISTS. --slave-exec-mode=name Modes for how replication events should be executed. Legal values are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, replication will not stop for operations - that are idempotent. In STRICT mode, replication will - stop on any unexpected difference between the master and - the slave + that are idempotent. For example, in row based + replication attempts to delete rows that doesn't exist + will be ignored.In STRICT mode, replication will stop on + any unexpected difference between the master and the + slave --slave-load-tmpdir=name The location where the slave should put its temporary files when replicating a LOAD DATA INFILE command @@ -1260,6 +1269,7 @@ skip-networking FALSE skip-show-database FALSE skip-slave-start FALSE slave-compressed-protocol FALSE +slave-ddl-exec-mode IDEMPOTENT slave-exec-mode STRICT slave-max-allowed-packet 1073741824 slave-net-timeout 3600 diff --git a/mysql-test/suite/rpl/r/create_or_replace_mix.result b/mysql-test/suite/rpl/r/create_or_replace_mix.result new file mode 100644 index 00000000000..096379c13ea --- /dev/null +++ b/mysql-test/suite/rpl/r/create_or_replace_mix.result @@ -0,0 +1,162 @@ +include/rpl_init.inc [topology=1->2] +create table t2 (a int) engine=myisam; +insert into t2 values (0),(1),(2),(2); +create temporary table t3 (a_in_temporary int) engine=myisam; +# +# Check how create table and create or replace table are logged +# +create table t1 (to_be_deleted int); +CREATE TABLE t1 AS SELECT 1 AS f1; +CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1; +CREATE OR REPLACE table t1 like t2; +CREATE OR REPLACE table t1 like t3; +drop table t1; +binlog from server 1 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t2 (a int) engine=myisam +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; insert into t2 values (0),(1),(2),(2) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create temporary table t3 (a_in_temporary int) engine=myisam +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 AS SELECT 1 AS f1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t2 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t3 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t2 (a int) engine=myisam +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into t2 values (0),(1),(2),(2) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create temporary table t3 (a_in_temporary int) engine=myisam +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (to_be_deleted int) +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 AS SELECT 1 AS f1 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t2 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t3 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +# +# Ensure that also failed create_or_replace are logged +# +create table t1 (a int); +create or replace table t1; +ERROR 42000: A table must have at least 1 column +drop table if exists t1; +Warnings: +Note 1051 Unknown table 'test.t1' +create or replace table t1 (a int primary key) select a from t2; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +create table t1 (a int); +create or replace table t1 (a int primary key) select a from t2; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +binlog from server 1 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create or replace table t1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t1` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +show tables; +Tables_in_test +t1 +t2 +drop table if exists t1,t2; +Warnings: +Note 1051 Unknown table 'test.t1' +# +# Ensure that CREATE are run as CREATE OR REPLACE on slave +# +create table t1 (server_2_to_be_delete int); +create table t1 (new_table int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `new_table` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# +# Ensure that DROP TABLE is run as DROP IF NOT EXISTS +# +create table t1 (server_1_ver_1 int); +create table t4 (server_1_ver_2 int); +drop table t1; +drop table t1,t4; +create table t1 (server_2_ver_2 int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `server_2_ver_2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t4` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (server_2_ver_2 int) +drop table t1; +# +# Ensure that CREATE ... SELECT is recorded as one GTID on the slave +# +create table t1 (a int); +insert into t1 values (0),(1),(2); +create table t2 engine=myisam select * from t1; +create or replace table t2 engine=innodb select * from t1; +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (a int) +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM +slave-bin.000001 # Table_map # # table_id: # (test.t2) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB +slave-bin.000001 # Table_map # # table_id: # (test.t2) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Xid # # COMMIT /* XID */ +drop table t1; +drop table t2; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/create_or_replace_row.result b/mysql-test/suite/rpl/r/create_or_replace_row.result new file mode 100644 index 00000000000..beb4976953e --- /dev/null +++ b/mysql-test/suite/rpl/r/create_or_replace_row.result @@ -0,0 +1,184 @@ +include/rpl_init.inc [topology=1->2] +create table t2 (a int) engine=myisam; +insert into t2 values (0),(1),(2),(2); +create temporary table t3 (a_in_temporary int) engine=myisam; +# +# Check how create table and create or replace table are logged +# +create table t1 (to_be_deleted int); +CREATE TABLE t1 AS SELECT 1 AS f1; +CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1; +CREATE OR REPLACE table t1 like t2; +CREATE OR REPLACE table t1 like t3; +drop table t1; +binlog from server 1 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t2 (a int) engine=myisam +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE `t1` ( + `f1` int(1) NOT NULL DEFAULT '0' +) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t1` ( + `f1` int(1) NOT NULL DEFAULT '0' +) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t2 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t1` ( + `a_in_temporary` int(11) DEFAULT NULL +) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t2 (a int) engine=myisam +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Table_map # # table_id: # (test.t2) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (to_be_deleted int) +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE TABLE `t1` ( + `f1` int(1) NOT NULL DEFAULT '0' +) +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t1` ( + `f1` int(1) NOT NULL DEFAULT '0' +) +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t2 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t1` ( + `a_in_temporary` int(11) DEFAULT NULL +) +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +# +# Ensure that also failed create_or_replace are logged +# +create table t1 (a int); +create or replace table t1; +ERROR 42000: A table must have at least 1 column +drop table if exists t1; +Warnings: +Note 1051 Unknown table 'test.t1' +create or replace table t1 (a int primary key) select a from t2; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +create table t1 (a int); +create or replace table t1 (a int primary key) select a from t2; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +binlog from server 1 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create or replace table t1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t1` ( + `a` int(11) NOT NULL, + PRIMARY KEY (`a`) +) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # ROLLBACK +show tables; +Tables_in_test +t1 +t2 +drop table if exists t1,t2; +Warnings: +Note 1051 Unknown table 'test.t1' +# +# Ensure that CREATE are run as CREATE OR REPLACE on slave +# +create table t1 (server_2_to_be_delete int); +create table t1 (new_table int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `new_table` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# +# Ensure that DROP TABLE is run as DROP IF NOT EXISTS +# +create table t1 (server_1_ver_1 int); +create table t4 (server_1_ver_2 int); +drop table t1; +drop table t1,t4; +create table t1 (server_2_ver_2 int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `server_2_ver_2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t4` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (server_2_ver_2 int) +drop table t1; +# +# Ensure that CREATE ... SELECT is recorded as one GTID on the slave +# +create table t1 (a int); +insert into t1 values (0),(1),(2); +create table t2 engine=myisam select * from t1; +create or replace table t2 engine=innodb select * from t1; +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (a int) +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Table_map # # table_id: # (test.t1) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM +slave-bin.000001 # Table_map # # table_id: # (test.t2) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE `t2` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB +slave-bin.000001 # Table_map # # table_id: # (test.t2) +slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F +slave-bin.000001 # Xid # # COMMIT /* XID */ +drop table t1; +drop table t2; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/create_or_replace_statement.result b/mysql-test/suite/rpl/r/create_or_replace_statement.result new file mode 100644 index 00000000000..de139ff0f7b --- /dev/null +++ b/mysql-test/suite/rpl/r/create_or_replace_statement.result @@ -0,0 +1,144 @@ +include/rpl_init.inc [topology=1->2] +create table t2 (a int) engine=myisam; +insert into t2 values (0),(1),(2),(2); +create temporary table t3 (a_in_temporary int) engine=myisam; +# +# Check how create table and create or replace table are logged +# +create table t1 (to_be_deleted int); +CREATE TABLE t1 AS SELECT 1 AS f1; +CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1; +CREATE OR REPLACE table t1 like t2; +CREATE OR REPLACE table t1 like t3; +drop table t1; +binlog from server 1 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t2 (a int) engine=myisam +master-bin.000001 # Gtid # # BEGIN GTID #-#-# +master-bin.000001 # Query # # use `test`; insert into t2 values (0),(1),(2),(2) +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create temporary table t3 (a_in_temporary int) engine=myisam +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE TABLE t1 AS SELECT 1 AS f1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t2 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t3 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t2 (a int) engine=myisam +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into t2 values (0),(1),(2),(2) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create temporary table t3 (a_in_temporary int) engine=myisam +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (to_be_deleted int) +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 AS SELECT 1 AS f1 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t2 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; CREATE OR REPLACE table t1 like t3 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +# +# Ensure that also failed create_or_replace are logged +# +create table t1 (a int); +create or replace table t1; +ERROR 42000: A table must have at least 1 column +drop table if exists t1; +Warnings: +Note 1051 Unknown table 'test.t1' +create or replace table t1 (a int primary key) select a from t2; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +create table t1 (a int); +create or replace table t1 (a int primary key) select a from t2; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +binlog from server 1 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create or replace table t1 +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create table t1 (a int) +master-bin.000001 # Gtid # # GTID #-#-# +master-bin.000001 # Query # # use `test`; create or replace table t1 (a int primary key) select a from t2 +show tables; +Tables_in_test +t2 +drop table if exists t1,t2; +Warnings: +Note 1051 Unknown table 'test.t1' +# +# Ensure that CREATE are run as CREATE OR REPLACE on slave +# +create table t1 (server_2_to_be_delete int); +create table t1 (new_table int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `new_table` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# +# Ensure that DROP TABLE is run as DROP IF NOT EXISTS +# +create table t1 (server_1_ver_1 int); +create table t4 (server_1_ver_2 int); +drop table t1; +drop table t1,t4; +create table t1 (server_2_ver_2 int); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `server_2_ver_2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t1`,`t4` /* generated by server */ +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (server_2_ver_2 int) +drop table t1; +# +# Ensure that CREATE ... SELECT is recorded as one GTID on the slave +# +create table t1 (a int); +insert into t1 values (0),(1),(2); +create table t2 engine=myisam select * from t1; +create or replace table t2 engine=innodb select * from t1; +binlog from server 2 +include/show_binlog_events.inc +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t1 (a int) +slave-bin.000001 # Gtid # # BEGIN GTID #-#-# +slave-bin.000001 # Query # # use `test`; insert into t1 values (0),(1),(2) +slave-bin.000001 # Query # # COMMIT +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create table t2 engine=myisam select * from t1 +slave-bin.000001 # Gtid # # GTID #-#-# +slave-bin.000001 # Query # # use `test`; create or replace table t2 engine=innodb select * from t1 +drop table t1; +drop table t2; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_gtid_startpos.result b/mysql-test/suite/rpl/r/rpl_gtid_startpos.result index 9be5903b2e9..1c9f771b5cc 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_startpos.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_startpos.result @@ -110,6 +110,8 @@ DROP TABLE t1; SET SQL_LOG_BIN=1; RESET SLAVE; SET GLOBAL gtid_slave_pos=""; +SET @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +SET GLOBAL slave_ddl_exec_mode=STRICT; include/start_slave.inc SELECT * FROM t1 ORDER BY a; a @@ -225,4 +227,5 @@ a 1 2 DROP TABLE t1; +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_row_log.result b/mysql-test/suite/rpl/r/rpl_row_log.result index d3d5b42c80a..83ec26486e0 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log.result +++ b/mysql-test/suite/rpl/r/rpl_row_log.result @@ -6,6 +6,8 @@ reset master; reset slave; start slave; include/wait_for_slave_to_start.inc +set @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +set @@global.slave_ddl_exec_mode=STRICT; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM; insert into t1 values (NULL); drop table t1; @@ -287,4 +289,5 @@ a b 5 1 6 1 drop table t1; +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result index 5dd5ff1b4ff..3b9733a18e8 100644 --- a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result @@ -6,6 +6,8 @@ reset master; reset slave; start slave; include/wait_for_slave_to_start.inc +set @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +set @@global.slave_ddl_exec_mode=STRICT; create table t1(n int not null auto_increment primary key)ENGINE=InnoDB; insert into t1 values (NULL); drop table t1; @@ -287,4 +289,5 @@ a b 5 1 6 1 drop table t1; +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result index 9872316dc97..a132b50a471 100644 --- a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result @@ -172,7 +172,7 @@ include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Gtid # # GTID #-#-# -slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS IN LIMIT 2 ******** include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info @@ -181,7 +181,7 @@ slave-bin.000002 # Gtid # # GTID #-#-# ******** [slave] SHOW BINLOG EVENTS IN LIMIT 2,3 ******** include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info -slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS ******** include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info diff --git a/mysql-test/suite/rpl/r/rpl_stm_log.result b/mysql-test/suite/rpl/r/rpl_stm_log.result index 360a0e526de..da925035c9c 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_log.result +++ b/mysql-test/suite/rpl/r/rpl_stm_log.result @@ -6,6 +6,8 @@ reset master; reset slave; start slave; include/wait_for_slave_to_start.inc +set @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +set @@global.slave_ddl_exec_mode=STRICT; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM; insert into t1 values (NULL); drop table t1; @@ -286,4 +288,5 @@ a b 5 1 6 1 drop table t1; +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result index 57d84eef52e..69e144b5cd1 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result +++ b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result @@ -154,7 +154,7 @@ include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info slave-bin.000002 # Binlog_checkpoint # # slave-bin.000002 slave-bin.000002 # Gtid # # GTID #-#-# -slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS IN LIMIT 2 ******** include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info @@ -163,7 +163,7 @@ slave-bin.000002 # Gtid # # GTID #-#-# ******** [slave] SHOW BINLOG EVENTS IN LIMIT 2,3 ******** include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info -slave-bin.000002 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ +slave-bin.000002 # Query # # use `test`; DROP TABLE IF EXISTS `t1` /* generated by server */ ******** [slave] SHOW BINLOG EVENTS ******** include/show_events.inc Log_name Pos Event_type Server_id End_log_pos Info diff --git a/mysql-test/suite/rpl/r/rpl_temp_table_mix_row.result b/mysql-test/suite/rpl/r/rpl_temp_table_mix_row.result index a0102baacfe..1933b0b82f8 100644 --- a/mysql-test/suite/rpl/r/rpl_temp_table_mix_row.result +++ b/mysql-test/suite/rpl/r/rpl_temp_table_mix_row.result @@ -62,7 +62,7 @@ slave-bin.000001 # Query # # use `test`; ALTER TABLE t1_tmp ADD COLUMN b INT slave-bin.000001 # Gtid # # GTID #-#-# slave-bin.000001 # Query # # DROP TEMPORARY TABLE IF EXISTS `test`.`t1_tmp` /* generated by server */ slave-bin.000001 # Gtid # # GTID #-#-# -slave-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */ +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t2` /* generated by server */ slave-bin.000001 # Gtid # # BEGIN GTID #-#-# slave-bin.000001 # Table_map # # table_id: # (test.t1) slave-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F @@ -73,7 +73,7 @@ slave-bin.000001 # Gtid # # BEGIN GTID #-#-# slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2) slave-bin.000001 # Xid # # COMMIT /* XID */ slave-bin.000001 # Gtid # # GTID #-#-# -slave-bin.000001 # Query # # use `test`; DROP TABLE `t3`,`t1` /* generated by server */ +slave-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS `t3`,`t1` /* generated by server */ # Bug#55478 Row events wrongly apply on the temporary table of the same name # ========================================================================== diff --git a/mysql-test/suite/rpl/t/create_or_replace.inc b/mysql-test/suite/rpl/t/create_or_replace.inc new file mode 100644 index 00000000000..8cabd8f12bf --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace.inc @@ -0,0 +1,137 @@ +# Test CREATE OR REPLACE TABLE in replication +--source include/have_innodb.inc + +--let $rpl_topology=1->2 +--source include/rpl_init.inc + +# Create help tables +create table t2 (a int) engine=myisam; +insert into t2 values (0),(1),(2),(2); +create temporary table t3 (a_in_temporary int) engine=myisam; + +--echo # +--echo # Check how create table and create or replace table are logged +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +create table t1 (to_be_deleted int); + +connection server_1; +CREATE TABLE t1 AS SELECT 1 AS f1; +CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1; +CREATE OR REPLACE table t1 like t2; +CREATE OR REPLACE table t1 like t3; +drop table t1; + +--echo binlog from server 1 +--source include/show_binlog_events.inc +save_master_pos; +connection server_2; +sync_with_master; +--echo binlog from server 2 +--source include/show_binlog_events.inc + +connection server_1; + +--echo # +--echo # Ensure that also failed create_or_replace are logged +--echo # + +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) + +create table t1 (a int); +--error ER_TABLE_MUST_HAVE_COLUMNS +create or replace table t1; +drop table if exists t1; +# The following is not logged as t1 does not exists; +--error ER_DUP_ENTRY +create or replace table t1 (a int primary key) select a from t2; + +create table t1 (a int); +# This should be logged as we will delete t1 +--error ER_DUP_ENTRY +create or replace table t1 (a int primary key) select a from t2; + +--echo binlog from server 1 +--source include/show_binlog_events.inc +save_master_pos; +connection server_2; +sync_with_master; +show tables; +connection server_1; + +drop table if exists t1,t2; + +--echo # +--echo # Ensure that CREATE are run as CREATE OR REPLACE on slave +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +create table t1 (server_2_to_be_delete int); +connection server_1; +create table t1 (new_table int); + +save_master_pos; +connection server_2; +sync_with_master; + +show create table t1; +connection server_1; +drop table t1; + +--echo # +--echo # Ensure that DROP TABLE is run as DROP IF NOT EXISTS +--echo # + +create table t1 (server_1_ver_1 int); +create table t4 (server_1_ver_2 int); + +save_master_pos; +connection server_2; +sync_with_master; +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) + +# Drop the table on the slave +drop table t1; +connection server_1; +drop table t1,t4; +create table t1 (server_2_ver_2 int); +save_master_pos; +connection server_2; +sync_with_master; +show create table t1; +--echo binlog from server 2 +--source include/show_binlog_events.inc +connection server_1; +drop table t1; + +--echo # +--echo # Ensure that CREATE ... SELECT is recorded as one GTID on the slave +--echo # + +save_master_pos; +connection server_2; +sync_with_master; +--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1) +connection server_1; + +create table t1 (a int); +insert into t1 values (0),(1),(2); +create table t2 engine=myisam select * from t1; +create or replace table t2 engine=innodb select * from t1; +save_master_pos; +connection server_2; +sync_with_master; +--echo binlog from server 2 +--source include/show_binlog_events.inc +connection server_1; +drop table t1; + +# Clean up +drop table t2; + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace_mix.cnf b/mysql-test/suite/rpl/t/create_or_replace_mix.cnf new file mode 100644 index 00000000000..03d69b2864f --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_mix.cnf @@ -0,0 +1,9 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/create_or_replace_mix.test b/mysql-test/suite/rpl/t/create_or_replace_mix.test new file mode 100644 index 00000000000..0cabef15ad7 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_mix.test @@ -0,0 +1,4 @@ +# Testing create or replace table in mixed mode. + +--source include/have_binlog_format_mixed.inc +--source create_or_replace.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace_row.cnf b/mysql-test/suite/rpl/t/create_or_replace_row.cnf new file mode 100644 index 00000000000..03d69b2864f --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_row.cnf @@ -0,0 +1,9 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/create_or_replace_row.test b/mysql-test/suite/rpl/t/create_or_replace_row.test new file mode 100644 index 00000000000..88dd8fd2d74 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_row.test @@ -0,0 +1,4 @@ +# Testing create or replace table in mixed mode. + +--source include/have_binlog_format_row.inc +--source create_or_replace.inc diff --git a/mysql-test/suite/rpl/t/create_or_replace_statement.cnf b/mysql-test/suite/rpl/t/create_or_replace_statement.cnf new file mode 100644 index 00000000000..03d69b2864f --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_statement.cnf @@ -0,0 +1,9 @@ +!include suite/rpl/my.cnf + +[mysqld.1] +log-slave-updates +loose-innodb + +[mysqld.2] +log-slave-updates +loose-innodb diff --git a/mysql-test/suite/rpl/t/create_or_replace_statement.test b/mysql-test/suite/rpl/t/create_or_replace_statement.test new file mode 100644 index 00000000000..2709e4142f4 --- /dev/null +++ b/mysql-test/suite/rpl/t/create_or_replace_statement.test @@ -0,0 +1,4 @@ +# Testing create or replace table in mixed mode. + +--source include/have_binlog_format_statement.inc +--source create_or_replace.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_startpos.test b/mysql-test/suite/rpl/t/rpl_gtid_startpos.test index 0797eead0ee..323e86426ce 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_startpos.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_startpos.test @@ -165,7 +165,7 @@ SET GLOBAL gtid_slave_pos=""; SELECT * FROM t1 ORDER BY a; -# Same thing, but this time using SQL_LOG_BIN=0 to avoid polliting the +# Same thing, but this time using SQL_LOG_BIN=0 to avoid polluting the # slave binlog. --connection server_2 @@ -175,6 +175,9 @@ DROP TABLE t1; SET SQL_LOG_BIN=1; RESET SLAVE; SET GLOBAL gtid_slave_pos=""; +# Ensure that the slave fails because of missing table to be dropped +SET @save_slave_ddl_exec_mode=@@global.slave_ddl_exec_mode; +SET GLOBAL slave_ddl_exec_mode=STRICT; --source include/start_slave.inc --sync_with_master @@ -349,6 +352,7 @@ SELECT * FROM t1 ORDER BY a; # Clean up. --connection server_1 DROP TABLE t1; - +--connection server_2 +set @@global.slave_ddl_exec_mode=@save_slave_ddl_exec_mode; --source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_stm_log.test b/mysql-test/suite/rpl/t/rpl_stm_log.test index 7e7e1d4033f..23130528465 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_log.test +++ b/mysql-test/suite/rpl/t/rpl_stm_log.test @@ -4,7 +4,5 @@ let $engine_type=MyISAM; -- source extra/rpl_tests/rpl_log.test - # End of 4.1 tests -# Adding comment for force manual merge 5.0 -> wl1012: Delete me --source include/rpl_end.inc diff --git a/mysql-test/suite/sys_vars/r/slave_ddl_exec_mode_basic.result b/mysql-test/suite/sys_vars/r/slave_ddl_exec_mode_basic.result new file mode 100644 index 00000000000..e758e61f648 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/slave_ddl_exec_mode_basic.result @@ -0,0 +1,39 @@ +SET @start_value = @@global.slave_ddl_exec_mode; +SELECT @@global.slave_ddl_exec_mode; +@@global.slave_ddl_exec_mode +IDEMPOTENT +SELECT @@slave_ddl_exec_mode = @@GLOBAL.slave_ddl_exec_mode; +@@slave_ddl_exec_mode = @@GLOBAL.slave_ddl_exec_mode +1 +1 Expected +SELECT COUNT(@@slave_ddl_exec_mode); +COUNT(@@slave_ddl_exec_mode) +1 +1 Expected +SELECT COUNT(@@local.slave_ddl_exec_mode); +ERROR HY000: Variable 'slave_ddl_exec_mode' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.slave_ddl_exec_mode); +ERROR HY000: Variable 'slave_ddl_exec_mode' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.slave_ddl_exec_mode); +COUNT(@@GLOBAL.slave_ddl_exec_mode) +1 +1 Expected +SELECT slave_ddl_exec_mode = @@SESSION.version; +ERROR 42S22: Unknown column 'slave_ddl_exec_mode' in 'field list' +Expected error 'Readonly variable' +SET @@GLOBAL.slave_ddl_exec_mode=STRICT; +SELECT @@GLOBAL.slave_ddl_exec_mode; +@@GLOBAL.slave_ddl_exec_mode +STRICT +SET @@GLOBAL.slave_ddl_exec_mode=IDEMPOTENT; +SELECT @@GLOBAL.slave_ddl_exec_mode; +@@GLOBAL.slave_ddl_exec_mode +IDEMPOTENT +SET @@GLOBAL.slave_ddl_exec_mode=XXX; +ERROR 42000: Variable 'slave_ddl_exec_mode' can't be set to the value of 'XXX' +SELECT @@GLOBAL.slave_ddl_exec_mode; +@@GLOBAL.slave_ddl_exec_mode +IDEMPOTENT +SET @@global.slave_ddl_exec_mode= @start_value; diff --git a/mysql-test/suite/sys_vars/t/slave_ddl_exec_mode_basic.test b/mysql-test/suite/sys_vars/t/slave_ddl_exec_mode_basic.test new file mode 100644 index 00000000000..64f8a75f443 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/slave_ddl_exec_mode_basic.test @@ -0,0 +1,67 @@ +############## mysql-test\t\slave_ddl_exec_mode_basic.test #################### +# # +# Variable Name: slave_ddl_exec_mode # +# Scope: GLOBAL & SESSION # +# Access Type: Dynamic # +# Data Type: Numeric # +# Default Value: 1 # +# Range: 1 - 65536 # +# # +# # +# Description: Test Cases of Dynamic System Variable slave_ddl_exec_mode # +# that checks the behavior of this variable in the following ways# +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +############################################################################### + +--source include/not_embedded.inc +--source include/load_sysvars.inc + +######################################################################## +# START OF slave_ddl_exec_mode TESTS # +######################################################################## + +SET @start_value = @@global.slave_ddl_exec_mode; + +SELECT @@global.slave_ddl_exec_mode; + +SELECT @@slave_ddl_exec_mode = @@GLOBAL.slave_ddl_exec_mode; +--echo 1 Expected + +SELECT COUNT(@@slave_ddl_exec_mode); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.slave_ddl_exec_mode); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.slave_ddl_exec_mode); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.slave_ddl_exec_mode); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT slave_ddl_exec_mode = @@SESSION.version; +--echo Expected error 'Readonly variable' + + +SET @@GLOBAL.slave_ddl_exec_mode=STRICT; +SELECT @@GLOBAL.slave_ddl_exec_mode; + +SET @@GLOBAL.slave_ddl_exec_mode=IDEMPOTENT; +SELECT @@GLOBAL.slave_ddl_exec_mode; + +--error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.slave_ddl_exec_mode=XXX; +SELECT @@GLOBAL.slave_ddl_exec_mode; + +SET @@global.slave_ddl_exec_mode= @start_value; + +######################################################################## +# END OF slave_ddl_exec_mode TESTS # +######################################################################## diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc index 0ddde226553..f5d892d4a07 100644 --- a/plugin/metadata_lock_info/metadata_lock_info.cc +++ b/plugin/metadata_lock_info/metadata_lock_info.cc @@ -37,6 +37,7 @@ static const LEX_STRING metadata_lock_info_lock_mode[] = { { C_STRING_WITH_LEN("MDL_SHARED_HIGH_PRIO") }, { C_STRING_WITH_LEN("MDL_SHARED_READ") }, { C_STRING_WITH_LEN("MDL_SHARED_WRITE") }, + { C_STRING_WITH_LEN("MDL_SHARED_UPGRADABLE") }, { C_STRING_WITH_LEN("MDL_SHARED_NO_WRITE") }, { C_STRING_WITH_LEN("MDL_SHARED_NO_READ_WRITE") }, { C_STRING_WITH_LEN("MDL_EXCLUSIVE") }, diff --git a/sql/handler.cc b/sql/handler.cc index 6af1682e080..dee76d21303 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1251,7 +1251,8 @@ int ha_commit_trans(THD *thd, bool all) the changes are not durable as they might be rolled back if the enclosing 'all' transaction is rolled back. */ - bool is_real_trans= all || thd->transaction.all.ha_list == 0; + bool is_real_trans= ((all || thd->transaction.all.ha_list == 0) && + !(thd->variables.option_bits & OPTION_GTID_BEGIN)); Ha_trx_info *ha_info= trans->ha_list; bool need_prepare_ordered, need_commit_ordered; my_xid xid; @@ -1266,7 +1267,7 @@ int ha_commit_trans(THD *thd, bool all) ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));); DBUG_PRINT("info", - ("all: %d thd->in_sub_stmt: %d ha_info: %p is_real_trans: %d", + ("all: %d thd->in_sub_stmt: %d ha_info: %p is_real_trans: %d", all, thd->in_sub_stmt, ha_info, is_real_trans)); /* We must not commit the normal transaction if a statement @@ -1471,7 +1472,8 @@ int ha_commit_one_phase(THD *thd, bool all) ha_commit_one_phase() can be called with an empty transaction.all.ha_list, see why in trans_register_ha()). */ - bool is_real_trans=all || thd->transaction.all.ha_list == 0; + bool is_real_trans= ((all || thd->transaction.all.ha_list == 0) && + !(thd->variables.option_bits & OPTION_GTID_BEGIN)); int res; DBUG_ENTER("ha_commit_one_phase"); if (is_real_trans && (res= thd->wait_for_prior_commit())) diff --git a/sql/log.cc b/sql/log.cc index 9ea1514ef77..f2f83dbe546 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1679,6 +1679,7 @@ static int binlog_close_connection(handlerton *hton, THD *thd) contain updates to non-transactional tables. Or it can be a flush of a statement cache. */ + static int binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr, Log_event *end_ev, bool all, bool using_stmt, @@ -1686,6 +1687,7 @@ binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr, { int error= 0; DBUG_ENTER("binlog_flush_cache"); + DBUG_PRINT("enter", ("end_ev: %p", end_ev)); if ((using_stmt && !cache_mngr->stmt_cache.empty()) || (using_trx && !cache_mngr->trx_cache.empty())) @@ -1744,9 +1746,10 @@ static inline int binlog_commit_flush_stmt_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr) { + DBUG_ENTER("binlog_commit_flush_stmt_cache"); Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), FALSE, TRUE, TRUE, 0); - return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE)); + DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, TRUE, FALSE)); } /** @@ -1761,9 +1764,10 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all, static inline int binlog_commit_flush_trx_cache(THD *thd, bool all, binlog_cache_mngr *cache_mngr) { + DBUG_ENTER("binlog_commit_flush_trx_cache"); Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, TRUE, 0); - return (binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE)); + DBUG_RETURN(binlog_flush_cache(thd, cache_mngr, &end_evt, all, FALSE, TRUE)); } /** @@ -5270,6 +5274,10 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional, (long) table, table->s->table_name.str, table->s->table_map_id)); + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_transactional= 1; + /* Pre-conditions */ DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open()); DBUG_ASSERT(table->s->table_map_id != ULONG_MAX); @@ -5287,7 +5295,7 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional, cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional)); if (with_annotate && *with_annotate) { - Annotate_rows_log_event anno(current_thd, is_transactional, false); + Annotate_rows_log_event anno(table->in_use, is_transactional, false); /* Annotate event should be written not more than once */ *with_annotate= 0; if ((error= anno.write(file))) @@ -5450,6 +5458,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, /* Generate a new global transaction ID, and write it to the binlog */ + bool MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, bool is_transactional, uint64 commit_id) @@ -5459,6 +5468,16 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, uint32 server_id= thd->variables.server_id; uint64 seq_no= thd->variables.gtid_seq_no; int err; + DBUG_ENTER("write_gtid_event"); + DBUG_PRINT("enter", ("standalone: %d", standalone)); + + if (thd->variables.option_bits & OPTION_GTID_BEGIN) + { + DBUG_PRINT("error", ("OPTION_GTID_BEGIN is set. " + "Master and slave will have different GTID values")); + /* Reset the flag, as we will write out a GTID anyway */ + thd->variables.option_bits&= ~OPTION_GTID_BEGIN; + } /* Reset the session variable gtid_seq_no, to reduce the risk of accidentally @@ -5483,7 +5502,7 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, seq_no= gtid.seq_no; } if (err) - return true; + DBUG_RETURN(true); Gtid_log_event gtid_event(thd, seq_no, domain_id, standalone, LOG_EVENT_SUPPRESS_USE_F, is_transactional, @@ -5491,10 +5510,10 @@ MYSQL_BIN_LOG::write_gtid_event(THD *thd, bool standalone, /* Write the event to the binary log. */ if (gtid_event.write(&mysql_bin_log.log_file)) - return true; + DBUG_RETURN(true); status_var_add(thd->status_var.binlog_bytes_written, gtid_event.data_written); - return false; + DBUG_RETURN(false); } @@ -5676,14 +5695,22 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) { THD *thd= event_info->thd; bool error= 1; - DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)"); binlog_cache_data *cache_data= 0; bool is_trans_cache= FALSE; bool using_trans= event_info->use_trans_cache(); bool direct= event_info->use_direct_logging(); ulong prev_binlog_id; + DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)"); LINT_INIT(prev_binlog_id); + if (thd->variables.option_bits & OPTION_GTID_BEGIN) + { + DBUG_PRINT("info", ("OPTION_GTID_BEGIN was set")); + /* Wait for commit from binary log before we commit */ + direct= 0; + using_trans= 1; + } + if (thd->binlog_evt_union.do_union) { /* @@ -5731,6 +5758,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info, my_bool *with_annotate) if (direct) { + DBUG_PRINT("info", ("direct is set")); file= &log_file; my_org_b_tell= my_b_tell(file); mysql_mutex_lock(&LOCK_log); @@ -7249,16 +7277,17 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry, uint64 commit_id) { binlog_cache_mngr *mngr= entry->cache_mngr; + DBUG_ENTER("MYSQL_BIN_LOG::write_transaction_or_stmt"); if (write_gtid_event(entry->thd, false, entry->using_trx_cache, commit_id)) - return ER_ERROR_ON_WRITE; + DBUG_RETURN(ER_ERROR_ON_WRITE); if (entry->using_stmt_cache && !mngr->stmt_cache.empty() && write_cache(entry->thd, mngr->get_binlog_cache_log(FALSE))) { entry->error_cache= &mngr->stmt_cache.cache_log; entry->commit_errno= errno; - return ER_ERROR_ON_WRITE; + DBUG_RETURN(ER_ERROR_ON_WRITE); } if (entry->using_trx_cache && !mngr->trx_cache.empty()) @@ -7279,7 +7308,7 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry, { entry->error_cache= &mngr->trx_cache.cache_log; entry->commit_errno= errno; - return ER_ERROR_ON_WRITE; + DBUG_RETURN(ER_ERROR_ON_WRITE); } } @@ -7287,7 +7316,7 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry, { entry->error_cache= NULL; entry->commit_errno= errno; - return ER_ERROR_ON_WRITE; + DBUG_RETURN(ER_ERROR_ON_WRITE); } status_var_add(entry->thd->status_var.binlog_bytes_written, entry->end_event->data_written); @@ -7298,7 +7327,7 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry, { entry->error_cache= NULL; entry->commit_errno= errno; - return ER_ERROR_ON_WRITE; + DBUG_RETURN(ER_ERROR_ON_WRITE); } } @@ -7306,16 +7335,16 @@ MYSQL_BIN_LOG::write_transaction_or_stmt(group_commit_entry *entry, { entry->error_cache= &mngr->stmt_cache.cache_log; entry->commit_errno= errno; - return ER_ERROR_ON_READ; + DBUG_RETURN(ER_ERROR_ON_WRITE); } if (mngr->get_binlog_cache_log(TRUE)->error) // Error on read { entry->error_cache= &mngr->trx_cache.cache_log; entry->commit_errno= errno; - return ER_ERROR_ON_READ; + DBUG_RETURN(ER_ERROR_ON_WRITE); } - return 0; + DBUG_RETURN(0); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 7f0933792be..4cebcb97461 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3984,6 +3984,8 @@ bool test_if_equal_repl_errors(int expected_error, int actual_error) case ER_AUTOINC_READ_FAILED: return (actual_error == ER_AUTOINC_READ_FAILED || actual_error == HA_ERR_AUTOINC_ERANGE); + case ER_UNKNOWN_TABLE: + return actual_error == ER_IT_IS_A_VIEW; default: break; } @@ -4018,6 +4020,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, rpl_gtid gtid; Relay_log_info const *rli= rgi->rli; Rpl_filter *rpl_filter= rli->mi->rpl_filter; + bool current_stmt_is_commit; DBUG_ENTER("Query_log_event::do_apply_event"); /* @@ -4044,7 +4047,9 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos)); clear_all_errors(thd, const_cast(rli)); - if (strcmp("COMMIT", query) == 0 && rgi->tables_to_lock) + current_stmt_is_commit= is_commit(); + + if (current_stmt_is_commit && rgi->tables_to_lock) { /* Cleaning-up the last statement context: @@ -4093,9 +4098,11 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, thd->variables.pseudo_thread_id= thread_id; // for temp tables DBUG_PRINT("query",("%s", thd->query())); - if (ignored_error_code((expected_error= error_code)) || - !unexpected_error_code(expected_error)) + if (!(expected_error= error_code) || + ignored_error_code(expected_error) || + !unexpected_error_code(expected_error)) { + thd->slave_expected_error= expected_error; if (flags2_inited) /* all bits of thd->variables.option_bits which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG @@ -4197,12 +4204,13 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, Record any GTID in the same transaction, so slave state is transactionally consistent. */ - if (strcmp("COMMIT", query) == 0 && (sub_id= rgi->gtid_sub_id)) + if (current_stmt_is_commit && (sub_id= rgi->gtid_sub_id)) { /* Clear the GTID from the RLI so we don't accidentally reuse it. */ rgi->gtid_sub_id= 0; gtid= rgi->current_gtid; + thd->variables.option_bits&= ~OPTION_GTID_BEGIN; if (rpl_global_gtid_slave_state.record_gtid(thd, >id, sub_id, true, false)) { rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, @@ -4232,6 +4240,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi, concurrency_error_code(expected_error))) { thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR; + thd->variables.option_bits&= ~OPTION_GTID_BEGIN; } /* Execute the query (note that we bypass dispatch_command()) */ Parser_state parser_state; @@ -4395,8 +4404,7 @@ Default database: '%s'. Query: '%s'", to shutdown trying to finish incomplete events group. */ DBUG_EXECUTE_IF("stop_slave_middle_group", - if (strcmp("COMMIT", query) != 0 && - strcmp("BEGIN", query) != 0) + if (!current_stmt_is_commit && is_begin() == 0) { if (thd->transaction.all.modified_non_trans_table) const_cast(rli)->abort_slave= 1; @@ -4457,7 +4465,7 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) { Relay_log_info *rli= rgi->rli; DBUG_ENTER("Query_log_event::do_shall_skip"); - DBUG_PRINT("debug", ("query: %s; q_len: %d", query, q_len)); + DBUG_PRINT("debug", ("query: '%s' q_len: %d", query, q_len)); DBUG_ASSERT(query && q_len > 0); DBUG_ASSERT(thd == rgi->thd); @@ -4473,13 +4481,13 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) { if (is_begin()) { - thd->variables.option_bits|= OPTION_BEGIN; + thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN; DBUG_RETURN(Log_event::continue_group(rgi)); } if (is_commit() || is_rollback()) { - thd->variables.option_bits&= ~OPTION_BEGIN; + thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN); DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } } @@ -5906,6 +5914,7 @@ error: thd->reset_query(); thd->get_stmt_da()->set_overwrite_status(true); thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN); thd->get_stmt_da()->set_overwrite_status(false); close_thread_tables(thd); /* @@ -6408,8 +6417,7 @@ Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event, { if (*need_dummy_event) return Query_log_event::dummy_event(packet, ev_offset, checksum_alg); - else - return 0; + return 0; } *need_dummy_event= true; @@ -6456,10 +6464,16 @@ Gtid_log_event::do_apply_event(rpl_group_info *rgi) this->server_id, this->seq_no)) return 1; } + + DBUG_ASSERT((thd->variables.option_bits & OPTION_GTID_BEGIN) == 0); if (flags2 & FL_STANDALONE) return 0; /* Execute this like a BEGIN query event. */ + thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN; + DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN")); + trans_begin(thd, 0); + thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1, &my_charset_bin, next_query_id()); Parser_state parser_state; @@ -7252,6 +7266,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi) /* For a slave Xid_log_event is COMMIT */ general_log_print(thd, COM_QUERY, "COMMIT /* implicit, from Xid_log_event */"); + thd->variables.option_bits&= ~OPTION_GTID_BEGIN; res= trans_commit(thd); /* Automatically rolls back on error. */ thd->mdl_context.release_transactional_locks(); @@ -7273,7 +7288,7 @@ Xid_log_event::do_shall_skip(rpl_group_info *rgi) if (rgi->rli->slave_skip_counter > 0) { DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION)); - thd->variables.option_bits&= ~OPTION_BEGIN; + thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN); DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } DBUG_RETURN(Log_event::do_shall_skip(rgi)); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index a52251462b1..484ff18eb32 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -479,6 +479,7 @@ ulong open_files_limit, max_binlog_size; ulong slave_trans_retries; uint slave_net_timeout; ulong slave_exec_mode_options; +ulong slave_ddl_exec_mode_options= SLAVE_EXEC_MODE_IDEMPOTENT; ulonglong slave_type_conversions_options; ulong thread_cache_size=0; ulonglong binlog_cache_size=0; diff --git a/sql/mysqld.h b/sql/mysqld.h index 12b5d857e6e..119e30e6b77 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -96,7 +96,7 @@ extern uint connection_count; extern my_bool opt_safe_user_create; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; -extern ulong slave_exec_mode_options; +extern ulong slave_exec_mode_options, slave_ddl_exec_mode_options; extern ulong slave_retried_transactions; extern ulonglong slave_type_conversions_options; extern my_bool read_only, opt_readonly; diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 3f79a0cb528..a36a15b3c27 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -352,7 +352,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, { DBUG_PRINT("info", ("resetting OPTION_BEGIN")); thd->variables.option_bits&= - ~(ulonglong)(OPTION_NOT_AUTOCOMMIT|OPTION_BEGIN|OPTION_BIN_LOG); + ~(ulonglong)(OPTION_NOT_AUTOCOMMIT |OPTION_BEGIN |OPTION_BIN_LOG | + OPTION_GTID_BEGIN); } else thd->variables.option_bits&= ~(ulonglong)OPTION_BIN_LOG; diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 9036f810020..48494401fda 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1583,6 +1583,7 @@ void rpl_group_info::cleanup_context(THD *thd, bool error) if (error) { trans_rollback_stmt(thd); // if a "statement transaction" + /* trans_rollback() also resets OPTION_GTID_BEGIN */ trans_rollback(thd); // if a "real transaction" } m_table_map.clear_tables(); diff --git a/sql/slave.cc b/sql/slave.cc index 6886a6345ab..0c321f29c77 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3125,9 +3125,10 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, DBUG_PRINT("exec_event",("%s(type_code: %d; server_id: %d)", ev->get_type_str(), ev->get_type_code(), ev->server_id)); - DBUG_PRINT("info", ("thd->options: %s%s; rgi->last_event_start_time: %lu", + DBUG_PRINT("info", ("thd->options: '%s%s%s' rgi->last_event_start_time: %lu", FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT), FLAGSTR(thd->variables.option_bits, OPTION_BEGIN), + FLAGSTR(thd->variables.option_bits, OPTION_GTID_BEGIN), (ulong) rgi->last_event_start_time)); /* diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d1c3bc25210..9e3ce76af98 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5389,6 +5389,10 @@ THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id, /* Fetch the type code for the RowsEventT template parameter */ int const general_type_code= RowsEventT::TYPE_CODE; + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_transactional= 1; + /* There is no good place to set up the transactional data, so we have to do it here. @@ -5584,6 +5588,10 @@ int THD::binlog_write_row(TABLE* table, bool is_trans, size_t const len= pack_row(table, cols, row_data, record); + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_trans= 1; + Rows_log_event* const ev= binlog_prepare_pending_rows_event(table, variables.server_id, cols, colcnt, len, is_trans, @@ -5617,6 +5625,10 @@ int THD::binlog_update_row(TABLE* table, bool is_trans, size_t const after_size= pack_row(table, cols, after_row, after_record); + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_trans= 1; + /* Don't print debug messages when running valgrind since they can trigger false warnings. @@ -5659,6 +5671,10 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans, size_t const len= pack_row(table, cols, row_data, record); + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_trans= 1; + Rows_log_event* const ev= binlog_prepare_pending_rows_event(table, variables.server_id, cols, colcnt, len, is_trans, @@ -5679,6 +5695,10 @@ int THD::binlog_remove_pending_rows_event(bool clear_maps, if (!mysql_bin_log.is_open()) DBUG_RETURN(0); + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_transactional= 1; + mysql_bin_log.remove_pending_rows_event(this, is_transactional); if (clear_maps) @@ -5698,6 +5718,10 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) if (!mysql_bin_log.is_open()) DBUG_RETURN(0); + /* Ensure that all events in a GTID group are in the same cache */ + if (variables.option_bits & OPTION_GTID_BEGIN) + is_transactional= 1; + /* Mark the event as the last event of a statement if the stmt_end flag is set. @@ -5945,6 +5969,14 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, show_query_type(qtype), (int) query_len, query_arg)); DBUG_ASSERT(query_arg && mysql_bin_log.is_open()); + /* If this is withing a BEGIN ... COMMIT group, don't log it */ + if (variables.option_bits & OPTION_GTID_BEGIN) + { + direct= 0; + is_trans= 1; + } + DBUG_PRINT("info", ("is_trans: %d direct: %d", is_trans, direct)); + if (get_binlog_local_stmt_filter() == BINLOG_FILTER_SET) { /* diff --git a/sql/sql_class.h b/sql/sql_class.h index 14f58b30f3c..f00b005b470 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1951,7 +1951,10 @@ public: uint in_sub_stmt; /* True when opt_userstat_running is set at start of query */ bool userstat_running; - /* True if we want to log all errors */ + /* + True if we have to log all errors. Are set by some engines to temporary + force errors to the error log. + */ bool log_all_errors; /* Do not set socket timeouts for wait_timeout (used with threadpool) */ @@ -2542,12 +2545,12 @@ public: */ LEX_STRING connection_name; char default_master_connection_buff[MAX_CONNECTION_NAME+1]; + uint8 password; /* 0, 1 or 2 */ + uint8 failed_com_change_user; bool slave_thread, one_shot_set; bool extra_port; /* If extra connection */ bool no_errors; - uint8 password; - uint8 failed_com_change_user; /** Set to TRUE if execution of the current compound statement @@ -2580,13 +2583,6 @@ public: /* for IS NULL => = last_insert_id() fix in remove_eq_conds() */ bool substitute_null_with_insert_id; bool in_lock_tables; - /** - True if a slave error. Causes the slave to stop. Not the same - as the statement execution error (is_error()), since - a statement may be expected to return an error, e.g. because - it returned an error on master, and this is OK on the slave. - */ - bool is_slave_error; bool bootstrap, cleanup_done; /** is set if some thread specific value(s) used in a statement. */ @@ -2603,6 +2599,20 @@ public: /* set during loop of derived table processing */ bool derived_tables_processing; bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ + /* True if we have to log the current statement */ + bool log_current_statement; + /** + True if a slave error. Causes the slave to stop. Not the same + as the statement execution error (is_error()), since + a statement may be expected to return an error, e.g. because + it returned an error on master, and this is OK on the slave. + */ + bool is_slave_error; + /* + In case of a slave, set to the error code the master got when executing + the query. 0 if no error on the master. + */ + int slave_expected_error; sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 719e0bae4ff..cdfa9f516f9 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3794,7 +3794,8 @@ void select_insert::abort_result_set() { */ changed= (info.copied || info.deleted || info.updated); transactional_table= table->file->has_transactions(); - if (thd->transaction.stmt.modified_non_trans_table) + if (thd->transaction.stmt.modified_non_trans_table || + thd->log_current_statement) { if (!can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; @@ -4200,7 +4201,9 @@ select_create::binlog_show_create_table(TABLE **tables, uint count) query.length(0); // Have to zero it since constructor doesn't result= store_create_info(thd, &tmp_table_list, &query, create_info, - /* show_database */ TRUE); + /* show_database */ TRUE, + test(create_info->options & + HA_LEX_CREATE_REPLACE)); DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */ if (mysql_bin_log.is_open()) @@ -4270,7 +4273,8 @@ bool select_create::send_eof() if (!table->s->tmp_table) { trans_commit_stmt(thd); - trans_commit_implicit(thd); + if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) + trans_commit_implicit(thd); } table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); @@ -4307,6 +4311,7 @@ bool select_create::send_eof() void select_create::abort_result_set() { + ulonglong save_option_bits; DBUG_ENTER("select_create::abort_result_set"); /* Avoid double calls, could happen in case of out of memory on cleanup */ @@ -4328,11 +4333,18 @@ void select_create::abort_result_set() We also roll back the statement regardless of whether the creation of the table succeeded or not, since we need to reset the binary log state. + + However if there was an orignal table that was deleted, as part of + create or replace table, then we must log the statement. */ - tmp_disable_binlog(thd); + + save_option_bits= thd->variables.option_bits; + if (!(thd->log_current_statement)) + thd->variables.option_bits&= ~OPTION_BIN_LOG; select_insert::abort_result_set(); thd->transaction.stmt.modified_non_trans_table= FALSE; - reenable_binlog(thd); + thd->variables.option_bits= save_option_bits; + /* possible error of writing binary log is ignored deliberately */ (void) thd->binlog_flush_pending_rows_event(TRUE, TRUE); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0d0f1a2634f..8ce2225e731 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -195,6 +195,8 @@ static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) @param thd Thread handle. @param mask Bitmask used for the SQL command match. + @return 0 No implicit commit + @return 1 Do a commit */ static bool stmt_causes_implicit_commit(THD *thd, uint mask) { @@ -207,12 +209,22 @@ static bool stmt_causes_implicit_commit(THD *thd, uint mask) switch (lex->sql_command) { case SQLCOM_DROP_TABLE: - skip= lex->drop_temporary; + skip= (lex->drop_temporary || + (thd->variables.option_bits & OPTION_GTID_BEGIN)); break; case SQLCOM_ALTER_TABLE: + /* If ALTER TABLE of non-temporary table, do implicit commit */ + skip= (lex->create_info.tmp_table()); + break; case SQLCOM_CREATE_TABLE: - /* If CREATE TABLE of non-temporary table, do implicit commit */ - skip= lex->create_info.tmp_table(); + /* + If CREATE TABLE of non-temporary table and the table is not part + if a BEGIN GTID ... COMMIT group, do a implicit commit. + This ensures that CREATE ... SELECT will in the same GTID group on the + master and slave. + */ + skip= (lex->create_info.tmp_table() || + (thd->variables.option_bits & OPTION_GTID_BEGIN)); break; case SQLCOM_SET_OPTION: skip= lex->autocommit ? FALSE : TRUE; @@ -2439,11 +2451,14 @@ mysql_execute_command(THD *thd) DBUG_ASSERT(! thd->in_sub_stmt); /* Statement transaction still should not be started. */ DBUG_ASSERT(thd->transaction.stmt.is_empty()); - /* Commit the normal transaction if one is active. */ - if (trans_commit_implicit(thd)) - goto error; - /* Release metadata locks acquired in this transaction. */ - thd->mdl_context.release_transactional_locks(); + if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) + { + /* Commit the normal transaction if one is active. */ + if (trans_commit_implicit(thd)) + goto error; + /* Release metadata locks acquired in this transaction. */ + thd->mdl_context.release_transactional_locks(); + } } #ifndef DBUG_OFF @@ -2869,6 +2884,17 @@ case SQLCOM_PREPARE: */ lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB; + /* + If we are a slave, we should add OR REPLACE if we don't have + IF EXISTS. This will help a slave to recover from + CREATE TABLE OR EXISTS failures by dropping the table and + retrying the create. + */ + if (thd->slave_thread && + slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT && + !(lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)) + create_info.options|= HA_LEX_CREATE_REPLACE; + #ifdef WITH_PARTITION_STORAGE_ENGINE { partition_info *part_info= thd->lex->part_info; @@ -3659,6 +3685,16 @@ end_with_restore_list: /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ thd->variables.option_bits|= OPTION_KEEP_LOG; } + /* + If we are a slave, we should add IF EXISTS if the query executed + on the master without an error. This will help a slave to + recover from multi-table DROP TABLE that was aborted in the + middle. + */ + if (thd->slave_thread && !thd->slave_expected_error && + slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT) + lex->check_exists= 1; + /* DDL and binlog write order are protected by metadata locks. */ res= mysql_rm_table(thd, first_table, lex->check_exists, lex->drop_temporary); @@ -4407,6 +4443,7 @@ end_with_restore_list: bool tx_release= (lex->tx_release == TVL_YES || (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO)); + if (trans_rollback(thd)) goto error; thd->mdl_context.release_transactional_locks(); @@ -5158,12 +5195,15 @@ finish: { /* No transaction control allowed in sub-statements. */ DBUG_ASSERT(! thd->in_sub_stmt); - /* If commit fails, we should be able to reset the OK status. */ - thd->get_stmt_da()->set_overwrite_status(true); - /* Commit the normal transaction if one is active. */ - trans_commit_implicit(thd); - thd->get_stmt_da()->set_overwrite_status(false); - thd->mdl_context.release_transactional_locks(); + if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) + { + /* If commit fails, we should be able to reset the OK status. */ + thd->get_stmt_da()->set_overwrite_status(true); + /* Commit the normal transaction if one is active. */ + trans_commit_implicit(thd); + thd->get_stmt_da()->set_overwrite_status(false); + thd->mdl_context.release_transactional_locks(); + } } else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) { @@ -6106,6 +6146,8 @@ void THD::reset_for_next_command() thd->query_start_used= 0; thd->query_start_sec_part_used= 0; thd->is_fatal_error= thd->time_zone_used= 0; + thd->log_current_statement= 0; + /* Clear the status flag that are expected to be cleared at the beginning of each SQL statement. diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 383888bac30..5e3b80ab7a9 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -110,6 +110,8 @@ /* The following is used to detect a conflict with DISTINCT */ #define SELECT_ALL (1ULL << 24) // SELECT, user, parser +#define OPTION_GTID_BEGIN (1ULL << 25) // GTID BEGIN found in log + /** The following can be set when importing tables in a 'wrong order' to suppress foreign key checks */ #define OPTION_NO_FOREIGN_KEY_CHECKS (1ULL << 26) // THD, user, binlog diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bcbe544b99c..53c98cf0d38 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1041,7 +1041,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if ((table_list->view ? view_store_create_info(thd, table_list, &buffer) : store_create_info(thd, table_list, &buffer, NULL, - FALSE /* show_database */))) + FALSE /* show_database */, FALSE))) goto exit; if (table_list->view) @@ -1526,6 +1526,8 @@ static void append_create_options(THD *thd, String *packet, to tailor the format of the statement. Can be NULL, in which case only SQL_MODE is considered when building the statement. + show_database Add database name to table name + create_or_replace Use CREATE OR REPLACE syntax NOTE Currently always return 0, but might return error code in the @@ -1536,7 +1538,8 @@ static void append_create_options(THD *thd, String *packet, */ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, - HA_CREATE_INFO *create_info_arg, bool show_database) + HA_CREATE_INFO *create_info_arg, bool show_database, + bool create_or_replace) { List field_list; char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], def_value_buf[MAX_FIELD_WIDTH]; @@ -1569,10 +1572,12 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, restore_record(table, s->default_values); // Get empty record + packet->append(STRING_WITH_LEN("CREATE ")); + if (create_or_replace) + packet->append(STRING_WITH_LEN("OR REPLACE ")); if (share->tmp_table) - packet->append(STRING_WITH_LEN("CREATE TEMPORARY TABLE ")); - else - packet->append(STRING_WITH_LEN("CREATE TABLE ")); + packet->append(STRING_WITH_LEN("TEMPORARY ")); + packet->append(STRING_WITH_LEN("TABLE ")); if (create_info_arg && (create_info_arg->options & HA_LEX_CREATE_IF_NOT_EXISTS)) packet->append(STRING_WITH_LEN("IF NOT EXISTS ")); diff --git a/sql/sql_show.h b/sql/sql_show.h index 10276e8b65e..0416f2fdaba 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -75,7 +75,8 @@ typedef struct system_status_var STATUS_VAR; #define IS_FILES_EXTRA 37 int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, - HA_CREATE_INFO *create_info_arg, bool show_database); + HA_CREATE_INFO *create_info_arg, bool show_database, + bool create_or_replace); int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff); int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 817823063eb..67d6795ecce 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4620,6 +4620,14 @@ int create_table_impl(THD *thd, /* Remove normal table without logging. Keep tables locked */ if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1, 1)) goto err; + + /* + We have to log this query, even if it failed later to ensure the + drop is done. + */ + thd->variables.option_bits|= OPTION_KEEP_LOG; + thd->log_current_statement= 1; + /* The test of query_tables is to ensure we have any tables in the select part @@ -4627,11 +4635,6 @@ int create_table_impl(THD *thd, if (thd->lex->query_tables && restart_trans_for_tables(thd, thd->lex->query_tables->next_global)) goto err; - /* - We have to log this query, even if it failed later to ensure the - drop is done. - */ - thd->variables.option_bits|= OPTION_KEEP_LOG; } else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) goto warn; @@ -4832,6 +4835,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, const char *db= create_table->db; const char *table_name= create_table->table_name; bool is_trans= FALSE; + bool result= 0; int create_table_mode; TABLE_LIST *pos_in_locked_tables= 0; DBUG_ENTER("mysql_create_table"); @@ -4859,7 +4863,10 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, promote_first_timestamp_column(&alter_info->create_list); if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info, &is_trans, create_table_mode) > 0) - DBUG_RETURN(1); + { + result= 1; + goto err; + } /* Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES @@ -4877,12 +4884,15 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); } +err: /* In RBR we don't need to log CREATE TEMPORARY TABLE */ if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) - DBUG_RETURN(0); - - bool result; - result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans); + DBUG_RETURN(result); + /* Write log if no error or if we already deleted a table */ + if (!result || thd->log_current_statement) + if (write_bin_log(thd, result ? FALSE : TRUE, thd->query(), + thd->query_length(), is_trans)) + result= 1; DBUG_RETURN(result); } @@ -5079,6 +5089,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, Alter_table_ctx local_alter_ctx; // Not used bool res= TRUE; bool is_trans= FALSE; + bool do_logging= FALSE; uint not_used; DBUG_ENTER("mysql_create_like_table"); @@ -5155,9 +5166,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, if ((local_create_info.table= thd->lex->query_tables->table)) pos_in_locked_tables= local_create_info.table->pos_in_locked_tables; - if ((res= (mysql_create_table_no_lock(thd, table->db, table->table_name, - &local_create_info, &local_alter_info, - &is_trans, C_ORDINARY_CREATE) > 0))) + res= (mysql_create_table_no_lock(thd, table->db, table->table_name, + &local_create_info, &local_alter_info, + &is_trans, C_ORDINARY_CREATE) > 0); + /* Remember to log if we deleted something */ + do_logging= thd->log_current_statement; + if (res) goto err; /* @@ -5252,7 +5266,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, /* Restore */ table->open_strategy= save_open_strategy; if (open_res) + { + res= 1; goto err; + } new_table= TRUE; } } @@ -5264,11 +5281,17 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, { int result __attribute__((unused))= store_create_info(thd, table, &query, - create_info, FALSE /* show_database */); + create_info, FALSE /* show_database */, + test(create_info->options & + HA_LEX_CREATE_REPLACE)); DBUG_ASSERT(result == 0); // store_create_info() always return 0 + do_logging= FALSE; if (write_bin_log(thd, TRUE, query.ptr(), query.length())) + { + res= 1; goto err; + } if (new_table) { @@ -5283,17 +5306,20 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, } } else // Case 1 - if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) - goto err; + do_logging= TRUE; } /* Case 3 and 4 does nothing under RBR */ } - else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans)) - goto err; + else + do_logging= TRUE; err: + if (do_logging && + write_bin_log(thd, res ? FALSE : TRUE, thd->query(), + thd->query_length(), is_trans)) + res= 1; DBUG_RETURN(res); } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 864808cff32..5800fab8d4a 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2601,11 +2601,23 @@ static Sys_var_enum Slave_exec_mode( "Modes for how replication events should be executed. Legal values " "are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode, " "replication will not stop for operations that are idempotent. " + "For example, in row based replication attempts to delete rows that " + "doesn't exist will be ignored." "In STRICT mode, replication will stop on any unexpected difference " "between the master and the slave", GLOBAL_VAR(slave_exec_mode_options), CMD_LINE(REQUIRED_ARG), slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_STRICT)); +static Sys_var_enum Slave_ddl_exec_mode( + "slave_ddl_exec_mode", + "Modes for how replication events should be executed. Legal values " + "are STRICT and IDEMPOTENT (default). In IDEMPOTENT mode, " + "replication will not stop for DDL operations that are idempotent. " + "This means that CREATE TABLE is treated CREATE TABLE OR REPLACE and " + "DROP TABLE is threated as DROP TABLE IF EXISTS. ", + GLOBAL_VAR(slave_ddl_exec_mode_options), CMD_LINE(REQUIRED_ARG), + slave_exec_mode_names, DEFAULT(SLAVE_EXEC_MODE_IDEMPOTENT)); + static const char *slave_type_conversions_name[]= {"ALL_LOSSY", "ALL_NON_LOSSY", 0}; static Sys_var_set Slave_type_conversions( "slave_type_conversions", @@ -3174,10 +3186,10 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) return false; } - if (thd->variables.option_bits & OPTION_AUTOCOMMIT && - thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT) - { // activating autocommit - + if (test_all_bits(thd->variables.option_bits, + (OPTION_AUTOCOMMIT | OPTION_NOT_AUTOCOMMIT))) + { + // activating autocommit if (trans_commit_stmt(thd) || trans_commit(thd)) { thd->variables.option_bits&= ~OPTION_AUTOCOMMIT; @@ -3194,16 +3206,17 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) transaction implicitly at the end (@sa stmt_causes_implicitcommit()). */ thd->variables.option_bits&= - ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_NOT_AUTOCOMMIT); + ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_NOT_AUTOCOMMIT | + OPTION_GTID_BEGIN); thd->transaction.all.modified_non_trans_table= false; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; return false; } - if (!(thd->variables.option_bits & OPTION_AUTOCOMMIT) && - !(thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT)) - { // disabling autocommit - + if ((thd->variables.option_bits & + (OPTION_AUTOCOMMIT |OPTION_NOT_AUTOCOMMIT)) == 0) + { + // disabling autocommit thd->transaction.all.modified_non_trans_table= false; thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT; thd->variables.option_bits|= OPTION_NOT_AUTOCOMMIT; @@ -3212,6 +3225,7 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) return false; // autocommit value wasn't changed } + static Sys_var_bit Sys_autocommit( "autocommit", "autocommit", SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_AUTOCOMMIT, DEFAULT(TRUE), diff --git a/sql/transaction.cc b/sql/transaction.cc index 256351ee373..213b6c1a4d8 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -251,6 +251,10 @@ bool trans_commit_implicit(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); + if (thd->variables.option_bits & OPTION_GTID_BEGIN) + DBUG_PRINT("error", ("OPTION_GTID_BEGIN is set. " + "Master and slave will have different GTID values")); + if (thd->in_multi_stmt_transaction_mode() || (thd->variables.option_bits & OPTION_TABLE_LOCK)) { @@ -302,6 +306,8 @@ bool trans_rollback(THD *thd) res= ha_rollback_trans(thd, TRUE); (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); + /* Reset the binlog transaction marker */ + thd->variables.option_bits&= ~OPTION_GTID_BEGIN; thd->transaction.all.modified_non_trans_table= FALSE; thd->lex->start_transaction_opt= 0; -- cgit v1.2.1